glimmer-dsl-tk 0.0.47 → 0.0.51

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: a534fbbe0b7c850fe702b42bf16eb4bc1854f68baa736b73ebf0bf6d5cc29f28
4
- data.tar.gz: b38740259743b4e579ec72251dee2018f826007dc975b3efe8a4b90d9b5031da
3
+ metadata.gz: 8e73712c604d4ac237f122877e2c4a558570b212fcbf0c192b3c3cccf760cd10
4
+ data.tar.gz: 6bf3e67c3cebdd497c2775d2a7f72cc5efefb68c2116bf61e0511a3fa4c54161
5
5
  SHA512:
6
- metadata.gz: 03d144a49d2494ce0ff6576aaf510157d15086868f69d14bf70c27b3c7ed08e68125a86892ace5c9c178b52255252ad44a3b90ba49e7ff91e71d5e47af301f7c
7
- data.tar.gz: 7543abee9889820cea1911ec3f6c395ea61ad96e761b8f7ad384cc17b50140854fb524852055e34eea7d221a38047bd1d3f053866a6d8b17363066739383529a
6
+ metadata.gz: ffe9c7c5fb555f4419828d34cca5a86aca6c98756afa37d7b83d2c46086e6ca964651b5f256e092a7c1622bb30f86b52c9e3168529f6bc45426ff5cbb9fceb37
7
+ data.tar.gz: aca17f0b69b67fa68ef13ac707a96416a3a88d16bf3607190c8cba553763fc9bebf7054a25db310dd5dd0975746f3f5e0717cba899fe8e9f0eaf0f4870fd2870
data/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # Change Log
2
2
 
3
+ ## 0.0.51
4
+
5
+ - Center application root/toplevel within screen by default (if x or y are specified, they are respected instead)
6
+ - Enhance Hello, Contextual Menu! & Hello, Menu Bar! to display a message box upon selecting a Language/Country
7
+ - Explicitly support all menu item attributes: `activebackground`, `activeforeground`, `background`, `bitmap`, `columnbreak`, `compound`, `font`, `foreground`, `hidemargin`, `indicatoron`, `menu`, `offvalue`, `onvalue`, `selectcolor`, `selectimage`, `state`, `underline`, `value`
8
+
9
+ ## 0.0.50
10
+
11
+ - Support manual binding of contextual menu by passing `bind: false` option (e.g. `menu(bind: false) {...}` as demonstrated in samples/hello/hello_contextual_menu.rb)
12
+ - Support binding multiple contextual menus (they show up consecutively unless there is conditional logic to control showing them individually)
13
+ - Update Hello, Contextual Menu! to add a comment and an example about manual menu binding
14
+ - Upgrade to glimmer 2.5.4
15
+
16
+ ## 0.0.49
17
+
18
+ - [API Breaking] Update menu bar support to require `menu_bar` keyword under `root` or `toplevel`
19
+ - Support contextual menu by nesting `menu` keyword under `root` or `toplevel`
20
+
21
+ ## 0.0.48
22
+
23
+ - Moved `OS` class to `Glimmer::Tk::OS` to avoid clashing with os gem when installed for users
24
+ - Moved `DragAndDropEvent` from `Glimmer::Tk::DraggableAndDroppable` into `Glimmer::Tk` namespace directly as `Glimmer::Tk::DragAndDropEvent`
25
+
3
26
  ## 0.0.47
4
27
 
5
28
  - Upgrade to glimmer 2.5.1 (includes more advanced data-binding/observer features)
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 Tk 0.0.47
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 Tk 0.0.51
2
2
  ## MRI Ruby Desktop Development GUI Library
