fzeet 0.6.5 → 0.6.6

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 (140) hide show
  1. data/LICENSE_CEF +29 -0
  2. data/checks/Bstr.rb +14 -0
  3. data/checks/Decimal.rb +27 -0
  4. data/checks/OSVERSIONINFOEX.rb +14 -0
  5. data/checks/Point.rb +65 -0
  6. data/checks/Rect.rb +104 -0
  7. data/checks/RunAll.rb +2 -0
  8. data/checks/SafeArray.rb +27 -0
  9. data/checks/Size.rb +45 -0
  10. data/checks/SystemTime.rb +43 -0
  11. data/checks/Variant.rb +160 -0
  12. data/examples/Control/DateTimePicker.rbw +1 -1
  13. data/examples/Control/MonthCalendar.rbw +1 -1
  14. data/examples/Control/{WebBrowser.rbw → WebBrowser/WebBrowser.rbw} +2 -2
  15. data/examples/Control/{WebBrowser1.rbw → WebBrowser/WebBrowser1.rbw} +0 -0
  16. data/examples/Control/WebBrowser/WebBrowser2.rbw +24 -0
  17. data/examples/Control/{WebBrowser3.rbw → WebBrowser/WebBrowser3.rbw} +0 -0
  18. data/examples/Control/{WebBrowser4.rbw → WebBrowser/WebBrowser4.rbw} +8 -3
  19. data/examples/Control/{WebBrowser4Sinatra.rb → WebBrowser/WebBrowser4Sinatra.rb} +0 -0
  20. data/examples/Control/{WebBrowser5.rbw → WebBrowser/WebBrowser5.rbw} +4 -2
  21. data/examples/Control/WebBrowser/jQueryUI.html +53 -0
  22. data/examples/Control/WebBrowser/jQueryUI.rbw +26 -0
  23. data/examples/MDI.rbw +2 -2
  24. data/examples/Raw/UIRibbon/Command.rbw +3 -3
  25. data/examples/Raw/UIRibbon/Minimal.rbw +3 -3
  26. data/examples/Version.rbw +1 -1
  27. data/lib/fzeet.rb +22 -7
  28. data/lib/fzeet/windows.rb +82 -5
  29. data/lib/fzeet/windows/com.rb +1 -318
  30. data/lib/fzeet/windows/com/Common.rb +318 -0
  31. data/lib/fzeet/windows/comctl.rb +1 -1
  32. data/lib/fzeet/windows/comctl/ComboBoxEx.rb +32 -0
  33. data/lib/fzeet/windows/comctl/DateTimePicker.rb +35 -0
  34. data/lib/fzeet/windows/comctl/Header.rb +61 -1
  35. data/lib/fzeet/windows/comctl/ListView.rb +133 -3
  36. data/lib/fzeet/windows/comctl/MonthCalendar.rb +35 -0
  37. data/lib/fzeet/windows/comctl/ProgressBar.rb +37 -0
  38. data/lib/fzeet/windows/comctl/PropertySheet.rb +50 -2
  39. data/lib/fzeet/windows/comctl/SysLink.rb +37 -0
  40. data/lib/fzeet/windows/comctl/Tab.rb +56 -0
  41. data/lib/fzeet/windows/comctl/TreeView.rb +81 -2
  42. data/lib/fzeet/windows/comctl/UpDown.rb +33 -0
  43. data/lib/fzeet/windows/comdlg.rb +1 -0
  44. data/lib/fzeet/windows/comdlg/ColorDialog.rb +41 -0
  45. data/lib/fzeet/windows/comdlg/Common.rb +87 -0
  46. data/lib/fzeet/windows/comdlg/FileDialog.rb +133 -0
  47. data/lib/fzeet/windows/comdlg/FindReplaceDialog.rb +102 -0
  48. data/lib/fzeet/windows/comdlg/FontDialog.rb +36 -0
  49. data/lib/fzeet/windows/comdlg/PrintDialog.rb +72 -0
  50. data/lib/fzeet/{Dialog → windows/comdlg}/ShellFileDialog.rb +0 -0
  51. data/lib/fzeet/windows/core.rb +5 -0
  52. data/lib/fzeet/windows/core/Common.rb +324 -0
  53. data/lib/fzeet/windows/core/Point.rb +42 -0
  54. data/lib/fzeet/windows/core/Rect.rb +114 -0
  55. data/lib/fzeet/windows/core/Size.rb +34 -0
  56. data/lib/fzeet/windows/core/SystemTime.rb +46 -0
  57. data/lib/fzeet/windows/core/Version.rb +57 -0
  58. data/lib/fzeet/windows/gdi.rb +1 -62
  59. data/lib/fzeet/windows/gdi/Common.rb +40 -0
  60. data/lib/fzeet/windows/gdi/Font.rb +64 -0
  61. data/lib/fzeet/windows/kernel.rb +1 -92
  62. data/lib/fzeet/windows/kernel/Common.rb +92 -0
  63. data/lib/fzeet/windows/libc.rb +1 -1
  64. data/lib/fzeet/windows/libcef.rb +1 -0
  65. data/lib/fzeet/windows/mshtml.rb +1 -1135
  66. data/lib/fzeet/windows/mshtml/Common.rb +1135 -0
  67. data/lib/fzeet/windows/ole.rb +1 -561
  68. data/lib/fzeet/windows/ole/Common.rb +112 -0
  69. data/lib/fzeet/windows/ole/PropVariant.rb +141 -0
  70. data/lib/fzeet/windows/oleaut.rb +3 -0
  71. data/lib/fzeet/windows/oleaut/Bstr.rb +39 -0
  72. data/lib/fzeet/windows/oleaut/Common.rb +187 -0
  73. data/lib/fzeet/windows/oleaut/SafeArray.rb +104 -0
  74. data/lib/fzeet/windows/oleaut/Variant.rb +269 -0
  75. data/lib/fzeet/windows/scintilla.rb +115 -1
  76. data/lib/fzeet/windows/{SciLexer.dll → scintilla/SciLexer.dll} +0 -0
  77. data/lib/fzeet/windows/shdocvw.rb +150 -0
  78. data/lib/fzeet/windows/shell.rb +1 -1
  79. data/lib/fzeet/windows/shell/Common.rb +94 -2
  80. data/lib/fzeet/windows/shlwapi.rb +1 -1
  81. data/lib/fzeet/windows/uiribbon.rb +416 -0
  82. data/lib/fzeet/windows/urlmon.rb +2 -2
  83. data/lib/fzeet/windows/user.rb +20 -0
  84. data/lib/fzeet/windows/user/Accelerator.rb +45 -0
  85. data/lib/fzeet/windows/user/Common.rb +3 -2
  86. data/lib/fzeet/windows/user/Control/Button.rb +54 -0
  87. data/lib/fzeet/windows/user/Control/ComboBox.rb +44 -1
  88. data/lib/fzeet/windows/user/Control/Common.rb +88 -1
  89. data/lib/fzeet/windows/user/Control/Edit.rb +50 -0
  90. data/lib/fzeet/windows/user/Control/ListBox.rb +69 -0
  91. data/lib/fzeet/windows/user/Control/Static.rb +31 -0
  92. data/lib/fzeet/windows/user/Menu.rb +130 -0
  93. data/lib/fzeet/windows/user/Message.rb +9 -0
  94. data/lib/fzeet/windows/user/MessageBox.rb +47 -0
  95. data/lib/fzeet/windows/user/SystemParametersInfo.rb +1 -1
  96. data/lib/fzeet/windows/user/Window.rb +5 -463
  97. data/lib/fzeet/{Window → windows/user/Window}/Common.rb +460 -0
  98. data/lib/fzeet/{Window → windows/user/Window}/Container.rb +0 -0
  99. data/lib/fzeet/{Window → windows/user/Window}/Dialog.rb +0 -0
  100. data/lib/fzeet/{Window → windows/user/Window}/MDI.rb +0 -0
  101. data/lib/fzeet/{Window → windows/user/Window}/View.rb +0 -0
  102. data/lib/fzeet/{Window → windows/user/Window}/Window.rb +0 -0
  103. data/lib/fzeet/{Window → windows/user/Window}/WindowMethods.rb +1 -1
  104. metadata +55 -61
  105. data/examples/Control/WebBrowser2.rbw +0 -39
  106. data/lib/fzeet/Accelerator.rb +0 -48
  107. data/lib/fzeet/Application.rb +0 -71
  108. data/lib/fzeet/Common.rb +0 -350
  109. data/lib/fzeet/Control.rb +0 -19
  110. data/lib/fzeet/Control/Button.rb +0 -57
  111. data/lib/fzeet/Control/ComboBox.rb +0 -46
  112. data/lib/fzeet/Control/ComboBoxEx.rb +0 -35
  113. data/lib/fzeet/Control/Common.rb +0 -89
  114. data/lib/fzeet/Control/DateTimePicker.rb +0 -38
  115. data/lib/fzeet/Control/Edit.rb +0 -53
  116. data/lib/fzeet/Control/ExplorerBrowser.rb +0 -66
  117. data/lib/fzeet/Control/Header.rb +0 -63
  118. data/lib/fzeet/Control/ListBox.rb +0 -72
  119. data/lib/fzeet/Control/ListView.rb +0 -133
  120. data/lib/fzeet/Control/MonthCalendar.rb +0 -38
  121. data/lib/fzeet/Control/ProgressBar.rb +0 -40
  122. data/lib/fzeet/Control/PropertySheet.rb +0 -51
  123. data/lib/fzeet/Control/Scintilla.rb +0 -117
  124. data/lib/fzeet/Control/Static.rb +0 -34
  125. data/lib/fzeet/Control/SysLink.rb +0 -40
  126. data/lib/fzeet/Control/Tab.rb +0 -59
  127. data/lib/fzeet/Control/TreeView.rb +0 -82
  128. data/lib/fzeet/Control/UpDown.rb +0 -36
  129. data/lib/fzeet/Control/WebBrowser.rb +0 -153
  130. data/lib/fzeet/Dialog.rb +0 -6
  131. data/lib/fzeet/Dialog/ColorDialog.rb +0 -44
  132. data/lib/fzeet/Dialog/Common.rb +0 -89
  133. data/lib/fzeet/Dialog/FileDialog.rb +0 -136
  134. data/lib/fzeet/Dialog/FindReplaceDialog.rb +0 -105
  135. data/lib/fzeet/Dialog/FontDialog.rb +0 -39
  136. data/lib/fzeet/Dialog/PrintDialog.rb +0 -75
  137. data/lib/fzeet/Menu.rb +0 -133
  138. data/lib/fzeet/UIRibbon.rb +0 -417
  139. data/lib/fzeet/Window.rb +0 -5
  140. data/lib/fzeet/windows/common.rb +0 -244
