glimmer-dsl-libui 0.4.14 → 0.4.15

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d51961908ec1315a42fe183bc79cbe86bc8d86e2dea9ac9a35d2dfaefaf3912d
4
- data.tar.gz: af6c03eb6d451816d32242c7f7d99ce3ed28755f363f3620faea2a590c3e0ea8
3
+ metadata.gz: 34cb8eb1da8d200b96163b3e2a0a607ed32dda75cb0df62088c5fcfaad2e2b18
4
+ data.tar.gz: 169bb5a5d620cc28606cdb03a7cd1e19544ae14d7c5d11dd2704cca869e3a2fe
5
5
  SHA512:
6
- metadata.gz: cb828f87dfbc9c56fd15123ecb29a3c499f22c315ef6582d47c629353e444f16c2b0755b958abe8d77f0506ee25c1cffbafa0a682ea2bfb1e9d649fa49cb7e9f
7
- data.tar.gz: ff5f76d4c7868c28d223a95bff04a5a3b9cf01879eec9231a709afd2e67a6ce6bb2a4df8a8ccf41406a1cf69aaf7250a40c7c726952f8e8b8cc280b0e8e77175
6
+ metadata.gz: b00b7729fcc0635faa743f9310d048a132d679d1550033302ee39b13dedd5d5f9e4ab79e5673b2cfceb2d887d87f33c24774a3b5d4f0b2bbfdfd8e366844acb2
7
+ data.tar.gz: c879ccd0d7f27b08080905669bff25543673e9117d44650dd31a57674596cf09aee3034a49b8af8c73f7976c1143ec0a8f7892a77252eb945318fafcc6f49da2
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Change Log
2
2
 
3
+ ## 0.4.15
4
+
5
+ - Support ability to attach multiple listeners on a control (e.g. multiple `on_changed {}` on `entry` or multiple `on_clicked` on `button`)
6
+ - Ensure clearing custom listeners on `#destroy` of a control
7
+ - Add `on_destroyed` as alias for `on_destroy` listener on `window`
8
+ - Avoid wasting time on `destroy` of a control (e.g. freeing resources) when the main window is getting destroyed, thus closing entire application instantaneously
9
+ - Have validation in examples/form_table.rb complain about nil values (no value entered)
10
+ - Fix Reset button in examples/meta_example.rb when on a version other than version 1
11
+ - Fix issue with calling `#destroy` on `open_type_features`
12
+
3
13
  ## 0.4.14
4
14
 
