fzeet 0.6.2 → 0.6.3

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/LICENSE_Scintilla ADDED
@@ -0,0 +1,20 @@
1
+ License for Scintilla and SciTE
2
+
3
+ Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org>
4
+
5
+ All Rights Reserved
6
+
7
+ Permission to use, copy, modify, and distribute this software and its
8
+ documentation for any purpose and without fee is hereby granted,
9
+ provided that the above copyright notice appear in all copies and that
10
+ both that copyright notice and this permission notice appear in
11
+ supporting documentation.
12
+
13
+ NEIL HODGSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
14
+ SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
15
+ AND FITNESS, IN NO EVENT SHALL NEIL HODGSON BE LIABLE FOR ANY
16
+ SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18
+ WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19
+ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
20
+ OR PERFORMANCE OF THIS SOFTWARE.
@@ -0,0 +1,7 @@
1
+ require 'fzeet'
2
+
3
+ include Fzeet
4
+
5
+ Application.run { |window| window.dialog = true
6
+ Button.new(window, :button1)
7
+ }
@@ -3,7 +3,7 @@ require 'fzeet'
3
3
  include Fzeet
4
4
 
5
5
  Application.run { |window| window.dialog = true
6
- Header.new(window, :header1, style: :buttons, position: [10, 10, 200, 30]).
6
+ Header.new(window, :header1, style: :buttons, height: 30, anchor: :ltr).
7
7
  insertItem(0, 'Item1', 100).
8
8
  insertItem(1, 'Item2', 100)
9
9
  }
@@ -3,9 +3,27 @@ require 'fzeet'
3
3
  include Fzeet
4
4
 
5
5
  Application.run { |window| window.dialog = true
6
- ListView.new(window, :listview1, style: [:border, :report], position: [10, 10, 200, 200]).
6
+ ascending = [true, true]
7
+
8
+ ListView.new(window, :listview1, style: :report, anchor: :ltrb).
7
9
  tap { |lv| lv.xstyle << :gridlines << :fullrowselect }.
8
10
  insertColumn(0, 'Column1', 100).insertColumn(1, 'Column2', 100).
9
- insertItem(0, 0, 'Item1').insertItem(0, 1, 'Item2').
10
- insertItem(1, 0, 'Item3').insertItem(1, 1, 'Item4')
11
+ insertItem(0, 0, 'Item5').insertItem(0, 1, 'Item2').
12
+ insertItem(1, 0, 'Item1').insertItem(1, 1, 'Item6').
13
+ insertItem(2, 0, 'Item3').insertItem(2, 1, 'Item4').
14
+
15
+ on(:columnclick) { |args|
16
+ lv, index = args[:sender], args[:index]
17
+ asc, header = ascending[index], lv.header
18
+
19
+ lv.sort(index) { |a, b| (asc) ? a.text <=> b.text : b.text <=> a.text }
20
+
21
+ header.count.times { |i|
22
+ style = (asc) ? :sortup : :sortdown if i == index
23
+
24
+ header.modifyItem(i, "Column#{i + 1}", style)
25
+ }
26
+
27
+ ascending[index] = !asc
28
+ }
11
29
  }
@@ -2,49 +2,12 @@ require 'fzeet'
2
2
 
3
3
  include Fzeet
4
4
 