@@ -1,4 +1,4 @@
1
- require_relative 'common'
1
+ require_relative 'core'
2
2
 
3
3
  module Fzeet
4
4
  module Windows
@@ -53,7 +53,7 @@ module Fzeet
53
53
  GET_FEATURE_FROM_THREAD_INTERNET = 0x00000040
54
54
  GET_FEATURE_FROM_THREAD_RESTRICTED = 0x00000080
55
55
 
56
- if WINVER.AtLeastWindowsXP?
56
+ if Version >= :xp && Version.sp >= 2
57
57
  attach_function :CoInternetSetFeatureEnabled, [:int, :ulong, :int], :long
58
58
  attach_function :CoInternetIsFeatureEnabled, [:int, :ulong], :long
59
59
  end
@@ -5,3 +5,23 @@ require_relative 'user/Menu'
5
5
  require_relative 'user/Accelerator'
6
6
  require_relative 'user/Control'
7
7
  require_relative 'user/SystemParametersInfo'
8
+
9
+ module Fzeet
10
+ class Command
11
+ @ids = {
12
+ OK: Windows::IDOK,
13
+ CANCEL: Windows::IDCANCEL,
14
+ }
15
+ @nextId = Windows::WM_APP + 1
16
+
17
+ def self.[](id)
18
+ return id if id.kind_of?(Integer)
19
+
20
+ id = id.upcase
21
+
22
+ @ids[id], @nextId = @nextId, @nextId + 1 unless @ids.include?(id)
23
+
24
+ @ids[id]
25
+ end
26
+ end
27
+ end
@@ -178,5 +178,50 @@ module Fzeet
178
178
 
