fzeet 0.4.2 → 0.5.0
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/Dialog/FileDialog.rbw +34 -0
- data/examples/Raw/UIRibbon/Command.dll +0 -0
- data/examples/Raw/UIRibbon/Command.rb +22 -0
- data/examples/Raw/UIRibbon/Command.rbw +51 -0
- data/examples/Raw/UIRibbon/Command.xml +65 -0
- data/examples/Raw/UIRibbon/Minimal.dll +0 -0
- data/examples/Raw/UIRibbon/Minimal.rb +16 -0
- data/examples/Raw/UIRibbon/Minimal.rbw +39 -0
- data/examples/Raw/UIRibbon/Minimal.xml +55 -0
- data/examples/UIRibbon/Command.dll +0 -0
- data/examples/UIRibbon/Command.rb +22 -0
- data/examples/UIRibbon/Command.rbw +20 -0
- data/examples/UIRibbon/Command.xml +65 -0
- data/examples/UIRibbon/Minimal.dll +0 -0
- data/examples/UIRibbon/Minimal.rb +16 -0
- data/examples/UIRibbon/Minimal.rbw +8 -0
- data/examples/UIRibbon/Minimal.xml +55 -0
- data/examples/UIRibbon/Viewer.rbw +9 -0
- data/examples/res/go-next-small.bmp +0 -0
- data/examples/res/go-next.bmp +0 -0
- data/examples/res/go-previous-small.bmp +0 -0
- data/examples/res/go-previous.bmp +0 -0
- data/lib/fzeet/Control.rb +1 -89
- data/lib/fzeet/ControlButton.rb +28 -0
- data/lib/fzeet/ControlCommon.rb +64 -0
- data/lib/fzeet/Dialog.rb +1 -0
- data/lib/fzeet/DialogCommon.rb +5 -0
- data/lib/fzeet/DialogFileDialog.rb +116 -0
- data/lib/fzeet/UIRibbon.rb +99 -0
- data/lib/fzeet/Window.rb +2 -336
- data/lib/fzeet/WindowCommon.rb +256 -0
- data/lib/fzeet/WindowDialog.rb +73 -0
- data/lib/fzeet/WindowWindow.rb +13 -0
- data/lib/fzeet/common.rb +2 -0
- data/lib/fzeet/windows/com.rb +186 -0
- data/lib/fzeet/windows/comctl.rb +1 -59
- data/lib/fzeet/windows/comctlbutton.rb +30 -0
- data/lib/fzeet/windows/comctlcommon.rb +34 -0
- data/lib/fzeet/windows/comdlg.rb +1 -0
- data/lib/fzeet/windows/comdlgcommon.rb +9 -0
- data/lib/fzeet/windows/comdlgofn.rb +70 -0
- data/lib/fzeet/windows/common.rb +18 -0
- data/lib/fzeet/windows/kernel.rb +3 -0
- data/lib/fzeet/windows/libc.rb +1 -0
- data/lib/fzeet/windows/ole.rb +213 -0
- data/lib/fzeet/windows/shell.rb +43 -0
- data/lib/fzeet/windows/uiribbon.rb +111 -0
- data/lib/fzeet/windows/user.rb +7 -438
- data/lib/fzeet/windows/usercommon.rb +8 -0
- data/lib/fzeet/windows/userctl.rb +1 -68
- data/lib/fzeet/windows/userctlbutton.rb +56 -0
- data/lib/fzeet/windows/userctlcommon.rb +12 -0
- data/lib/fzeet/windows/userkbd.rb +20 -0
- data/lib/fzeet/windows/usermbox.rb +62 -0
- data/lib/fzeet/windows/usermenu.rb +50 -0
- data/lib/fzeet/windows/usermsg.rb +1 -6
- data/lib/fzeet/windows/userspi.rb +29 -0
- data/lib/fzeet/windows/userwnd.rb +276 -0
- data/lib/fzeet/windows.rb +24 -4
- data/lib/fzeet.rb +2 -0
- metadata +54 -6
- /data/examples/{Dialog.rbw → Dialog/Dialog.rbw} +0 -0
- /data/examples/{DialogApplication.rbw → Dialog/DialogApplication.rbw} +0 -0
@@ -0,0 +1,64 @@
|
|
1
|
+
require_relative 'WindowMethods'
|
2
|
+
|
3
|
+
module Fzeet
|
4
|
+
class Control < Handle
|
5
|
+
include WindowMethods
|
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 self.crackNotification(args) end
|
18
|
+
|
19
|
+
def initialize(className, parent, id, opts = {})
|
20
|
+
@parent = parent
|
21
|
+
@id = Command[id]
|
22
|
+
|
23
|
+
handlers = {}
|
24
|
+
|
25
|
+
opts.delete_if { |k, v|
|
26
|
+
next false unless v.kind_of?(Proc)
|
27
|
+
|
28
|
+
handlers[k] = v; true
|
29
|
+
}
|
30
|
+
|
31
|
+
_opts = {
|
32
|
+
xstyle: [],
|
33
|
+
caption: id.capitalize,
|
34
|
+
style: [],
|
35
|
+
x: Windows::CW_USEDEFAULT,
|
36
|
+
y: Windows::CW_USEDEFAULT,
|
37
|
+
width: Windows::CW_USEDEFAULT,
|
38
|
+
height: Windows::CW_USEDEFAULT,
|
39
|
+
}
|
40
|
+
badopts = opts.keys - _opts.keys; raise "Bad option(s): #{badopts.join(', ')}." unless badopts.empty?
|
41
|
+
_opts.merge!(opts)
|
42
|
+
|
43
|
+
_opts[:xstyle] = Fzeet.flags(_opts[:xstyle], *self.class::Prefix[:xstyle])
|
44
|
+
_opts[:caption] = _opts[:caption].to_s
|
45
|
+
_opts[:style] = Fzeet.flags([:child, :visible, :tabstop], :ws_) | Fzeet.flags(_opts[:style], *self.class::Prefix[:style])
|
46
|
+
|
47
|
+
@handle = Windows.DetonateLastError(FFI::Pointer::NULL, :CreateWindowEx,
|
48
|
+
_opts[:xstyle], className, _opts[:caption], _opts[:style],
|
49
|
+
_opts[:x], _opts[:y], _opts[:width], _opts[:height],
|
50
|
+
@parent.handle, FFI::Pointer.new(@id), Windows.GetModuleHandle(nil), nil
|
51
|
+
)
|
52
|
+
|
53
|
+
attach
|
54
|
+
|
55
|
+
sendmsg(:setfont, Font.handle, 1)
|
56
|
+
|
57
|
+
handlers.each { |k, v| on(k, &v) }
|
58
|
+
end
|
59
|
+
|
60
|
+
attr_reader :parent, :id
|
61
|
+
|
62
|
+
def dispose; detach end
|
63
|
+
end
|
64
|
+
end
|
data/lib/fzeet/Dialog.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require_relative 'DialogFileDialog'
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require_relative 'DialogCommon'
|
2
|
+
|
3
|
+
module Fzeet
|
4
|
+
class FileDialog
|
5
|
+
def initialize(opts = {})
|
6
|
+
_opts = {
|
7
|
+
filter: nil,
|
8
|
+
customFilter: nil,
|
9
|
+
filterIndex: 0,
|
10
|
+
fileTitle: nil,
|
11
|
+
initialDir: nil,
|
12
|
+
title: nil,
|
13
|
+
flags: 0,
|
14
|
+
fileExtension: nil,
|
15
|
+
defExt: nil,
|
16
|
+
custData: 0,
|
17
|
+
hook: nil,
|
18
|
+
templateName: nil,
|
19
|
+
xflags: 0
|
20
|
+
}
|
21
|
+
badopts = opts.keys - _opts.keys; raise "Bad option(s): #{badopts.join(', ')}." unless badopts.empty?
|
22
|
+
_opts.merge!(opts)
|
23
|
+
|
24
|
+
@ofn = Windows::OPENFILENAME.new
|
25
|
+
|
26
|
+
@ofn[:lStructSize] = @ofn.size
|
27
|
+
@ofn[:hInstance] = Windows.GetModuleHandle(nil)
|
28
|
+
end
|
29
|
+
|
30
|
+
attr_reader :ofn
|
31
|
+
|
32
|
+
def path; @path && @path.dup end
|
33
|
+
end
|
34
|
+
|
35
|
+
class OpenFileDialog < FileDialog
|
36
|
+
def initialize(opts = {})
|
37
|
+
super
|
38
|
+
end
|
39
|
+
|
40
|
+
def show(window = Application.window)
|
41
|
+
ofn[:hwndOwner] = window.handle
|
42
|
+
ofn[:nMaxFile] = 4096
|
43
|
+
ofn[:lpstrFile] = path = FFI::MemoryPointer.new(:char, ofn[:nMaxFile])
|
44
|
+
|
45
|
+
@path = nil
|
46
|
+
|
47
|
+
DialogResult.new((Windows.GetOpenFileName(ofn) == 0) ? Windows::IDCANCEL : Windows::IDOK).tap { |result|
|
48
|
+
@path = ofn[:lpstrFile].read_string if result.ok?
|
49
|
+
}
|
50
|
+
ensure
|
51
|
+
path.free
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class SaveFileDialog < FileDialog
|
56
|
+
def initialize(opts = {})
|
57
|
+
super
|
58
|
+
end
|
59
|
+
|
60
|
+
def show(window = Application.window)
|
61
|
+
ofn[:hwndOwner] = window.handle
|
62
|
+
ofn[:nMaxFile] = 4096
|
63
|
+
ofn[:lpstrFile] = path = FFI::MemoryPointer.new(:char, ofn[:nMaxFile])
|
64
|
+
|
65
|
+
@path = nil
|
66
|
+
|
67
|
+
DialogResult.new((Windows.GetSaveFileName(ofn) == 0) ? Windows::IDCANCEL : Windows::IDOK).tap { |result|
|
68
|
+
@path = ofn[:lpstrFile].read_string if result.ok?
|
69
|
+
}
|
70
|
+
ensure
|
71
|
+
path.free
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class FolderDialog
|
76
|
+
def initialize(opts = {})
|
77
|
+
_opts = {
|
78
|
+
root: nil,
|
79
|
+
displayName: nil,
|
80
|
+
title: nil,
|
81
|
+
flags: 0,
|
82
|
+
hook: nil,
|
83
|
+
param: 0,
|
84
|
+
image: 0
|
85
|
+
}
|
86
|
+
badopts = opts.keys - _opts.keys; raise "Bad option(s): #{badopts.join(', ')}." unless badopts.empty?
|
87
|
+
_opts.merge!(opts)
|
88
|
+
|
89
|
+
@bi = Windows::BROWSEINFO.new
|
90
|
+
|
91
|
+
@bi[:ulFlags] = Fzeet.flags([:returnonlyfsdirs, :usenewui], :bif_)
|
92
|
+
end
|
93
|
+
|
94
|
+
attr_reader :bi
|
95
|
+
|
96
|
+
def path; @path && @path.dup end
|
97
|
+
|
98
|
+
def show(window = Application.window)
|
99
|
+
bi[:hwndOwner] = window.handle
|
100
|
+
|
101
|
+
@path = nil
|
102
|
+
|
103
|
+
DialogResult.new(((pidl = Windows.SHBrowseForFolder(bi)).null?) ? Windows::IDCANCEL : Windows::IDOK).tap { |result|
|
104
|
+
next unless result.ok?
|
105
|
+
|
106
|
+
FFI::MemoryPointer.new(:char, 4096) { |p|
|
107
|
+
Windows.SHGetPathFromIDList(pidl, p)
|
108
|
+
|
109
|
+
@path = p.read_string
|
110
|
+
}
|
111
|
+
}
|
112
|
+
ensure
|
113
|
+
Windows.CoTaskMemFree(pidl)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require_relative 'WindowCommon'
|
2
|
+
|
3
|
+
module Fzeet
|
4
|
+
class UIRibbon
|
5
|
+
class Command
|
6
|
+
include Toggle
|
7
|
+
|
8
|
+
def initialize(ribbon, id)
|
9
|
+
@ribbon, @id = ribbon, id
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_reader :ribbon, :id
|
13
|
+
|
14
|
+
def [](k) Windows::PROPVARIANT.new.tap { |v| ribbon.uif.GetUICommandProperty(id, k, v) } end
|
15
|
+
def []=(k, v) ribbon.uif.SetUICommandProperty(id, k, v) end
|
16
|
+
|
17
|
+
def enabled?; self[Windows::UI_PKEY_Enabled].bool end
|
18
|
+
def enabled=(enabled) self[Windows::UI_PKEY_Enabled] = Windows::PROPVARIANT[:bool, enabled] end
|
19
|
+
end
|
20
|
+
|
21
|
+
def [](id) Command.new(self, id) end
|
22
|
+
|
23
|
+
def initialize(window, name = Application.name, resname = 'APPLICATION_RIBBON')
|
24
|
+
@executesAllVerbs = {}
|
25
|
+
|
26
|
+
@window = window
|
27
|
+
|
28
|
+
@uich = Windows::UICommandHandler.new
|
29
|
+
|
30
|
+
@uich.instance_variable_set(:@ribbon, self)
|
31
|
+
|
32
|
+
class << @uich
|
33
|
+
attr_reader :ribbon
|
34
|
+
|
35
|
+
def Execute(*args) @ribbon.execute(*args) end
|
36
|
+
end
|
37
|
+
|
38
|
+
@uia = Windows::UIApplication.new
|
39
|
+
|
40
|
+
@uia.instance_variable_set(:@uich, @uich)
|
41
|
+
|
42
|
+
class << @uia
|
43
|
+
attr_reader :uich
|
44
|
+
|
45
|
+
def OnCreateUICommand(*args) @uich.QueryInterface(@uich.class::IID, args[-1]); Windows::S_OK end
|
46
|
+
end
|
47
|
+
|
48
|
+
@uif = Windows::UIFramework.new
|
49
|
+
|
50
|
+
@uif.Initialize(@window.handle, @uia)
|
51
|
+
@uif.LoadUI(@hdll = Windows.LoadRibbonDll(name), "#{resname}\0".encode('utf-16le'))
|
52
|
+
|
53
|
+
@window.on(:destroy) {
|
54
|
+
@uich.Release
|
55
|
+
@uia.Release
|
56
|
+
@uif.Destroy; @uif.Release
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
attr_reader :window, :uich, :uia, :uif
|
61
|
+
|
62
|
+
def execute(commandId, verb, key, value, props)
|
63
|
+
args = {
|
64
|
+
commandId: commandId,
|
65
|
+
ribbon: self,
|
66
|
+
sender: Command.new(self, commandId)
|
67
|
+
}
|
68
|
+
|
69
|
+
result = Windows::E_NOTIMPL
|
70
|
+
|
71
|
+
begin
|
72
|
+
if @executesAllVerbs.include?(commandId)
|
73
|
+
@executesAllVerbs[commandId].each { |handler|
|
74
|
+
(handler.arity == 0) ? handler.call : handler.call(args)
|
75
|
+
}
|
76
|
+
|
77
|
+
result = Windows::S_OK
|
78
|
+
end
|
79
|
+
rescue
|
80
|
+
Fzeet.message %Q{#{$!}\n\n#{$!.backtrace.join("\n")}}, icon: :error
|
81
|
+
end
|
82
|
+
|
83
|
+
result
|
84
|
+
end
|
85
|
+
|
86
|
+
def on(*args, &block)
|
87
|
+
case args.size
|
88
|
+
when 1
|
89
|
+
case args[0]
|
90
|
+
when Integer; (@executesAllVerbs[args[0]] ||= []) << block
|
91
|
+
else raise ArgumentError
|
92
|
+
end
|
93
|
+
else raise ArgumentError
|
94
|
+
end
|
95
|
+
|
96
|
+
self
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
data/lib/fzeet/Window.rb
CHANGED
@@ -1,336 +1,2 @@
|
|
1
|
-
require_relative '
|
2
|
-
|
3
|
-
module Fzeet
|
4
|
-
class BasicWindow < Handle
|
5
|
-
include WindowMethods
|
6
|
-
|
7
|
-
Prefix = {
|
8
|
-
xstyle: [:ws_ex_],
|
9
|
-
style: [:ws_, :ds_],
|
10
|
-
message: [:wm_],
|
11
|
-
notification: []
|
12
|
-
}
|
13
|
-
|
14
|
-
WindowProc = FFI::Function.new(:long, [:pointer, :uint, :uint, :long], convention: :stdcall) { |hwnd, uMsg, wParam, lParam|
|
15
|
-
begin
|
16
|
-
if uMsg == Windows::WM_NCCREATE
|
17
|
-
@@instances[hwnd.to_i] = ObjectSpace._id2ref(
|
18
|
-
Windows::CREATESTRUCT.new(FFI::Pointer.new(lParam))[:lpCreateParams].to_i
|
19
|
-
)
|
20
|
-
|
21
|
-
@@instances[hwnd.to_i].instance_variable_set(:@handle, hwnd)
|
22
|
-
end
|
23
|
-
|
24
|
-
result = @@instances[hwnd.to_i].windowProc(hwnd, uMsg, wParam, lParam) if @@instances[hwnd.to_i]
|
25
|
-
rescue
|
26
|
-
answer = Fzeet.message %Q{#{$!}\n\n#{$!.backtrace.join("\n")}}, buttons: [:abort, :retry, :ignore], icon: :error
|
27
|
-
|
28
|
-
Application.quit if answer.abort?
|
29
|
-
ensure
|
30
|
-
if uMsg == Windows::WM_NCDESTROY
|
31
|
-
@@instances[hwnd.to_i].dialog = false
|
32
|
-
|
33
|
-
@@instances.delete(hwnd.to_i)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
result || Windows.DefWindowProc(hwnd, uMsg, wParam, lParam)
|
38
|
-
}
|
39
|
-
|
40
|
-
DialogProc = FFI::Function.new(:int, [:pointer, :uint, :uint, :long], convention: :stdcall) { |hwnd, uMsg, wParam, lParam|
|
41
|
-
begin
|
42
|
-
if uMsg == Windows::WM_INITDIALOG
|
43
|
-
@@instances[hwnd.to_i] = ObjectSpace._id2ref(lParam)
|
44
|
-
|
45
|
-
@@instances[hwnd.to_i].instance_variable_set(:@handle, hwnd)
|
46
|
-
end
|
47
|
-
|
48
|
-
result = @@instances[hwnd.to_i].windowProc(hwnd, uMsg, wParam, lParam) if @@instances[hwnd.to_i]
|
49
|
-
rescue
|
50
|
-
answer = Fzeet.message %Q{#{$!}\n\n#{$!.backtrace.join("\n")}}, buttons: [:abort, :retry, :ignore], icon: :error
|
51
|
-
|
52
|
-
Application.quit if answer.abort?
|
53
|
-
ensure
|
54
|
-
if uMsg == Windows::WM_NCDESTROY
|
55
|
-
@@instances[hwnd.to_i].dialog = false
|
56
|
-
|
57
|
-
@@instances.delete(hwnd.to_i)
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
(result.nil?) ? 0 : 1
|
62
|
-
}
|
63
|
-
|
64
|
-
WindowClass = Fzeet::WindowClass.new(nil, 'Fzeet.BasicWindow')
|
65
|
-
|
66
|
-
def self.[](name, opts = {})
|
67
|
-
Class.new(self) { |klass|
|
68
|
-
klass.const_set(:WindowClass, Fzeet::WindowClass.new(self::WindowClass, name, opts))
|
69
|
-
}
|
70
|
-
end
|
71
|
-
|
72
|
-
def self.crackMessage(hwnd, uMsg, wParam, lParam)
|
73
|
-
window = @@instances[hwnd.to_i]
|
74
|
-
|
75
|
-
args = {
|
76
|
-
hwnd: hwnd,
|
77
|
-
uMsg: uMsg,
|
78
|
-
wParam: wParam,
|
79
|
-
lParam: lParam,
|
80
|
-
result: (window.kind_of?(Dialog)) ? 1 : 0,
|
81
|
-
window: window,
|
82
|
-
sender: window
|
83
|
-
}
|
84
|
-
|
85
|
-
case uMsg
|
86
|
-
when Windows::WM_CREATE
|
87
|
-
args[:cs] = Windows::CREATESTRUCT.new(FFI::Pointer.new(lParam))
|
88
|
-
when Windows::WM_NCCREATE
|
89
|
-
args[:result] = 1
|
90
|
-
args[:cs] = Windows::CREATESTRUCT.new(FFI::Pointer.new(lParam))
|
91
|
-
when Windows::WM_COMMAND
|
92
|
-
args[:command], args[:notification], args[:hctl] = Windows.LOWORD(wParam), Windows.HIWORD(wParam), FFI::Pointer.new(lParam)
|
93
|
-
args[:sender] = @@instances[args[:hctl].to_i] unless args[:hctl].null?
|
94
|
-
when Windows::WM_NOTIFY
|
95
|
-
args[:nmh] = Windows::NMHDR.new(FFI::Pointer.new(lParam))
|
96
|
-
args[:command], args[:notification], args[:hctl] = args[:nmh][:idFrom], args[:nmh][:code], args[:nmh][:hwndFrom]
|
97
|
-
(args[:sender] = @@instances[args[:hctl].to_i]).class.crackNotification(args)
|
98
|
-
when \
|
99
|
-
Windows::WM_MOUSEMOVE,
|
100
|
-
Windows::WM_LBUTTONDOWN, Windows::WM_LBUTTONUP, Windows::WM_LBUTTONDBLCLK,
|
101
|
-
Windows::WM_RBUTTONDOWN, Windows::WM_RBUTTONUP, Windows::WM_RBUTTONDBLCLK,
|
102
|
-
Windows::WM_MBUTTONDOWN, Windows::WM_MBUTTONUP, Windows::WM_MBUTTONDBLCLK,
|
103
|
-
Windows::WM_CONTEXTMENU
|
104
|
-
|
105
|
-
args[:x], args[:y] = Windows.GET_X_LPARAM(lParam), Windows.GET_Y_LPARAM(lParam)
|
106
|
-
|
107
|
-
if uMsg == Windows::WM_CONTEXTMENU && args[:x] == -1
|
108
|
-
Windows.DetonateLastError(0, :GetCursorPos, pt = Point.new)
|
109
|
-
|
110
|
-
args[:keyboard], args[:x], args[:y] = true, pt[:x], pt[:y]
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
args
|
115
|
-
end
|
116
|
-
|
117
|
-
def initialize(opts = {})
|
118
|
-
_opts = {
|
119
|
-
xstyle: [],
|
120
|
-
caption: Application.name,
|
121
|
-
style: [],
|
122
|
-
x: Windows::CW_USEDEFAULT,
|
123
|
-
y: Windows::CW_USEDEFAULT,
|
124
|
-
width: Windows::CW_USEDEFAULT,
|
125
|
-
height: Windows::CW_USEDEFAULT,
|
126
|
-
parent: nil,
|
127
|
-
menu: nil
|
128
|
-
}
|
129
|
-
badopts = opts.keys - _opts.keys; raise "Bad option(s): #{badopts.join(', ')}." unless badopts.empty?
|
130
|
-
_opts.merge!(opts)
|
131
|
-
|
132
|
-
yield self, _opts if block_given?
|
133
|
-
|
134
|
-
_opts[:xstyle] = Fzeet.flags(_opts[:xstyle], *self.class::Prefix[:xstyle])
|
135
|
-
_opts[:caption] = _opts[:caption].to_s
|
136
|
-
_opts[:style] = Fzeet.flags(_opts[:style], *self.class::Prefix[:style])
|
137
|
-
|
138
|
-
@messages ||= {}
|
139
|
-
@commands ||= {}
|
140
|
-
@notifies ||= {}
|
141
|
-
|
142
|
-
@processed = [0, 0]
|
143
|
-
|
144
|
-
@handle = Windows.CreateWindowEx(
|
145
|
-
_opts[:xstyle], self.class::WindowClass.name, _opts[:caption], _opts[:style],
|
146
|
-
_opts[:x], _opts[:y], _opts[:width], _opts[:height],
|
147
|
-
_opts[:parent] && _opts[:parent].handle, nil, Windows.GetModuleHandle(nil), FFI::Pointer.new(object_id)
|
148
|
-
)
|
149
|
-
|
150
|
-
if @handle.null?
|
151
|
-
raise "CreateWindowEx failed (last error #{Windows.GetLastError()})." unless [
|
152
|
-
[Windows::WM_NCCREATE, 0], [Windows::WM_CREATE, -1],
|
153
|
-
[Windows::WM_DESTROY, 0], [Windows::WM_NCDESTROY, 0]
|
154
|
-
].include?(@processed)
|
155
|
-
else
|
156
|
-
@parent = _opts[:parent]
|
157
|
-
self.menu = _opts[:menu] if _opts[:menu]
|
158
|
-
|
159
|
-
on(:destroy) {
|
160
|
-
menu.rdetach if self.menu
|
161
|
-
|
162
|
-
eachChild(&:dispose)
|
163
|
-
}
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
attr_reader :parent
|
168
|
-
|
169
|
-
def dispose; Windows.DestroyWindow(@handle) end
|
170
|
-
|
171
|
-
def windowProc(hwnd, uMsg, wParam, lParam)
|
172
|
-
args, result = nil, nil
|
173
|
-
|
174
|
-
if (handlers = @messages[uMsg])
|
175
|
-
args ||= self.class.crackMessage(hwnd, uMsg, wParam, lParam)
|
176
|
-
|
177
|
-
handlers.each { |handler|
|
178
|
-
(handler.arity == 0) ? handler.call : handler.call(args)
|
179
|
-
|
180
|
-
result = args[:result]; @processed[0], @processed[1] = uMsg, result
|
181
|
-
}
|
182
|
-
end
|
183
|
-
|
184
|
-
if uMsg == Windows::WM_COMMAND && (handlers = @commands[Windows.LOWORD(wParam)])
|
185
|
-
args ||= self.class.crackMessage(hwnd, uMsg, wParam, lParam)
|
186
|
-
|
187
|
-
handlers[:all].each { |handler|
|
188
|
-
(handler.arity == 0) ? handler.call : handler.call(args)
|
189
|
-
|
190
|
-
result = args[:result]; @processed[0], @processed[1] = uMsg, result
|
191
|
-
} if handlers[:all]
|
192
|
-
|
193
|
-
handlers[Windows.HIWORD(wParam)].each { |handler|
|
194
|
-
(handler.arity == 0) ? handler.call : handler.call(args)
|
195
|
-
|
196
|
-
result = args[:result]; @processed[0], @processed[1] = uMsg, result
|
197
|
-
} if handlers[Windows.HIWORD(wParam)]
|
198
|
-
end
|
199
|
-
|
200
|
-
if uMsg == Windows::WM_NOTIFY && (handlers = @notifies[(nmh = Windows::NMHDR.new(FFI::Pointer.new(lParam)))[:idFrom]])
|
201
|
-
args ||= self.class.crackMessage(hwnd, uMsg, wParam, lParam)
|
202
|
-
|
203
|
-
handlers[:all].each { |handler|
|
204
|
-
(handler.arity == 0) ? handler.call : handler.call(args)
|
205
|
-
|
206
|
-
result = args[:result]; @processed[0], @processed[1] = uMsg, result
|
207
|
-
} if handlers[:all]
|
208
|
-
|
209
|
-
handlers[nmh[:code]].each { |handler|
|
210
|
-
(handler.arity == 0) ? handler.call : handler.call(args)
|
211
|
-
|
212
|
-
result = args[:result]; @processed[0], @processed[1] = uMsg, result
|
213
|
-
} if handlers[nmh[:code]]
|
214
|
-
end
|
215
|
-
|
216
|
-
result
|
217
|
-
end
|
218
|
-
|
219
|
-
def onMessage(msg, &block)
|
220
|
-
((@messages ||= {})[Fzeet.constant(msg, :wm_)] ||= []) << block
|
221
|
-
|
222
|
-
self
|
223
|
-
end
|
224
|
-
|
225
|
-
def onCommand(cmd, notification = :all, &block)
|
226
|
-
notification = Fzeet.constant(notification, *self[cmd].class::Prefix[:notification]) unless
|
227
|
-
notification.kind_of?(Integer) || notification == :all
|
228
|
-
|
229
|
-
(((@commands ||= {})[Command[cmd]] ||= {})[notification] ||= []) << block
|
230
|
-
|
231
|
-
self
|
232
|
-
end
|
233
|
-
|
234
|
-
def onNotify(cmd, notification = :all, &block)
|
235
|
-
notification = Fzeet.constant(notification, *self[cmd].class::Prefix[:notification]) unless
|
236
|
-
notification.kind_of?(Integer) || notification == :all
|
237
|
-
|
238
|
-
(((@notifies ||= {})[Command[cmd]] ||= {})[notification] ||= []) << block
|
239
|
-
|
240
|
-
self
|
241
|
-
end
|
242
|
-
|
243
|
-
def on(*args, &block)
|
244
|
-
case args.length
|
245
|
-
when 1; onMessage(*args, &block)
|
246
|
-
when 2, 3
|
247
|
-
case Fzeet.constant(args.shift, :wm_)
|
248
|
-
when Windows::WM_COMMAND; onCommand(*args, &block)
|
249
|
-
when Windows::WM_NOTIFY; onNotify(*args, &block)
|
250
|
-
else raise ArgumentError
|
251
|
-
end
|
252
|
-
else raise ArgumentError
|
253
|
-
end
|
254
|
-
end
|
255
|
-
end
|
256
|
-
|
257
|
-
Window = BasicWindow['Fzeet.Window']
|
258
|
-
|
259
|
-
class Window
|
260
|
-
def initialize(opts = {})
|
261
|
-
(opts[:style] ||= []) << :overlappedwindow << :clipchildren
|
262
|
-
|
263
|
-
super
|
264
|
-
end
|
265
|
-
end
|
266
|
-
|
267
|
-
Dialog = BasicWindow['Fzeet.Dialog',
|
268
|
-
wndProc: BasicWindow::DialogProc
|
269
|
-
]
|
270
|
-
|
271
|
-
class Dialog
|
272
|
-
def initialize(parent, opts = {}, &block)
|
273
|
-
@parent = parent
|
274
|
-
|
275
|
-
_opts = {
|
276
|
-
xstyle: [:noparentnotify],
|
277
|
-
caption: Application.name,
|
278
|
-
style: [:sysmenu, :visible],
|
279
|
-
x: 0,
|
280
|
-
y: 0,
|
281
|
-
width: 200,
|
282
|
-
height: 150,
|
283
|
-
modal: false
|
284
|
-
}
|
285
|
-
badopts = opts.keys - _opts.keys; raise "Bad option(s): #{badopts.join(', ')}." unless badopts.empty?
|
286
|
-
_opts.merge!(opts)
|
287
|
-
|
288
|
-
_opts[:xstyle] = Fzeet.flags(_opts[:xstyle], *self.class::Prefix[:xstyle])
|
289
|
-
_opts[:caption] = _opts[:caption].to_s
|
290
|
-
_opts[:style] = Fzeet.flags(_opts[:style], *self.class::Prefix[:style])
|
291
|
-
|
292
|
-
@messages ||= {}
|
293
|
-
@commands ||= {}
|
294
|
-
@notifies ||= {}
|
295
|
-
|
296
|
-
@processed = [0, 0]
|
297
|
-
|
298
|
-
dt = Windows::DLGTEMPLATE.new
|
299
|
-
|
300
|
-
dt[:style] = _opts[:style]
|
301
|
-
dt[:dwExtendedStyle] = _opts[:xstyle]
|
302
|
-
dt[:x] = _opts[:x]
|
303
|
-
dt[:y] = _opts[:y]
|
304
|
-
dt[:cx] = _opts[:width]
|
305
|
-
dt[:cy] = _opts[:height]
|
306
|
-
|
307
|
-
on(:initdialog) { self.text = _opts[:caption] }
|
308
|
-
|
309
|
-
on(:initdialog, &block) if block
|
310
|
-
|
311
|
-
if _opts[:modal]
|
312
|
-
@result = Windows.DetonateLastError([-1, 0], :DialogBoxIndirectParam,
|
313
|
-
Windows.GetModuleHandle(nil),
|
314
|
-
dt,
|
315
|
-
@parent && @parent.handle,
|
316
|
-
BasicWindow::DialogProc,
|
317
|
-
object_id
|
318
|
-
)
|
319
|
-
else
|
320
|
-
@handle = Windows.DetonateLastError(FFI::Pointer::NULL, :CreateDialogIndirectParam,
|
321
|
-
Windows.GetModuleHandle(nil),
|
322
|
-
dt,
|
323
|
-
@parent && @parent.handle,
|
324
|
-
BasicWindow::DialogProc,
|
325
|
-
object_id
|
326
|
-
)
|
327
|
-
|
328
|
-
self.dialog = true
|
329
|
-
end
|
330
|
-
end
|
331
|
-
|
332
|
-
def end(result) Windows.DetonateLastError(0, :EndDialog, @handle, Command[result]); self end
|
333
|
-
|
334
|
-
def result; DialogResult.new(@result) end
|
335
|
-
end
|
336
|
-
end
|
1
|
+
require_relative 'WindowWindow'
|
2
|
+
require_relative 'WindowDialog'
|