5
- pointers, pages = [], 3
6
-
7
5
  Application.run { |window| window.dialog = true
8
- psps = Class.new(FFI::Struct) {
9
- layout \
10
- :array, [Windows::PROPSHEETPAGE, pages]
11
- }.new
12
-
13
- dt = Windows::DLGTEMPLATE.new
14
-
15
- dt[:style] = Fzeet.flags([:'3dlook', :control, :child, :tabstop], :ds_, :ws_)
16
- dt[:x], dt[:y], dt[:cx], dt[:cy] = 100, 100, 300, 150
17
-
18
- pages.times { |i|
19
- psp = psps[:array][i]
20
-
21
- psp[:dwSize] = psp.size
22
- psp[:dwFlags] = Fzeet.flags([:dlgindirect, :usetitle], :psp_)
23
- psp[:hInstance] = Windows.GetModuleHandle(nil)
24
- psp[:template][:pResource] = dt
25
- psp[:pszTitle] = pointers.push(FFI::MemoryPointer.from_string("Page#{i + 1}")).last
26
- }
27
-
28
- psh = Windows::PROPSHEETHEADER.new
29
-
30
- psh[:dwSize] = psh.size
31
- psh[:dwFlags] = Fzeet.flags(:propsheetpage, :psh_)
32
- psh[:hwndParent] = window.handle
33
- psh[:hInstance] = Windows.GetModuleHandle(nil)
34
- psh[:pszCaption] = pointers.push(FFI::MemoryPointer.from_string('Sheet')).last
35
- psh[:nPages] = pages
36
- psh[:start][:nStartPage] = 1
37
- psh[:pages][:ppsp] = psps
38
-
39
6
  Button.new(window, :sheet, position: [10, 10, 76, 24]) {
40
- Windows.DetonateLastError(-1, :PropertySheet, psh)
7
+ PropertySheet.new(window)
41
8
  }
42
9
 
43
10
  Button.new(window, :wizard, position: [90, 10, 76, 24]) {
44
- psh[:dwFlags] |= Windows::PSH_WIZARD
45
- Windows.DetonateLastError(-1, :PropertySheet, psh)
46
- psh[:dwFlags] &= ~Windows::PSH_WIZARD
11
+ PropertySheet.new(window, wizard: true)
47
12
  }
48
-
49
- window.on(:destroy) { pointers.each(&:free) }
50
13
  }
@@ -0,0 +1,20 @@
1
+ require 'fzeet'
2
+
3
+ include Fzeet
4
+
5
+ Application.run { |window|
6
+ Scintilla.new(window, :sci1, anchor: :ltrb).tap { |sci|
7
+ sci.focus = true
8
+
9
+ sci.font = 'Courier New'
10
+ sci.fontSize = 10
11
+
12
+ sci.tabWidth = 2
13
+
14
+ sci.text = <<-RUBY
15
+ def foo
16
+ 42
17
+ end
18
+ RUBY
19
+ }
20
+ }
@@ -0,0 +1,18 @@
1
+ require 'fzeet'
2
+
3
+ include Fzeet
4
+
5
+ Application.run { |window| window.dialog = true
6
+ Tab.new(window, :tab1, anchor: :ltrb).
7
+ insert('Tab1').
8
+ insert('Tab2').
9
+ insert('Tab3').
10
+
11
+ on(:selchanging) { |args|
12
+ args[:result] = 1 if question('Change?').no?
13
+ }.
14
+
15
+ on(:selchange) { |args|
16
+ message "Tab#{args[:sender].current.index + 1} selected"
17
+ }
18
+ }
@@ -3,26 +3,13 @@ require 'fzeet'
3
3
  include Fzeet
4
4
 
5
5
  Application.run { |window| window.dialog = true
6
- TreeView.new(window, :treeview1, style: [:border, :haslines, :linesatroot, :hasbuttons], position: [10, 10, 200, 200])
7
-
8
- tv = window[:treeview1]
9
- tvis = Windows::TVINSERTSTRUCT.new
10
- tvi = tvis[:item]
11
- pointers = []
12
-
13
- tvis[:hInsertAfter] = Windows::TVI_LAST
14
- tvi[:mask] = Windows::TVIF_TEXT
15
-
16
- tvis[:hParent] = Windows::TVI_ROOT
17
- tvi[:pszText] = pointers.push(FFI::MemoryPointer.from_string('Foo')).last
18
- hfoo = tv.sendmsg(:insertitem, 0, tvis.pointer)
19
- tvis[:hParent] = hfoo
20
- tvi[:pszText] = pointers.push(FFI::MemoryPointer.from_string('Baz')).last
21
- hbaz = tv.sendmsg(:insertitem, 0, tvis.pointer)
22
-
23
- tvis[:hParent] = Windows::TVI_ROOT
24
- tvi[:pszText] = pointers.push(FFI::MemoryPointer.from_string('Bar')).last
25
- hbar = tv.sendmsg(:insertitem, 0, tvis.pointer)
26
-
27
- pointers.each(&:free)
6
+ TreeView.new(window, :treeview1, style: [:haslines, :linesatroot, :hasbuttons], anchor: :ltrb).
7
+ append('Foo').
8
+ append('Baz').
9
+ append('Quux').
10
+ parent. # Baz
11
+ parent. # Foo
12
+ append('Baz1').
13
+ root. # window[:treeview1]
14
+ append('Bar')
28
15
  }