179
179
  attach_function :CreateAcceleratorTable, :CreateAcceleratorTableA, [:pointer, :int], :pointer
180
180
  attach_function :DestroyAcceleratorTable, [:pointer], :int
181
+
182
+ module AcceleratorTableMethods
183
+ def translate?(msg, window) Windows.TranslateAccelerator(window.handle, @handle, msg) != 0 end
184
+ end
185
+ end
186
+
187
+ class AcceleratorTable < Handle
188
+ include Windows::AcceleratorTableMethods
189
+
190
+ def initialize(*args)
191
+ FFI::MemoryPointer.new(Windows::ACCEL, args.size) { |paccels|
192
+ args.each_with_index { |data, i|
193
+ accel = Windows::ACCEL.new(paccels + i * Windows::ACCEL.size)
194
+
195
+ data.unshift(0) if data.size == 2
196
+
197
+ accel[:fVirt] = Fzeet.flags(data[0], :f)
198
+
199
+ accel[:key] = case key = data[1]
200
+ when Integer
201
+ accel[:fVirt] |= Windows::FVIRTKEY
202
+
203
+ key
204
+ when Symbol
205
+ accel[:fVirt] |= Windows::FVIRTKEY
206
+
207
+ ((key = key.to_s).length == 1) ? key.upcase.ord : Fzeet.constant(key, :vk_)
208
+ when String
209
+ if key.length == 1
210
+ key.ord
211
+ else
212
+ accel[:fVirt] |= Windows::FVIRTKEY
213
+
214
+ Fzeet.constant(key, :vk_)
215
+ end
216
+ end
217
+
218
+ accel[:cmd] = Command[data[2]]
219
+ }
220
+
221
+ @handle = Windows.DetonateLastError(FFI::Pointer::NULL, :CreateAcceleratorTable, paccels, args.size); attach
222
+ }
223
+ end
224
+
225
+ def dispose; Windows.DestroyAcceleratorTable(@handle); detach end
181
226
  end
