fzeet 0.6.2 → 0.6.3

Sign up to get free protection for your applications and to get access to all the features.
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