@@ -0,0 +1,23 @@
1
+ require 'fzeet'
2
+
3
+ include Fzeet
4
+
5
+ Application.run { |window|
6
+ Container.new(window, height: 100, anchor: :ltr).tap { |w|
7
+ w.style << :border
8
+
9
+ Button.new(w, :button1, position: [10, 10, 76, 24])
10
+ }
11
+
12
+ Container.new(window, height: 100, anchor: :lrb).tap { |w|
13
+ w.style << :border
14
+
15
+ Button.new(w, :button2, position: [10, 10, 76, 24])
16
+
17
+ Container.new(w, height: 50, anchor: :lrb).tap { |w1|
18
+ w1.style << :border
19
+
20
+ Button.new(w1, :button3, anchor: :ltrb)
21
+ }
22
+ }
23
+ }
data/examples/MDI.rbw ADDED
@@ -0,0 +1,30 @@
1
+ require 'fzeet'
2
+
3
+ include Fzeet
4
+
5
+ Application.run(Frame.new) { |window|
6
+ children, total = [], 0
7
+
8
+ window.menu.
9
+ append(:popup, '&File', PopupMenu.new.
10
+ append(:string, '&New', :new)
11
+ )
12
+
13
+ window.
14
+ on(:command, :new) {
15
+ children << MDIChild.new(window.client, caption: "Child#{total += 1}").
16
+ on(:close) { |args|
17
+ args[:result] = nil if args[:sender].question('Close?', buttons: [:yes, :No]).yes?
18
+ }.
19
+
20
+ on(:destroy) { |args| children.delete(args[:sender]) }
21
+ }.
22
+
23
+ on(:close) {
24
+ window.client.eachChild { |child|
25
+ # Ask each child if it's ok to close
26
+ }
27
+
28
+ window.dispose
29
+ }
30
+ }
@@ -5,19 +5,24 @@ include Fzeet
5
5
  Application.run { |window|
6
6
  UIRibbon.new(window).
7
7
  on(:size) {
8
- window[:edit1].position = 10, window.ribbon.height + 10, 100, 18
8
+ window[:edit1].position = 10, window.ribbon.height + 10, 200, 18
9
9
  }
10
10
 
11
11
  Edit.new(window, :edit1, caption: '').
12
- on(:setfocus) {
12
+ on(:setfocus) { |args|
13
13
  window.ribbon.uif.SetUICommandProperty(CmdTabGroup1, Windows::UI_PKEY_ContextAvailable, Windows::PROPVARIANT[:int, 1])
14
- }.
15
14
 
16
- on(:killfocus) {
17
- window.ribbon.uif.SetUICommandProperty(CmdTabGroup1, Windows::UI_PKEY_ContextAvailable, Windows::PROPVARIANT[:int, 0])
15
+ args[:sender].cuebanner = 'Now click outside...'
18
16
  }.
19
17
 
20
18
  cuebanner = 'Click here...'
21
19
 
22
- window.on(:lbuttondown) { window[:edit1].focus = false if window[:edit1].focus? }
20
+ window.on(:lbuttondown) {
21
+ window.ribbon.uif.SetUICommandProperty(CmdTabGroup1, Windows::UI_PKEY_ContextAvailable, Windows::PROPVARIANT[:int, 0])
22
+
23
+ if window[:edit1].focus?
24
+ window[:edit1].focus = false
25
+ window[:edit1].cuebanner = 'Click here...'
26
+ end
27
+ }
23
28
  }
@@ -51,6 +51,7 @@ module Fzeet
51
51
 
52
52
  while msg.get!
53
53
  msg.translate.dispatch unless
54
+ (window.client && Windows.TranslateMDISysAccel(window.client.handle, msg) != 0) ||
54
55
  accelerators.any? { |table| table.translate?(msg, @window) } ||
55
56
  dialogs.any? { |dialog| dialog.dlgmsg?(msg) }
56
57
  end
data/lib/fzeet/Common.rb CHANGED
@@ -172,11 +172,11 @@ module Fzeet
172
172
  def self.instance?(handle) @@instances.include?(handle.to_i) end
173
173
  def self.instance(handle) raise "#{self}.#{__method__} failed." unless (instance = @@instances[handle.to_i]); instance end
174
174
 
175
- def self.wrap(handle, iface)
175
+ def self.wrap(handle, *ifaces)
176
176
  Object.new.tap { |o|
177
177
  o.instance_variable_set(:@handle, handle)
178
178
  o.class.send(:attr_reader, :handle)
179
- o.class.send(:include, iface)
179
+ ifaces.each { |iface| o.class.send(:include, iface) }
180
180
  }
181
181
  end
182
182
 
@@ -300,13 +300,15 @@ module Fzeet
300
300
  holds.each { |hold| Windows.SelectObject(@handle, hold) }
301
301
  end
302
302
 
303
+ def textExtent(text) Windows.DetonateLastError(0, :GetTextExtentPoint, @handle, text, text.length, s = Size.new); s end
304
+
303
305
  def color; Windows.GetTextColor(@handle) end
304
306
  def color=(color) Windows.SetTextColor(@handle, color) end
305
307
 
306
308
  def background; Windows.GetBkColor(@handle) end
307
309
  def background=(background) Windows.SetBkColor(@handle, background) end
308
310
 
309
- def fillRect(rect, brush) Windows.DetonateLastError(0, :FillRect, @handle, rect, brush.handle); self end
311
+ def fillRect(rect, brush) Windows.DetonateLastError(0, :FillRect, @handle, rect, (brush.kind_of?(FFI::Pointer)) ? brush : brush.handle); self end
310
312
 
311
313
  def text(text, rect, flags = 0) Windows.DetonateLastError(0, :DrawText, @handle, text, -1, rect, Fzeet.flags(flags, :dt_)); self end
312
314
 
@@ -29,6 +29,18 @@ module Fzeet
29
29
  def initialize(parent, id, opts = {}, &block)
30
30
  super('Button', parent, id, opts)
31
31
 
32
+ width, height = 0, 0
33
+
34
+ using(ScreenDC.new) { |dc| dc.select(Font) {
35
+ minw = dc.textExtent('W' * 8).to_a[0]
36
+ width, height = dc.textExtent("W#{text}W").to_a
37
+
38
+ width = minw if width < minw; height = (height * 1.8).ceil
39
+ }}
40
+
41
+ self.location = 10, 10 if location.client!(parent).to_a == [0, 0]
42
+ self.size = width, height if size.to_a == [0, 0]
43
+
32
44
  @parent.on(:command, @id, &block) if block
33
45
  end
34
46
 
@@ -32,11 +32,12 @@ module Fzeet
32
32
  xstyle: [],
33
33
  caption: id.capitalize,
34
34
  style: [],
35
- x: Windows::CW_USEDEFAULT,
36
- y: Windows::CW_USEDEFAULT,
37
- width: Windows::CW_USEDEFAULT,
38
- height: Windows::CW_USEDEFAULT,
39
- position: []
35
+ x: 0,
36
+ y: 0,
37
+ width: 0,
38
+ height: 0,
39
+ position: [],
40
+ anchor: nil
40
41
  }