182
227
  end
@@ -1,11 +1,12 @@
1
- require_relative '../common'
1
+ require_relative '../kernel'
2
+ require_relative '../gdi'
2
3
 
3
4
  module Fzeet
4
5
  module Windows
5
6
  ffi_lib 'user32'
6
7
  ffi_convention :stdcall
7
8
 
8
- if WINVER.AtLeastWindowsVista?
9
+ if Version >= :vista
9
10
  attach_function :SetProcessDPIAware, [], :int
10
11
  end
11
12
 
@@ -59,4 +59,58 @@ module Fzeet
59
59
  BN_SETFOCUS = 6
60
60
  BN_KILLFOCUS = 7
61
61
  end
62
+
63
+ module ButtonMethods
64
+ def image=(image) sendmsg(:setimage, Windows::IMAGE_BITMAP, image.handle) end
65
+
66
+ def note=(text) Windows.LPWSTR(text) { |p| sendmsg(:setnote, 0, p) } end
67
+
68
+ def checked?; sendmsg(:getcheck) == Windows::BST_CHECKED end
69
+ def checked=(checked) sendmsg(:setcheck, (checked) ? Windows::BST_CHECKED : Windows::BST_UNCHECKED) end
70
+
71
+ def indeterminate?; sendmsg(:getcheck) == Windows::BST_INDETERMINATE end
72
+ def indeterminate=(indeterminate) sendmsg(:setcheck, (indeterminate) ? Windows::BST_INDETERMINATE : Windows::BST_UNCHECKED) end
73
+
74
+ def pushed?; (sendmsg(:getstate) & Windows::BST_PUSHED) == Windows::BST_PUSHED end
75
+ def pushed=(pushed) sendmsg(:setstate, (pushed) ? 1 : 0) end
76
+ end
77
+
78
+ class Button < Control
79
+ include ButtonMethods
80
+
81
+ Prefix = {
82
+ xstyle: [:ws_ex_],
83
+ style: [:bs_, :ws_],
84
+ message: [:bm_, :bcm_, :ccm_, :wm_],
85
+ notification: [:bn_, :bcn_, :nm_]
86
+ }
87
+
88
+ def initialize(parent, id, opts = {}, &block)
89
+ super('Button', parent, id, opts)
90
+
91
+ width, height = 0, 0
92
+
93
+ using(ScreenDC.new) { |dc| dc.select(Font) {
94
+ minw = dc.textExtent('W' * 8).to_a[0]
95
+ width, height = dc.textExtent("W#{text}W").to_a
96
+
97
+ width = minw if width < minw; height = (height * 1.8).ceil
98
+ }}
99
+
100
+ self.location = 10, 10 if location.client!(parent).to_a == [0, 0]
101
+ self.size = width, height if size.to_a == [0, 0]
102
+
103
+ @parent.on(:command, @id, &block) if block
104
+ end
105
+
106
+ def on(notification, &block)
107
+ if (notification = Fzeet.constant(notification, *self.class::Prefix[:notification])) < Windows::BCN_LAST
108
+ @parent.on(:command, @id, notification, &block)
109
+ else
110
+ @parent.on(:notify, @id, notification, &block)
111
+ end
112
+
113
+ self
114
+ end
115
+ end
62
116
  end
