fzeet 0.6.2 → 0.6.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,59 @@
1
+ require_relative 'Common'
2
+
3
+ module Fzeet
4
+ module TabMethods
5
+ class Item
6
+ def initialize(tab, i) @tab, @index = tab, i end
7
+
8
+ attr_reader :tab, :index
9
+ end
10
+
11
+ def [](i) Item.new(self, i) end
12
+
13
+ def count; sendmsg(:getitemcount) end
14
+ alias :size :count
15
+ alias :length :count
16
+
17
+ def insert(text, i = count)
18
+ tci = Windows::TCITEM.new
19
+
20
+ tci[:mask] = Fzeet.flags(:text, :tcif_)
21
+ tci[:pszText] = ptext = FFI::MemoryPointer.from_string(text)
22
+
23
+ sendmsg(:insertitem, i, tci.pointer)
24
+
25
+ self
26
+ ensure
27
+ ptext.free
28
+ end
29
+
30
+ def current; self[sendmsg(:getcursel)] end
31
+ end
32
+
33
+ class Tab < Control
34
+ include TabMethods
35
+
36
+ Prefix = {
37
+ xstyle: [:tcs_ex_, :ws_ex_],
38
+ style: [:tcs_, :ws_],
39
+ message: [:tcm_, :ccm_, :wm_],
40
+ notification: [:tcn_, :nm_]
41
+ }
42
+
43
+ def self.crackNotification(args) end
44
+
45
+ def initialize(parent, id, opts = {}, &block)
46
+ super('SysTabControl32', parent, id, opts)
47
+
48
+ style << :clipsiblings
49
+
50
+ @parent.on(:notify, @id, &block) if block
51
+ end
52
+
53
+ def on(notification, &block)
54
+ @parent.on(:notify, @id, Fzeet.constant(notification, *self.class::Prefix[:notification]), &block)
55
+
56
+ self
57
+ end
58
+ end
59
+ end
@@ -2,7 +2,57 @@ require_relative 'Common'
2
2
 
3
3
  module Fzeet
4
4
  module TreeViewMethods
5
+ class Item
6
+ def initialize(text) @text = text end
5
7
 
8
+ attr_reader :text, :root, :parent, :handle
9
+
10
+ def root=(root) raise 'Can\'t change established @root.' if @root; @root = root end
11
+ def parent=(parent) raise 'Can\'t change established @parent.' if @parent; @parent = parent end
12
+ def handle=(handle) raise 'Can\'t change established @handle.' if @handle; @handle = handle end
13
+
14
+ def append(text)
15
+ item = Item.new(text)
16
+
17
+ tvis = Windows::TVINSERTSTRUCT.new
18
+
19
+ tvis[:hInsertAfter] = Windows::TVI_LAST
20
+ tvis[:hParent] = @handle
21
+
22
+ tvi = tvis[:item]
23
+
24
+ tvi[:mask] = Windows::TVIF_TEXT
25
+ tvi[:pszText] = ptext = FFI::MemoryPointer.from_string(item.text)
26
+
27
+ item.root, item.parent = @root, self
28
+ item.handle = @root.sendmsg(:insertitem, 0, tvis.pointer)
29
+
30
+ item
31
+ ensure
32
+ ptext.free
33
+ end
34
+ end
35
+
36
+ def append(text)
37
+ item = Item.new(text)
38
+
39
+ tvis = Windows::TVINSERTSTRUCT.new
40
+
41
+ tvis[:hInsertAfter] = Windows::TVI_LAST
42
+ tvis[:hParent] = Windows::TVI_ROOT
43
+
44
+ tvi = tvis[:item]
45
+
46
+ tvi[:mask] = Windows::TVIF_TEXT
47
+ tvi[:pszText] = ptext = FFI::MemoryPointer.from_string(item.text)
48
+
49
+ item.root, item.parent = self, self
50
+ item.handle = sendmsg(:insertitem, 0, tvis.pointer)
51
+
52
+ item
53
+ ensure
54
+ ptext.free
55
+ end
6
56
  end
7
57
 
8
58
  class TreeView < Control