41
42
  badopts = opts.keys - _opts.keys; raise "Bad option(s): #{badopts.join(', ')}." unless badopts.empty?
42
43
  _opts.merge!(opts)
@@ -57,6 +58,13 @@ module Fzeet
57
58
  sendmsg(:setfont, Font.handle, 1)
58
59
 
59
60
  handlers.each { |k, v| on(k, &v) }
61
+
62
+ case _opts[:anchor]
63
+ when :ltr; @parent.on(:size) { self.position = @parent.rect.tap { |r| r[:bottom] = _opts[:height] }.to_a }
64
+ when :lrb; @parent.on(:size) { self.position = @parent.rect.tap { |r| r[:top] = r[:bottom] - _opts[:height]; r[:bottom] = _opts[:height] }.to_a }
65
+ when :ltrb; @parent.on(:size) { self.position = @parent.rect.to_a }
66
+ else raise ArgumentError, "Bad anchor spec: #{_opts[:anchor]}."
67
+ end if _opts[:anchor]
60
68
  end
61
69
 
62
70
  attr_reader :parent, :id
@@ -2,6 +2,15 @@ require_relative 'Common'
2
2
 
3
3
  module Fzeet
4
4
  module HeaderMethods
5
+ Prefix = {
6
+ xstyle: [:ws_ex_],
7
+ style: [:hds_, :ws_],
8
+ message: [:hdm_, :ccm_, :wm_],
9
+ notification: [:hdn_, :nm_]
10
+ }
11
+
12
+ def count; sendmsg(:getitemcount) end
13
+
5
14
  def insertItem(i, text, width)
