fzeet 0.6.0 → 0.6.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.
Files changed (34) hide show
  1. data/examples/Dialog/ColorDialog.rbw +21 -0
  2. data/examples/Dialog/FileDialog.rbw +47 -0
  3. data/examples/Dialog/FindReplaceDialog.rbw +38 -0
  4. data/examples/Dialog/FontDialog.rbw +33 -0
  5. data/examples/Dialog/PrintDialog.rbw +31 -0
  6. data/examples/Dialog/ShellFileDialog.rbw +43 -0
  7. data/examples/Version.rbw +5 -1
  8. data/lib/fzeet/Common.rb +6 -1
  9. data/lib/fzeet/Dialog/ColorDialog.rb +44 -0
  10. data/lib/fzeet/Dialog/Common.rb +84 -0
  11. data/lib/fzeet/Dialog/FileDialog.rb +83 -27
  12. data/lib/fzeet/Dialog/FindReplaceDialog.rb +105 -0
  13. data/lib/fzeet/Dialog/FontDialog.rb +39 -0
  14. data/lib/fzeet/Dialog/PrintDialog.rb +75 -0
  15. data/lib/fzeet/Dialog/ShellFileDialog.rb +133 -0
  16. data/lib/fzeet/Dialog.rb +5 -1
  17. data/lib/fzeet/windows/com.rb +16 -1
  18. data/lib/fzeet/windows/comdlg/ColorDialog.rb +34 -0
  19. data/lib/fzeet/windows/comdlg/Common.rb +37 -1
  20. data/lib/fzeet/windows/comdlg/FileDialog.rb +37 -0
  21. data/lib/fzeet/windows/comdlg/FindReplaceDialog.rb +50 -0
  22. data/lib/fzeet/windows/comdlg/FontDialog.rb +78 -0
  23. data/lib/fzeet/windows/comdlg/PrintDialog.rb +198 -0
  24. data/lib/fzeet/windows/comdlg.rb +4 -0
  25. data/lib/fzeet/windows/gdi.rb +3 -0
  26. data/lib/fzeet/windows/shell/{FolderDialog.rb → BrowseForFolder.rb} +11 -0
  27. data/lib/fzeet/windows/shell/Common.rb +56 -0
  28. data/lib/fzeet/windows/shell/FileDialog.rb +78 -0
  29. data/lib/fzeet/windows/shell.rb +2 -1
  30. data/lib/fzeet/windows/user/Message.rb +1 -0
  31. data/lib/fzeet/windows.rb +1 -0
  32. metadata +24 -6
  33. data/examples/Dialog/FileAndFolderDialog.rbw +0 -34
  34. data/lib/fzeet/Dialog/FolderDialog.rb +0 -45