3
3
  [![Gem Version](https://badge.fury.io/rb/glimmer-dsl-tk.svg)](http://badge.fury.io/rb/glimmer-dsl-tk)
4
4
  [![Ruby](https://github.com/AndyObtiva/glimmer-dsl-tk/actions/workflows/ruby.yml/badge.svg)](https://github.com/AndyObtiva/glimmer-dsl-tk/actions/workflows/ruby.yml)
@@ -53,7 +53,7 @@ Glimmer app:
53
53
 
54
54
  NOTE: Glimmer DSL for Tk is currently in early alpha mode (incomplete). Please help make better by contributing, adopting for small or low risk projects, and providing feedback. It is still an early alpha, so the more feedback and issues you report the better.
55
55
 
56
- Other [Glimmer](https://github.com/AndyObtiva/glimmer) DSL gems:
56
+ Other [Glimmer](https://github.com/AndyObtiva/glimmer) DSL gems you might be interested in:
57
57
  - [glimmer-dsl-swt](https://github.com/AndyObtiva/glimmer-dsl-swt): Glimmer DSL for SWT (JRuby Desktop Development GUI Framework)
58
58
  - [glimmer-dsl-opal](https://github.com/AndyObtiva/glimmer-dsl-opal): Glimmer DSL for Opal (Pure Ruby Web GUI and Auto-Webifier of Desktop Apps)
59
59
  - [glimmer-dsl-libui](https://github.com/AndyObtiva/glimmer-dsl-libui): Glimmer DSL for LibUI (Prerequisite-Free Ruby Desktop Development GUI Library)
@@ -86,6 +86,7 @@ Other [Glimmer](https://github.com/AndyObtiva/glimmer) DSL gems:
86
86
  - [Icon Photo](#icon-photo)
87
87
  - [Root Background](#root-background)
88
88
  - [Toplevel Mac Style](#toplevel-mac-style)
89
+ - [Root/Toplevel Centered Within Screen](#root-toplevel-centered-within-screen)
89
90
  - [Text Defaults](#text-defaults)
90
91
  - [The Grid Geometry Manager](#the-grid-geometry-manager)
91
92
  - [Data-Binding](#data-binding)
@@ -125,6 +126,7 @@ Other [Glimmer](https://github.com/AndyObtiva/glimmer) DSL gems:
125
126
  - [Hello, Scrollbar!](#hello-scrollbar)
126
127
  - [Hello, Scrollbar Frame!](#hello-scrollbar-frame)
127
128
  - [Hello, Menu Bar!](#hello-menu-bar)
129
+ - [Hello, Contextual Menu!](#hello-contextual-menu)
128
130
  - [Applications](#applications)
129
131
  - [Glimmer Tk Calculator](#glimmer-tk-calculator)
130
132
  - [Y3network Ruby UI](#y3network-ruby-ui)
@@ -182,7 +184,7 @@ gem install glimmer-dsl-tk
182
184
 
183
185
  Add the following to `Gemfile`:
184
186
  ```
185
- gem 'glimmer-dsl-tk', '0.0.47'
187
+ gem 'glimmer-dsl-tk', '0.0.51'
186
188
  ```
187
189
 
188
190
  And, then run:
@@ -208,6 +210,7 @@ Tk Concepts consist of:
208
210
  - [Widgets](https://tkdocs.com/tutorial/concepts.html#widgets): Widgets are all the things that you see onscreen. In our example, we had a button, an entry, a few labels, and a frame. Others are things like checkboxes, tree views, scrollbars, text areas, and so on. Widgets are what are often referred to as "controls"; you'll also often see them referred to as "windows," particularly in Tk's documentation, a holdover from its X11 roots (so under that terminology, both a toplevel window and things like a button would be called windows).
209
211
  - [Geometry Management](https://tkdocs.com/tutorial/concepts.html#geometry): If you've been playing around creating widgets, you've probably noticed that just by creating them, they didn't end up showing up onscreen. Having things actually put in the onscreen window, and precisely where in the window they show up is a separate step called geometry management.
210
212
  - [Event Handling](https://tkdocs.com/tutorial/concepts.html#events): In Tk, as in most other user interface toolkits, there is an event loop which receives events from the operating system. These are things like button presses, keystrokes, mouse movement, window resizing, and so on.
213
+ - [Themes](https://tkdocs.com/tutorial/styles.html): Tk apps are themable. You can list available themes with `::Tk::Tile::Style.theme_names` (e.g. `["aqua", "clam", "alt", "default", "classic"]` on Mac) and select a theme with `::Tk::Tile::Style.theme_use 'theme_name'` (e.g. `::Tk::Tile::Style.theme_use 'classic'`). Theme defaults to `'clam'` in Linux and `'aqua'` in Mac.
211
214
 
212
215
  Learn more at the official [Tk Concepts Tutorial](https://tkdocs.com/tutorial/concepts.html)
213
216
 
@@ -310,6 +313,7 @@ keyword(args) | attributes | event bindings & callbacks
310
313
  `list` | `selectmode`, `selection` | None
311
314
  `message_box(type: , message: , detail: , title: , icon: , default: , parent: )` | None | None
312
315
  `menu(label: nil) (label is nil if nested under root/toplevel for menu bar)` | None | None
316
+ `menu_bar` | None | None
313
317
  `menu_item(style = :command, label: , underline: )` (style also can be `:radiobutton`, `:checkbutton`, `:separator`, `:about`, `:preferences`, `:quit`, `:help`) | `state`, `accelerator`, `selection` & `variable` (if `:radiobutton` or `:checkbutton`), `image`, `compound` | `command`
314
318
  `notebook` | None | None
315
319
  `radiobutton` | `text`, `variable` (Boolean), `image` (optional keyword args: `subsample`, `zoom`, `from`, `to`, `shrink`, `compositingrule`), `compound` (`'center', 'top', 'bottom', 'left', 'right'`), `value` (default: `text`) | `command {}`
@@ -578,6 +582,10 @@ Tk.tk_call("::tk::unsupported::MacWindowStyle", "style", tk_toplevel_widget, mac
578
582
 
579
583
  More details can be found at the [Hello, Toplevel!](#hello-toplevel) sample.
580
584
 
585
+ #### Root/Toplevel Centered Within Screen
586
+
587
+ `root` and `toplevel` are centered within screen by default unless `x` or `y` attributes are specified, in which case, they are honored instead.
588
+
581
589
  #### Text Defaults
582
590
 
583
591
  `text` widget has these defaults:
@@ -3232,7 +3240,7 @@ root { |r|
3232
3240
  anchor 'center'
3233
3241
  }
3234
3242
 
3235
- menu {
3243
+ menu_bar {
3236
3244
  # Mac-specific application menu (right next to the Apple menu)
3237
3245
  if OS.mac?
3238
3246
  menu(:application) {
@@ -3496,6 +3504,192 @@ Glimmer app:
3496
3504
 
3497
3505
  ![glimmer dsl tk screenshot sample hello menu-bar](images/glimmer-dsl-tk-screenshot-sample-hello-menu-bar-help.png)
3498
3506
 
3507
+ ### Hello, Contextual Menu!
3508
+
3509
+ Glimmer code (from [samples/hello/hello_contextual_menu.rb](samples/hello/hello_contextual_menu.rb)):
3510
+
3511
+ ```ruby
3512
+ require 'glimmer-dsl-tk'
3513
+
3514
+ include Glimmer
3515
+
3516
+ COLORS = [:white, :red, :yellow, :green, :blue, :magenta, :gray, :black]
3517
+
3518
+ Tk::Tile::Style.theme_use 'classic' if OS.mac? # this enables setting background on label just for demo purposes
3519
+
3520
+ root { |r|
3521
+ title 'Hello, Contextual Menu!'
3522
+
3523
+ @label = label {
3524
+ grid row_weight: 1, column_weight: 1
3525
+ text 'Right-Click To Pop Up Contextual Menu!'
3526
+ font size: 50
3527
+ anchor 'center'
3528
+ }
3529
+
3530
+ # Contextual Menu is bound to mouse right-click (and CTRL-click on Mac) by default
3531
+ # (Read Comment Below for Alternative)
3532
+ menu {
3533
+ menu(label: 'Edit', underline: 0) {
3534
+ menu_item(label: 'Cut', underline: 2) {
3535
+ accelerator OS.mac? ? 'Command+X' : 'Control+X'
3536
+ }
3537
+
3538
+ menu_item(label: 'Copy', underline: 0) {
3539
+ accelerator OS.mac? ? 'Command+C' : 'Control+C'
3540
+ }
3541
+
3542
+ menu_item(label: 'Paste', underline: 0) {
3543
+ accelerator OS.mac? ? 'Command+V' : 'Control+V'
3544
+ }
3545
+ }
3546
+
3547
+ menu(label: 'Options', underline: 0) {
3548
+ menu_item(:checkbutton, label: 'Enabled', underline: 0) {
3549
+ on('command') do
3550
+ @select_one_menu.children.each { |menu_item| menu_item.state = menu_item.state == 'disabled' ? 'normal' : 'disabled' }
3551
+ @select_multiple_menu.children.each { |menu_item| menu_item.state = menu_item.state == 'disabled' ? 'normal' : 'disabled' }
3552
+ end
3553
+ }
3554
+
3555
+ @select_one_menu = menu(label: 'Select One', underline: 7) {
3556
+ menu_item(:radiobutton, label: 'Option 1') {
3557
+ state 'disabled'
3558
+ }
3559
+ menu_item(:radiobutton, label: 'Option 2') {
3560
+ state 'disabled'
3561
+ }
3562
+ menu_item(:radiobutton, label: 'Option 3') {
3563
+ state 'disabled'
3564
+ }
3565
+ }
3566
+
3567
+ @select_multiple_menu = menu(label: 'Select Multiple', underline: 7) {
3568
+ menu_item(:checkbutton, label: 'Option 4') {
3569
+ state 'disabled'
3570
+ }
3571
+ menu_item(:checkbutton, label: 'Option 5') {
3572
+ state 'disabled'
3573
+ }
3574
+ menu_item(:checkbutton, label: 'Option 6') {
3575
+ state 'disabled'
3576
+ }
3577
+ }
3578
+ }
3579
+
3580
+ menu(label: 'Language', underline: 3) {
3581
+ ['denmark', 'finland', 'france', 'germany', 'italy', 'mexico', 'netherlands', 'norway', 'usa'].each do |image_name|
3582
+ menu_item(:radiobutton, label: image_name.capitalize) {
3583
+ selection image_name == 'usa'
3584
+ image File.expand_path("images/#{image_name}.png", __dir__)
3585
+ }
3586
+ end
3587
+ }
3588
+
3589
+ menu(label: 'Country', underline: 0) {
3590
+ ['denmark', 'finland', 'france', 'germany', 'italy', 'mexico', 'netherlands', 'norway', 'usa'].each do |image_name|
3591
+ menu_item(:radiobutton, label: image_name.capitalize) {
3592
+ selection image_name == 'usa'
3593
+ image File.expand_path("images/#{image_name}.png", __dir__)
3594
+ compound 'left'
3595
+ }
3596
+ end
3597
+ }
3598
+
3599
+ menu(label: 'Format', underline: 3) {
3600
+ menu(label: 'Background Color', underline: 0) {
3601
+ COLORS.each { |color_style|
3602
+ menu_item(:radiobutton, label: color_style.to_s.split('_').map(&:capitalize).join(' ')) {
3603
+ on('command') do
3604
+ @label.background = color_style
3605
+ end
3606
+ }
3607
+ }
3608
+ }
3609
+
3610
+ menu(label: 'Foreground Color', underline: 11) {
3611
+ COLORS.each { |color_style|
3612
+ menu_item(:radiobutton, label: color_style.to_s.split('_').map(&:capitalize).join(' ')) {
3613
+ on('command') do
3614
+ @label.foreground = color_style
3615
+ end
3616
+ }
3617
+ }
3618
+ }
3619
+ }
3620
+
3621
+ menu(label: 'View', underline: 0) {
3622
+ menu_item(:radiobutton, label: 'Small', underline: 0) {
3623
+ accelerator 'Control+S'
3624
+
3625
+ on('command') do
3626
+ @label.font = {size: 25}
3627
+ end
3628
+ }
3629
+
3630
+ menu_item(:radiobutton, label: 'Medium', underline: 0) {
3631
+ accelerator 'Control+M'
3632
+ selection true
3633
+
3634
+ on('command') do
3635
+ @label.font = {size: 50}
3636
+ end
3637
+ }
3638
+
3639
+ menu_item(:radiobutton, label: 'Large', underline: 0) {
3640
+ accelerator 'Control+L'
3641
+
3642
+ on('command') do
3643
+ @label.font = {size: 75}
3644
+ end
3645
+ }
3646
+ }
3647
+ }
3648
+
3649
+ # You can replace `menu {` code with `menu(bind: false) {` if you want to bind manually,
3650
+ # which can be useful if you want to show menu at a specific location based on conditional logic.
3651
+ #
3652
+ # You can also repurpose a `menu_bar` as a contextual menu by declaring `@menu = menu_bar {` and
3653
+ # binding to mouse right-click.
3654
+ #
3655
+ # Example:
3656
+ #
3657
+ # @menu = menu(bind: false) {
3658
+ # menu(label: 'File', underline: 0) {
3659
+ # menu_item(label: 'Exit')
3660
+ # }
3661
+ # }
3662
+ # if OS.mac?
3663
+ # on('2') do |event|
3664
+ # @menu.popup(event.x_root, event.y_root)
3665
+ # end
3666
+ # on('Control-1') do |event|
3667
+ # @menu.popup(event.x_root, event.y_root)
3668
+ # end
3669
+ # else
3670
+ # on('3') do |event|
3671
+ # @menu.popup(event.x_root, event.y_root)
3672
+ # end
3673
+ # end
3674
+ }.open
3675
+ ```
3676
+
3677
+ Run with [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed:
3678
+
3679
+ ```
3680
+ ruby -r glimmer-dsl-tk -e "require 'samples/hello/hello_contextual_menu'"
3681
+ ```
3682
+
3683
+ Alternatively, run from cloned project without [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed:
3684
+
3685
+ ```
3686
+ ruby -r ./lib/glimmer-dsl-tk.rb samples/hello/hello_contextual_menu.rb
3687
+ ```
3688
+
3689
+ Glimmer app:
3690
+
3691
+ ![glimmer dsl tk screenshot sample hello contextual-menu](images/glimmer-dsl-tk-screenshot-sample-hello-contextual-menu.png)
3692
+
3499
3693
  ## Applications
3500
3694
 
3501
3695
  ### Glimmer Tk Calculator
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.47
1
+ 0.0.51
Binary file
@@ -0,0 +1,23 @@
1
+ module Glimmer
2
+ module Tk
3
+ DragAndDropEvent = Struct.new(:source, :target, :tooltip, :x_root, :y_root, :data, :drop_accepted) do
4
+ alias drop_accepted? drop_accepted
5
+
6
+ def as_json(*)
7
+ klass = self.class.name
8
+ {
9
+ JSON.create_id => klass,
10
+ "v" => [values[0].object_id, values[1].object_id, values[2].object_id].concat(values.drop 3),
11
+ }
12
+ end
13
+
14
+ def to_json(*args)
15
+ as_json.to_json(*args)
16
+ end
17
+
18
+ def self.json_create(object)
19
+ new(*[ObjectSpace._id2ref(object["v"][0]), ObjectSpace._id2ref(object["v"][1]).proxy, ObjectSpace._id2ref(object["v"][2])].concat(object["v"].drop 3))
20
+ end
21
+ end
22
+ end
23
+ end
@@ -19,6 +19,7 @@
19
19
  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
+ require_relative 'drag_and_drop_event'
22
23
  require "json"
23
24
 
24
25
  module Glimmer
@@ -65,11 +66,11 @@ module Glimmer
65
66
  def on_drop_block=(value)
66
67
  @on_drop_block = value
67
68
  self.tk.bind("<DropEvent>", proc { |tk_event|
68
- drop_event = DragAndDropEvent.json_create(JSON.parse("{" + tk_event.detail + "}"))
69
+ drop_event = Glimmer::Tk::DragAndDropEvent.json_create(JSON.parse("{" + tk_event.detail + "}"))
69
70
  @on_drop_block.call(drop_event) if self == drop_event.target
70
71
  })
71
72
  self.tk.bind("<DropCheckEvent>", proc { |tk_event|
72
- drop_check_event = DragAndDropEvent.json_create(JSON.parse("{" + tk_event.detail + "}"))
73
+ drop_check_event = Glimmer::Tk::DragAndDropEvent.json_create(JSON.parse("{" + tk_event.detail + "}"))
73
74
  drop_check_event.source.event_generate("<DropAcceptedEvent>")
74
75
  })
75
76
  end
@@ -86,7 +87,7 @@ module Glimmer
86
87
  tooltip = WidgetProxy.new('toplevel', root_parent_proxy, [])
87
88
  tooltip.overrideredirect(1) #create tooltip window to display dragged data
88
89
  tooltip.geometry("+#{tk_event.x_root + 10}+#{tk_event.y_root - 2}")
89
- drag_event = DragAndDropEvent.new(self, nil, tooltip, tk_event.x_root, tk_event.y_root, nil, false)
90
+ drag_event = Glimmer::Tk::DragAndDropEvent.new(self, nil, tooltip, tk_event.x_root, tk_event.y_root, nil, false)
90
91
  if @drag_source
91
92
  tk_event.widget.configure(:cursor => "hand2")
92
93
  # Default data to drag is text
@@ -159,26 +160,6 @@ module Glimmer
159
160
  @tk.bind_remove('<DropCheckEvent>')
160
161
  @on_drop_block = nil
161
162
  end
162
-
163
- DragAndDropEvent = Struct.new(:source, :target, :tooltip, :x_root, :y_root, :data, :drop_accepted) do
164
- alias drop_accepted? drop_accepted
165
-
166
- def as_json(*)
167
- klass = self.class.name
168
- {
169
- JSON.create_id => klass,
170
- "v" => [values[0].object_id, values[1].object_id, values[2].object_id].concat(values.drop 3),
171
- }
172
- end
173
-
174
- def to_json(*args)
175
- as_json.to_json(*args)
176
- end
177
-
178
- def self.json_create(object)
179
- new(*[ObjectSpace._id2ref(object["v"][0]), ObjectSpace._id2ref(object["v"][1]).proxy, ObjectSpace._id2ref(object["v"][2])].concat(object["v"].drop 3))
180
- end
181
- end
182
163
  end
183
164
  end
184
165
  end
@@ -36,10 +36,13 @@ module Glimmer
36
36
  'Control' => 'Control',
37
37
  }
38
38
 
39
+ ATTRIBUTES = %w[activebackground activeforeground background bitmap columnbreak compound font foreground hidemargin indicatoron menu offvalue onvalue selectcolor selectimage state underline value]
40
+
39
41
  attr_reader :options
40
42
 
41
43
  def initialize(underscored_widget_name, parent_proxy, args, &block)
42
44
  @options = args.last.is_a?(Hash) ? args.last : {}
45
+ @label = @options[:label]
43
46
  super
44
47
  end
45
48
 
@@ -62,17 +65,14 @@ module Glimmer
62
65
  end.join('-')
63
66
  end
64
67
 
65
- def state=(value)
66
- @state = value
67
- configure_menu_item_attribute(state: value)
68
- end
69
-
70
- def state
71
- @state
68
+ def label=(value)
69
+ @last_label = @label
70
+ @label = value
71
+ configure_menu_item_attribute(label: @label)
72
72
  end
73
73
 
74
74
  def label
75
- @options[:label]
75
+ @label
76
76
  end
77
77
 
78
78
  def image=(*args)
@@ -151,9 +151,9 @@ module Glimmer
151
151
 
152
152
  def selection=(value)
153
153
  if value
154
- variable.value = label
154
+ self.value = variable.value = label
155
155
  elsif checkbutton?
156
- variable.value = ''
156
+ self.value = variable.value = ''
157
157
  end
158
158
  end
159
159
 
@@ -170,7 +170,34 @@ module Glimmer
170
170
  elsif quit? && attribute_value_hash[:command]
171
171
  ::Tk.ip_eval("proc ::tk::mac::Quit {} {#{::Tk.install_cmd(attribute_value_hash[:command])}}") if OS.mac?
172
172
  else
173
- @parent_proxy.tk.entryconfigure label, attribute_value_hash
173
+ if attribute_value_hash.keys.first.to_s == 'label'
174
+ @parent_proxy.tk.entryconfigure @last_label, attribute_value_hash
175
+ self.value = variable.value = attribute_value_hash.values.first if variable.value == @last_label
176
+ else
177
+ @parent_proxy.tk.entryconfigure label, attribute_value_hash
178
+ end
179
+ end
180
+ end
181
+
182
+ def has_attributes_attribute?(attribute)
183
+ attribute = attribute.to_s
184
+ attribute = attribute.sub(/\?$/, '').sub(/=$/, '')
185
+ ATTRIBUTES.include?(attribute)
186
+ end
187
+
188
+ def set_attribute(attribute, value)
189
+ if has_attributes_attribute?(attribute)
190
+ configure_menu_item_attribute(attribute => value)
191
+ else
192
+ super
193
+ end
194
+ end
195
+
196
+ def get_attribute(attribute)
197
+ if has_attributes_attribute?(attribute)
198
+ @parent_proxy.tk.entrycget label, attribute
199
+ else
200
+ super
174
201
  end
175
202
  end
176
203
 
@@ -34,7 +34,22 @@ module Glimmer
34
34
  def post_add_content
35
35
  case @parent_proxy
36
36
  when ToplevelProxy
37
- @parent_proxy.tk['menu'] = @tk
37
+ if @keyword == 'menu_bar'
38
+ @parent_proxy.tk['menu'] = @tk
39
+ elsif @options[:bind].nil? || @options[:bind]
40
+ if OS.mac?
41
+ @parent_proxy.handle_listener('2') do |event|
42
+ popup(event.x_root, event.y_root)
43
+ end
44
+ @parent_proxy.handle_listener('Control-1') do |event|
45
+ popup(event.x_root, event.y_root)
46
+ end
47
+ else
48
+ @parent_proxy.handle_listener('3') do |event|
49
+ popup(event.x_root, event.y_root)
50
+ end
51
+ end
52
+ end
38
53
  end
39
54
  end
40
55
 
@@ -75,8 +90,7 @@ module Glimmer
75
90
  # elsif @parent_proxy.parent_proxy.is_a?(ToplevelProxy) && OS.windows? && system?
76
91
  # @tk = ::TkSysMenu_System.new(@parent_proxy.tk).tap {|tk| tk.singleton_class.include(Glimmer::Tk::Widget); tk.proxy = self}
77
92
  else
78
- tk_widget_class = self.class.tk_widget_class_for(@keyword)
79
- @tk = tk_widget_class.new(@parent_proxy.tk).tap {|tk| tk.singleton_class.include(Glimmer::Tk::Widget); tk.proxy = self}
93
+ @tk = ::Tk::Menu.new(@parent_proxy.tk).tap {|tk| tk.singleton_class.include(Glimmer::Tk::Widget); tk.proxy = self}
80
94
  end
81
95
  case @parent_proxy
82
96
  when MenuProxy
@@ -85,5 +99,6 @@ module Glimmer
85
99
  end
86
100
  end
87
101
  end
102
+ MenuBarProxy = MenuProxy
88
103
  end
89
104
  end
@@ -19,18 +19,30 @@
19
19
  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
- class OS
23
- class << self
24
- def mac?
25
- Tk.windowingsystem == 'aqua'
26
- end
27
-
28
- def windows?
29
- Tk.windowingsystem == 'win32'
30
- end
31
-
32
- def linux?
33
- Tk.windowingsystem == 'x11'
22
+ require 'tk'
23
+
24
+ module Glimmer
25
+ module Tk
26
+ class OS
27
+ class << self
28
+ def mac?
29
+ ::Tk.windowingsystem == 'aqua'
30
+ end
31
+
32
+ def windows?
33
+ ::Tk.windowingsystem == 'win32'
34
+ end
35
+
36
+ def linux?
37
+ ::Tk.windowingsystem == 'x11'
38
+ end
39
+ end
34
40
  end
35
41
  end
36
42
  end
43
+
44
+ begin
45
+ OS
46
+ rescue
47
+ ::OS = Glimmer::Tk::OS
48
+ end
@@ -36,6 +36,7 @@ module Glimmer
36
36
  alias escapable? escapable
37
37
 
38
38
  def post_add_content
39
+ center_within_screen unless @x || @y
39
40
  if escapable?
40
41
  on('KeyPress') do |event|
41
42
  if event.keysym == 'Escape'
@@ -93,10 +94,12 @@ module Glimmer
93
94
  end
94
95
 
95
96
  def x=(value)
97
+ @x = value
96
98
  self.geometry = "#{@width || DEFAULT_WIDTH}x#{@height || DEFAULT_HEIGHT}#{value.to_i > 0 ? '+' : '-'}#{value.to_i.abs}#{y_sign}#{abs_y}"
97
99
  end
98
100
 
99
101
  def y=(value)
102
+ @y = value
100
103
  self.geometry = "#{@width || DEFAULT_WIDTH}x#{@height || DEFAULT_HEIGHT}#{x_sign}#{abs_x}#{value.to_i > 0 ? '+' : '-'}#{value.to_i.abs}"
101
104
  end
102
105
 
@@ -110,6 +113,17 @@ module Glimmer
110
113
  end
111
114
  end
112
115
 
116
+ def center_within_screen
117
+ monitor_width, monitor_height = wm_maxsize
118
+ update :idletasks
119
+ current_width = width
120
+ current_height = height
121
+ self.x = (winfo_screenwidth - width) / 2
122
+ self.y = (winfo_screenheight - height) / 2
123
+ self.width = width
124
+ self.height = height
125
+ end
126
+
113
127
  private
114
128
 
115
129
  def sign_number(sign, number)
@@ -29,7 +29,6 @@ require 'puts_debuggerer' if ENV['pd'].to_s.downcase == 'true'
29
29
  require 'tk'
30
30
  #require 'tkextlib/bwidget' # does not work on Windows
31
31
  #require 'tkextlib/iwidgets' # does not work on Windows
32
- require 'os'
33
32
  require 'facets/hash/symbolize_keys'
34
33
  require 'facets/string/underscore'
35
34
  require 'facets/string/camelcase'
@@ -38,6 +37,7 @@ require 'delegate'
38
37
  # Internal requires
39
38
  # require 'ext/glimmer/config'
40
39
  # require 'ext/glimmer'
40
+ require 'glimmer/tk/os'
41
41
  require 'glimmer/dsl/tk/dsl'
42
42
 
43
43
  Glimmer::Config.loop_max_count = -1
@@ -48,11 +48,11 @@ Glimmer::Config.excluded_keyword_checkers << lambda do |method_symbol, *args|
48
48
  result ||= method == 'load_iseq'
49
49
  end
50
50
 
51
- Tk::Tile::Style.theme_use 'clam' if OS.linux?
51
+ ::Tk::Tile::Style.theme_use 'clam' if OS.linux?
52
52
 
53
53
  ::TkOption.add '*tearOff', 0
54
54
 
55
- class ::Tk::TkSysMenu_Window < Tk::Menu
56
- include Tk::SystemMenu
55
+ class ::Tk::TkSysMenu_Window < ::Tk::Menu
56
+ include ::Tk::SystemMenu
57
57
  SYSMENU_NAME = 'window'
58
58
  end
@@ -0,0 +1,192 @@
1
+ # Copyright (c) 2020-2021 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require 'glimmer-dsl-tk'
23
+
24
+ include Glimmer
25
+
26
+ COLORS = [:white, :red, :yellow, :green, :blue, :magenta, :gray, :black]
27
+
28
+ Tk::Tile::Style.theme_use 'classic' if OS.mac? # this enables setting background on label just for demo purposes
29
+
30
+ root { |r|
31
+ title 'Hello, Contextual Menu!'
32
+
33
+ @label = label {
34
+ grid row_weight: 1, column_weight: 1
35
+ text 'Right-Click To Pop Up Contextual Menu!'
36
+ font size: 50
37
+ anchor 'center'
38
+ }
39
+
40
+ # Contextual Menu is bound to mouse right-click (and CTRL-click on Mac) by default
41
+ # (Read Comment Below for Alternative)
42
+ menu {
43
+ menu(label: 'Edit', underline: 0) {
44
+ menu_item(label: 'Cut', underline: 2) {
45
+ accelerator OS.mac? ? 'Command+X' : 'Control+X'
46
+ }
47
+
48
+ menu_item(label: 'Copy', underline: 0) {
49
+ accelerator OS.mac? ? 'Command+C' : 'Control+C'
50
+ }
51
+
52
+ menu_item(label: 'Paste', underline: 0) {
53
+ accelerator OS.mac? ? 'Command+V' : 'Control+V'
54
+ }
55
+ }
56
+
57
+ menu(label: 'Options', underline: 0) {
58
+ menu_item(:checkbutton, label: 'Enabled', underline: 0) {
59
+ on('command') do
60
+ @select_one_menu.children.each { |menu_item| menu_item.state = menu_item.state == 'disabled' ? 'normal' : 'disabled' }
61
+ @select_multiple_menu.children.each { |menu_item| menu_item.state = menu_item.state == 'disabled' ? 'normal' : 'disabled' }
62
+ end
63
+ }
64
+
65
+ @select_one_menu = menu(label: 'Select One', underline: 7) {
66
+ menu_item(:radiobutton, label: 'Option 1') {
67
+ state 'disabled'
68
+ }
69
+ menu_item(:radiobutton, label: 'Option 2') {
70
+ state 'disabled'
71
+ }
72
+ menu_item(:radiobutton, label: 'Option 3') {
73
+ state 'disabled'
74
+ }
75
+ }
76
+
77
+ @select_multiple_menu = menu(label: 'Select Multiple', underline: 7) {
78
+ menu_item(:checkbutton, label: 'Option 4') {
79
+ state 'disabled'
80
+ }
81
+ menu_item(:checkbutton, label: 'Option 5') {
82
+ state 'disabled'
83
+ }
84
+ menu_item(:checkbutton, label: 'Option 6') {
85
+ state 'disabled'
86
+ }
87
+ }
88
+ }
89
+
90
+ menu(label: 'Language', underline: 3) {
91
+ ['denmark', 'finland', 'france', 'germany', 'italy', 'mexico', 'netherlands', 'norway', 'usa'].each do |image_name|
92
+ menu_item(:radiobutton, label: image_name.capitalize) {
93
+ selection image_name == 'usa'
94
+ image File.expand_path("images/#{image_name}.png", __dir__)
95
+
96
+ on('command') do
97
+ message_box(parent: r, title: 'Language Selection', message: "You selected the language of #{image_name.capitalize}!")
98
+ end
99
+ }
100
+ end
101
+ }
102
+
103
+ menu(label: 'Country', underline: 0) {
104
+ ['denmark', 'finland', 'france', 'germany', 'italy', 'mexico', 'netherlands', 'norway', 'usa'].each do |image_name|
105
+ menu_item(:radiobutton, label: image_name.capitalize) {
106
+ selection image_name == 'usa'
107
+ image File.expand_path("images/#{image_name}.png", __dir__)
108
+ compound 'left'
109
+
110
+ on('command') do
111
+ message_box(parent: r, title: 'Country Selection', message: "You selected the country of #{image_name.capitalize}!")
112
+ end
113
+ }
114
+ end
115
+ }
116
+
117
+ menu(label: 'Format', underline: 3) {
118
+ menu(label: 'Background Color', underline: 0) {
119
+ COLORS.each { |color_style|
120
+ menu_item(:radiobutton, label: color_style.to_s.split('_').map(&:capitalize).join(' ')) {
121
+ on('command') do
122
+ @label.background = color_style
123
+ end
124
+ }
125
+ }
126
+ }
127
+
128
+ menu(label: 'Foreground Color', underline: 11) {
129
+ COLORS.each { |color_style|
130
+ menu_item(:radiobutton, label: color_style.to_s.split('_').map(&:capitalize).join(' ')) {
131
+ on('command') do
132
+ @label.foreground = color_style
133
+ end
134
+ }
135
+ }
136
+ }
137
+ }
138
+
139
+ menu(label: 'View', underline: 0) {
140
+ menu_item(:radiobutton, label: 'Small', underline: 0) {
141
+ accelerator 'Control+S'
142
+
143
+ on('command') do
144
+ @label.font = {size: 25}
145
+ end
146
+ }
147
+
148
+ menu_item(:radiobutton, label: 'Medium', underline: 0) {
149
+ accelerator 'Control+M'
150
+ selection true
151
+
152
+ on('command') do
153
+ @label.font = {size: 50}
154
+ end
155
+ }
156
+
157
+ menu_item(:radiobutton, label: 'Large', underline: 0) {
158
+ accelerator 'Control+L'
159
+
160
+ on('command') do
161
+ @label.font = {size: 75}
162
+ end
163
+ }
164
+ }
165
+ }
166
+
167
+ # You can replace `menu {` code with `menu(bind: false) {` if you want to bind manually,
168
+ # which can be useful if you want to show menu at a specific location based on conditional logic.
169
+ #
170
+ # You can also repurpose a `menu_bar` as a contextual menu by declaring `@menu = menu_bar {` and
171
+ # binding to mouse right-click.
172
+ #
173
+ # Example:
174
+ #
175
+ # @menu = menu(bind: false) {
176
+ # menu(label: 'File', underline: 0) {
177
+ # menu_item(label: 'Exit')
178
+ # }
179
+ # }
180
+ # if OS.mac?
181
+ # on('2') do |event|
182
+ # @menu.popup(event.x_root, event.y_root)
183
+ # end
184
+ # on('Control-1') do |event|
185
+ # @menu.popup(event.x_root, event.y_root)
186
+ # end
187
+ # else
188
+ # on('3') do |event|
189
+ # @menu.popup(event.x_root, event.y_root)
190
+ # end
191
+ # end
192
+ }.open
@@ -37,7 +37,7 @@ root { |r|
37
37
  anchor 'center'
38
38
  }
39
39
 
40
- menu {
40
+ menu_bar {
41
41
  # Mac-specific application menu (right next to the Apple menu)
42
42
  if OS.mac?
43
43
  menu(:application) {
@@ -157,6 +157,10 @@ root { |r|
157
157
  menu_item(:radiobutton, label: image_name.capitalize) {
158
158
  selection image_name == 'usa'
159
159
  image File.expand_path("images/#{image_name}.png", __dir__)
160
+
161
+ on('command') do
162
+ message_box(parent: r, title: 'Language Selection', message: "You selected the language of #{image_name.capitalize}!")
163
+ end
160
164
  }
161
165
  end
162
166
  }
@@ -167,6 +171,10 @@ root { |r|
167
171
  selection image_name == 'usa'
168
172
  image File.expand_path("images/#{image_name}.png", __dir__)
169
173
  compound 'left'
174
+
175
+ on('command') do
176
+ message_box(parent: r, title: 'Country Selection', message: "You selected the country of #{image_name.capitalize}!")
177
+ end
170
178
  }
171
179
  end
172
180
  }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: glimmer-dsl-tk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.47
4
+ version: 0.0.51
5
5
  platform: ruby
6
6
  authors:
7
7
  - AndyMaleh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-11-22 00:00:00.000000000 Z
11
+ date: 2021-12-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: glimmer
@@ -208,6 +208,7 @@ files:
208
208
  - lib/glimmer/dsl/tk/widget_expression.rb
209
209
  - lib/glimmer/tk/checkbutton_proxy.rb
210
210
  - lib/glimmer/tk/combobox_proxy.rb
211
+ - lib/glimmer/tk/drag_and_drop_event.rb
211
212
  - lib/glimmer/tk/draggable_and_droppable.rb
212
213
  - lib/glimmer/tk/entry_proxy.rb
213
214
  - lib/glimmer/tk/frame_proxy.rb
@@ -217,6 +218,7 @@ files:
217
218
  - lib/glimmer/tk/menu_item_proxy.rb
218
219
  - lib/glimmer/tk/menu_proxy.rb
219
220
  - lib/glimmer/tk/notebook_proxy.rb
221
+ - lib/glimmer/tk/os.rb
220
222
  - lib/glimmer/tk/radiobutton_proxy.rb
221
223
  - lib/glimmer/tk/root_proxy.rb
222
224
  - lib/glimmer/tk/scrollbar_frame_proxy.rb
@@ -228,7 +230,6 @@ files:
228
230
  - lib/glimmer/tk/variable_owner.rb
229
231
  - lib/glimmer/tk/widget.rb
230
232
  - lib/glimmer/tk/widget_proxy.rb
231
- - lib/os.rb
232
233
  - samples/elaborate/meta_sample.rb
233
234
  - samples/hello/hello_built_in_dialog.rb
234
235
  - samples/hello/hello_button.rb
@@ -236,6 +237,7 @@ files:
236
237
  - samples/hello/hello_combobox.rb
237
238
  - samples/hello/hello_computed.rb
238
239
  - samples/hello/hello_computed/contact.rb
240
+ - samples/hello/hello_contextual_menu.rb
239
241
  - samples/hello/hello_drag_and_drop.rb
240
242
  - samples/hello/hello_entry.rb
241
243
  - samples/hello/hello_frame.rb