6
15
  hdi = Windows::HDITEM.new
7
16
 
@@ -17,18 +26,26 @@ module Fzeet
17
26
  ensure
18
27
  ptext.free
19
28
  end
29
+
30
+ def modifyItem(i, text, style = 0)
31
+ hdi = Windows::HDITEM.new
32
+
33
+ hdi[:mask] = Fzeet.flags([:text, :format], :hdi_)
34
+ hdi[:pszText] = ptext = FFI::MemoryPointer.from_string(text)
35
+ hdi[:fmt] = Fzeet.flags([:left, :string], :hdf_)
36
+ hdi[:fmt] |= Fzeet.flags([*style].compact, :hdf_)
37
+
38
+ sendmsg(:setitem, i, hdi.pointer)
39
+
40
+ self
41
+ ensure
42
+ ptext.free
43
+ end
20
44
  end
21
45
 
22
46
  class Header < Control
23
47
  include HeaderMethods
24
48
 
25
- Prefix = {
26
- xstyle: [:ws_ex_],
27
- style: [:hds_, :ws_],
28
- message: [:hdm_, :ccm_, :wm_],
29
- notification: [:hdn_, :nm_]
30
- }
31
-
32
49
  def self.crackNotification(args) end
33
50
 
34
51
  def initialize(parent, id, opts = {}, &block)
@@ -43,6 +43,12 @@ module Fzeet
43
43
  ptext.free if ptext
44
44
  end
45
45
 
46
+ class Item
47
+ def initialize(lvi) @subitems = [lvi] end
48
+
49
+ attr_reader :subitems
50
+ end
51
+
46
52
  def insertItem(i, j, text)
47
53
  lvi = Windows::LVITEM.new
48
54
 
@@ -51,16 +57,39 @@ module Fzeet
51
57
  lvi[:iSubItem] = j
52
58
  lvi[:pszText] = ptext = FFI::MemoryPointer.from_string(text)
53
59
 
54
- if j > 0
55
- sendmsg(:setitem, 0, lvi.pointer)
56
- else
60
+ if j == 0
61
+ @items << Item.new(lvi)
62
+
63
+ lvi[:mask] |= Windows::LVIF_PARAM
64
+ lvi[:lParam] = @items[i].object_id
65
+
57
66
  sendmsg(:insertitem, 0, lvi.pointer)
67
+ else
68
+ @items[i].subitems << lvi
69
+
70
+ sendmsg(:setitem, 0, lvi.pointer)
71
+ end
72
+
73
+ @items[i].subitems[j].instance_variable_set(:@text, text)
74
+
75
+ class << @items[i].subitems[j]
76
+ attr_reader :text
58
77
  end
59
78
 
60
79
  self
61
80
  ensure
62
81
  ptext.free if ptext
63
82
  end