@@ -1,4 +1,4 @@
1
- require_relative 'Common'
1
+ require_relative 'ListBox'
2
2
 
3
3
  module Fzeet
4
4
  module Windows
@@ -69,4 +69,47 @@ module Fzeet
69
69
  CBN_SELENDOK = 9
70
70
  CBN_SELENDCANCEL = 10
71
71
  end
72
+
73
+ module ComboBoxMethods
74
+ include ListBoxMethods
75
+
76
+ def textlen(i) raise "GETLBTEXTLEN failed." if (len = sendmsg(:getlbtextlen, i)) == -1; len end
77
+
78
+ def [](i)
79
+ i = sendmsg(:getcursel) if i == :selected
80
+
81
+ return '' if i == -1 || (len = textlen(i) + 1) == 1
82
+
83
+ ''.tap { |item|
84
+ FFI::MemoryPointer.new(:char, len) { |buf|
85
+ raise "GETLBTEXT failed." if sendmsg(:getlbtext, i, buf) == -1
86
+
87
+ item << buf.read_string
88
+ }
89
+ }
90
+ end
91
+ end
92
+
93
+ class ComboBox < Control
94
+ include ComboBoxMethods
95
+
96
+ Prefix = {
97
+ xstyle: [:ws_ex_],
98
+ style: [:cbs_, :ws_],
99
+ message: [:cb_, :wm_],
100
+ notification: [:cbn_]
101
+ }
102
+
103
+ def initialize(parent, id, opts = {}, &block)
104
+ super('ComboBox', parent, id, opts)
105
+
106
+ @parent.on(:command, @id, &block) if block
107
+ end
108
+
109
+ def on(notification, &block)
110
+ @parent.on(:command, @id, Fzeet.constant(notification, *self.class::Prefix[:notification]), &block)
111
+
112
+ self
113
+ end
114
+ end
72
115
  end
@@ -1,4 +1,5 @@
1
- require_relative '../Window'
1
+ require_relative '../SystemParametersInfo'
2
+ require_relative '../Window/WindowMethods'
2
3
 
3
4
  module Fzeet
4
5
  module Windows
@@ -9,4 +10,90 @@ module Fzeet
9
10
  :code, :uint
10
11
  end
11
12
  end