5
15
  - Support passing width or height alone to `image` keyword, calculating the other dimension automatically while preserving original aspect ratio
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 />](https://github.com/AndyObtiva/glimmer) Glimmer DSL for LibUI 0.4.14
1
+ # [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 />](https://github.com/AndyObtiva/glimmer) Glimmer DSL for LibUI 0.4.15
2
2
  ## Prerequisite-Free Ruby Desktop Development GUI Library
3
3
  [![Gem Version](https://badge.fury.io/rb/glimmer-dsl-libui.svg)](http://badge.fury.io/rb/glimmer-dsl-libui)
4
4
  [![Join the chat at https://gitter.im/AndyObtiva/glimmer](https://badges.gitter.im/AndyObtiva/glimmer.svg)](https://gitter.im/AndyObtiva/glimmer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
@@ -100,7 +100,7 @@ class FormTable
100
100
  end
101
101
 
102
102
  def launch
103
- window('Contacts', 600, 600) { |w|
103
+ window('Contacts', 600, 600) {
104
104
  margined true
105
105
 
106
106
  vertical_box {
@@ -138,8 +138,8 @@ class FormTable
138
138
 
139
139
  on_clicked do
140
140
  new_row = [name, email, phone, city, state]
141
- if new_row.include?('')
142
- msg_box_error(w, 'Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
141
+ if new_row.map(&:to_s).include?('')
142
+ msg_box_error('Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
143
143
  else
144
144
  @contacts << Contact.new(*new_row) # automatically inserts a row into the table due to explicit data-binding
145
145
  @unfiltered_contacts = @contacts.dup
@@ -184,6 +184,12 @@ class FormTable
184
184
 
185
185
  on_changed do |row, type, row_data|
186
186
  puts "Row #{row} #{type}: #{row_data}"
187
+ $stdout.flush # for Windows
188
+ end
189
+
190
+ on_edited do |row, row_data| # only fires on direct table editing
191
+ puts "Row #{row} edited: #{row_data}"
192
+ $stdout.flush # for Windows
187
193
  end
188
194
  }
189
195
  }
@@ -500,7 +506,7 @@ gem install glimmer-dsl-libui
500
506
  Or install via Bundler `Gemfile`:
501
507
 
502
508
  ```ruby
503
- gem 'glimmer-dsl-libui', '~> 0.4.14'
509
+ gem 'glimmer-dsl-libui', '~> 0.4.15'
504
510
  ```
505
511
 
506
512
  Test that installation worked by running the [Meta-Example](#examples):
@@ -769,7 +775,7 @@ data = [
769
775
  ['Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA'],
770
776
  ]
771
777
 
772
- window('Contacts', 600, 600) { |w|
778
+ window('Contacts', 600, 600) {
773
779
  margined true
774
780
 
775
781
  vertical_box {
@@ -802,8 +808,8 @@ window('Contacts', 600, 600) { |w|
802
808
 
803
809
  on_clicked do
804
810
  new_row = [@name_entry.text, @email_entry.text, @phone_entry.text, @city_entry.text, @state_entry.text]
805
- if new_row.include?('')
806
- msg_box_error(w, 'Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
811
+ if new_row.map(&:to_s).include?('')
812
+ msg_box_error('Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
807
813
  else
808
814
  data << new_row # automatically inserts a row into the table due to implicit data-binding
809
815
  @unfiltered_data = data.dup
@@ -847,6 +853,12 @@ window('Contacts', 600, 600) { |w|
847
853
 
848
854
  on_changed do |row, type, row_data|
849
855
  puts "Row #{row} #{type}: #{row_data}"
856
+ $stdout.flush # for Windows
857
+ end
858
+
859
+ on_edited do |row, row_data| # only fires on direct table editing
860
+ puts "Row #{row} edited: #{row_data}"
861
+ $stdout.flush # for Windows
850
862
  end
851
863
  }
852
864
  }
@@ -1340,13 +1352,16 @@ Note that `area`, `path`, and nested shapes are all truly declarative, meaning t
1340
1352
  - `horizontal_box`, `vertical_box`, `grid`, and `form` controls have `padded` as `true` upon instantiation to ensure more user-friendly GUI by default
1341
1353
  - `group` controls have `margined` as `true` upon instantiation to ensure more user-friendly GUI by default
1342
1354
  - All controls nested under a `horizontal_box`, `vertical_box`, and `form` have `stretchy` property (fill maximum space) as `true` by default (passed to `box_append`/`form_append` method)
1355
+ - If an event listener is repeated under a control (e.g. two `on_clicked {}` listeners under `button`), it does not overwrite the previous listener, yet it is added to an `Array` of listeners for the event. [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) provides multiple-event-listener support unlike [LibUI](https://github.com/kojix2/LibUI)
1343
1356
  - `window` instatiation args can be left off, having the following defaults when unspecified: `title` as `''`, `width` as `190`, `height` as `150`, and `has_menubar` as `true`)
1344
1357
  - `window` has an `on_closing` listener by default that quits application upon hitting the close button (can be overridden with a manual `on_closing` implementation that returns integer `0` for success)
1345
1358
  - `group` has `title` property default to `''` if not specified in instantiation args, so it can be instantiated without args with `title` property specified in nested block (e.g. `group {title 'Address'; ...}`)
1346
1359
  - `button`, `checkbox`, and `label` have `text` default to `''` if not specified in instantiation args, so they can be instantiated without args with `text` property specified in nested block (e.g. `button {text 'Greet'; on_clicked {puts 'Hello'}}`)
1347
1360
  - `quit_menu_item` has an `on_clicked` listener by default that quits application upon selecting the quit menu item (can be overridden with a manual `on_clicked` implementation that returns integer `0` for success)
1348
1361
  - If an `on_closing` listener was defined on `window` and it does not return an integer, default exit behavior is assumed (`window.destroy` is called followed by `LibUI.quit`, returning `0`).
1349
- - If an `on_clicked` listener was defined on `quit_menu_item` and it does not return an integer, default exit behavior is assumed (`main_window.destroy` is called followed by `LibUI.quit`, returning `0`).
1362
+ - If multiple `on_closing` listeners were added for `window`, and none return an integer, they are all executed. On the other hand, if one of them returns an integer, it is counted as the final return value and stops the chain of listener execution.
1363
+ - If an `on_clicked` listener was defined on `quit_menu_item` and it does not return an integer, default exit behavior is assumed (`quit_menu_item.destroy` and `main_window.destroy` are called followed by `LibUI.quit`, returning `0`).
1364
+ - If multiple `on_clicked` listeners were added for `quit_menu_item`, and none return an integer, they are all executed. On the other hand, if one of them returns an integer, it is counted as the final return value and stops the chain of listener execution.
1350
1365
  - All boolean property readers return `true` or `false` in Ruby instead of the [libui](https://github.com/andlabs/libui) original `0` or `1` in C.
1351
1366
  - All boolean property writers accept `true`/`false` in addition to `1`/`0` in Ruby
1352
1367
  - All string property readers return a `String` object in Ruby instead of the [libui](https://github.com/andlabs/libui) Fiddle pointer object.
@@ -6710,6 +6725,11 @@ window('Editable column animal sounds', 400, 200) {
6710
6725
  }
6711
6726
 
6712
6727
  cell_rows data
6728
+
6729
+ on_edited do |row, row_data| # only fires on direct table editing
6730
+ puts "Row #{row} edited: #{row_data}"
6731
+ $stdout.flush
6732
+ end
6713
6733
  }
6714
6734
  }
6715
6735
 
@@ -6822,7 +6842,7 @@ class FormTable
6822
6842
  end
6823
6843
 
6824
6844
  def launch
6825
- window('Contacts', 600, 600) { |w|
6845
+ window('Contacts', 600, 600) {
6826
6846
  margined true
6827
6847
 
6828
6848
  vertical_box {
@@ -6860,8 +6880,8 @@ class FormTable
6860
6880
 
6861
6881
  on_clicked do
6862
6882
  new_row = [name, email, phone, city, state]
6863
- if new_row.include?('')
6864
- msg_box_error(w, 'Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
6883
+ if new_row.map(&:to_s).include?('')
6884
+ msg_box_error('Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
6865
6885
  else
6866
6886
  @contacts << Contact.new(*new_row) # automatically inserts a row into the table due to explicit data-binding
6867
6887
  @unfiltered_contacts = @contacts.dup
@@ -6906,6 +6926,12 @@ class FormTable
6906
6926
 
6907
6927
  on_changed do |row, type, row_data|
6908
6928
  puts "Row #{row} #{type}: #{row_data}"
6929
+ $stdout.flush # for Windows
6930
+ end
6931
+
6932
+ on_edited do |row, row_data| # only fires on direct table editing
6933
+ puts "Row #{row} edited: #{row_data}"
6934
+ $stdout.flush # for Windows
6909
6935
  end
6910
6936
  }
6911
6937
  }
@@ -6916,13 +6942,13 @@ end
6916
6942
  FormTable.new.launch
6917
6943
  ```
6918
6944
 
6919
- New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version (with explicit [data-binding](#data-binding)):
6945
+ New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (with explicit [data-binding](#data-binding)):
6920
6946
 
6921
6947
  ```ruby
6922
6948
  require 'glimmer-dsl-libui'
6923
6949
 
6924
6950
  class FormTable
6925
- Contact = Struct.new(:name, :email, :phone, :city, :state)
6951
+ Contact = Struct.new(:name, :email, :phone, :city, :state_province)
6926
6952
 
6927
6953
  include Glimmer
6928
6954
 
@@ -6939,7 +6965,7 @@ class FormTable
6939
6965
  end
6940
6966
 
6941
6967
  def launch
6942
- window('Contacts', 600, 600) { |w|
6968
+ window('Contacts', 600, 600) {
6943
6969
  margined true
6944
6970
 
6945
6971
  vertical_box {
@@ -6977,8 +7003,8 @@ class FormTable
6977
7003
 
6978
7004
  on_clicked do
6979
7005
  new_row = [name, email, phone, city, state]
6980
- if new_row.include?('')
6981
- msg_box_error(w, 'Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
7006
+ if new_row.map(&:to_s).include?('')
7007
+ msg_box_error('Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
6982
7008
  else
6983
7009
  @contacts << Contact.new(*new_row) # automatically inserts a row into the table due to implicit data-binding
6984
7010
  @unfiltered_contacts = @contacts.dup
@@ -7016,13 +7042,19 @@ class FormTable
7016
7042
  text_column('Email')
7017
7043
  text_column('Phone')
7018
7044
  text_column('City')
7019
- text_column('State/Province')
7045
+ text_column('State')
7020
7046
 
7021
7047
  editable true
7022
- cell_rows <=> [self, :contacts, column_attributes: {'State/Province' => :state}] # explicit data-binding to Model Array with column_attributes mapping for a specific column
7048
+ cell_rows <=> [self, :contacts, column_attributes: {'State' => :state_province}] # explicit data-binding to Model Array with column_attributes mapping for a specific column
7023
7049
 
7024
7050
  on_changed do |row, type, row_data|
7025
7051
  puts "Row #{row} #{type}: #{row_data}"
7052
+ $stdout.flush # for Windows
7053
+ end
7054
+
7055
+ on_edited do |row, row_data| # only fires on direct table editing
7056
+ puts "Row #{row} edited: #{row_data}"
7057
+ $stdout.flush # for Windows
7026
7058
  end
7027
7059
  }
7028
7060
  }
@@ -7033,7 +7065,7 @@ end
7033
7065
  FormTable.new.launch
7034
7066
  ```
7035
7067
 
7036
- New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version (with explicit [data-binding](#data-binding)):
7068
+ New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 3 (with explicit [data-binding](#data-binding)):
7037
7069
 
7038
7070
  ```ruby
7039
7071
 
@@ -7057,7 +7089,7 @@ class FormTable
7057
7089
  end
7058
7090
 
7059
7091
  def launch
7060
- window('Contacts', 600, 600) { |w|
7092
+ window('Contacts', 600, 600) {
7061
7093
  margined true
7062
7094
 
7063
7095
  vertical_box {
@@ -7095,8 +7127,8 @@ class FormTable
7095
7127
 
7096
7128
  on_clicked do
7097
7129
  new_row = [name, email, phone, city, state]
7098
- if new_row.include?('')
7099
- msg_box_error(w, 'Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
7130
+ if new_row.map(&:to_s).include?('')
7131
+ msg_box_error('Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
7100
7132
  else
7101
7133
  @contacts << Contact.new(*new_row) # automatically inserts a row into the table due to implicit data-binding
7102
7134
  @unfiltered_contacts = @contacts.dup
@@ -7141,6 +7173,12 @@ class FormTable
7141
7173
 
7142
7174
  on_changed do |row, type, row_data|
7143
7175
  puts "Row #{row} #{type}: #{row_data}"
7176
+ $stdout.flush # for Windows
7177
+ end
7178
+
7179
+ on_edited do |row, row_data| # only fires on direct table editing
7180
+ puts "Row #{row} edited: #{row_data}"
7181
+ $stdout.flush # for Windows
7144
7182
  end
7145
7183
  }
7146
7184
  }
@@ -7172,7 +7210,7 @@ class FormTable
7172
7210
  end
7173
7211
 
7174
7212
  def launch
7175
- window('Contacts', 600, 600) { |w|
7213
+ window('Contacts', 600, 600) {
7176
7214
  margined true
7177
7215
 
7178
7216
  vertical_box {
@@ -7210,8 +7248,8 @@ class FormTable
7210
7248
 
7211
7249
  on_clicked do
7212
7250
  new_row = [name, email, phone, city, state]
7213
- if new_row.include?('')
7214
- msg_box_error(w, 'Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
7251
+ if new_row.map(&:to_s).include?('')
7252
+ msg_box_error('Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
7215
7253
  else
7216
7254
  data << new_row # automatically inserts a row into the table due to implicit data-binding
7217
7255
  @unfiltered_data = data.dup
@@ -7256,6 +7294,12 @@ class FormTable
7256
7294
 
7257
7295
  on_changed do |row, type, row_data|
7258
7296
  puts "Row #{row} #{type}: #{row_data}"
7297
+ $stdout.flush # for Windows
7298
+ end
7299
+
7300
+ on_edited do |row, row_data| # only fires on direct table editing
7301
+ puts "Row #{row} edited: #{row_data}"
7302
+ $stdout.flush # for Windows
7259
7303
  end
7260
7304
  }
7261
7305
  }
@@ -7281,7 +7325,7 @@ data = [
7281
7325
  ['Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA'],
7282
7326
  ]
7283
7327
 
7284
- window('Contacts', 600, 600) { |w|
7328
+ window('Contacts', 600, 600) {
7285
7329
  margined true
7286
7330
 
7287
7331
  vertical_box {
@@ -7314,8 +7358,8 @@ window('Contacts', 600, 600) { |w|
7314
7358
 
7315
7359
  on_clicked do
7316
7360
  new_row = [@name_entry.text, @email_entry.text, @phone_entry.text, @city_entry.text, @state_entry.text]
7317
- if new_row.include?('')
7318
- msg_box_error(w, 'Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
7361
+ if new_row.map(&:to_s).include?('')
7362
+ msg_box_error('Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
7319
7363
  else
7320
7364
  data << new_row # automatically inserts a row into the table due to implicit data-binding
7321
7365
  @unfiltered_data = data.dup
@@ -7359,6 +7403,12 @@ window('Contacts', 600, 600) { |w|
7359
7403
 
7360
7404
  on_changed do |row, type, row_data|
7361
7405
  puts "Row #{row} #{type}: #{row_data}"
7406
+ $stdout.flush # for Windows
7407
+ end
7408
+
7409
+ on_edited do |row, row_data| # only fires on direct table editing
7410
+ puts "Row #{row} edited: #{row_data}"
7411
+ $stdout.flush # for Windows
7362
7412
  end
7363
7413
  }
7364
7414
  }
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.14
1
+ 0.4.15
@@ -22,6 +22,11 @@ window('Editable column animal sounds', 400, 200) {
22
22
  }
23
23
 
24
24
  cell_rows data
25
+
26
+ on_edited do |row, row_data| # only fires on direct table editing
27
+ puts "Row #{row} edited: #{row_data}"
28
+ $stdout.flush
29
+ end
25
30
  }
26
31
  }
27
32
 
@@ -18,7 +18,7 @@ class FormTable
18
18
  end
19
19
 
20
20
  def launch
21
- window('Contacts', 600, 600) { |w|
21
+ window('Contacts', 600, 600) {
22
22
  margined true
23
23
 
24
24
  vertical_box {
@@ -56,8 +56,8 @@ class FormTable
56
56
 
57
57
  on_clicked do
58
58
  new_row = [name, email, phone, city, state]
59
- if new_row.include?('')
60
- msg_box_error(w, 'Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
59
+ if new_row.map(&:to_s).include?('')
60
+ msg_box_error('Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
61
61
  else
62
62
  @contacts << Contact.new(*new_row) # automatically inserts a row into the table due to explicit data-binding
63
63
  @unfiltered_contacts = @contacts.dup
@@ -102,6 +102,12 @@ class FormTable
102
102
 
103
103
  on_changed do |row, type, row_data|
104
104
  puts "Row #{row} #{type}: #{row_data}"
105
+ $stdout.flush # for Windows
106
+ end
107
+
108
+ on_edited do |row, row_data| # only fires on direct table editing
109
+ puts "Row #{row} edited: #{row_data}"
110
+ $stdout.flush # for Windows
105
111
  end
106
112
  }
107
113
  }
@@ -1,7 +1,7 @@
1
1
  require 'glimmer-dsl-libui'
2
2
 
3
3
  class FormTable
4
- Contact = Struct.new(:name, :email, :phone, :city, :state)
4
+ Contact = Struct.new(:name, :email, :phone, :city, :state_province)
5
5
 
6
6
  include Glimmer
7
7
 
@@ -18,7 +18,7 @@ class FormTable
18
18
  end
19
19
 
20
20
  def launch
21
- window('Contacts', 600, 600) { |w|
21
+ window('Contacts', 600, 600) {
22
22
  margined true
23
23
 
24
24
  vertical_box {
@@ -56,8 +56,8 @@ class FormTable
56
56
 
57
57
  on_clicked do
58
58
  new_row = [name, email, phone, city, state]
59
- if new_row.include?('')
60
- msg_box_error(w, 'Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
59
+ if new_row.map(&:to_s).include?('')
60
+ msg_box_error('Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
61
61
  else
62
62
  @contacts << Contact.new(*new_row) # automatically inserts a row into the table due to implicit data-binding
63
63
  @unfiltered_contacts = @contacts.dup
@@ -95,13 +95,19 @@ class FormTable
95
95
  text_column('Email')
96
96
  text_column('Phone')
97
97
  text_column('City')
98
- text_column('State/Province')
98
+ text_column('State')
99
99
 
100
100
  editable true
101
- cell_rows <=> [self, :contacts, column_attributes: {'State/Province' => :state}] # explicit data-binding to Model Array with column_attributes mapping for a specific column
101
+ cell_rows <=> [self, :contacts, column_attributes: {'State' => :state_province}] # explicit data-binding to Model Array with column_attributes mapping for a specific column
102
102
 
103
103
  on_changed do |row, type, row_data|
104
104
  puts "Row #{row} #{type}: #{row_data}"
105
+ $stdout.flush # for Windows
106
+ end
107
+
108
+ on_edited do |row, row_data| # only fires on direct table editing
109
+ puts "Row #{row} edited: #{row_data}"
110
+ $stdout.flush # for Windows
105
111
  end
106
112
  }
107
113
  }
@@ -19,7 +19,7 @@ class FormTable
19
19
  end
20
20
 
21
21
  def launch
22
- window('Contacts', 600, 600) { |w|
22
+ window('Contacts', 600, 600) {
23
23
  margined true
24
24
 
25
25
  vertical_box {
@@ -57,8 +57,8 @@ class FormTable
57
57
 
58
58
  on_clicked do
59
59
  new_row = [name, email, phone, city, state]
60
- if new_row.include?('')
61
- msg_box_error(w, 'Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
60
+ if new_row.map(&:to_s).include?('')
61
+ msg_box_error('Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
62
62
  else
63
63
  @contacts << Contact.new(*new_row) # automatically inserts a row into the table due to implicit data-binding
64
64
  @unfiltered_contacts = @contacts.dup
@@ -103,6 +103,12 @@ class FormTable
103
103
 
104
104
  on_changed do |row, type, row_data|
105
105
  puts "Row #{row} #{type}: #{row_data}"
106
+ $stdout.flush # for Windows
107
+ end
108
+
109
+ on_edited do |row, row_data| # only fires on direct table editing
110
+ puts "Row #{row} edited: #{row_data}"
111
+ $stdout.flush # for Windows
106
112
  end
107
113
  }
108
114
  }
@@ -16,7 +16,7 @@ class FormTable
16
16
  end
17
17
 
18
18
  def launch
19
- window('Contacts', 600, 600) { |w|
19
+ window('Contacts', 600, 600) {
20
20
  margined true
21
21
 
22
22
  vertical_box {
@@ -54,8 +54,8 @@ class FormTable
54
54
 
55
55
  on_clicked do
56
56
  new_row = [name, email, phone, city, state]
57
- if new_row.include?('')
58
- msg_box_error(w, 'Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
57
+ if new_row.map(&:to_s).include?('')
58
+ msg_box_error('Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
59
59
  else
60
60
  data << new_row # automatically inserts a row into the table due to implicit data-binding
61
61
  @unfiltered_data = data.dup
@@ -100,6 +100,12 @@ class FormTable
100
100
 
101
101
  on_changed do |row, type, row_data|
102
102
  puts "Row #{row} #{type}: #{row_data}"
103
+ $stdout.flush # for Windows
104
+ end
105
+
106
+ on_edited do |row, row_data| # only fires on direct table editing
107
+ puts "Row #{row} edited: #{row_data}"
108
+ $stdout.flush # for Windows
103
109
  end
104
110
  }
105
111
  }
@@ -10,7 +10,7 @@ data = [
10
10
  ['Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA'],
11
11
  ]
12
12
 
13
- window('Contacts', 600, 600) { |w|
13
+ window('Contacts', 600, 600) {
14
14
  margined true
15
15
 
16
16
  vertical_box {
@@ -43,8 +43,8 @@ window('Contacts', 600, 600) { |w|
43
43
 
44
44
  on_clicked do
45
45
  new_row = [@name_entry.text, @email_entry.text, @phone_entry.text, @city_entry.text, @state_entry.text]
46
- if new_row.include?('')
47
- msg_box_error(w, 'Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
46
+ if new_row.map(&:to_s).include?('')
47
+ msg_box_error('Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
48
48
  else
49
49
  data << new_row # automatically inserts a row into the table due to implicit data-binding
50
50
  @unfiltered_data = data.dup
@@ -88,6 +88,12 @@ window('Contacts', 600, 600) { |w|
88
88
 
89
89
  on_changed do |row, type, row_data|
90
90
  puts "Row #{row} #{type}: #{row_data}"
91
+ $stdout.flush # for Windows
92
+ end
93
+
94
+ on_edited do |row, row_data| # only fires on direct table editing
95
+ puts "Row #{row} edited: #{row_data}"
96
+ $stdout.flush # for Windows
91
97
  end
92
98
  }
93
99
  }
@@ -180,7 +180,9 @@ class MetaExample
180
180
  }
181
181
  button('Reset') {
182
182
  on_clicked do
183
- self.code_text = File.read(file_path_for(selected_example))
183
+ version_number = @version_spinbox.value == 1 ? '' : @version_spinbox.value
184
+ example = "#{selected_example}#{version_number}"
185
+ self.code_text = File.read(file_path_for(example))
184
186
  end
185
187
  }
186
188
  }
Binary file
@@ -22,7 +22,6 @@
22
22
  require 'glimmer/libui/control_proxy'
23
23
  require 'glimmer/libui/control_proxy/area_proxy'
24
24
  require 'glimmer/libui/parent'
25
- require 'glimmer/libui/control_proxy/transformable'
26
25
  require 'glimmer/libui/data_bindable'
27
26
 
28
27
  module Glimmer
@@ -48,7 +47,7 @@ module Glimmer
48
47
  @string
49
48
  else
50
49
  @string = value
51
- redraw
50
+ request_auto_redraw
52
51
  end
53
52
  end
54
53
  alias string= string
@@ -59,7 +58,7 @@ module Glimmer
59
58
  @font
60
59
  else
61
60
  @font = value
62
- redraw
61
+ request_auto_redraw
63
62
  end
64
63
  end
65
64
  alias font= font
@@ -70,7 +69,7 @@ module Glimmer
70
69
  @color
71
70
  else
72
71
  @color = Glimmer::LibUI.interpret_color(value)
73
- redraw
72
+ request_auto_redraw
74
73
  end
75
74
  end
76
75
  alias color= color
@@ -81,7 +80,7 @@ module Glimmer
81
80
  @background
82
81
  else
83
82
  @background = Glimmer::LibUI.interpret_color(value)
84
- redraw
83
+ request_auto_redraw
85
84
  end
86
85
  end
87
86
  alias background= background
@@ -92,7 +91,7 @@ module Glimmer
92
91
  @underline
93
92
  else
94
93
  @underline = value
95
- redraw
94
+ request_auto_redraw
96
95
  end
97
96
  end
98
97
  alias underline= underline
@@ -103,7 +102,7 @@ module Glimmer
103
102
  @underline_color
104
103
  else
105
104
  @underline_color = value
106
- redraw
105
+ request_auto_redraw
107
106
  end
108
107
  end
109
108
  alias underline_color= underline_color
@@ -114,12 +113,21 @@ module Glimmer
114
113
  @open_type_features
115
114
  else
116
115
  @open_type_features = value
117
- redraw
116
+ request_auto_redraw
118
117
  end
119
118
  end
120
119
  alias open_type_features= open_type_features
121
120
  alias set_open_type_features open_type_features
122
121
 
122
+ def remove_open_type_features
123
+ return if @removing_open_type_features
124
+ @removing_open_type_features = true
125
+ @open_type_features&.destroy
126
+ @open_type_features = nil
127
+ request_auto_redraw
128
+ @removing_open_type_features = false
129
+ end
130
+
123
131
  def post_add_content(block = nil)
124
132
  block ||= @block
125
133
  block_result = block&.call
@@ -189,6 +197,7 @@ module Glimmer
189
197
  end
190
198
 
191
199
  def destroy
200
+ return if ControlProxy.main_window_proxy&.destroying?
192
201
  open_type_features.destroy unless open_type_features.nil?
193
202
  @parent_proxy&.children&.delete(self)
194
203
  end
@@ -36,9 +36,9 @@ module Glimmer
36
36
  attr_accessor :current_area_draw_params
37
37
  end
38
38
 
39
- LISTENERS = ['on_draw', 'on_mouse_event', 'on_mouse_move', 'on_mouse_down', 'on_mouse_up', 'on_mouse_drag_start', 'on_mouse_drag', 'on_mouse_drop', 'on_mouse_crossed', 'on_mouse_enter', 'on_mouse_exit', 'on_drag_broken', 'on_key_event', 'on_key_down', 'on_key_up']
39
+ CUSTOM_LISTENER_NAMES = ['on_draw', 'on_mouse_event', 'on_mouse_move', 'on_mouse_down', 'on_mouse_up', 'on_mouse_drag_start', 'on_mouse_drag', 'on_mouse_drop', 'on_mouse_crossed', 'on_mouse_enter', 'on_mouse_exit', 'on_drag_broken', 'on_key_event', 'on_key_down', 'on_key_up']
40
40
 
41
- LISTENER_ALIASES = {
41
+ CUSTOM_LISTENER_NAME_ALIASES = {
42
42
  on_drawn: 'on_draw',
43
43
  on_mouse_moved: 'on_mouse_move',
44
44
  on_mouse_drag_started: 'on_mouse_drag_start',
@@ -105,7 +105,7 @@ module Glimmer
105
105
 
106
106
  def draw(area_draw_params)
107
107
  children.dup.each {|child| child.draw(area_draw_params)}
108
- on_draw.each {|listener| listener.call(area_draw_params)}
108
+ notify_custom_listeners('on_draw', area_draw_params)
109
109
  end
110
110
 
111
111
  def redraw
@@ -156,37 +156,37 @@ module Glimmer
156
156
  @area_handler.MouseEvent = fiddle_closure_block_caller(0, [1, 1, 1]) do |_, _, area_mouse_event|
157
157
  area_mouse_event = ::LibUI::FFI::AreaMouseEvent.new(area_mouse_event)
158
158
  area_mouse_event = area_mouse_event_hash(area_mouse_event)
159
- on_mouse_event.each { |listener| listener.call(area_mouse_event)}
160
- on_mouse_move.each { |listener| listener.call(area_mouse_event)} if area_mouse_event[:x].between?(0, area_mouse_event[:area_width]) && area_mouse_event[:y].between?(0, area_mouse_event[:area_height])
159
+ notify_custom_listeners('on_mouse_event', area_mouse_event)
160
+ notify_custom_listeners('on_mouse_move', area_mouse_event) if area_mouse_event[:x].between?(0, area_mouse_event[:area_width]) && area_mouse_event[:y].between?(0, area_mouse_event[:area_height])
161
161
  unless @last_area_mouse_event.nil?
162
- on_mouse_down.each { |listener| listener.call(area_mouse_event)} if area_mouse_event[:down] > 0 && @last_area_mouse_event[:down] == 0
163
- on_mouse_up.each { |listener| listener.call(area_mouse_event)} if area_mouse_event[:up] > 0 && @last_area_mouse_event[:up] == 0
164
- on_mouse_drag_start.each { |listener| listener.call(area_mouse_event)} if area_mouse_event[:held] > 0 && @last_area_mouse_event[:held] == 0
165
- on_mouse_drag.each { |listener| listener.call(area_mouse_event)} if area_mouse_event[:held] > 0
166
- on_mouse_drop.each { |listener| listener.call(area_mouse_event)} if area_mouse_event[:held] == 0 && @last_area_mouse_event[:held] > 0
162
+ notify_custom_listeners('on_mouse_down', area_mouse_event) if area_mouse_event[:down] > 0 && @last_area_mouse_event[:down] == 0
163
+ notify_custom_listeners('on_mouse_up', area_mouse_event) if area_mouse_event[:up] > 0 && @last_area_mouse_event[:up] == 0
164
+ notify_custom_listeners('on_mouse_drag_start', area_mouse_event) if area_mouse_event[:held] > 0 && @last_area_mouse_event[:held] == 0
165
+ notify_custom_listeners('on_mouse_drag', area_mouse_event) if area_mouse_event[:held] > 0
166
+ notify_custom_listeners('on_mouse_drop', area_mouse_event) if area_mouse_event[:held] == 0 && @last_area_mouse_event[:held] > 0
167
167
  end
168
168
  @last_area_mouse_event = area_mouse_event
169
169
  end
170
170
  @area_handler.MouseCrossed = fiddle_closure_block_caller(0, [1, 1, 4]) do |_, _, left|
171
171
  left = Glimmer::LibUI.integer_to_boolean(left)
172
- on_mouse_crossed.each { |listener| listener.call(left) }
172
+ notify_custom_listeners('on_mouse_crossed', left)
173
173
  if left
174
- on_mouse_exit.each { |listener| listener.call(left) }
174
+ notify_custom_listeners('on_mouse_exit', left)
175
175
  else
176
- on_mouse_enter.each { |listener| listener.call(left) }
176
+ notify_custom_listeners('on_mouse_enter', left)
177
177
  end
178
178
  end
179
179
  @area_handler.DragBroken = fiddle_closure_block_caller(0, [1, 1]) do |_, _|
180
- on_drag_broken.each { |listener| listener.call }
180
+ notify_custom_listeners('on_drag_broken')
181
181
  end
182
182
  @area_handler.KeyEvent = fiddle_closure_block_caller(0, [1, 1, 1]) do |_, _, area_key_event|
183
183
  area_key_event = ::LibUI::FFI::AreaKeyEvent.new(area_key_event)
184
184
  area_key_event = area_key_event_hash(area_key_event)
185
- on_key_event.each { |listener| listener.call(area_key_event) }
185
+ notify_custom_listeners('on_key_event', area_key_event)
186
186
  if area_key_event[:up]
187
- on_key_up.each { |listener| listener.call(area_key_event) }
187
+ notify_custom_listeners('on_key_up', area_key_event)
188
188
  else
189
- on_key_down.each { |listener| listener.call(area_key_event) }
189
+ notify_custom_listeners('on_key_down', area_key_event)
190
190
  end
191
191
  end
192
192
  @listeners_installed = true
@@ -42,6 +42,7 @@ module Glimmer
42
42
  end
43
43
 
44
44
  def destroy_child(child)
45
+ child.deregister_all_custom_listeners
45
46
  ::LibUI.send("box_delete", @libui, children.index(child))
46
47
  ControlProxy.control_proxies.delete(child)
47
48
  end
@@ -34,36 +34,8 @@ module Glimmer
34
34
  include Column
35
35
  include EnableableColumn
36
36
 
37
- def on_clicked(&block)
38
- # TODO consider generalizing into custom listeners and moving to ControlProxy
39
- @on_clicked_procs ||= []
40
- if block.nil?
41
- @on_clicked_procs
42
- else
43
- @on_clicked_procs << block
44
- block
45
- end
46
- end
47
-
48
- def can_handle_listener?(listener_name)
49
- listener_name == 'on_clicked' || super
50
- end
37
+ CUSTOM_LISTENER_NAMES = ['on_clicked']
51
38
 
52
- def handle_listener(listener_name, &listener)
53
- case listener_name
54
- when 'on_clicked'
55
- on_clicked(&listener)
56
- else
57
- super
58
- end
59
- end
60
-
61
- def notify_listeners(listener_name, *args)
62
- @on_clicked_procs&.each do |on_clicked_proc|
63
- on_clicked_proc.call(*args)
64
- end
65
- end
66
-
67
39
  private
68
40
 
69
41
  def build_control
@@ -39,6 +39,7 @@ module Glimmer
39
39
  end
40
40
 
41
41
  def destroy_child(child)
42
+ child.deregister_all_custom_listeners
42
43
  ::LibUI.send("form_delete", @libui, children.index(child))
43
44
  ControlProxy.control_proxies.delete(child)
44
45
  end
@@ -179,6 +179,8 @@ module Glimmer
179
179
  end
180
180
 
181
181
  def destroy
182
+ return if ControlProxy.main_window_proxy&.destroying?
183
+ deregister_all_custom_listeners
182
184
  @parent_proxy&.children&.delete(self)
183
185
  ControlProxy.control_proxies.delete(self)
184
186
  end
@@ -35,29 +35,39 @@ module Glimmer
35
35
 
36
36
  def handle_listener(listener_name, &listener)
37
37
  if listener_name == 'on_clicked'
38
- @default_behavior_listener = Proc.new do
39
- return_value = listener.call(self)
38
+ @on_clicked_listeners ||= []
39
+ @on_clicked_listeners << listener
40
+ @default_behavior_listener ||= Proc.new do
41
+ return_value = nil
42
+ @on_clicked_listeners.each do |l|
43
+ return_value = l.call(self)
44
+ break if return_value.is_a?(Numeric)
45
+ end
40
46
  if return_value.is_a?(Numeric)
41
47
  return_value
42
48
  else
43
49
  destroy
50
+ ControlProxy.main_window_proxy&.destroy
44
51
  ::LibUI.quit
45
52
  0
46
53
  end
54
+ end.tap do |default_behavior_listener|
55
+ ::LibUI.on_should_quit(&default_behavior_listener)
47
56
  end
48
- ::LibUI.on_should_quit(&@default_behavior_listener)
49
57
  end
50
58
  end
59
+
60
+ def destroy
61
+ @on_clicked_listeners&.clear
62
+ super
63
+ end
51
64
 
52
65
  private
53
66
 
54
67
  def build_control
55
68
  @libui = @parent_proxy.append_quit_item(*@args)
56
- handle_listener('on_clicked') do
57
- ControlProxy.main_window_proxy&.destroy
58
- ::LibUI.quit
59
- 0
60
- end
69
+ # setup default on_clicked listener if no on_clicked listeners are setup
70
+ handle_listener('on_clicked') {} if @on_clicked_listeners.nil? || @on_clicked_listeners.empty?
61
71
  end
62
72
  end
63
73
  end
@@ -33,15 +33,24 @@ module Glimmer
33
33
  include Parent
34
34
 
35
35
  def destroy
36
+ return if ControlProxy.main_window_proxy&.destroying?
37
+ return if @destroying
38
+ @destroying = true
39
+ deregister_all_custom_listeners
36
40
  ::LibUI.free_open_type_features(@libui)
37
- @parent_proxy&.children&.delete(self)
41
+ @parent_proxy&.remove_open_type_features
38
42
  ControlProxy.control_proxies.delete(self)
43
+ @destroying = false
39
44
  end
40
45
 
41
46
  def redraw
42
- @parent_proxy.redraw
47
+ @parent_proxy&.redraw
43
48
  end
44
49
 
50
+ def request_auto_redraw
51
+ @parent_proxy&.request_auto_redraw
52
+ end
53
+
45
54
  private
46
55
 
47
56
  def build_control
@@ -31,6 +31,8 @@ module Glimmer
31
31
  # Follows the Proxy Design Pattern
32
32
  class OpenTypeTagProxy < ControlProxy
33
33
  def destroy
34
+ return if ControlProxy.main_window_proxy&.destroying?
35
+ deregister_all_custom_listeners
34
36
  @parent_proxy&.children&.delete(self)
35
37
  ControlProxy.control_proxies.delete(self)
36
38
  end
@@ -140,6 +140,8 @@ module Glimmer
140
140
  end
141
141
 
142
142
  def destroy
143
+ return if ControlProxy.main_window_proxy&.destroying?
144
+ deregister_all_custom_listeners
143
145
  @parent_proxy&.children&.delete(self)
144
146
  ControlProxy.control_proxies.delete(self)
145
147
  end
@@ -36,7 +36,7 @@ module Glimmer
36
36
  class TableProxy < ControlProxy
37
37
  include Glimmer::FiddleConsumer
38
38
 
39
- LISTENERS = ['on_changed', 'on_edited']
39
+ CUSTOM_LISTENER_NAMES = ['on_changed', 'on_edited']
40
40
 
41
41
  attr_reader :model_handler, :model, :table_params, :columns, :column_attributes
42
42
 
@@ -91,18 +91,18 @@ module Glimmer
91
91
  if @cell_rows.size < @last_cell_rows.size && @last_cell_rows.include_all?(*@cell_rows)
92
92
  @last_cell_rows.array_diff_indexes(@cell_rows).reverse.each do |row|
93
93
  ::LibUI.table_model_row_deleted(model, row)
94
- on_changed.each {|listener| listener.call(row, :deleted, @last_cell_rows[row])}
94
+ notify_custom_listeners('on_changed', row, :deleted, @last_cell_rows[row])
95
95
  end
96
96
  elsif @cell_rows.size > @last_cell_rows.size && @cell_rows.include_all?(*@last_cell_rows)
97
97
  @cell_rows.array_diff_indexes(@last_cell_rows).each do |row|
98
98
  ::LibUI.table_model_row_inserted(model, row)
99
- on_changed.each {|listener| listener.call(row, :inserted, @cell_rows[row])}
99
+ notify_custom_listeners('on_changed', row, :inserted, @cell_rows[row])
100
100
  end
101
101
  else
102
102
  @cell_rows.each_with_index do |new_row_data, row|
103
103
  if new_row_data != @last_cell_rows[row]
104
104
  ::LibUI.table_model_row_changed(model, row)
105
- on_changed.each {|listener| listener.call(row, :changed, @cell_rows[row])}
105
+ notify_custom_listeners('on_changed', row, :changed, @cell_rows[row])
106
106
  end
107
107
  end
108
108
  end
@@ -270,7 +270,7 @@ module Glimmer
270
270
  @cell_rows[row].send(attribute)[1] = ::LibUI.table_value_string(val).to_s
271
271
  end
272
272
  when Column::ButtonColumnProxy
273
- @columns[column].notify_listeners(:on_clicked, row)
273
+ @columns[column].notify_custom_listeners('on_clicked', row)
274
274
  when Column::CheckboxColumnProxy
275
275
  column = @columns[column].index
276
276
  @cell_rows[row] ||= []
@@ -292,7 +292,7 @@ module Glimmer
292
292
  @cell_rows[row].send(attribute)[0] = ::LibUI.table_value_int(val).to_i == 1
293
293
  end
294
294
  end
295
- on_edited.each {|listener| listener.call(row, @cell_rows[row])}
295
+ notify_custom_listeners('on_edited', row, @cell_rows[row])
296
296
  end
297
297
 
298
298
  @model = ::LibUI.new_table_model(@model_handler)
@@ -60,6 +60,8 @@ module Glimmer
60
60
  end
61
61
 
62
62
  def destroy
63
+ return if ControlProxy.main_window_proxy&.destroying?
64
+ deregister_all_custom_listeners
63
65
  @parent_proxy&.children&.delete(self)
64
66
  ControlProxy.control_proxies.delete(self)
65
67
  end
@@ -29,6 +29,10 @@ module Glimmer
29
29
  #
30
30
  # Follows the Proxy Design Pattern
31
31
  class WindowProxy < ControlProxy
32
+ CUSTOM_LISTENER_NAMES = ['on_destroy']
33
+ CUSTOM_LISTENER_NAME_ALIASES = {
34
+ on_destroyed: 'on_destroy',
35
+ }
32
36
  DEFAULT_TITLE = ''
33
37
  DEFAULT_WIDTH = 190
34
38
  DEFAULT_HEIGHT = 150
@@ -44,22 +48,20 @@ module Glimmer
44
48
  end
45
49
 
46
50
  def destroy
51
+ return if @destroying
52
+ @destroying = true
53
+ @on_closing_listeners&.clear
47
54
  super
48
55
  ControlProxy.image_proxies.each { |image_proxy| ::LibUI.free_image(image_proxy.libui) unless image_proxy.area_image? }
49
- @on_destroy_procs&.each { |on_destroy_proc| on_destroy_proc.call(self)}
56
+ notify_custom_listeners('on_destroy', self)
57
+ deregister_custom_listeners('on_destroy')
58
+ @destroying = false
50
59
  end
51
60
 
52
- def on_destroy(&block)
53
- # TODO look into a way to generalize this logic for multiple listeners
54
- @on_destroy_procs ||= []
55
- if block.nil?
56
- @on_destroy_procs
57
- else
58
- @on_destroy_procs << block
59
- block
60
- end
61
+ def destroying?
62
+ @destroying
61
63
  end
62
-
64
+
63
65
  def show
64
66
  super
65
67
  unless @shown_at_least_once
@@ -69,29 +71,29 @@ module Glimmer
69
71
  end
70
72
  end
71
73
 
72
- def can_handle_listener?(listener_name)
73
- listener_name == 'on_destroy' || super
74
- end
75
-
76
74
  def handle_listener(listener_name, &listener)
77
75
  case listener_name
78
- when 'on_destroy'
79
- on_destroy(&listener)
80
- else
81
- default_behavior_listener = nil
82
- if listener_name == 'on_closing'
83
- default_behavior_listener = Proc.new do
84
- return_value = listener.call(self)
85
- if return_value.is_a?(Numeric)
86
- return_value
87
- else
88
- destroy
89
- ::LibUI.quit
90
- 0
91
- end
76
+ when 'on_closing'
77
+ @on_closing_listeners ||= []
78
+ @on_closing_listeners << listener
79
+ @default_behavior_listener ||= Proc.new do
80
+ return_value = nil
81
+ @on_closing_listeners.each do |l|
82
+ return_value = l.call(self)
83
+ break if return_value.is_a?(Numeric)
84
+ end
85
+ if return_value.is_a?(Numeric)
86
+ return_value
87
+ else
88
+ destroy
89
+ ::LibUI.quit
90
+ 0
92
91
  end
92
+ end.tap do |default_behavior_listener|
93
+ super(listener_name, &default_behavior_listener)
93
94
  end
94
- super(listener_name, &(default_behavior_listener || listener))
95
+ else
96
+ super
95
97
  end
96
98
  end
97
99
 
@@ -168,11 +170,8 @@ module Glimmer
168
170
  @height = construction_args[2]
169
171
  @libui = ControlProxy.new_control(@keyword, construction_args)
170
172
  @libui.tap do
171
- handle_listener('on_closing') do
172
- destroy
173
- ::LibUI.quit
174
- 0
175
- end
173
+ # setup default on_closing listener if no on_closing listeners are setup
174
+ handle_listener('on_closing') {} if @on_closing_listeners.nil? || @on_closing_listeners.empty?
176
175
  end
177
176
  end
178
177
  end
@@ -169,31 +169,49 @@ module Glimmer
169
169
  def handle_listener(listener_name, &listener)
170
170
  safe_listener = Proc.new { listener.call(self) }
171
171
  if ::LibUI.respond_to?("#{libui_api_keyword}_#{listener_name}")
172
- ::LibUI.send("#{libui_api_keyword}_#{listener_name}", @libui, &safe_listener)
172
+ if listeners[listener_name].nil?
173
+ ::LibUI.send("#{libui_api_keyword}_#{listener_name}", @libui) do
174
+ listeners_for(listener_name).map { |listener| listener.call }.last
175
+ end
176
+ end
177
+ listeners_for(listener_name) << safe_listener
173
178
  elsif ::LibUI.respond_to?("control_#{listener_name}")
174
- ::LibUI.send("control_#{listener_name}", @libui, &safe_listener)
179
+ if listeners[listener_name].nil?
180
+ ::LibUI.send("control_#{listener_name}", @libui) do
181
+ listeners_for(listener_name).map { |listener| listener.call }.last
182
+ end
183
+ end
184
+ listeners_for(listener_name) << safe_listener
175
185
  elsif has_custom_listener?(listener_name)
176
186
  handle_custom_listener(listener_name, &listener)
177
187
  end
178
188
  end
179
189
 
190
+ def listeners
191
+ @listeners ||= {}
192
+ end
193
+
194
+ def listeners_for(listener_name)
195
+ listeners[listener_name] ||= []
196
+ end
197
+
180
198
  def has_custom_listener?(listener_name)
181
199
  listener_name = listener_name.to_s
182
- custom_listeners.include?(listener_name) || custom_listener_aliases.stringify_keys.keys.include?(listener_name)
200
+ custom_listener_names.include?(listener_name) || custom_listener_name_aliases.stringify_keys.keys.include?(listener_name)
183
201
  end
184
202
 
185
- def custom_listeners
186
- self.class.constants.include?(:LISTENERS) ? self.class::LISTENERS : []
203
+ def custom_listener_names
204
+ self.class.constants.include?(:CUSTOM_LISTENER_NAMES) ? self.class::CUSTOM_LISTENER_NAMES : []
187
205
  end
188
206
 
189
- def custom_listener_aliases
190
- self.class.constants.include?(:LISTENER_ALIASES) ? self.class::LISTENER_ALIASES : {}
207
+ def custom_listener_name_aliases
208
+ self.class.constants.include?(:CUSTOM_LISTENER_NAME_ALIASES) ? self.class::CUSTOM_LISTENER_NAME_ALIASES : {}
191
209
  end
192
210
 
193
211
  def handle_custom_listener(listener_name, &listener)
194
212
  listener_name = listener_name.to_s
195
- listener_name = custom_listener_aliases.stringify_keys[listener_name] || listener_name
196
- instance_variable_name = "@#{listener_name}_procs"
213
+ listener_name = custom_listener_name_aliases.stringify_keys[listener_name] || listener_name
214
+ instance_variable_name = "@#{listener_name}_procs" # TODO ensure clearing custom listeners on destroy of a control
197
215
  instance_variable_set(instance_variable_name, []) if instance_variable_get(instance_variable_name).nil?
198
216
  if listener.nil?
199
217
  instance_variable_get(instance_variable_name)
@@ -203,6 +221,21 @@ module Glimmer
203
221
  end
204
222
  end
205
223
 
224
+ def notify_custom_listeners(listener_name, *args)
225
+ handle_custom_listener(listener_name).each do |listener|
226
+ listener.call(*args)
227
+ end
228
+ end
229
+
230
+ def deregister_custom_listeners(listener_name)
231
+ handle_custom_listener(listener_name).clear
232
+ end
233
+
234
+ # deregisters all custom listeners except on_destroy, which can only be deregistered after destruction of a control, using deregister_custom_listeners
235
+ def deregister_all_custom_listeners
236
+ (custom_listener_names - ['on_destroy']).each { |listener_name| deregister_custom_listeners(listener_name) }
237
+ end
238
+
206
239
  def respond_to?(method_name, *args, &block)
207
240
  respond_to_libui?(method_name, *args, &block) ||
208
241
  (
@@ -289,6 +322,8 @@ module Glimmer
289
322
  end
290
323
 
291
324
  def destroy
325
+ # TODO exclude menus from this initial return
326
+ return if !is_a?(ControlProxy::WindowProxy) && ControlProxy.main_window_proxy&.destroying?
292
327
  data_binding_model_attribute_observer_registrations.each(&:deregister)
293
328
  if parent_proxy.nil?
294
329
  default_destroy
@@ -302,6 +337,7 @@ module Glimmer
302
337
  end
303
338
 
304
339
  def default_destroy
340
+ deregister_all_custom_listeners
305
341
  send_to_libui('destroy')
306
342
  ControlProxy.control_proxies.delete(self)
307
343
  end
@@ -116,6 +116,7 @@ module Glimmer
116
116
  end
117
117
 
118
118
  def destroy
119
+ return if ControlProxy.main_window_proxy&.destroying?
119
120
  @parent.children.delete(self)
120
121
  end
121
122
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: glimmer-dsl-libui
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.14
4
+ version: 0.4.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Maleh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-04 00:00:00.000000000 Z
11
+ date: 2021-12-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: glimmer