83
+
84
+ def sort(j = 0)
85
+ sendmsg(:sortitems, j,
86
+ FFI::Function.new(:int, [:long, :long, :long], convention: :stdcall) { |lParam1, lParam2, lParamSort|
87
+ yield ObjectSpace._id2ref(lParam1).subitems[lParamSort], ObjectSpace._id2ref(lParam2).subitems[lParamSort], j
88
+ }
89
+ )
90
+
91
+ self
92
+ end
64
93
  end
65
94
 
66
95
  class ListView < Control
@@ -73,14 +102,26 @@ module Fzeet
73
102
  notification: [:lvn_, :nm_]
74
103
  }
75
104
 
76
- def self.crackNotification(args) end
105
+ def self.crackNotification(args)
106
+ case args[:notification]
107
+ when Windows::LVN_COLUMNCLICK
108
+ args[:nmlv] = Windows::NMLISTVIEW.new(FFI::Pointer.new(args[:lParam]))
109
+ args[:index] = args[:nmlv][:iSubItem]
110
+ end
111
+ end
77
112
 
78
113
  def initialize(parent, id, opts = {}, &block)
79
114
  super('SysListView32', parent, id, opts)
80
115
 
116
+ @header = Handle.wrap(FFI::Pointer.new(sendmsg(:getheader)), WindowMethods, HeaderMethods)
117
+
118
+ @items = []
119
+
81
120
  @parent.on(:notify, @id, &block) if block
82
121
  end
83
122
 
123
+ attr_reader :header, :items
124
+
84
125
  def on(notification, &block)
85
126
  @parent.on(:notify, @id, Fzeet.constant(notification, *self.class::Prefix[:notification]), &block)
86
127
 