13
+
14
+ class Control < Handle
15
+ include WindowMethods
16
+
17
+ Windows::NONCLIENTMETRICS.new.tap { |ncm|
18
+ ncm[:cbSize] = ncm.size
19
+
20
+ Windows.DetonateLastError(0, :SystemParametersInfo, Windows::SPI_GETNONCLIENTMETRICS, ncm.size, ncm, 0)
21
+
22
+ Font = IndirectFont.new(ncm[:lfMenuFont])
23
+
24
+ at_exit { Font.dispose }
25
+ }
26
+
27
+ def self.crackNotification(args) end
28
+
29
+ def initialize(className, parent, id, opts = {})
30
+ @parent = parent
31
+ @id = Command[id]
32
+
33
+ handlers = {}
34
+
35
+ opts.delete_if { |k, v|
36
+ next false unless v.kind_of?(Proc)
37
+
38
+ handlers[k] = v; true
39
+ }
40
+
41
+ _opts = {
42
+ xstyle: [],
43
+ caption: id.capitalize,
44
+ style: [],
45
+ x: 0,
46
+ y: 0,
47
+ width: 0,
48
+ height: 0,
49
+ position: [],
50
+ anchor: nil
51
+ }
52
+ badopts = opts.keys - _opts.keys; raise "Bad option(s): #{badopts.join(', ')}." unless badopts.empty?
53
+ _opts.merge!(opts)
54
+
55
+ _opts[:xstyle] = Fzeet.flags(_opts[:xstyle], *self.class::Prefix[:xstyle])
56
+ _opts[:caption] = _opts[:caption].to_s
57
+ _opts[:style] = Fzeet.flags([:child, :visible, :tabstop], :ws_) | Fzeet.flags(_opts[:style], *self.class::Prefix[:style])
58
+ _opts[:x], _opts[:y], _opts[:width], _opts[:height] = _opts[:position] unless _opts[:position].empty?
59
+
60
+ @handle = Windows.DetonateLastError(FFI::Pointer::NULL, :CreateWindowEx,
61
+ _opts[:xstyle], className, _opts[:caption], _opts[:style],
62
+ _opts[:x], _opts[:y], _opts[:width], _opts[:height],
63
+ @parent.handle, FFI::Pointer.new(@id), Windows.GetModuleHandle(nil), nil
64
+ )
65
+
66
+ attach
67
+
68
+ sendmsg(:setfont, Font.handle, 1)
69
+
70
+ handlers.each { |k, v| on(k, &v) }
71
+
72
+ case _opts[:anchor]
73
+ when :ltr
74
+ @parent.on(:size) { |args|
75
+ self.position = @parent.rect.tap { |r| r[:bottom] = _opts[:height] }.to_a
76
+
77
+ args[:result] = nil if @parent.class == MDIChild
78
+ }
79
+ when :lrb
80
+ @parent.on(:size) { |args|
81
+ self.position = @parent.rect.tap { |r| r[:top] = r[:bottom] - _opts[:height]; r[:bottom] = _opts[:height] }.to_a
82
+
83
+ args[:result] = nil if @parent.class == MDIChild
84
+ }
85
+ when :ltrb
86
+ @parent.on(:size) { |args|
87
+ self.position = @parent.rect.to_a
88
+
89
+ args[:result] = nil if @parent.class == MDIChild
90
+ }
91
+ else raise ArgumentError, "Bad anchor spec: #{_opts[:anchor]}."
92
+ end if _opts[:anchor]
93
+ end
94
+
95
+ attr_reader :parent, :id
96
+
97
+ def dispose; detach end
98
+ end
12
99
  end
@@ -68,4 +68,54 @@ module Fzeet
68
68
  EN_ALIGN_LTR_EC = 0x0700
69
69
  EN_ALIGN_RTL_EC = 0x0701
70
70
  end