@@ -0,0 +1,21 @@
1
+ require 'fzeet'
2
+
3
+ include Fzeet
4
+
5
+ Application.run { |window|
6
+ dialog = ColorDialog.new
7
+
8
+ dialog.on(:initdialog) { message 'on(:initdialog)' }
9
+
10
+ window.menu = Menu.new.
11
+ append(:popup, '&View', PopupMenu.new.
12
+ append(:string, '&Color...', :color)
13
+ )
14
+
15
+ window.
16
+ on(:command, :color) {
17
+ message dialog.color if dialog.show.ok?
18
+ }.
19
+
20
+ on(:destroy) { dialog.dispose }
21
+ }
@@ -0,0 +1,47 @@
1
+ require 'fzeet'
2
+
3
+ include Fzeet
4
+
5
+ Application.run { |window|
6
+ window.menu = Menu.new.
7
+ append(:popup, '&File', PopupMenu.new.
8
+ append(:string, '&Open...', :open).
9
+ append(:string, 'Open &Multiple...', :openMultiple).
10
+ append(:string, 'Save &As...', :saveAs).
11
+
12
+ append(:separator).
13
+
14
+ append(:string, 'Browse For &Folder...', :browseForFolder)
15
+ )
16
+
17
+ window.
18
+ on(:command, :open) {
19
+ FileOpenDialog.new { |dialog|
20
+ dialog.on(:initdialog) { message 'on(:initdialog)' }
21
+
22
+ message dialog.path if dialog.show.ok?
23
+ }
24
+ }.
25
+
26
+ on(:command, :openMultiple) {
27
+ FileOpenDialog.new(flags: :allowmultiselect) { |dialog|
28
+ message dialog.paths.join("\n") if dialog.show.ok?
29
+ }
30
+ }.
31
+
32
+ on(:command, :saveAs) {
33
+ FileSaveDialog.new { |dialog|
34
+ dialog.on(:initdialog) { message 'on(:initdialog)' }
35
+
36
+ message dialog.path if dialog.show.ok?
37
+ }
38
+ }.
39
+
40
+ on(:command, :browseForFolder) {
41
+ dialog = FolderDialog.new
42
+
43
+ dialog.on(Windows::BFFM_IUNKNOWN) { message 'Windows::BFFM_IUNKNOWN' }
44
+
45
+ message dialog.path if dialog.show.ok?
46
+ }
47
+ }
@@ -0,0 +1,38 @@
1
+ require 'fzeet'
2
+
3
+ include Fzeet
4
+
5
+ Application.run { |window|
6
+ window.menu = Menu.new.
7
+ append(:popup, '&Edit', PopupMenu.new.
8
+ append(:string, '&Find...', :find).
9
+ append(:string, '&Replace...', :replace)
10
+ )
11
+
12
+ window.
13
+ on(:command, :find) {
14
+ dialog = FindDialog.new
15
+
16
+ dialog.on(:initdialog) { |args| message 'on(:initdialog)'; args[:result] = 1 }
17
+
18
+ dialog.show.
19
+ onNotify(:findnext) { message "on(:findnext) - #{dialog.findWhat}" }.
20
+ onNotify(:dialogterm) { [:find, :replace].each { |id| window.menu[id].enabled = true } }
21
+
22
+ [:find, :replace].each { |id| window.menu[id].enabled = false }
23
+ }.
24
+
25
+ on(:command, :replace) {
26
+ dialog = ReplaceDialog.new
27
+
28
+ dialog.on(:initdialog) { |args| message 'on(:initdialog)'; args[:result] = 1 }
29
+
30
+ dialog.show.
31
+ onNotify(:findnext) { message "on(:findnext) - #{dialog.findWhat}" }.
32
+ onNotify(:replace) { message "on(:replace) - #{dialog.findWhat} with #{dialog.replaceWith}" }.
33
+ onNotify(:replaceall) { message "on(:replaceall) - #{dialog.findWhat} with #{dialog.replaceWith}" }.
34
+ onNotify(:dialogterm) { [:find, :replace].each { |id| window.menu[id].enabled = true } }
35
+
36
+ [:find, :replace].each { |id| window.menu[id].enabled = false }
37
+ }
38
+ }
@@ -0,0 +1,33 @@
1
+ require 'fzeet'
2
+
3
+ include Fzeet
4
+
5
+ Application.run(View.new) { |window|
6
+ font = IndirectFont.new(Control::Font.logfont)
7
+ color = 0
8
+
9
+ window.menu = Menu.new.
10
+ append(:popup, '&View', PopupMenu.new.
11
+ append(:string, '&Font...', :font)
12
+ )
13
+
14
+ window.
15
+ on(:command, :font) {
16
+ dialog = FontDialog.new(font: font, color: color)
17
+
18
+ dialog.on(:initdialog) { message 'on(:initdialog)' }
19
+
20
+ next unless dialog.show.ok?
21
+
22
+ font.dispose; font = dialog.font; color = dialog.color
23
+
24
+ window.invalidate
25
+ }.
26
+
27
+ on(:paint) { window.paint { |dc| dc.select(font) {
28
+ dc.color = color
29
+ dc.sms 'The quick brown fox jumps over the lazy dog. 1234567890'
30
+ }}}.
31
+
32
+ on(:destroy) { font.dispose }
33
+ }
@@ -0,0 +1,31 @@
1
+ require 'fzeet'
2
+
3
+ include Fzeet
4
+
5
+ Application.run { |window|
6
+ window.menu = Menu.new.
7
+ append(:popup, '&File', PopupMenu.new.
8
+ append(:string, 'Page Set&up...', :pageSetup).
9
+ append(:string, '&Print...', :print).
10
+ append(:string, 'P&rint1...', :print1)
11
+ )
12
+
13
+ window.
14
+ on(:command, :pageSetup) {
15
+ dialog = PageSetupDialog.new
16
+
17
+ message dialog.show.ok?
18
+ }.
19
+
20
+ on(:command, :print) {
21
+ dialog = PrintDialog.new
22
+
23
+ message dialog.show.ok?
24
+ }.
25
+
26
+ on(:command, :print1) {
27
+ dialog = PrintDialogEx.new
28
+
29
+ message dialog.show.ok?
30
+ }
31
+ }
@@ -0,0 +1,43 @@
1
+ require 'fzeet'
2
+
3
+ include Fzeet
4
+
5
+ Application.run { |window|
6
+ window.menu = Menu.new.
7
+ append(:popup, '&File', PopupMenu.new.
8
+ append(:string, '&Open...', :open).
9
+ append(:string, 'Open &Multiple...', :openMultiple).
10
+ append(:string, 'Save &As...', :saveAs).
11
+
12
+ append(:separator).
13
+
14
+ append(:string, 'Select &Folder...', :selectFolder)
15
+ )
16
+
17
+ window.
18
+ on(:command, :open) {
19
+ ShellFileOpenDialog.new { |dialog|
20
+ message dialog.path if dialog.show.ok?
21
+ }
22
+ }.
23
+
24
+ on(:command, :openMultiple) {
25
+ ShellFileOpenDialog.new { |dialog|
26
+ dialog.SetOptions(Windows::FOS_ALLOWMULTISELECT)
27
+
28
+ message dialog.paths.join("\n") if dialog.show.ok?
29
+ }
30
+ }.
31
+
32
+ on(:command, :saveAs) {
33
+ ShellFileSaveDialog.new { |dialog|
34
+ message dialog.path if dialog.show.ok?
35
+ }
36
+ }.
37
+
38
+ on(:command, :selectFolder) {
39
+ ShellFolderDialog.new { |dialog|
40
+ message dialog.path if dialog.show.ok?
41
+ }
42
+ }
43
+ }
data/examples/Version.rbw CHANGED
@@ -2,4 +2,8 @@ require 'fzeet'
2
2
 
