fzeet 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/examples/Command.rbw +29 -1
- data/examples/LifeCycle1.rbw +2 -2
- data/examples/LifeCycleNC.rbw +30 -0
- data/examples/Menu/Menu.rbw +48 -0
- data/examples/Minimal.rbw +3 -1
- data/examples/Raw/Command.rbw +1 -1
- data/examples/Raw/LifeCycle.rbw +1 -1
- data/examples/Raw/Minimal.rbw +1 -1
- data/lib/fzeet/Accelerator.rb +21 -0
- data/lib/fzeet/Application.rb +17 -11
- data/lib/fzeet/Control.rb +54 -1
- data/lib/fzeet/Menu.rb +82 -0
- data/lib/fzeet/Window.rb +42 -3
- data/lib/fzeet/WindowMethods.rb +49 -0
- data/lib/fzeet/common.rb +51 -1
- data/lib/fzeet/windows/gdi.rb +2 -0
- data/lib/fzeet/windows/kernel.rb +0 -10
- data/lib/fzeet/windows/user.rb +56 -0
- data/lib/fzeet/windows.rb +10 -0
- metadata +7 -4
data/examples/Command.rbw
CHANGED
@@ -2,4 +2,32 @@ require 'fzeet'
|
|
2
2
|
|
3
3
|
include Fzeet
|
4
4
|
|
5
|
-
|
5
|
+
Application.run { |window|
|
6
|
+
window.
|
7
|
+
on(:create) {
|
8
|
+
window.menu = Menu.new.
|
9
|
+
append(:popup, 'Menu&1', PopupMenu.new.
|
10
|
+
append(:string, "Item&1\tAlt+I", :item1)
|
11
|
+
)
|
12
|
+
|
13
|
+
Application.accelerators << AcceleratorTable.new(
|
14
|
+
[:alt, :I, :item1]
|
15
|
+
)
|
16
|
+
|
17
|
+
Button.new(window, :button1, x: 10, y: 10, width: 76, height: 24)
|
18
|
+
}.
|
19
|
+
|
20
|
+
on(:command, :item1) {
|
21
|
+
message 'on(:command, :item1)'
|
22
|
+
|
23
|
+
window[:button1].enabled = true
|
24
|
+
window.menu[:item1].enabled = false
|
25
|
+
}.
|
26
|
+
|
27
|
+
on(:command, :button1) { |args|
|
28
|
+
message 'on(:command, :button1)'
|
29
|
+
|
30
|
+
window.menu[:item1].enabled = true
|
31
|
+
args[:sender].enabled = false
|
32
|
+
}
|
33
|
+
}
|
data/examples/LifeCycle1.rbw
CHANGED
@@ -15,11 +15,11 @@ class LifeCycle1Window < Window
|
|
15
15
|
args[:result] = -1 if question('Create?').no?
|
16
16
|
end
|
17
17
|
|
18
|
-
def onClose
|
18
|
+
def onClose
|
19
19
|
dispose if question('Close?', buttons: [:yes, :No]).yes?
|
20
20
|
end
|
21
21
|
|
22
|
-
def onDestroy
|
22
|
+
def onDestroy
|
23
23
|
message __method__
|
24
24
|
end
|
25
25
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'fzeet'
|
2
|
+
|
3
|
+
include Fzeet
|
4
|
+
|
5
|
+
Application.quitWhenMainWindowCloses = false
|
6
|
+
|
7
|
+
Application.run { |window|
|
8
|
+
window.
|
9
|
+
on(:nccreate) { |args|
|
10
|
+
args[:result] = 0 if question('NCCreate?').no?
|
11
|
+
}.
|
12
|
+
|
13
|
+
on(:create) { |args|
|
14
|
+
args[:result] = -1 if question('Create?').no?
|
15
|
+
}.
|
16
|
+
|
17
|
+
on(:close) {
|
18
|
+
window.dispose if question('Close?', buttons: [:yes, :No]).yes?
|
19
|
+
}.
|
20
|
+
|
21
|
+
on(:destroy) {
|
22
|
+
message 'on(:destroy)'
|
23
|
+
}.
|
24
|
+
|
25
|
+
on(:ncdestroy) {
|
26
|
+
message 'on(:ncdestroy)'
|
27
|
+
|
28
|
+
Application.quit
|
29
|
+
}
|
30
|
+
}
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'fzeet'
|
2
|
+
|
3
|
+
include Fzeet
|
4
|
+
|
5
|
+
Application.run { |window|
|
6
|
+
window.
|
7
|
+
on(:create) {
|
8
|
+
window.menu = Menu.new.
|
9
|
+
append(:popup, 'Menu&1', PopupMenu.new.
|
10
|
+
append(:string, 'Item&1', :item1).
|
11
|
+
append([:string, :grayed], 'Item&2', :item2).
|
12
|
+
append([:string, :checked], 'Item&3', :item3).
|
13
|
+
|
14
|
+
append(:separator).
|
15
|
+
|
16
|
+
append([:string, :usecheckbitmaps, :checked], 'Item&4', :item4).
|
17
|
+
append([:string, :usecheckbitmaps], 'Item&5', :item5).
|
18
|
+
|
19
|
+
append(:separator).
|
20
|
+
|
21
|
+
append(:popup, 'Menu&2', PopupMenu.new.
|
22
|
+
append([:string, :usecheckbitmaps, :checked], 'Item&6', :item6).
|
23
|
+
append([:string, :usecheckbitmaps], 'Item&7', :item7)
|
24
|
+
)
|
25
|
+
).
|
26
|
+
|
27
|
+
append(:string, 'Item&8', :item8).
|
28
|
+
|
29
|
+
append([:popup, :rightjustify], 'Menu&3', PopupMenu.new.
|
30
|
+
append(:string, 'Item&9', :item9)
|
31
|
+
)
|
32
|
+
}
|
33
|
+
|
34
|
+
window.
|
35
|
+
on(:command, :item1) { window.menu[:item2].toggle(:enabled) }.
|
36
|
+
on(:command, :item2) { message 'on(:command, :item2)' }.
|
37
|
+
on(:command, :item3) { window.menu[:item3].toggle(:checked) }
|
38
|
+
|
39
|
+
[:item4, :item5].each { |id|
|
40
|
+
window.on(:command, id) { window.menu[id].select(:item4, :item5) }
|
41
|
+
}
|
42
|
+
|
43
|
+
[:item6, :item7].each { |id|
|
44
|
+
window.on(:command, id) { window.menu[id].select(:item6, :item7) }
|
45
|
+
}
|
46
|
+
|
47
|
+
window.on(:command, :item8) { message 'on(:command, :item8)' }
|
48
|
+
}
|
data/examples/Minimal.rbw
CHANGED
data/examples/Raw/Command.rbw
CHANGED
data/examples/Raw/LifeCycle.rbw
CHANGED
@@ -38,7 +38,7 @@ WindowProc = FFI::Function.new(:long, [:pointer, :uint, :uint, :long], conventio
|
|
38
38
|
onDestroy(hwnd)
|
39
39
|
end
|
40
40
|
|
41
|
-
|
41
|
+
result || DefWindowProc(hwnd, uMsg, wParam, lParam)
|
42
42
|
}
|
43
43
|
|
44
44
|
wc = WNDCLASSEX.new
|
data/examples/Raw/Minimal.rbw
CHANGED
@@ -16,7 +16,7 @@ WindowProc = FFI::Function.new(:long, [:pointer, :uint, :uint, :long], conventio
|
|
16
16
|
onDestroy(hwnd)
|
17
17
|
end
|
18
18
|
|
19
|
-
|
19
|
+
result || DefWindowProc(hwnd, uMsg, wParam, lParam)
|
20
20
|
}
|
21
21
|
|
22
22
|
wc = WNDCLASSEX.new
|
data/lib/fzeet/Accelerator.rb
CHANGED
@@ -1,7 +1,28 @@
|
|
1
1
|
require_relative 'common'
|
2
2
|
|
3
3
|
module Fzeet
|
4
|
+
module AcceleratorTableMethods
|
5
|
+
def translate?(msg, window) Windows.TranslateAccelerator(window.handle, @handle, msg) != 0 end
|
6
|
+
end
|
7
|
+
|
4
8
|
class AcceleratorTable < Handle
|
9
|
+
include AcceleratorTableMethods
|
10
|
+
|
11
|
+
def initialize(*args)
|
12
|
+
FFI::MemoryPointer.new(Windows::ACCEL, args.size) { |paccels|
|
13
|
+
args.each_with_index { |data, i|
|
14
|
+
accel = Windows::ACCEL.new(paccels + i * Windows::ACCEL.size)
|
15
|
+
|
16
|
+
accel[:fVirt] = [*data[0]].inject(0) { |flags, flag| flags |= Windows.const_get("F#{flag.upcase}") }
|
17
|
+
accel[:fVirt] |= Windows::FVIRTKEY if data[1].kind_of?(Symbol)
|
18
|
+
accel[:key] = data[1].to_s.ord
|
19
|
+
accel[:cmd] = Command[data[2]]
|
20
|
+
}
|
21
|
+
|
22
|
+
@handle = Windows.DetonateLastError(FFI::Pointer::NULL, :CreateAcceleratorTable, paccels, args.size); attach
|
23
|
+
}
|
24
|
+
end
|
5
25
|
|
26
|
+
def dispose; Windows.DestroyAcceleratorTable(@handle); detach end
|
6
27
|
end
|
7
28
|
end
|
data/lib/fzeet/Application.rb
CHANGED
@@ -6,33 +6,39 @@ module Fzeet
|
|
6
6
|
@version = '0.1.0'
|
7
7
|
@authors = []
|
8
8
|
|
9
|
+
@quitWhenMainWindowCloses = true
|
10
|
+
|
9
11
|
@window = nil
|
12
|
+
@accelerators = []
|
10
13
|
|
11
14
|
class << self
|
12
|
-
attr_accessor :name, :version, :authors
|
13
|
-
attr_reader :window
|
15
|
+
attr_accessor :name, :version, :authors, :quitWhenMainWindowCloses
|
16
|
+
attr_reader :window, :accelerators
|
14
17
|
end
|
15
18
|
|
16
19
|
def self.run(window = nil, &block)
|
17
20
|
return 0 if (@window = window || Window.new(&block)).handle.null?
|
18
21
|
|
19
|
-
@window.on(:destroy) {
|
20
|
-
|
21
|
-
Windows.ShowWindow(@window.handle, Windows::SW_SHOWNORMAL)
|
22
|
-
Windows.UpdateWindow(@window.handle)
|
22
|
+
@window.on(:destroy) { quit } if @quitWhenMainWindowCloses
|
23
23
|
|
24
|
-
|
24
|
+
@window.show.update
|
25
25
|
|
26
|
-
|
27
|
-
raise 'GetMessage failed.' if get == -1
|
26
|
+
msg = Message.new
|
28
27
|
|
29
|
-
|
30
|
-
|
28
|
+
while msg.get!
|
29
|
+
msg.translate.dispatch unless
|
30
|
+
accelerators.any? { |table| table.translate?(msg, @window) }
|
31
31
|
end
|
32
32
|
|
33
33
|
msg[:wParam]
|
34
34
|
rescue
|
35
35
|
Fzeet.message %Q{#{$!}\n\n#{$!.backtrace.join("\n")}}, icon: :error
|
36
36
|
end
|
37
|
+
|
38
|
+
def self.quit(code = 0)
|
39
|
+
accelerators.each(&:dispose)
|
40
|
+
|
41
|
+
Windows.PostQuitMessage(code)
|
42
|
+
end
|
37
43
|
end
|
38
44
|
end
|
data/lib/fzeet/Control.rb
CHANGED
@@ -1,7 +1,60 @@
|
|
1
|
-
require_relative '
|
1
|
+
require_relative 'WindowMethods'
|
2
2
|
|
3
3
|
module Fzeet
|
4
4
|
class Control < Handle
|
5
|
+
include WindowMethods
|
5
6
|
|
7
|
+
Windows::NONCLIENTMETRICS.new.tap { |ncm|
|
8
|
+
ncm[:cbSize] = ncm.size
|
9
|
+
|
10
|
+
Windows.DetonateLastError(0, :SystemParametersInfo, Windows::SPI_GETNONCLIENTMETRICS, ncm.size, ncm, 0)
|
11
|
+
|
12
|
+
Font = IndirectFont.new(ncm[:lfMenuFont])
|
13
|
+
|
14
|
+
at_exit { Font.dispose }
|
15
|
+
}
|
16
|
+
|
17
|
+
def initialize(className, parent, id, opts = {})
|
18
|
+
@parent = parent
|
19
|
+
@id = Command[id]
|
20
|
+
|
21
|
+
_opts = {
|
22
|
+
xstyle: [],
|
23
|
+
caption: id.capitalize,
|
24
|
+
style: [:child, :visible],
|
25
|
+
x: Windows::CW_USEDEFAULT,
|
26
|
+
y: Windows::CW_USEDEFAULT,
|
27
|
+
width: Windows::CW_USEDEFAULT,
|
28
|
+
height: Windows::CW_USEDEFAULT,
|
29
|
+
}
|
30
|
+
badopts = opts.keys - _opts.keys; raise "Bad option(s): #{badopts.join(', ')}." unless badopts.empty?
|
31
|
+
_opts.merge!(opts)
|
32
|
+
|
33
|
+
_opts[:xstyle] = _opts[:xstyle].inject(0) { |flags, xstyle| flags |= Windows.const_get("WS_EX_#{xstyle.upcase}") }
|
34
|
+
_opts[:caption] = _opts[:caption].to_s
|
35
|
+
_opts[:style] = _opts[:style].inject(0) { |flags, style| flags |= Windows.const_get("WS_#{style.upcase}") }
|
36
|
+
|
37
|
+
@handle = Windows.DetonateLastError(FFI::Pointer::NULL, :CreateWindowEx,
|
38
|
+
_opts[:xstyle], className, _opts[:caption], _opts[:style],
|
39
|
+
_opts[:x], _opts[:y], _opts[:width], _opts[:height],
|
40
|
+
@parent.handle, FFI::Pointer.new(@id), Windows.GetModuleHandle(nil), nil
|
41
|
+
)
|
42
|
+
|
43
|
+
attach
|
44
|
+
|
45
|
+
sendmsg(:setfont, Font.handle, 1)
|
46
|
+
end
|
47
|
+
|
48
|
+
attr_reader :parent, :id
|
49
|
+
|
50
|
+
def dispose; detach end
|
51
|
+
end
|
52
|
+
|
53
|
+
class Button < Control
|
54
|
+
def initialize(parent, id, opts = {}, &block)
|
55
|
+
super('Button', parent, id, opts)
|
56
|
+
|
57
|
+
@parent.on(:command, @id, &block) if block
|
58
|
+
end
|
6
59
|
end
|
7
60
|
end
|
data/lib/fzeet/Menu.rb
CHANGED
@@ -2,14 +2,96 @@ require_relative 'common'
|
|
2
2
|
|
3
3
|
module Fzeet
|
4
4
|
class MenuItem
|
5
|
+
include Toggle
|
5
6
|
|
7
|
+
def initialize(menu, id) @menu, @id = menu, Command[id] end
|
8
|
+
|
9
|
+
attr_reader :menu, :id
|
10
|
+
|
11
|
+
def enabled?
|
12
|
+
flags = Windows.DetonateLastError(-1, :GetMenuState, @menu.handle, @id, 0)
|
13
|
+
|
14
|
+
(flags & Windows::MF_GRAYED) != Windows::MF_GRAYED
|
15
|
+
end
|
16
|
+
|
17
|
+
def enabled=(enabled)
|
18
|
+
Windows.DetonateLastError(-1, :EnableMenuItem,
|
19
|
+
@menu.handle,
|
20
|
+
@id,
|
21
|
+
(enabled) ? Windows::MF_ENABLED : Windows::MF_GRAYED
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
def checked?
|
26
|
+
flags = Windows.DetonateLastError(-1, :GetMenuState, @menu.handle, @id, 0)
|
27
|
+
|
28
|
+
(flags & Windows::MF_CHECKED) == Windows::MF_CHECKED
|
29
|
+
end
|
30
|
+
|
31
|
+
def checked=(checked)
|
32
|
+
Windows.DetonateLastError(-1, :CheckMenuItem,
|
33
|
+
@menu.handle,
|
34
|
+
@id,
|
35
|
+
(checked) ? Windows::MF_CHECKED : Windows::MF_UNCHECKED
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
def select(first, last)
|
40
|
+
Windows.DetonateLastError(0, :CheckMenuRadioItem,
|
41
|
+
@menu.handle, Command[first], Command[last], @id, 0
|
42
|
+
)
|
43
|
+
|
44
|
+
self
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
module MenuMethods
|
49
|
+
def rdetach; submenus.each(&:rdetach); detach end
|
50
|
+
|
51
|
+
def [](id) MenuItem.new(self, id) end
|
52
|
+
|
53
|
+
def append(flags, item = nil, id = 0)
|
54
|
+
Windows.DetonateLastError(0, :AppendMenu,
|
55
|
+
@handle,
|
56
|
+
[*flags].inject(0) { |flags, flag| flags |= Windows.const_get("MF_#{flag.upcase}") },
|
57
|
+
case id
|
58
|
+
when Integer; id
|
59
|
+
when Symbol; Command[id]
|
60
|
+
when MenuMethods; submenus << id; id.handle.to_i
|
61
|
+
else raise ArgumentError
|
62
|
+
end,
|
63
|
+
item
|
64
|
+
)
|
65
|
+
|
66
|
+
self
|
67
|
+
end
|
6
68
|
end
|
7
69
|
|
8
70
|
class Menu < Handle
|
71
|
+
include MenuMethods
|
72
|
+
|
73
|
+
def initialize
|
74
|
+
@submenus = []
|
9
75
|
|
76
|
+
@handle = Windows.DetonateLastError(FFI::Pointer::NULL, :CreateMenu); attach
|
77
|
+
end
|
78
|
+
|
79
|
+
attr_reader :submenus
|
80
|
+
|
81
|
+
def dispose; Windows.DestroyMenu(@handle); rdetach end
|
10
82
|
end
|
11
83
|
|
12
84
|
class PopupMenu < Handle
|
85
|
+
include MenuMethods
|
86
|
+
|
87
|
+
def initialize
|
88
|
+
@submenus = []
|
89
|
+
|
90
|
+
@handle = Windows.DetonateLastError(FFI::Pointer::NULL, :CreatePopupMenu); attach
|
91
|
+
end
|
92
|
+
|
93
|
+
attr_reader :submenus
|
13
94
|
|
95
|
+
def dispose; Windows.DestroyMenu(@handle); rdetach end
|
14
96
|
end
|
15
97
|
end
|
data/lib/fzeet/Window.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
-
require_relative '
|
1
|
+
require_relative 'WindowMethods'
|
2
2
|
|
3
3
|
module Fzeet
|
4
4
|
class Window < Handle
|
5
|
+
include WindowMethods
|
6
|
+
|
5
7
|
WindowProc = FFI::Function.new(:long, [:pointer, :uint, :uint, :long], convention: :stdcall) { |hwnd, uMsg, wParam, lParam|
|
6
8
|
begin
|
7
9
|
if uMsg == Windows::WM_NCCREATE
|
@@ -55,6 +57,9 @@ module Fzeet
|
|
55
57
|
when Windows::WM_NCCREATE
|
56
58
|
args[:result] = 1
|
57
59
|
args[:cs] = Windows::CREATESTRUCT.new(FFI::Pointer.new(lParam))
|
60
|
+
when Windows::WM_COMMAND
|
61
|
+
args[:command], args[:notification], args[:hctl] = Windows.LOWORD(wParam), Windows.HIWORD(wParam), FFI::Pointer.new(lParam)
|
62
|
+
args[:sender] = @@instances[args[:hctl].to_i] unless args[:hctl].null?
|
58
63
|
end
|
59
64
|
|
60
65
|
args
|
@@ -82,6 +87,7 @@ module Fzeet
|
|
82
87
|
_opts[:style] = _opts[:style].inject(0) { |flags, style| flags |= Windows.const_get("WS_#{style.upcase}") }
|
83
88
|
|
84
89
|
@messages ||= {}
|
90
|
+
@commands ||= {}
|
85
91
|
|
86
92
|
@processed = [0, 0]
|
87
93
|
|
@@ -92,13 +98,19 @@ module Fzeet
|
|
92
98
|
)
|
93
99
|
|
94
100
|
if @handle.null?
|
95
|
-
raise
|
101
|
+
raise "CreateWindowEx failed (last error #{Windows.GetLastError()})." unless [
|
96
102
|
[Windows::WM_NCCREATE, 0], [Windows::WM_CREATE, -1],
|
97
103
|
[Windows::WM_DESTROY, 0], [Windows::WM_NCDESTROY, 0]
|
98
104
|
].include?(@processed)
|
99
105
|
else
|
100
106
|
@parent = _opts[:parent]
|
101
107
|
self.menu = _opts[:menu] if _opts[:menu]
|
108
|
+
|
109
|
+
on(:destroy) {
|
110
|
+
menu.rdetach if self.menu
|
111
|
+
|
112
|
+
eachChild(&:dispose)
|
113
|
+
}
|
102
114
|
end
|
103
115
|
end
|
104
116
|
|
@@ -113,12 +125,28 @@ module Fzeet
|
|
113
125
|
args ||= self.class.crackMessage(hwnd, uMsg, wParam, lParam)
|
114
126
|
|
115
127
|
handlers.each { |handler|
|
116
|
-
handler.call(args)
|
128
|
+
(handler.arity == 0) ? handler.call : handler.call(args)
|
117
129
|
|
118
130
|
result = args[:result]; @processed[0], @processed[1] = uMsg, result
|
119
131
|
}
|
120
132
|
end
|
121
133
|
|
134
|
+
if uMsg == Windows::WM_COMMAND && (handlers = @commands[Windows.LOWORD(wParam)])
|
135
|
+
args ||= self.class.crackMessage(hwnd, uMsg, wParam, lParam)
|
136
|
+
|
137
|
+
handlers[:all].each { |handler|
|
138
|
+
(handler.arity == 0) ? handler.call : handler.call(args)
|
139
|
+
|
140
|
+
result = args[:result]; @processed[0], @processed[1] = uMsg, result
|
141
|
+
} if handlers[:all]
|
142
|
+
|
143
|
+
handlers[Windows.HIWORD(wParam)].each { |handler|
|
144
|
+
(handler.arity == 0) ? handler.call : handler.call(args)
|
145
|
+
|
146
|
+
result = args[:result]; @processed[0], @processed[1] = uMsg, result
|
147
|
+
} if handlers[Windows.HIWORD(wParam)]
|
148
|
+
end
|
149
|
+
|
122
150
|
result
|
123
151
|
end
|
124
152
|
|
@@ -128,9 +156,20 @@ module Fzeet
|
|
128
156
|
self
|
129
157
|
end
|
130
158
|
|
159
|
+
def onCommand(cmd, notification = :all, &block)
|
160
|
+
(((@commands ||= {})[Command[cmd]] ||= {})[notification] ||= []) << block
|
161
|
+
|
162
|
+
self
|
163
|
+
end
|
164
|
+
|
131
165
|
def on(*args, &block)
|
132
166
|
case args.length
|
133
167
|
when 1; onMessage(*args, &block)
|
168
|
+
when 2, 3
|
169
|
+
case Windows.const_get("WM_#{args.shift.upcase}")
|
170
|
+
when Windows::WM_COMMAND; onCommand(*args, &block)
|
171
|
+
else raise ArgumentError
|
172
|
+
end
|
134
173
|
else raise ArgumentError
|
135
174
|
end
|
136
175
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require_relative 'common'
|
2
|
+
|
3
|
+
module Fzeet
|
4
|
+
module WindowMethods
|
5
|
+
include Toggle
|
6
|
+
|
7
|
+
def show(cmdShow = :shownormal) Windows.ShowWindow(@handle, Windows.const_get("SW_#{cmdShow.upcase}")); self end
|
8
|
+
def update; Windows.DetonateLastError(0, :UpdateWindow, @handle); self end
|
9
|
+
|
10
|
+
def enabled?; Windows.IsWindowEnabled(@handle) != 0 end
|
11
|
+
def enabled=(enabled) Windows.EnableWindow(@handle, (enabled) ? 1 : 0) end
|
12
|
+
|
13
|
+
def [](id) Handle.instance(Windows.DetonateLastError(FFI::Pointer::NULL, :GetDlgItem, @handle, Command[id])) end
|
14
|
+
|
15
|
+
EnumChildProc = FFI::Function.new(:int, [:pointer, :long], convention: :stdcall) { |hwnd, lParam|
|
16
|
+
ObjectSpace._id2ref(lParam).call(Handle.instance(hwnd)) if Handle.instance?(hwnd); 1
|
17
|
+
}
|
18
|
+
|
19
|
+
def eachChild(&block) Windows.EnumChildWindows(@handle, EnumChildProc, block.object_id); self end
|
20
|
+
|
21
|
+
def sendmsg(msg, wParam = 0, lParam = 0)
|
22
|
+
Windows.SendMessage(
|
23
|
+
@handle,
|
24
|
+
Windows.const_get("WM_#{msg.upcase}"),
|
25
|
+
wParam.to_i,
|
26
|
+
((lparam = lParam.to_i) > 0x7fff_ffff) ? lparam - 0x1_0000_0000 : lparam
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
30
|
+
def postmsg(msg, wParam = 0, lParam = 0)
|
31
|
+
Windows.DetonateLastError(0, :PostMessage,
|
32
|
+
@handle,
|
33
|
+
Windows.const_get("WM_#{msg.upcase}"),
|
34
|
+
wParam.to_i,
|
35
|
+
((lparam = lParam.to_i) > 0x7fff_ffff) ? lparam - 0x1_0000_0000 : lparam
|
36
|
+
)
|
37
|
+
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
def menu; (Handle.instance?(handle = Windows.GetMenu(@handle))) ? Handle.instance(handle) : nil end
|
42
|
+
|
43
|
+
def menu=(menu)
|
44
|
+
self.menu.dispose if self.menu
|
45
|
+
|
46
|
+
Windows.DetonateLastError(0, :SetMenu, @handle, menu.handle) if menu
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/fzeet/common.rb
CHANGED
@@ -1,6 +1,23 @@
|
|
1
1
|
require_relative 'windows'
|
2
2
|
|
3
3
|
module Fzeet
|
4
|
+
module Toggle
|
5
|
+
def toggle(what) send("#{what}=", !send("#{what}?")); self end
|
6
|
+
end
|
7
|
+
|
8
|
+
class Command
|
9
|
+
@ids = {}
|
10
|
+
@nextId = Windows::WM_APP + 1
|
11
|
+
|
12
|
+
def self.[](id)
|
13
|
+
id = id.upcase
|
14
|
+
|
15
|
+
@ids[id], @nextId = @nextId, @nextId + 1 unless @ids.include?(id)
|
16
|
+
|
17
|
+
@ids[id]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
4
21
|
class DialogResult
|
5
22
|
def initialize(id)
|
6
23
|
@id = id
|
@@ -37,7 +54,7 @@ module Fzeet
|
|
37
54
|
Windows.const_get("MB_ICON#{_opts[:icon].upcase}")
|
38
55
|
|
39
56
|
DialogResult.new(
|
40
|
-
Windows.MessageBox
|
57
|
+
Windows.DetonateLastError(0, :MessageBox, _opts[:window] && _opts[:window].handle, message.to_s, _opts[:caption].to_s, flags)
|
41
58
|
)
|
42
59
|
end
|
43
60
|
|
@@ -50,6 +67,15 @@ module Fzeet
|
|
50
67
|
|
51
68
|
module_function :message, :question
|
52
69
|
|
70
|
+
class Message < Windows::MSG
|
71
|
+
def get!(window = nil, msgFilterMin = 0, msgFilterMax = 0)
|
72
|
+
Windows.DetonateLastError(-1, :GetMessage, self, window && window.handle, msgFilterMin, msgFilterMax) != 0
|
73
|
+
end
|
74
|
+
|
75
|
+
def translate; Windows.TranslateMessage(self); self end
|
76
|
+
def dispatch; Windows.DispatchMessage(self); self end
|
77
|
+
end
|
78
|
+
|
53
79
|
class Handle
|
54
80
|
@@instances = {}
|
55
81
|
|
@@ -69,4 +95,28 @@ module Fzeet
|
|
69
95
|
def attach; @@instances[@handle.to_i] = self end
|
70
96
|
def detach; @@instances.delete(@handle.to_i) end
|
71
97
|
end
|
98
|
+
|
99
|
+
def using(o, cleanup = :dispose)
|
100
|
+
yield o
|
101
|
+
ensure
|
102
|
+
o.send(cleanup)
|
103
|
+
end
|
104
|
+
|
105
|
+
module_function :using
|
106
|
+
|
107
|
+
module FontMethods
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
class IndirectFont < Handle
|
112
|
+
include FontMethods
|
113
|
+
|
114
|
+
def initialize(logfont)
|
115
|
+
@handle = Windows.DetonateLastError(FFI::Pointer::NULL, :CreateFontIndirect, @logfont = logfont); attach
|
116
|
+
end
|
117
|
+
|
118
|
+
attr_reader :logfont
|
119
|
+
|
120
|
+
def dispose; Windows.DeleteObject(@handle); detach end
|
121
|
+
end
|
72
122
|
end
|
data/lib/fzeet/windows/gdi.rb
CHANGED
data/lib/fzeet/windows/kernel.rb
CHANGED
@@ -7,16 +7,6 @@ module Fzeet
|
|
7
7
|
|
8
8
|
attach_function :GetLastError, [], :ulong
|
9
9
|
|
10
|
-
def DetonateLastError(on, name, *args)
|
11
|
-
raise "#{name} failed (last error #{GetLastError()})." if (failed = [*on].include?(result = send(name, *args)))
|
12
|
-
|
13
|
-
result
|
14
|
-
ensure
|
15
|
-
yield failed if block_given?
|
16
|
-
end
|
17
|
-
|
18
|
-
module_function :DetonateLastError
|
19
|
-
|
20
10
|
class ACTCTX < FFI::Struct
|
21
11
|
layout \
|
22
12
|
:cbSize, :ulong,
|
data/lib/fzeet/windows/user.rb
CHANGED
@@ -94,10 +94,16 @@ module Fzeet
|
|
94
94
|
attach_function :ShowWindow, [:pointer, :int], :int
|
95
95
|
|
96
96
|
attach_function :UpdateWindow, [:pointer], :int
|
97
|
+
|
98
|
+
attach_function :IsWindowEnabled, [:pointer], :int
|
97
99
|
attach_function :EnableWindow, [:pointer, :int], :int
|
98
100
|
|
99
101
|
attach_function :GetDlgItem, [:pointer, :int], :pointer
|
100
102
|
|
103
|
+
callback :WNDENUMPROC, [:pointer, :long], :int
|
104
|
+
|
105
|
+
attach_function :EnumChildWindows, [:pointer, :WNDENUMPROC, :long], :int
|
106
|
+
|
101
107
|
attach_function :GetMenu, [:pointer], :pointer
|
102
108
|
attach_function :SetMenu, [:pointer, :pointer], :int
|
103
109
|
|
@@ -105,13 +111,21 @@ module Fzeet
|
|
105
111
|
attach_function :CreatePopupMenu, [], :pointer
|
106
112
|
attach_function :DestroyMenu, [:pointer], :int
|
107
113
|
|
114
|
+
MF_SEPARATOR = 0x00000800
|
108
115
|
MF_ENABLED = 0x00000000
|
109
116
|
MF_GRAYED = 0x00000001
|
117
|
+
MF_UNCHECKED = 0x00000000
|
118
|
+
MF_CHECKED = 0x00000008
|
119
|
+
MF_USECHECKBITMAPS = 0x00000200
|
110
120
|
MF_STRING = 0x00000000
|
111
121
|
MF_POPUP = 0x00000010
|
122
|
+
MF_RIGHTJUSTIFY = 0x00004000
|
112
123
|
|
113
124
|
attach_function :AppendMenu, :AppendMenuA, [:pointer, :uint, :uint, :string], :int
|
125
|
+
attach_function :GetMenuState, [:pointer, :uint, :uint], :uint
|
114
126
|
attach_function :EnableMenuItem, [:pointer, :uint, :uint], :int
|
127
|
+
attach_function :CheckMenuItem, [:pointer, :uint, :uint], :ulong
|
128
|
+
attach_function :CheckMenuRadioItem, [:pointer, :uint, :uint, :uint, :uint], :int
|
115
129
|
|
116
130
|
FVIRTKEY = 1
|
117
131
|
FSHIFT = 0x04
|
@@ -160,5 +174,47 @@ module Fzeet
|
|
160
174
|
attach_function :SendMessage, :SendMessageA, [:pointer, :uint, :uint, :long], :long
|
161
175
|
attach_function :PostMessage, :PostMessageA, [:pointer, :uint, :uint, :long], :int
|
162
176
|
attach_function :PostQuitMessage, [:int], :void
|
177
|
+
|
178
|
+
SPI_GETNONCLIENTMETRICS = 0x0029
|
179
|
+
|
180
|
+
class LOGFONT < FFI::Struct
|
181
|
+
layout \
|
182
|
+
:lfHeight, :long,
|
183
|
+
:lfWidth, :long,
|
184
|
+
:lfEscapement, :long,
|
185
|
+
:lfOrientation, :long,
|
186
|
+
:lfWeight, :long,
|
187
|
+
:lfItalic, :uchar,
|
188
|
+
:lfUnderline, :uchar,
|
189
|
+
:lfStrikeOut, :uchar,
|
190
|
+
:lfCharSet, :uchar,
|
191
|
+
:lfOutPrecision, :uchar,
|
192
|
+
:lfClipPrecision, :uchar,
|
193
|
+
:lfQuality, :uchar,
|
194
|
+
:lfPitchAndFamily, :uchar,
|
195
|
+
:lfFaceName, [:char, 32]
|
196
|
+
end
|
197
|
+
|
198
|
+
class NONCLIENTMETRICS < FFI::Struct
|
199
|
+
layout \
|
200
|
+
:cbSize, :uint,
|
201
|
+
:iBorderWidth, :int,
|
202
|
+
:iScrollWidth, :int,
|
203
|
+
:iScrollHeight, :int,
|
204
|
+
:iCaptionWidth, :int,
|
205
|
+
:iCaptionHeight, :int,
|
206
|
+
:lfCaptionFont, LOGFONT,
|
207
|
+
:iSmCaptionWidth, :int,
|
208
|
+
:iSmCaptionHeight, :int,
|
209
|
+
:lfSmCaptionFont, LOGFONT,
|
210
|
+
:iMenuWidth, :int,
|
211
|
+
:iMenuHeight, :int,
|
212
|
+
:lfMenuFont, LOGFONT,
|
213
|
+
:lfStatusFont, LOGFONT,
|
214
|
+
:lfMessageFont, LOGFONT,
|
215
|
+
:iPaddedBorderWidth, :int
|
216
|
+
end
|
217
|
+
|
218
|
+
attach_function :SystemParametersInfo, :SystemParametersInfoA, [:uint, :uint, :pointer, :uint], :int
|
163
219
|
end
|
164
220
|
end
|
data/lib/fzeet/windows.rb
CHANGED
@@ -6,6 +6,16 @@ require_relative 'windows/gdi'
|
|
6
6
|
|
7
7
|
module Fzeet
|
8
8
|
module Windows
|
9
|
+
def DetonateLastError(on, name, *args)
|
10
|
+
raise "#{name} failed (last error #{GetLastError()})." if (failed = [*on].include?(result = send(name, *args)))
|
11
|
+
|
12
|
+
result
|
13
|
+
ensure
|
14
|
+
yield failed if block_given?
|
15
|
+
end
|
16
|
+
|
17
|
+
module_function :DetonateLastError
|
18
|
+
|
9
19
|
COMMON_CONTROLS_ACTCTX = {handle: INVALID_HANDLE_VALUE, cookie: FFI::MemoryPointer.new(:ulong), activated: false}
|
10
20
|
|
11
21
|
at_exit {
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fzeet
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 13
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 4
|
9
|
-
-
|
10
|
-
version: 0.4.
|
9
|
+
- 1
|
10
|
+
version: 0.4.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Radoslav Peev
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-08-
|
18
|
+
date: 2010-08-13 00:00:00 +03:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -54,6 +54,7 @@ files:
|
|
54
54
|
- lib/fzeet/Control.rb
|
55
55
|
- lib/fzeet/Menu.rb
|
56
56
|
- lib/fzeet/Window.rb
|
57
|
+
- lib/fzeet/WindowMethods.rb
|
57
58
|
- lib/fzeet/windows.rb
|
58
59
|
- lib/fzeet.rb
|
59
60
|
- examples/Raw/Command.rbw
|
@@ -65,8 +66,10 @@ files:
|
|
65
66
|
- examples/LifeCycle.rbw
|
66
67
|
- examples/LifeCycle1.rbw
|
67
68
|
- examples/LifeCycle2.rbw
|
69
|
+
- examples/LifeCycleNC.rbw
|
68
70
|
- examples/MessageBox.rbw
|
69
71
|
- examples/Minimal.rbw
|
72
|
+
- examples/Menu/Menu.rbw
|
70
73
|
- LICENSE
|
71
74
|
has_rdoc: true
|
72
75
|
homepage:
|