fzeet 0.4.0 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|