foxguib 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (109) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data/changelog.txt +128 -0
  4. data/doc/www/index.html +173 -0
  5. data/doc/www/upload.rb +9 -0
  6. data/examples/event_handler.rb +67 -0
  7. data/examples/event_handlers.rbin +0 -0
  8. data/examples/guib_testdialog.rb +31 -0
  9. data/examples/testdialog.rb +29 -0
  10. data/exe/foxguib +1 -0
  11. data/foxGUIb-debug.rb +37 -0
  12. data/foxGUIb.rb +88 -0
  13. data/foxGUIb_win32.rbw +1 -0
  14. data/foxguib.gemspec +26 -0
  15. data/license.txt +49 -0
  16. data/readme.txt +1 -0
  17. data/release_notes.txt +68 -0
  18. data/src/assert.rb +8 -0
  19. data/src/cfgman.rb +27 -0
  20. data/src/code-gen/code-generator.rb +171 -0
  21. data/src/code-gen/property-generators.rb +65 -0
  22. data/src/code-gen/widget-generator.rb +22 -0
  23. data/src/convert.rb +60 -0
  24. data/src/direct_widget_manipulation.rb +343 -0
  25. data/src/docman.rb +260 -0
  26. data/src/document.rb +405 -0
  27. data/src/event_categories.yaml +85 -0
  28. data/src/event_listener.rb +57 -0
  29. data/src/events.yaml +77 -0
  30. data/src/events_docu.yaml +228 -0
  31. data/src/get_events.rb +64 -0
  32. data/src/gui/ArrowButton.tga +0 -0
  33. data/src/gui/BoxMinus.tga +0 -0
  34. data/src/gui/BoxPlus.tga +0 -0
  35. data/src/gui/Button.tga +0 -0
  36. data/src/gui/CheckButton.tga +0 -0
  37. data/src/gui/ComboBox.tga +0 -0
  38. data/src/gui/Dial.tga +0 -0
  39. data/src/gui/GroupBox.tga +0 -0
  40. data/src/gui/HorizontalFrame.tga +0 -0
  41. data/src/gui/HorizontalSeparator.tga +0 -0
  42. data/src/gui/Label.tga +0 -0
  43. data/src/gui/MDIChild.tga +0 -0
  44. data/src/gui/MDIClient.tga +0 -0
  45. data/src/gui/Matrix.tga +0 -0
  46. data/src/gui/MenuCaption.tga +0 -0
  47. data/src/gui/MenuCascade.tga +0 -0
  48. data/src/gui/MenuCheck.tga +0 -0
  49. data/src/gui/MenuCommand.tga +0 -0
  50. data/src/gui/MenuPane.tga +0 -0
  51. data/src/gui/MenuRadio.tga +0 -0
  52. data/src/gui/MenuSeparator.tga +0 -0
  53. data/src/gui/MenuTitle.tga +0 -0
  54. data/src/gui/Menubar.tga +0 -0
  55. data/src/gui/Packer.tga +0 -0
  56. data/src/gui/ProgressBar.tga +0 -0
  57. data/src/gui/RadioButton.tga +0 -0
  58. data/src/gui/RadioMutex.tga +0 -0
  59. data/src/gui/ScrollWindow.tga +0 -0
  60. data/src/gui/Scrollbar.tga +0 -0
  61. data/src/gui/Shutter.tga +0 -0
  62. data/src/gui/ShutterItem.tga +0 -0
  63. data/src/gui/Slider.tga +0 -0
  64. data/src/gui/Spinner.tga +0 -0
  65. data/src/gui/Splitter.tga +0 -0
  66. data/src/gui/StatusBar.tga +0 -0
  67. data/src/gui/Statusline.tga +0 -0
  68. data/src/gui/Switcher.tga +0 -0
  69. data/src/gui/TabBar.tga +0 -0
  70. data/src/gui/TabBook.tga +0 -0
  71. data/src/gui/TabItem.tga +0 -0
  72. data/src/gui/Text.tga +0 -0
  73. data/src/gui/TextField.tga +0 -0
  74. data/src/gui/ToggleButton.tga +0 -0
  75. data/src/gui/Toolbar.tga +0 -0
  76. data/src/gui/VerticalFrame.tga +0 -0
  77. data/src/gui/VerticalSeparator.tga +0 -0
  78. data/src/gui/_guib_event_editor.rb +185 -0
  79. data/src/gui/_guib_event_editor.rbin +0 -0
  80. data/src/gui/_guib_genruby.rb +414 -0
  81. data/src/gui/_guib_genruby.rbin +0 -0
  82. data/src/gui/_guib_mainwin.rb +574 -0
  83. data/src/gui/_guib_mainwin.rbin +0 -0
  84. data/src/gui/event_editor.rb +180 -0
  85. data/src/gui/genruby.rb +155 -0
  86. data/src/gui/guib__console.rb +265 -0
  87. data/src/gui/mainwin.rb +71 -0
  88. data/src/gui/ruby_console.rb +263 -0
  89. data/src/gui/svg/Matrix.svg +87 -0
  90. data/src/gui/svg/MenuCheck.svg +135 -0
  91. data/src/gui/svg/MenuRadio.svg +130 -0
  92. data/src/gui/svg/RadioMutex.svg +119 -0
  93. data/src/gui/textview.rb +101 -0
  94. data/src/gui/textview.rbin +0 -0
  95. data/src/minitest.rb +60 -0
  96. data/src/prop-lists.rb +323 -0
  97. data/src/prop-types.rb +606 -0
  98. data/src/properties.rb +119 -0
  99. data/src/propman.rb +88 -0
  100. data/src/relink_mechanisms.rb +95 -0
  101. data/src/serialize.rb +167 -0
  102. data/src/state_machine.rb +73 -0
  103. data/src/version.rb +6 -0
  104. data/src/widget-lists.rb +118 -0
  105. data/src/widget-selector.rb +85 -0
  106. data/src/widgettree-controls.rb +183 -0
  107. data.tar.gz.sig +0 -0
  108. metadata +236 -0
  109. metadata.gz.sig +0 -0