71
+
72
+ module EditMethods
73
+ def clear; self.text = ''; self end
74
+
75
+ def select(s = 0, e = -1) sendmsg(:setsel, s, e); self end
76
+
77
+ def cuebanner=(text) Windows.LPWSTR(text) { |p| sendmsg(:setcuebanner, 1, p) } end
78
+
79
+ def showBalloontip(text, title = '', icon = 1)
80
+ Windows.LPWSTR(text) { |ptext| Windows.LPWSTR(title) { |ptitle|
81
+ ebt = Windows::EDITBALLOONTIP.new
82
+
83
+ ebt[:cbStruct] = ebt.size
84
+ ebt[:pszTitle] = ptitle
85
+ ebt[:pszText] = ptext
86
+ ebt[:ttiIcon] = Fzeet.constant(icon, :tti_)
87
+
88
+ sendmsg(:showBalloontip, 0, ebt.pointer)
89
+ }}
90
+
91
+ self
92
+ end
93
+
94
+ def hideBalloontip; sendmsg(:hideBalloontip); self end
95
+ end
96
+
97
+ class Edit < Control
98
+ include EditMethods
99
+
100
+ Prefix = {
101
+ xstyle: [:ws_ex_],
102
+ style: [:es_, :ws_],
103
+ message: [:em_, :wm_],
104
+ notification: [:en_]
105
+ }
106
+
107
+ def initialize(parent, id, opts = {}, &block)
108
+ super('Edit', parent, id, opts)
109
+
110
+ style << :border; reframe
111
+
112
+ @parent.on(:command, @id, &block) if block
113
+ end
114
+
115
+ def on(notification, &block)
116
+ @parent.on(:command, @id, Fzeet.constant(notification, *self.class::Prefix[:notification]), &block)
117
+
118
+ self
119
+ end
120
+ end
71
121
  end
@@ -75,4 +75,73 @@ module Fzeet
75
75
  LBN_SETFOCUS = 4
76
76
  LBN_KILLFOCUS = 5
77
77
  end
78
+
79
+ module ListBoxMethods
80
+ def textlen(i) raise "GETTEXTLEN failed." if (len = sendmsg(:gettextlen, i)) == -1; len end
81
+
82
+ def [](i)
83
+ i = sendmsg(:getcursel) if i == :selected
84
+
85
+ return '' if i == -1 || (len = textlen(i) + 1) == 1
86
+
87
+ ''.tap { |item|
88
+ FFI::MemoryPointer.new(:char, len) { |buf|
89
+ raise "GETTEXT failed." if sendmsg(:gettext, i, buf) == -1
90
+
91
+ item << buf.read_string
92
+ }
93
+ }
94
+ end
95
+
96
+ def clear; sendmsg(:resetcontent); self end
97
+
98
+ def append(item)
99
+ [*item].each { |item|
100
+ p = FFI::MemoryPointer.from_string(item.to_s)
101
+
102
+ raise 'ADDSTRING failed.' if [-1, -2].include?(sendmsg(:addstring, 0, p).tap { p.free })
103
+ }
104
+
105
+ self
106
+ end
107
+
108
+ def selected=(i)
109
+ i = case i
110
+ when -1; 0xffffffff
111
+ when :first; 0
112
+ when :last; length - 1
113
+ else i
114
+ end
115
+
116
+ raise 'SETCURSEL failed.' if sendmsg(:setcursel, i) == -1 && i != 0xffffffff
117
+
118
+ self
119
+ end
120
+
121
+ def length; raise 'GETCOUNT failed.' if (len = sendmsg(:getcount)) == -1; len end
122
+ def each; length.times { |i| yield self[i] }; self end
123
+ end
124
+
125
+ class ListBox < Control
126
+ include ListBoxMethods
127
+
128
+ Prefix = {
129
+ xstyle: [:ws_ex_],
130
+ style: [:lbs_, :ws_],
131
+ message: [:lb_, :wm_],
132
+ notification: [:lbn_]
133
+ }
134
+
135
+ def initialize(parent, id, opts = {}, &block)
136
+ super('ListBox', parent, id, opts)
137
+
138
+ @parent.on(:command, @id, &block) if block
139
+ end
140
+
141
+ def on(notification, &block)
142
+ @parent.on(:command, @id, Fzeet.constant(notification, *self.class::Prefix[:notification]), &block)
143
+
144
+ self
145
+ end
146
+ end
78
147
  end