3
3
  include Fzeet
4
4
 
5
- message Windows::WINVER
5
+ message <<-MSG
6
+ Ruby #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}
7
+
8
+ Windows #{Windows::WINVER}
9
+ MSG
data/lib/fzeet/Common.rb CHANGED
@@ -166,7 +166,7 @@ module Fzeet
166
166
  @@instances = {}
167
167
 
168
168
  def self.instance?(handle) @@instances.include?(handle.to_i) end
169
- def self.instance(handle) raise "#{self}.instance failed." unless (instance = @@instances[handle.to_i]); instance end
169
+ def self.instance(handle) raise "#{self}.#{__method__} failed." unless (instance = @@instances[handle.to_i]); instance end
170
170
 
171
171
  def self.wrap(handle, iface)
172
172
  Object.new.tap { |o|
@@ -180,6 +180,8 @@ module Fzeet
180
180
 
181
181
  def attach; @@instances[@handle.to_i] = self end
182
182
  def detach; @@instances.delete(@handle.to_i) end
183
+
184
+ def dup; raise "#{self}.#{__method__} is not implemented." end
183
185
  end
184
186
 
185
187
  def using(o, cleanup = :dispose)
@@ -294,6 +296,9 @@ module Fzeet
294
296
  holds.each { |hold| Windows.SelectObject(@handle, hold) }
295
297
  end
296
298
 
299
+ def color; Windows.GetTextColor(@handle) end
300
+ def color=(color) Windows.SetTextColor(@handle, color) end
301
+
297
302
  def fillRect(rect, brush) Windows.DetonateLastError(0, :FillRect, @handle, rect, brush.handle); self end
298
303
 
299
304
  def text(text, rect, flags = 0) Windows.DetonateLastError(0, :DrawText, @handle, text, -1, rect, Fzeet.flags(flags, :dt_)); self end
@@ -0,0 +1,44 @@
1
+ require_relative 'Common'
2
+
3
+ module Fzeet
4
+ class ColorDialog < CommonDialog
5
+ DialogStruct = Windows::CHOOSECOLOR
6
+
7
+ HookProc = -> *args { CommonDialog::HookProc.(*args.unshift(DialogStruct)) }
8
+
9
+ def initialize(opts = {})
10
+ _opts = {
11
+
12
+ }
13
+ badopts = opts.keys - _opts.keys; raise "Bad option(s): #{badopts.join(', ')}." unless badopts.empty?
14
+ _opts.merge!(opts)
15
+
16
+ @struct = DialogStruct.new
17
+
18
+ @struct[:lStructSize] = @struct.size
19
+ @struct[:hInstance] = Windows.GetModuleHandle(nil)
20
+ @struct[:lpCustColors] = @buf = FFI::MemoryPointer.new(:ulong, 16)
21
+ @struct[:Flags] = Fzeet.flags(:enablehook, :cc_)
22
+ @struct[:lCustData] = object_id
23
+ @struct[:lpfnHook] = HookProc
24
+
25
+ super()
26
+
27
+ begin
28
+ yield self
29
+ ensure
30
+ dispose
31
+ end if block_given?
32
+ end
33
+
34
+ def dispose; @buf.free end
35
+
36
+ def show(window = Application.window)
37
+ @struct[:hwndOwner] = window.handle
38
+
39
+ DialogResult.new((Windows.ChooseColor(@struct) == 0) ? Windows::IDCANCEL : Windows::IDOK)
40
+ end
41
+
42
+ def color; result = @struct[:rgbResult]; [Windows.GetRValue(result), Windows.GetBValue(result), Windows.GetBValue(result)] end
43
+ end
44
+ end
@@ -1,5 +1,89 @@
1
1
  require_relative '../Window/Dialog'
2
2
 
3
3
  module Fzeet
4
+ class CommonDialog < Handle
5
+ include WindowMethods
4
6
 
7
+ HookProc = -> klass, hwnd, uMsg, wParam, lParam {
8
+ begin
9
+ if klass == Windows::BROWSEINFO
10
+ if uMsg == Windows::BFFM_IUNKNOWN
11
+ instance = ObjectSpace._id2ref(lParam)
12
+
13
+ if @@instances.include?(hwnd.to_i)
14
+ @@instances.delete(hwnd.to_i)
15
+ else
16
+ @@instances[hwnd.to_i] = instance
17
+
18
+ @@instances[hwnd.to_i].instance_variable_set(:@handle, hwnd)
19
+ end
20
+ end
21
+ else
22
+ if uMsg == Windows::WM_INITDIALOG
23
+ @@instances[hwnd.to_i] = ObjectSpace._id2ref(
24
+ klass.new(FFI::Pointer.new(lParam))[:lCustData].to_i
25
+ )
26
+
27
+ @@instances[hwnd.to_i].instance_variable_set(:@handle, hwnd)
28
+ end
29
+ end
30
+
31
+ result = @@instances[hwnd.to_i].hookProc(hwnd, uMsg, wParam, lParam) if @@instances[hwnd.to_i]
32
+ rescue
33
+ answer = Fzeet.message %Q{#{$!}\n\n#{$!.backtrace.join("\n")}}, buttons: [:abort, :retry, :ignore], icon: :error
34
+
35
+ Application.quit if answer.abort?
36
+ ensure
37
+ if uMsg == Windows::WM_NCDESTROY
38
+ @@instances.delete(hwnd.to_i)
39
+ end
40
+ end
41
+
42
+ result || 0
43
+ }
44
+
45
+ def self.crackMessage(hwnd, uMsg, wParam, lParam)
46
+ window = @@instances[hwnd.to_i]
47
+
48
+ args = {
49
+ hwnd: hwnd,
50
+ uMsg: uMsg,
51
+ wParam: wParam,
52
+ lParam: lParam,
53
+ result: 0,
54
+ window: window,
55
+ sender: window
56
+ }
57
+
58
+ args
59
+ end
60
+
61
+ def initialize
62
+ @messages = {}
63
+ end
64
+
65
+ attr_reader :struct
66
+
67
+ def hookProc(hwnd, uMsg, wParam, lParam)
68
+ args, result = nil, nil
69
+
70
+ if (handlers = @messages[uMsg])
71
+ args ||= self.class.crackMessage(hwnd, uMsg, wParam, lParam)
72
+
73
+ handlers.each { |handler|
74
+ (handler.arity == 0) ? handler.call : handler.call(args)
75
+
76
+ result = args[:result]
77
+ }
78
+ end
79
+
80
+ result
81
+ end
82
+
83
+ def on(msg, &block)
84
+ (@messages[Fzeet.constant(msg, :wm_)] ||= []) << block
85
+
86
+ self
87
+ end
88
+ end
5
89
  end
@@ -1,7 +1,11 @@
1
1
  require_relative 'Common'
2
2
 
3
3
  module Fzeet
4
- class FileDialog
4
+ class FileDialog < CommonDialog
5
+ DialogStruct = Windows::OPENFILENAME
6
+
7
+ HookProc = -> *args { CommonDialog::HookProc.(*args.unshift(DialogStruct)) }
8
+
5
9
  def initialize(opts = {})
6
10
  _opts = {
7
11
  filter: nil,
@@ -21,54 +25,106 @@ module Fzeet
21
25
  badopts = opts.keys - _opts.keys; raise "Bad option(s): #{badopts.join(', ')}." unless badopts.empty?
22
26
  _opts.merge!(opts)
23
27
 
24
- @ofn = Windows::OPENFILENAME.new
28
+ @struct = DialogStruct.new
29
+
30
+ @struct[:lStructSize] = @struct.size
31
+ @struct[:hInstance] = Windows.GetModuleHandle(nil)
32
+ @struct[:lpstrFile] = @buf = FFI::MemoryPointer.new(:char, 4096)
33
+ @struct[:nMaxFile] = @buf.size
34
+ @struct[:Flags] = Fzeet.flags([:enablehook, :explorer, :enablesizing] + [*_opts[:flags]], :ofn_)
35
+ @struct[:lCustData] = object_id
36
+ @struct[:lpfnHook] = HookProc
25
37
 
26
- @ofn[:lStructSize] = @ofn.size
27
- @ofn[:hInstance] = Windows.GetModuleHandle(nil)
38
+ super()
39
+
40
+ begin
41
+ yield self
42
+ ensure
43
+ dispose
44
+ end if block_given?
28
45
  end
29
46
 
30
- attr_reader :ofn
47
+ def dispose; @buf.free end
31
48
 
32
- def path; @path && @path.dup end
49
+ def path; @buf.read_string end
33
50
  end
34
51
 
35
- class OpenFileDialog < FileDialog
36
- def initialize(opts = {})
37
- super
52
+ class FileOpenDialog < FileDialog
53
+ def show(window = Application.window)
54
+ @struct[:hwndOwner] = window.handle
55
+
56
+ DialogResult.new((Windows.GetOpenFileName(@struct) == 0) ? Windows::IDCANCEL : Windows::IDOK)
38
57
  end
39
58
 
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])
59
+ def paths
60
+ return [path] if
61
+ (path = @buf.read_string).length + 1 != @struct[:nFileOffset]
44
62
 
45
- @path = nil
63
+ result, tip = [], path.length + 1
46
64
 
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
65
+ until @buf.get_bytes(tip, 2) == "\0\0"
66
+ result << (name = @buf.get_string(tip))
67
+
68
+ tip += name.length + 1
69
+ end
70
+
71
+ result.map! { |name| "#{path}\\#{name}" }
52
72
  end
53
73
  end
54
74
 
55
- class SaveFileDialog < FileDialog
75
+ class FileSaveDialog < FileDialog
76
+ def show(window = Application.window)
77
+ @struct[:hwndOwner] = window.handle
78
+
79
+ DialogResult.new((Windows.GetSaveFileName(@struct) == 0) ? Windows::IDCANCEL : Windows::IDOK)
80
+ end
81
+ end
82
+
83
+ class FolderDialog < CommonDialog
84
+ DialogStruct = Windows::BROWSEINFO
85
+
86
+ HookProc = -> *args { CommonDialog::HookProc.(*args.unshift(DialogStruct)) }
87
+
56
88
  def initialize(opts = {})
57
- super
89
+ _opts = {
90
+ root: nil,
91
+ displayName: nil,
92
+ title: nil,
93
+ flags: 0,
94
+ hook: nil,
95
+ param: 0,
96
+ image: 0
97
+ }
98
+ badopts = opts.keys - _opts.keys; raise "Bad option(s): #{badopts.join(', ')}." unless badopts.empty?
99
+ _opts.merge!(opts)
100
+
101
+ @struct = DialogStruct.new
102
+
103
+ @struct[:ulFlags] = Fzeet.flags([:returnonlyfsdirs, :usenewui], :bif_)
104
+ @struct[:lpfn] = HookProc
105
+ @struct[:lParam] = object_id
106
+
107
+ super()
58
108
  end
59
109
 
110
+ def path; @path && @path.dup end
111
+
60
112
  def show(window = Application.window)
61
- ofn[:hwndOwner] = window.handle
62
- ofn[:nMaxFile] = 4096
63
- ofn[:lpstrFile] = path = FFI::MemoryPointer.new(:char, ofn[:nMaxFile])
113
+ @struct[:hwndOwner] = window.handle
64
114
 
65
115
  @path = nil
66
116
 
67
- DialogResult.new((Windows.GetSaveFileName(ofn) == 0) ? Windows::IDCANCEL : Windows::IDOK).tap { |result|
68
- @path = ofn[:lpstrFile].read_string if result.ok?
117
+ DialogResult.new(((pidl = Windows.SHBrowseForFolder(@struct)).null?) ? Windows::IDCANCEL : Windows::IDOK).tap { |result|
118
+ next unless result.ok?
119
+
120
+ FFI::MemoryPointer.new(:char, 4096) { |p|
121
+ Windows.SHGetPathFromIDList(pidl, p)
122
+
123
+ @path = p.read_string
124
+ }
69
125
  }
70
126
  ensure
71
- path.free
127
+ Windows.CoTaskMemFree(pidl)
72
128
  end
73
129
  end
74
130
  end
@@ -0,0 +1,105 @@
1
+ require_relative 'Common'
2
+
3
+ module Fzeet
4
+ class FindReplaceDialog < CommonDialog
5
+ DialogStruct = Windows::FINDREPLACE
6
+
7
+ HookProc = -> *args { CommonDialog::HookProc.(*args.unshift(DialogStruct)) }
8
+
9
+ Message = Windows.DetonateLastError(0, :RegisterWindowMessage, Windows::FINDMSGSTRING)
10
+
11
+ def initialize(opts = {})
12
+ _opts = {
13
+
14
+ }
15
+ badopts = opts.keys - _opts.keys; raise "Bad option(s): #{badopts.join(', ')}." unless badopts.empty?
16
+ _opts.merge!(opts)
17
+
18
+ @frNotifies = {}
19
+
20
+ @struct = DialogStruct.new
21
+
22
+ @struct[:lStructSize] = @struct.size
23
+ @struct[:hInstance] = Windows.GetModuleHandle(nil)
24
+ @struct[:Flags] = Fzeet.flags(:enablehook, :fr_)
25
+ @struct[:lpstrFindWhat] = @findbuf = FFI::MemoryPointer.new(:char, 4096)
26
+ @struct[:lpstrReplaceWith] = @replacebuf = FFI::MemoryPointer.new(:char, 4096)
27
+ @struct[:wFindWhatLen] = @findbuf.size
28
+ @struct[:wReplaceWithLen] = @replacebuf.size
29
+ @struct[:lCustData] = object_id
30
+ @struct[:lpfnHook] = HookProc
31
+
32
+ super()
33
+ end
34
+
35
+ def dispose; [@findbuf, @replacebuf].each(&:free) end
36
+
37
+ def findWhat; @findbuf.read_string end
38
+ def replaceWith; @replacebuf.read_string end
39
+
40
+ def frProc(args)
41
+ return unless args[:lParam] == @struct.pointer.address
42
+
43
+ (handlers = @frNotifies[:all]) and handlers.each { |handler|
44
+ (handler.arity == 0) ? handler.call : handler.call(args)
45
+ }
46
+
47
+ if @struct[:Flags] & Windows::FR_DIALOGTERM != 0
48
+ (handlers = @frNotifies[Windows::FR_DIALOGTERM]) and handlers.each { |handler|
49
+ (handler.arity == 0) ? handler.call : handler.call(args)
50
+ }
51
+
52
+ self.dialog = false
53
+
54
+ dispose
55
+ elsif @struct[:Flags] & Windows::FR_FINDNEXT != 0
56
+ (handlers = @frNotifies[Windows::FR_FINDNEXT]) and handlers.each { |handler|
57
+ (handler.arity == 0) ? handler.call : handler.call(args)
58
+ }
59
+ elsif @struct[:Flags] & Windows::FR_REPLACE != 0
60
+ (handlers = @frNotifies[Windows::FR_REPLACE]) and handlers.each { |handler|
61
+ (handler.arity == 0) ? handler.call : handler.call(args)
62
+ }
63
+ elsif @struct[:Flags] & Windows::FR_REPLACEALL != 0
64
+ (handlers = @frNotifies[Windows::FR_REPLACEALL]) and handlers.each { |handler|
65
+ (handler.arity == 0) ? handler.call : handler.call(args)
66
+ }
67
+ end
68
+ end
69
+
70
+ def onNotify(notification, &block)
71
+ notification = Fzeet.constant(notification, :fr_) unless
72
+ notification.kind_of?(Integer) || notification == :all
73
+
74
+ (@frNotifies[notification] ||= []) << block
75
+
76
+ self
77
+ end
78
+ end
79
+
80
+ class FindDialog < FindReplaceDialog
81
+ def show(window = Application.window)
82
+ @struct[:hwndOwner] = window.handle
83
+ @handle = Windows.DetonateLastError(FFI::Pointer::NULL, :FindText, @struct)
84
+
85
+ self.dialog = true
86
+
87
+ window.on(FindReplaceDialog::Message, &method(:frProc))
88
+
89
+ self
90
+ end
91
+ end
92
+
93
+ class ReplaceDialog < FindReplaceDialog
94
+ def show(window = Application.window)
95
+ @struct[:hwndOwner] = window.handle
96
+ @handle = Windows.DetonateLastError(FFI::Pointer::NULL, :ReplaceText, @struct)
97
+
98
+ self.dialog = true
99
+
100
+ window.on(FindReplaceDialog::Message, &method(:frProc))
101
+
102
+ self
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,39 @@
1
+ require_relative 'Common'
2
+
3
+ module Fzeet
4
+ class FontDialog < CommonDialog
5
+ DialogStruct = Windows::CHOOSEFONT
6
+
7
+ HookProc = -> *args { CommonDialog::HookProc.(*args.unshift(DialogStruct)) }
8
+
9
+ def initialize(opts = {})
10
+ _opts = {
11
+ font: Control::Font,
12
+ color: 0
13
+ }
14
+ badopts = opts.keys - _opts.keys; raise "Bad option(s): #{badopts.join(', ')}." unless badopts.empty?
15
+ _opts.merge!(opts)
16
+
17
+ @struct = DialogStruct.new
18
+
19
+ @struct[:lStructSize] = @struct.size
20
+ @struct[:hInstance] = Windows.GetModuleHandle(nil)
21
+ @struct[:lpLogFont] = _opts[:font].logfont.pointer
22
+ @struct[:Flags] = Fzeet.flags([:enablehook, :both, :inittologfontstruct, :effects], :cf_)
23
+ @struct[:rgbColors] = _opts[:color]
24
+ @struct[:lCustData] = object_id
25
+ @struct[:lpfnHook] = HookProc
26
+
27
+ super()
28
+ end
29
+
30
+ def show(window = Application.window)
31
+ @struct[:hwndOwner] = window.handle
32
+
33
+ DialogResult.new((Windows.ChooseFont(@struct) == 0) ? Windows::IDCANCEL : Windows::IDOK)
34
+ end
35
+
36
+ def font; IndirectFont.new(Windows::LOGFONT.new(@struct[:lpLogFont])) end
37
+ def color; @struct[:rgbColors] end
38
+ end
39
+ end