@@ -0,0 +1,51 @@
1
+ require_relative 'Common'
2
+
3
+ module Fzeet
4
+ class PropertyPage
5
+ class PROPSHEETPAGEA1 < FFI::Struct
6
+ layout \
7
+ :array, [Windows::PROPSHEETPAGE, 1]
8
+ end
9
+
10
+ def initialize
11
+
12
+ end
13
+ end
14
+
15
+ class PropertySheet
16
+ def initialize(parent, opts = {wizard: false})
17
+ pointers = []
18
+
19
+ psps = PropertyPage::PROPSHEETPAGEA1.new
20
+
21
+ dt = Windows::DLGTEMPLATE.new
22
+
23
+ dt[:style] = Fzeet.flags([:'3dlook', :control, :child, :tabstop], :ds_, :ws_)
24
+ dt[:x], dt[:y], dt[:cx], dt[:cy] = 100, 100, 300, 150
25
+
26
+ psp = psps[:array][0]
27
+
28
+ psp[:dwSize] = psp.size
29
+ psp[:dwFlags] = Fzeet.flags([:dlgindirect, :usetitle], :psp_)
30
+ psp[:hInstance] = Windows.GetModuleHandle(nil)
31
+ psp[:template][:pResource] = dt
32
+ psp[:pszTitle] = pointers.push(FFI::MemoryPointer.from_string("Page")).last
33
+
34
+ psh = Windows::PROPSHEETHEADER.new
35
+
36
+ psh[:dwSize] = psh.size
37
+ psh[:dwFlags] = Fzeet.flags(:propsheetpage, :psh_)
38
+ psh[:dwFlags] |= Windows::PSH_WIZARD if opts[:wizard]
39
+ psh[:hwndParent] = parent.handle
40
+ psh[:hInstance] = Windows.GetModuleHandle(nil)
41
+ psh[:pszCaption] = pointers.push(FFI::MemoryPointer.from_string('Sheet')).last
42
+ psh[:nPages] = 1
43
+ psh[:start][:nStartPage] = 0
44
+ psh[:pages][:ppsp] = psps
45
+
46
+ Windows.DetonateLastError(-1, :PropertySheet, psh)
47
+ ensure
48
+ pointers.each(&:free)
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,109 @@
1
+ require_relative 'Common'
2
+
3
+ module Fzeet
4
+ module ScintillaMethods
5
+ def text
6
+ FFI::MemoryPointer.new(:uchar, len = sendmsg(:gettextlength) + 1) { |p|
7
+ sendmsg(:gettext, len, p)
8
+
9
+ return p.read_string
10
+ }
11
+ end
12
+
13
+ def text=(text)
14
+ p = FFI::MemoryPointer.from_string(text)
15
+
16
+ sendmsg(:settext, 0, p)
17
+ ensure
18
+ p.free
19
+ end
20
+
21
+ def font
22
+ FFI::MemoryPointer.new(:uchar, 33) { |p|
23
+ sendmsg(:stylegetfont, Windows::STYLE_DEFAULT, p)
24
+
25
+ return p.read_string
26
+ }
27
+ end
28
+
29
+ def font=(name)
30
+ p = FFI::MemoryPointer.from_string(name)
31
+
32
+ sendmsg(:stylesetfont, Windows::STYLE_DEFAULT, p)
33
+ ensure
34
+ p.free
35
+ end
36
+
37
+ def fontSize; sendmsg(:stylegetsize, Windows::STYLE_DEFAULT) end
38
+ def fontSize=(size) sendmsg(:stylesetsize, Windows::STYLE_DEFAULT, size) end
39
+
40
+ def tabWidth; sendmsg(:gettabwidth) end
41
+ def tabWidth=(tabWidth) sendmsg(:settabwidth, tabWidth) end
42
+ end
43
+
44
+ class Scintilla < Control
45
+ include ScintillaMethods
46
+
47
+ Prefix = {
48
+ xstyle: [:ws_ex_],
49
+ style: [:ws_],
50
+ message: [:sci_, :wm_],
51
+ notification: [:scn_, :scen_, :nm_]
52
+ }
53
+
54
+ def self.crackNotification(args)
55
+ case args[:notification]
56
+ when \
57
+ Windows::SCN_STYLENEEDED,
58
+ Windows::SCN_CHARADDED,
59
+ Windows::SCN_SAVEPOINTREACHED,
60
+ Windows::SCN_SAVEPOINTLEFT,
61
+ Windows::SCN_MODIFYATTEMPTRO,
62
+ Windows::SCN_KEY,
63
+ Windows::SCN_DOUBLECLICK,
64
+ Windows::SCN_UPDATEUI,
65
+ Windows::SCN_MODIFIED,
66
+ Windows::SCN_MACRORECORD,
67
+ Windows::SCN_MARGINCLICK,
68
+ Windows::SCN_NEEDSHOWN,
69
+ Windows::SCN_PAINTED,
70
+ Windows::SCN_USERLISTSELECTION,
71
+ Windows::SCN_URIDROPPED,
72
+ Windows::SCN_DWELLSTART,
73
+ Windows::SCN_DWELLEND,
74
+ Windows::SCN_ZOOM,
75
+ Windows::SCN_HOTSPOTCLICK,
76
+ Windows::SCN_HOTSPOTDOUBLECLICK,
77
+ Windows::SCN_CALLTIPCLICK,
78
+ Windows::SCN_AUTOCSELECTION,
79
+ Windows::SCN_INDICATORCLICK,
80
+ Windows::SCN_INDICATORRELEASE,
81
+ Windows::SCN_AUTOCCANCELLED,
82
+ Windows::SCN_AUTOCCHARDELETED
83
+
84
+ args[:scn] = Windows::SCNotification.new(FFI::Pointer.new(args[:lParam]))
85
+ end
86
+ end
87
+
88
+ def initialize(parent, id, opts = {}, &block)
89
+ super('Scintilla', parent, id, opts)
90
+
91
+ @parent.on(:notify, @id, &block) if block
92
+ end
93
+
94
+ def on(notification, &block)
95
+ case c = Fzeet.constant(notification, *self.class::Prefix[:notification])
96
+ when \
97
+ Windows::SCEN_CHANGE,
98
+ Windows::SCEN_SETFOCUS,
99
+ Windows::SCEN_KILLFOCUS
100
+
101
+ @parent.on(:command, @id, c, &block)
102
+ else
103
+ @parent.on(:notify, @id, c, &block)
104
+ end
105
+
106
+ self
107
+ end
108
+ end
109
+ end