data/src/document.rb ADDED
@@ -0,0 +1,405 @@
1
+ # Copyright (c) 2004-2006 by Henon (meinrad dot recheis at gmail dot com)
2
+
3
+ require "assert"
4
+ require "code-gen/code-generator"
5
+ require "serialize"
6
+ require "widgettree-controls"
7
+ require "relink_mechanisms"
8
+
9
+ MARKED_COLOR = Fox::FXRGB(1, 150, 250)
10
+
11
+ class UserData # TODO: to be ELIMINATED
12
+ def initialize treeitem, manager
13
+ raise "treeitem is nil" unless treeitem
14
+ @treeitem = treeitem
15
+ @manager = manager
16
+ end
17
+ attr_accessor :treeitem, :manager
18
+ end
19
+
20
+ class Document
21
+ include CodeGenerator
22
+ include Serialize
23
+ include WidgettreeControls
24
+ def initialize etype
25
+ @switcherIndex = 0
26
+ create_dlg # @ WidgettreeControls.rb
27
+ @w = {}
28
+ @names = {}
29
+ @implicit_children = true
30
+ name = nil
31
+ @type = etype
32
+ init(etype) if etype
33
+ @gendlg_state = {}
34
+ end
35
+
36
+ attr_accessor :doclist_item
37
+ attr_accessor :name
38
+ attr_accessor :topwin, :type,
39
+ :dlg,
40
+ :marked,
41
+ :marked_wcolor,
42
+ :fxtree,
43
+ :switcherIndex, # the switcher-index of the treelist for this Document
44
+ :gendlg_state
45
+ # ~ attr_reader :w # breaks codegen
46
+
47
+ def init etype
48
+ @w[@root.to_s] = MAINWIN.topwin
49
+ classname = name = ""
50
+ if etype == "mainwin"
51
+ classname = "#{DialogBox}"
52
+ name = "mainWindow"
53
+ elsif etype == "dlg"
54
+ classname = "#{DialogBox}"
55
+ name = "dialogBox"
56
+ elsif etype == "popup"
57
+ # TODO:
58
+ end
59
+ if name
60
+ @topwin = add_widget classname, nil, @root
61
+ rename_wdg(@topwin, name)
62
+ @topwin.resize(500, 400)
63
+ @topwin.show(PLACEMENT_SCREEN)
64
+ end
65
+ if etype == "mainwin"
66
+ def @topwin.class
67
+ MainWindow
68
+ end
69
+ end
70
+ end
71
+
72
+ def load filename
73
+ data = load_from_file(filename)
74
+ @name = filename
75
+ @names = data[:names] # to avoid inconsistencies while loading the widgettree
76
+ @type = data[:type]
77
+ @gendlg_state = data[:gendlg_state]
78
+ init @type
79
+ rename_wdg(@topwin, data[:hierarchy].first[:name])
80
+ @topwin.set_name(data[:hierarchy].first[:name])
81
+ @topwin.deserialize(data[:hierarchy].first[ :prop])
82
+ load_widgettree data[:hierarchy].first[:sub], "inside", @topwin
83
+ @names = data[:names] # to reset to the saved state
84
+ @topwin.layout
85
+ @fxtree.currentItem = @topwin.userData.treeitem
86
+ @topwin.update_properties
87
+ unmark
88
+ mark @topwin
89
+ end
90
+
91
+ # recursive loading function of a subtree. used by "load" and "paste".
92
+ # hashes: an array of hashes representing widgets that shall be created where(=inside/after/before the relativeWidget)
93
+ def load_widgettree hashes, where, relativeWdg
94
+ tmp = @implicit_children
95
+ @implicit_children = false
96
+ hashes.each { |hash|
97
+ # hash[:name]=get_name(hash[:name]) if @w.has_key?( hash[:name])
98
+ wdg = add_widget(hash[:cl], where, relativeWdg.userData.treeitem)
99
+ unless wdg
100
+ puts "add_widget returned nil for <#{hash[:name]}>!"
101
+ next
102
+ end
103
+ wdg.deserialize hash[:prop]
104
+ wdg.behaviour = hash[:behaviour] if hash[:behaviour]
105
+ load_widgettree hash[:sub], "inside", wdg
106
+ rename_wdg(wdg, hash[:name])
107
+ }
108
+ @implicit_children = tmp
109
+ end
110
+
111
+ def save filename
112
+ unmark
113
+ data = {
114
+ type: @type,
115
+ names: @names,
116
+ hierarchy: [],
117
+ gendlg_state: @gendlg_state
118
+ }
119
+ start_node = @root.below
120
+ traverse(@topwin, data[:hierarchy])
121
+ if filename
122
+ $fxapp.beginWaitCursor
123
+ save_to_file filename, data
124
+ $fxapp.endWaitCursor
125
+ else
126
+ puts "no filename given. didn't save."
127
+ end
128
+ data
129
+ end
130
+
131
+ def traverse(widget, nodelist)
132
+ return unless widget
133
+ hash = {}
134
+ subnodes = []
135
+ hash[:sub] = subnodes
136
+ nodelist << hash
137
+ # wdg=@w[treenode.to_s]
138
+ hash[:name] = widget.wdg_name # wdg.userData.treeitem.text
139
+ hash[:cl] = widget.class.to_s.sub("FX::", "")
140
+ prophash = {}
141
+ hash[:prop] = prophash
142
+ widget.serialize prophash
143
+ hash[:behaviour] = widget.behaviour
144
+ widget.each_child { |child|
145
+ traverse(child, subnodes) if child.respond_to? :hilighted=
146
+ }
147
+ traverse(widget.menu, subnodes) if widget.respond_to? :menu
148
+ end
149
+
150
+ def add_widget classname, opts = "after", currentitem = @fxtree.currentItem
151
+ assert(currentitem)
152
+ wdg = parent = parentitem = nil
153
+ if currentitem.parent == @root and opts != "inside"
154
+ # linking as subnode
155
+ parent = @w[currentitem.to_s]
156
+ parentitem = currentitem
157
+ opts = "inside"
158
+ elsif opts == "after" or opts == "before"
159
+ parent = @w[currentitem.parent.to_s]
160
+ parentitem = currentitem.parent
161
+ siblingitem = currentitem
162
+ elsif opts == "inside"
163
+ parent = @w[currentitem.to_s]
164
+ parentitem = currentitem
165
+ elsif currentitem == @root
166
+ parent = @w[currentitem.to_s]
167
+ parentitem = currentitem
168
+ end
169
+ begin
170
+ wdg = create_wdg(classname, parent)
171
+ raise "error creating wdg" unless wdg
172
+ wdg.wdg_name = name = add_reference(classname.downcase, wdg)
173
+ currentitem = @fxtree.appendItem parentitem, name
174
+ wdg.userData = UserData.new(currentitem, self)
175
+ @fxtree.currentItem = currentitem
176
+ if opts == "after" or opts == "before"
177
+ currentitem = relink_wdg(currentitem, opts, siblingitem).userData.treeitem
178
+ end
179
+ create_implicit_children classname
180
+ expand_parents currentitem
181
+ @fxtree.forceRefresh
182
+ set_dirty
183
+ wdg.update_properties
184
+ rescue
185
+ puts $!
186
+ puts $!.backtrace.join("\n")
187
+ end
188
+ wdg
189
+ end
190
+
191
+ def create_wdg classname, p
192
+ wdg = nil
193
+ assert(p)
194
+ check_integrity classname, p
195
+ wdg = eval(classname).new p
196
+ m = wdg.method(:backColor)
197
+ # cache real backColor so that marked widgets don't get confused with their markedColor and real backColor
198
+ def wdg.backColor=c
199
+ @backColor = c
200
+ super unless @hilighted
201
+ end
202
+
203
+ def wdg.backColor
204
+ @backColor
205
+ end
206
+
207
+ def wdg.hilighted=b
208
+ @hilighted = b
209
+ c = @hilighted ? MARKED_COLOR : @backColor
210
+ setBackColor(c)
211
+ end
212
+ wdg.backColor = wdg.getBackColor
213
+ wdg.enable
214
+ wdg.connect(SEL_LEFTBUTTONPRESS) {
215
+ onClick wdg
216
+ 0
217
+ }
218
+ wdg.connect(SEL_RIGHTBUTTONPRESS) { |x, y, e|
219
+ unmark; # mark wdg
220
+ onClick wdg
221
+ @wdgMenu.popup_over(wdg, e.rootclick_x, e.rootclick_y)
222
+ 0
223
+ }
224
+ wdg.create
225
+ wdg.recalc
226
+ wdg.shell.forceRefresh
227
+ wdg.create_defaults
228
+ unmark
229
+ mark wdg
230
+ wdg
231
+ end
232
+
233
+ def create_implicit_children parentclass
234
+ return unless @implicit_children
235
+ if ["Menubar"].member? parentclass
236
+ add_widget "MenuTitle", "inside"
237
+ elsif ["MenuTitle", "MenuCascade", "OptionMenu", "MenuButton"].member? parentclass
238
+ add_widget "MenuPane", "inside"
239
+ elsif ["TabItem"].member? parentclass
240
+ add_widget "VerticalFrame", "after"
241
+ end
242
+ end
243
+
244
+ def rename_wdg wdg, newName
245
+ return unless wdg
246
+ begin
247
+ nil.instance_eval("@#{newName}", __FILE__, __LINE__) # check if newName is a suitable instance variable name
248
+ rescue Exception
249
+ puts $!
250
+ puts $!.backtrace
251
+ return
252
+ end
253
+ item = wdg.userData.treeitem
254
+ return if item.nil?
255
+ return if item == newName
256
+ if @w.has_key? newName
257
+ puts "<#{newName}> already exists!"
258
+ return
259
+ end
260
+ oldName = item.to_s
261
+ item.text = newName
262
+ wdg.wdg_name = newName
263
+ wdg.userData.treeitem = item
264
+ @w[newName] = wdg
265
+ @w.delete oldName if @w[oldName] == @w[newName]
266
+ @fxtree.update
267
+ true
268
+ end
269
+
270
+ def check_integrity type, parent
271
+ if type == "MenuPane" and !parent.respond_to?(:menu=)
272
+ raise "error: #{parent.class} cannot be parent to a MenuPane!"
273
+ elsif type == "MenuTitle" and !parent.is_a? FXToolBar
274
+ raise "not allowed: behavior undefined!"
275
+ elsif type == "MenuCascade" and !parent.is_a? FXPopup
276
+ raise "not allowed: behavior undefined!"
277
+ elsif type == "TabItem" and !parent.is_a? FXTabBar
278
+ raise 'error: #{parent.class} cannot hold a TabItem!'
279
+ end
280
+ end
281
+
282
+ # moves a widget in the browser and the gui
283
+ def relink_wdg item, where, relativeItem
284
+ assert(relativeItem, item, where)
285
+ wdg = @w[item.to_s]
286
+ parent = @w[relativeItem.parent.to_s]
287
+ relativeWdg = @w[relativeItem.to_s]
288
+ unless RelinkMechanisms.relink_possible?(wdg, where, relativeWdg)
289
+ puts "relink of #{wdg} #{where} #{relativeWdg} is not possible" # TODO log4r!
290
+ return
291
+ end
292
+ new = nil
293
+ if where == "before"
294
+ new = @fxtree.insertItem relativeItem, relativeItem.parent, FXTreeItem.new(item.to_s)
295
+ elsif where == "after"
296
+ new = if relativeItem.next
297
+ @fxtree.insertItem relativeItem.next, relativeItem.parent, FXTreeItem.new(item.to_s)
298
+ else
299
+ @fxtree.appendItem relativeItem.parent, FXTreeItem.new(item.to_s)
300
+ end
301
+ elsif where == "inside"
302
+ new = @fxtree.appendItem relativeItem, FXTreeItem.new(item.to_s)
303
+ else
304
+ return
305
+ end
306
+ expand_parents new
307
+ @fxtree.currentItem = new
308
+ a = []
309
+ subitem = nil
310
+ item.each { |subitem| a << subitem }
311
+ a.each { |subitem|
312
+ @fxtree.reparentItem subitem, new
313
+ }
314
+ RelinkMechanisms.relink_wdg wdg, where, relativeWdg
315
+ @fxtree.removeItem item
316
+ wdg.userData.treeitem = new # TODO don't use userData. better a singleton instance var
317
+ unmark
318
+ mark wdg
319
+ @fxtree.forceRefresh
320
+ wdg.shell.forceRefresh
321
+ set_dirty
322
+ wdg
323
+ end
324
+
325
+ # used to add a newly instanciated widget to the hashmap @widgets which
326
+ # associates widget names to widget references
327
+ # note: this method renames ambiguous names
328
+ def add_reference name, wdg
329
+ assert(wdg)
330
+ name = get_name(name)
331
+ @w[name] = wdg
332
+ wdg.set_name name
333
+ name
334
+ end
335
+
336
+ # makes shure a widget name is unique within the widgettree
337
+ # applies a simple renaming scheme and returns the unique name
338
+ def get_name(name)
339
+ begin
340
+ if @names.has_key? name
341
+ @names[name] += 1
342
+ else
343
+ @names[name] = 1
344
+ end
345
+ postfix = ""
346
+ postfix = @names[name].to_s if @names[name] > 0
347
+ wdg_name = name + postfix
348
+ end while(@w.has_key?(wdg_name)) # check, that name is unique
349
+ wdg_name
350
+ end
351
+
352
+ # sets the document as modified, as to ask the user to save on exit
353
+ def set_dirty
354
+ unless @dirty
355
+ @dirty = true
356
+ DocMan.instance.set_dirty self
357
+ end
358
+ end
359
+
360
+ def show # ????
361
+ MAINWIN.topwin.show(Fox::PLACEMENT_SCREEN)
362
+ end
363
+
364
+ # expands or collapses all subnodes of the item in the widget browser treelist
365
+ def expand item, bool = true
366
+ if bool
367
+ @fxtree.expandTree item
368
+ else
369
+ @fxtree.collapseTree item
370
+ end
371
+ item.each { |sub|
372
+ expand sub, bool
373
+ }
374
+ end
375
+
376
+ # expands all parents for the item to be shown
377
+ def expand_parents item
378
+ assert item
379
+ unless item.parent.nil?
380
+ @fxtree.expandTree item.parent
381
+ expand_parents item.parent
382
+ end
383
+ end
384
+
385
+ # colorizes the background of the currently selected widget.
386
+ # if marked allready the original color is restored
387
+ def mark wdg
388
+ return unless wdg
389
+ if wdg == @marked
390
+ wdg.hilighted = wdg.instance_eval { !@hilighted }
391
+ else
392
+ unmark
393
+ wdg.hilighted = true
394
+ @marked = wdg
395
+ $__wdg__ = @marked # for console debugging
396
+ end
397
+ end
398
+
399
+ # makes shure the current widget is not marked
400
+ def unmark
401
+ return unless @marked
402
+ @marked.hilighted = false
403
+ @marked = nil
404
+ end
405
+ end
@@ -0,0 +1,85 @@
1
+ ---
2
+ DND Events :
3
+ - SEL_BEGINDRAG
4
+ - SEL_ENDDRAG
5
+ - SEL_DRAGGED
6
+ - SEL_DND_ENTER
7
+ - SEL_DND_LEAVE
8
+ - SEL_DND_DROP
9
+ - SEL_DND_MOTION
10
+ - SEL_DND_REQUEST
11
+ Keyboard Events :
12
+ - SEL_KEYPRESS
13
+ - SEL_KEYRELEASE
14
+ - SEL_KEYMAP
15
+ Mouse Events :
16
+ - SEL_LEFTBUTTONPRESS
17
+ - SEL_LEFTBUTTONRELEASE
18
+ - SEL_MIDDLEBUTTONPRESS
19
+ - SEL_MIDDLEBUTTONRELEASE
20
+ - SEL_RIGHTBUTTONPRESS
21
+ - SEL_RIGHTBUTTONRELEASE
22
+ - SEL_MOTION
23
+ - SEL_CLICKED
24
+ - SEL_DOUBLECLICKED
25
+ - SEL_TRIPLECLICKED
26
+ - SEL_MOUSEWHEEL
27
+ Clipboard Events :
28
+ - SEL_CLIPBOARD_LOST
29
+ - SEL_CLIPBOARD_GAINED
30
+ - SEL_CLIPBOARD_REQUEST
31
+ Focus Events :
32
+ - SEL_FOCUS_SELF
33
+ - SEL_FOCUS_RIGHT
34
+ - SEL_FOCUS_LEFT
35
+ - SEL_FOCUS_DOWN
36
+ - SEL_FOCUS_UP
37
+ - SEL_FOCUS_NEXT
38
+ - SEL_FOCUS_PREV
39
+ - SEL_FOCUSIN
40
+ - SEL_FOCUSOUT
41
+ Window Events:
42
+ - SEL_ENTER
43
+ - SEL_LEAVE
44
+ - SEL_PAINT
45
+ - SEL_CREATE
46
+ - SEL_DESTROY
47
+ - SEL_UNMAP
48
+ - SEL_MAP
49
+ - SEL_CONFIGURE
50
+ - SEL_UPDATE
51
+ - SEL_RAISED
52
+ - SEL_LOWERED
53
+ - SEL_CLOSE
54
+ - SEL_DELETE
55
+ - SEL_MINIMIZE
56
+ - SEL_RESTORE
57
+ - SEL_MAXIMIZE
58
+ Common Events:
59
+ - SEL_COMMAND
60
+ - SEL_CHANGED
61
+ Selection Events:
62
+ - SEL_SELECTION_LOST
63
+ - SEL_SELECTION_GAINED
64
+ - SEL_SELECTION_REQUEST
65
+ - SEL_DESELECTED
66
+ - SEL_SELECTED
67
+ TreeList Events:
68
+ - SEL_EXPANDED
69
+ - SEL_COLLAPSED
70
+ Time Events:
71
+ - SEL_TIMEOUT
72
+ - SEL_CHORE
73
+ Other Events:
74
+ - SEL_SIGNAL
75
+ - SEL_LASSOED
76
+ - SEL_PICKED
77
+ - SEL_QUERY_TIP
78
+ - SEL_QUERY_HELP
79
+ - SEL_UNGRABBED
80
+ - SEL_VERIFY
81
+ - SEL_INSERTED
82
+ - SEL_REPLACED
83
+ - SEL_DELETED
84
+ - SEL_OPENED
85
+ - SEL_CLOSED
@@ -0,0 +1,57 @@
1
+ # Copyright (c) 2004-2006 by Henon (meinrad dot recheis at gmail dot com)
2
+
3
+ class Module
4
+ def __sends__ *args
5
+ args.each { |arg|
6
+ class_eval <<-CEEND, __FILE__, __LINE__ + 1
7
+ def on_#{arg}(&callback)
8
+ @#{arg}_observers ||= {}
9
+ @#{arg}_observers[caller[0]]=callback
10
+ return caller[0]
11
+ end
12
+ def del_#{arg}(id)
13
+ @#{arg}_observers ||= {}
14
+ return @#{arg}_observers.delete( id)
15
+ end
16
+ private
17
+ def #{arg} *the_args
18
+ @#{arg}_observers ||= {}
19
+ @#{arg}_observers.each { |caller, cb|
20
+ cb.call *the_args
21
+ }
22
+ end
23
+ CEEND
24
+ }
25
+ end
26
+ end
27
+
28
+ if __FILE__ == $0
29
+ class TextBox
30
+ __sends__ "text_changed", "key_pressed"
31
+
32
+ def initialize txt = ""
33
+ @txt = txt
34
+ end
35
+
36
+ def txt= txt
37
+ @txt = txt
38
+ text_changed
39
+ end
40
+
41
+ def key_press key
42
+ key_pressed key
43
+ end
44
+ end
45
+
46
+ box = TextBox.new
47
+ text_changed_id = box.on_text_changed { puts "Text changed!" }
48
+ 5.times { |i|
49
+ box.on_key_pressed { |k| puts "(#{i}) Key pressed: #{k}" }
50
+ }
51
+
52
+ box.txt = "New text!"
53
+ box.del_text_changed(text_changed_id)
54
+ box.txt = "New text!"
55
+
56
+ box.key_press "j"
57
+ end
data/src/events.yaml ADDED
@@ -0,0 +1,77 @@
1
+ ---
2
+ - SEL_ENDDRAG
3
+ - SEL_DRAGGED
4
+ - SEL_LASSOED
5
+ - SEL_TIMEOUT
6
+ - SEL_SIGNAL
7
+ - SEL_CLIPBOARD_LOST
8
+ - SEL_CLIPBOARD_GAINED
9
+ - SEL_CLIPBOARD_REQUEST
10
+ - SEL_CHORE
11
+ - SEL_FOCUS_SELF
12
+ - SEL_FOCUS_RIGHT
13
+ - SEL_FOCUS_LEFT
14
+ - SEL_FOCUS_DOWN
15
+ - SEL_FOCUS_UP
16
+ - SEL_FOCUS_NEXT
17
+ - SEL_FOCUS_PREV
18
+ - SEL_DND_ENTER
19
+ - SEL_KEYPRESS
20
+ - SEL_DND_LEAVE
21
+ - SEL_KEYRELEASE
22
+ - SEL_DND_DROP
23
+ - SEL_LEFTBUTTONPRESS
24
+ - SEL_DND_MOTION
25
+ - SEL_LEFTBUTTONRELEASE
26
+ - SEL_DND_REQUEST
27
+ - SEL_MIDDLEBUTTONPRESS
28
+ - SEL_IO_READ
29
+ - SEL_MIDDLEBUTTONRELEASE
30
+ - SEL_IO_WRITE
31
+ - SEL_RIGHTBUTTONPRESS
32
+ - SEL_IO_EXCEPT
33
+ - SEL_RIGHTBUTTONRELEASE
34
+ - SEL_PICKED
35
+ - SEL_MOTION
36
+ - SEL_QUERY_TIP
37
+ - SEL_ENTER
38
+ - SEL_QUERY_HELP
39
+ - SEL_LEAVE
40
+ - SEL_FOCUSIN
41
+ - SEL_FOCUSOUT
42
+ - SEL_KEYMAP
43
+ - SEL_UNGRABBED
44
+ - SEL_PAINT
45
+ - SEL_CREATE
46
+ - SEL_DESTROY
47
+ - SEL_UNMAP
48
+ - SEL_MAP
49
+ - SEL_CONFIGURE
50
+ - SEL_SELECTION_LOST
51
+ - SEL_SELECTION_GAINED
52
+ - SEL_SELECTION_REQUEST
53
+ - SEL_RAISED
54
+ - SEL_LOWERED
55
+ - SEL_CLOSE
56
+ - SEL_DELETE
57
+ - SEL_MINIMIZE
58
+ - SEL_RESTORE
59
+ - SEL_MAXIMIZE
60
+ - SEL_UPDATE
61
+ - SEL_COMMAND
62
+ - SEL_CLICKED
63
+ - SEL_DOUBLECLICKED
64
+ - SEL_TRIPLECLICKED
65
+ - SEL_MOUSEWHEEL
66
+ - SEL_CHANGED
67
+ - SEL_VERIFY
68
+ - SEL_DESELECTED
69
+ - SEL_SELECTED
70
+ - SEL_INSERTED
71
+ - SEL_REPLACED
72
+ - SEL_DELETED
73
+ - SEL_OPENED
74
+ - SEL_CLOSED
75
+ - SEL_EXPANDED
76
+ - SEL_COLLAPSED
77
+ - SEL_BEGINDRAG