data/lib/fzeet/Control.rb CHANGED
@@ -2,6 +2,7 @@ require_relative 'Control/Button'
2
2
  require_relative 'Control/SysLink' if Fzeet::Windows::WINVER.AtLeastWindowsXP?
3
3
  require_relative 'Control/Static'
4
4
  require_relative 'Control/Edit'
5
+ require_relative 'Control/Scintilla'
5
6
  require_relative 'Control/UpDown'
6
7
  require_relative 'Control/MonthCalendar'
7
8
  require_relative 'Control/DateTimePicker'
@@ -12,3 +13,5 @@ require_relative 'Control/Header'
12
13
  require_relative 'Control/ListView'
13
14
  require_relative 'Control/TreeView'
14
15
  require_relative 'Control/ProgressBar'
16
+ require_relative 'Control/PropertySheet'
17
+ require_relative 'Control/Tab'
@@ -87,6 +87,80 @@ module Fzeet
87
87
  result || Windows.DefWindowProc(hwnd, uMsg, wParam, lParam)
88
88
  }
89
89
 
90
+ FrameProc = FFI::Function.new(:long, [:pointer, :uint, :uint, :long], convention: :stdcall) { |hwnd, uMsg, wParam, lParam|
91
+ begin
92
+ if uMsg == Windows::WM_NCCREATE
93
+ @@instances[hwnd.to_i] = ObjectSpace._id2ref(
94
+ Windows::CREATESTRUCT.new(FFI::Pointer.new(lParam))[:lpCreateParams].to_i
95
+ )
96
+
97
+ @@instances[hwnd.to_i].instance_variable_set(:@handle, hwnd)
98
+ end
99
+
100
+ if uMsg == Windows::WM_CREATE
101
+ @@instances[hwnd.to_i].menu = Menu.new.
102
+ append(:popup, '&Window', PopupMenu.new)
103
+
104
+ ccs = Windows::CLIENTCREATESTRUCT.new
105
+
106
+ ccs[:hWindowMenu] = @@instances[hwnd.to_i].menu.submenus[0].handle
107
+ ccs[:idFirstChild] = 50000
108
+
109
+ hwndClient = Windows.DetonateLastError(FFI::Pointer::NULL, :CreateWindowEx,
110
+ 0, 'MDIClient', nil, Fzeet.flags([:child, :clipsiblings, :clipchildren, :visible], :ws_),
111
+ 0, 0, 0, 0,
112
+ hwnd, nil, Windows.GetModuleHandle(nil), ccs
113
+ )
114
+
115
+ @@instances[hwnd.to_i].instance_variable_set(:@client, Handle.wrap(hwndClient, WindowMethods))
116
+ end
117
+
118
+ result = @@instances[hwnd.to_i].windowProc(hwnd, uMsg, wParam, lParam) if @@instances[hwnd.to_i]
119
+ rescue
120
+ answer = Fzeet.message %Q{#{$!}\n\n#{$!.backtrace.join("\n")}}, buttons: [:abort, :retry, :ignore], icon: :error
121
+
122
+ Application.quit if answer.abort?
123
+ ensure
124
+ if uMsg == Windows::WM_NCDESTROY
125
+ @@instances[hwnd.to_i].dialog = false
126
+
127
+ @@instances.delete(hwnd.to_i)
128
+ end
129
+ end
130
+
131
+ hwndClient = @@instances[hwnd.to_i] && @@instances[hwnd.to_i].client && @@instances[hwnd.to_i].client.handle
132
+
133
+ result || Windows.DefFrameProc(hwnd, hwndClient, uMsg, wParam, lParam)
134
+ }
135
+
136
+ MDIChildProc = FFI::Function.new(:long, [:pointer, :uint, :uint, :long], convention: :stdcall) { |hwnd, uMsg, wParam, lParam|
137
+ begin
138
+ if uMsg == Windows::WM_NCCREATE
139
+ @@instances[hwnd.to_i] = ObjectSpace._id2ref(
140
+ Windows::MDICREATESTRUCT.new(
141
+ Windows::CREATESTRUCT.new(FFI::Pointer.new(lParam))[:lpCreateParams]
142
+ )[:lParam]
143
+ )
144
+
145
+ @@instances[hwnd.to_i].instance_variable_set(:@handle, hwnd)
146
+ end
147
+
148
+ result = @@instances[hwnd.to_i].windowProc(hwnd, uMsg, wParam, lParam) if @@instances[hwnd.to_i]
149
+ rescue
150
+ answer = Fzeet.message %Q{#{$!}\n\n#{$!.backtrace.join("\n")}}, buttons: [:abort, :retry, :ignore], icon: :error
151
+
152
+ Application.quit if answer.abort?
153
+ ensure
154
+ if uMsg == Windows::WM_NCDESTROY
155
+ @@instances[hwnd.to_i].dialog = false
156
+
157
+ @@instances.delete(hwnd.to_i)
158
+ end
159
+ end
160
+
161
+ result || Windows.DefMDIChildProc(hwnd, uMsg, wParam, lParam)
162
+ }
163
+
90
164
  DialogProc = FFI::Function.new(:int, [:pointer, :uint, :uint, :long], convention: :stdcall) { |hwnd, uMsg, wParam, lParam|
91
165
  begin
92
166
  if uMsg == Windows::WM_INITDIALOG
@@ -173,9 +247,10 @@ module Fzeet
173
247
  y: Windows::CW_USEDEFAULT,
174
248
  width: Windows::CW_USEDEFAULT,
175
249
  height: Windows::CW_USEDEFAULT,
176
- position: [],
177
250
  parent: nil,
178
- menu: nil
251
+ menu: nil,
252
+ position: [],
253
+ anchor: nil
179
254
  }
180
255
  badopts = opts.keys - _opts.keys; raise "Bad option(s): #{badopts.join(', ')}." unless badopts.empty?
181
256
  _opts.merge!(opts)
@@ -213,10 +288,17 @@ module Fzeet
213
288
 
214
289
  eachChild(&:dispose)
215
290
  }
291
+
292
+ case _opts[:anchor]
293
+ when :ltr; @parent.on(:size) { self.position = @parent.rect.tap { |r| r[:bottom] = _opts[:height] }.to_a }
294
+ when :lrb; @parent.on(:size) { self.position = @parent.rect.tap { |r| r[:top] = r[:bottom] - _opts[:height]; r[:bottom] = _opts[:height] }.to_a }
295
+ when :ltrb; @parent.on(:size) { self.position = @parent.rect.to_a }
296
+ else raise ArgumentError, "Bad anchor spec: #{_opts[:anchor]}."
297
+ end if _opts[:anchor] && @parent
216
298
  end
217
299
  end
218
300
 
219
- attr_reader :parent, :ribbon
301
+ attr_reader :parent, :client, :ribbon
220
302
 
221
303
  def dispose; Windows.DestroyWindow(@handle) end
222
304
 
@@ -0,0 +1,29 @@
1
+ require_relative 'Common'
2
+
3
+ module Fzeet
4
+ Container = BasicWindow['Fzeet.Container']
5
+
6
+ class Container
7
+ def initialize(parent, opts = {})
8
+ opts[:parent] = parent
9
+ (opts[:style] ||= []) << :visible << :child << :clipsiblings << :clipchildren
10
+
11
+ super(opts)
12
+
13
+ style >> :caption >> :thickframe
14
+
15
+ on(:erasebkgnd) { |args|
16
+ Handle.wrap(FFI::Pointer.new(args[:wParam]), DCMethods).
17
+ fillRect(
18
+ rect,
19
+ case @parent
20
+ when Dialog; FFI::Pointer.new(Windows::CTLCOLOR_DLG + 1)
21
+ when BasicWindow; FFI::Pointer.new(Windows.DetonateLastError(-1, :GetClassLong, @parent.handle, Windows::GCL_HBRBACKGROUND))
22
+ end
23
+ )
24
+
25
+ args[:result] = 1
26
+ }
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,30 @@
1
+ require_relative 'Common'
2
+
3
+ module Fzeet
4
+ Frame = BasicWindow['Fzeet.Frame',
5
+ wndProc: BasicWindow::FrameProc,
6
+ background: SystemBrush.new(:appworkspace)
7
+ ]
8
+
9
+ class Frame
10
+ def initialize(opts = {})
11
+ (opts[:style] ||= []) << :overlappedwindow << :clipsiblings << :clipchildren
12
+
13
+ super
14
+ end
15
+ end
16
+
17
+ MDIChild = BasicWindow['Fzeet.MDIChild',
18
+ wndProc: BasicWindow::MDIChildProc
19
+ ]
20
+
21
+ class MDIChild
22
+ def initialize(parent, opts = {})
23
+ (opts[:xstyle] ||= []) << :mdichild
24
+ (opts[:style] ||= []) << :child << :overlappedwindow << :clipsiblings << :clipchildren << :visible
25
+ opts[:parent] = parent
26
+
27
+ super(opts)
28
+ end
29
+ end
30
+ end
@@ -7,7 +7,7 @@ module Fzeet
7
7
 
8
8
  class View
9
9
  def initialize(opts = {})
10
- (opts[:style] ||= []) << :overlappedwindow << :clipchildren
10
+ (opts[:style] ||= []) << :overlappedwindow << :clipsiblings << :clipchildren
11
11
 
12
12
  super
13
13
  end
@@ -5,7 +5,7 @@ module Fzeet
5
5
 
6
6
  class Window
7
7
  def initialize(opts = {})
8
- (opts[:style] ||= []) << :overlappedwindow << :clipchildren
8
+ (opts[:style] ||= []) << :overlappedwindow << :clipsiblings << :clipchildren
9
9
 
10
10
  super
11
11
  end
@@ -4,8 +4,19 @@ module Fzeet
4
4
  module WindowMethods
5
5
  include Toggle
6
6
 
7
- def message(message, opts = {window: self}) Fzeet.message(message, opts) end
8
- def question(message, opts = {window: self}) Fzeet.question(message, opts) end
7
+ def message(message, opts = {})
8
+ opts[:window] ||= self
9
+ opts[:caption] ||= text
10
+
11
+ Fzeet.message(message, opts)
12
+ end
13
+
14
+ def question(message, opts = {})
15
+ opts[:window] ||= self
16
+ opts[:caption] ||= text
17
+
18
+ Fzeet.question(message, opts)
19
+ end
9
20
 
10
21
  def sendmsg(msg, wParam = 0, lParam = 0)
11
22
  Windows.SendMessage(
data/lib/fzeet/Window.rb CHANGED
@@ -1,3 +1,5 @@
1
1
  require_relative 'Window/Window'
2
2
  require_relative 'Window/View'
3
+ require_relative 'Window/Container'
4
+ require_relative 'Window/MDI'
3
5
  require_relative 'Window/Dialog'
Binary file
@@ -0,0 +1,88 @@
1
+ require_relative 'Common'
2
+
3
+ module Fzeet
4
+ module Windows
5
+ TCS_SCROLLOPPOSITE = 0x0001
6
+ TCS_BOTTOM = 0x0002
7
+ TCS_RIGHT = 0x0002
8
+ TCS_MULTISELECT = 0x0004
9
+ TCS_FLATBUTTONS = 0x0008
10
+ TCS_FORCEICONLEFT = 0x0010
11
+ TCS_FORCELABELLEFT = 0x0020
12
+ TCS_HOTTRACK = 0x0040
13
+ TCS_VERTICAL = 0x0080
14
+ TCS_TABS = 0x0000
15
+ TCS_BUTTONS = 0x0100
16
+ TCS_SINGLELINE = 0x0000
17
+ TCS_MULTILINE = 0x0200
18
+ TCS_RIGHTJUSTIFY = 0x0000
19
+ TCS_FIXEDWIDTH = 0x0400
20
+ TCS_RAGGEDRIGHT = 0x0800
21
+ TCS_FOCUSONBUTTONDOWN = 0x1000
22
+ TCS_OWNERDRAWFIXED = 0x2000
23
+ TCS_TOOLTIPS = 0x4000
24
+ TCS_FOCUSNEVER = 0x8000
25
+
26
+ TCS_EX_FLATSEPARATORS = 0x00000001
27
+ TCS_EX_REGISTERDROP = 0x00000002
28
+
29
+ TCM_FIRST = 0x1300
30
+ TCM_GETIMAGELIST = TCM_FIRST + 2
31
+ TCM_SETIMAGELIST = TCM_FIRST + 3
32
+ TCM_GETITEMCOUNT = TCM_FIRST + 4
33
+ TCM_GETITEM = TCM_FIRST + 5
34
+ TCM_SETITEM = TCM_FIRST + 6
35
+ TCM_INSERTITEM = TCM_FIRST + 7
36
+ TCM_DELETEITEM = TCM_FIRST + 8
37
+ TCM_DELETEALLITEMS = TCM_FIRST + 9
38
+ TCM_GETITEMRECT = TCM_FIRST + 10
39
+ TCM_GETCURSEL = TCM_FIRST + 11
40
+ TCM_SETCURSEL = TCM_FIRST + 12
41
+ TCM_HITTEST = TCM_FIRST + 13
42
+ TCM_SETITEMEXTRA = TCM_FIRST + 14
43
+ TCM_ADJUSTRECT = TCM_FIRST + 40
44
+ TCM_SETITEMSIZE = TCM_FIRST + 41
45
+ TCM_REMOVEIMAGE = TCM_FIRST + 42
46
+ TCM_SETPADDING = TCM_FIRST + 43
47
+ TCM_GETROWCOUNT = TCM_FIRST + 44
48
+ TCM_GETTOOLTIPS = TCM_FIRST + 45
49
+ TCM_SETTOOLTIPS = TCM_FIRST + 46
50
+ TCM_GETCURFOCUS = TCM_FIRST + 47
51
+ TCM_SETCURFOCUS = TCM_FIRST + 48
52
+ TCM_SETMINTABWIDTH = TCM_FIRST + 49
53
+ TCM_DESELECTALL = TCM_FIRST + 50
54
+ TCM_HIGHLIGHTITEM = TCM_FIRST + 51
55
+ TCM_SETEXTENDEDSTYLE = TCM_FIRST + 52
56
+ TCM_GETEXTENDEDSTYLE = TCM_FIRST + 53
57
+ TCM_SETUNICODEFORMAT = CCM_SETUNICODEFORMAT
58
+ TCM_GETUNICODEFORMAT = CCM_GETUNICODEFORMAT
59
+
60
+ TCN_FIRST = 0x1_0000_0000 - 550
61
+ TCN_LAST = 0x1_0000_0000 - 580
62
+ TCN_KEYDOWN = TCN_FIRST - 0
63
+ TCN_SELCHANGE = TCN_FIRST - 1
64
+ TCN_SELCHANGING = TCN_FIRST - 2
65
+ TCN_GETOBJECT = TCN_FIRST - 3
66
+ TCN_FOCUSCHANGE = TCN_FIRST - 4
67
+
68
+ TCIF_TEXT = 0x0001
69
+ TCIF_IMAGE = 0x0002
70
+ TCIF_RTLREADING = 0x0004
71
+ TCIF_PARAM = 0x0008
72
+ TCIF_STATE = 0x0010
73
+
74
+ TCIS_BUTTONPRESSED = 0x0001
75
+ TCIS_HIGHLIGHTED = 0x0002
76
+
77
+ class TCITEM < FFI::Struct
78
+ layout \
79
+ :mask, :uint,
80
+ :dwState, :ulong,
81
+ :dwStateMask, :ulong,
82
+ :pszText, :pointer,
83
+ :cchTextMax, :int,
84
+ :iImage, :int,
85
+ :lParam, :long
86
+ end
87
+ end
88
+ end
@@ -11,3 +11,4 @@ require_relative 'comctl/ListView'
11
11
  require_relative 'comctl/TreeView'
12
12
  require_relative 'comctl/ProgressBar'
13
13
  require_relative 'comctl/PropertySheet'
14
+ require_relative 'comctl/Tab'
@@ -48,6 +48,8 @@ module Fzeet
48
48
 
49
49
  attach_function :SelectObject, [:pointer, :pointer], :pointer
50
50
 
51
+ attach_function :GetTextExtentPoint, :GetTextExtentPointA, [:pointer, :string, :int, :pointer], :int
52
+
51
53
  attach_function :GetTextColor, [:pointer], :ulong
52
54
  attach_function :SetTextColor, [:pointer, :ulong], :ulong
53
55