glimmer-dsl-tk 0.0.37 → 0.0.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2454b5a3d7bd7159328cab0c0c82a4ebcdb54066bec28a1549e3cbca61d1bd8d
4
- data.tar.gz: 7535984b2838617c7a40ee336c653e6c5c9029c7e49b3a4a13f1815897ecec8d
3
+ metadata.gz: 5c6969620ced6ade48e45e36bd48909bfe282a412e2f57d8a201f398082c6836
4
+ data.tar.gz: d8d4bc858b5fdf7399b10d71922a2e12aaf1cbf0b4c8c0db4bf78416e025a5d0
5
5
  SHA512:
6
- metadata.gz: d377872669979a76bf149aec8683ade86fadd7efa50817abe4f8e582a0f3b53ac354759f3e7e6aa4e683fcd6296308eb7339c049718fcd7c673e4452f1052614
7
- data.tar.gz: b321a3e34b16f9a1719797c51f25521a48c4c12ba39f92a730618dedc54f564754f24e73f60118023213583e3629c188643684cc7d326628613c982c0a87e7d0
6
+ metadata.gz: 35a7d92e7f5b9098a9dcd50a5045447237bd66b89dfdd9f5ea10d45201b050a66b7b272266f275645552980a043cda9b59b6b96f591521a7da326fce4ff60524
7
+ data.tar.gz: c866f8e9a51d4dd291900ebb0c3b506f5a8d0975d1df779474ebf0997114d4384f5a9d2610e868a3196c1ba1b93cfeb98311d41f4e2b35b1582c64cee2b9dc71
data/CHANGELOG.md CHANGED
@@ -1,7 +1,18 @@
1
1
  # Change Log
2
2
 
3
+ ## 0.0.38
4
+
5
+ - Hello, Menu Bar! sample
6
+ - Support `menu` and `menu_item` widgets including `:command` (default), `:separator`, `:radiobutton`, and `:checkbutton` styles
7
+ - Support menu item `accelerator` attribute
8
+ - Support menu item `selection` attribute
9
+ - Support menu item `state` attribute
10
+ - Support menu item command event, which is triggered on mouse/keyboard menu item selection or via accelerator
11
+ - Support `toplevel` `iconphoto` (more conveniently via direct path) and `resizable` attributes
12
+
3
13
  ## 0.0.37
4
14
 
15
+ - Support `focus: true` or `focus: [integer]` option for all selection formatting methods (`add_selection_format`, `remove_selection_format`, `toggle_selection_format`, `add_selection_font_format`, `remove_selection_font_format`, `toggle_selection_font_format`)
5
16
  - Have `text` widget grab focus after every formatting modification in Hello, Text! (e.g. after clicking `B` for Bold)
6
17
 
7
18
  ## 0.0.36
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.37
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.38
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)
@@ -57,7 +57,7 @@ Other [Glimmer](https://github.com/AndyObtiva/glimmer) DSL gems:
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)
60
- - [glimmer-dsl-gtk](https://github.com/AndyObtiva/glimmer-dsl-gtk): Ruby-GNOME Desktop Development GUI Library
60
+ - [glimmer-dsl-gtk](https://github.com/AndyObtiva/glimmer-dsl-gtk): Glimmer DSL for GTK (Ruby-GNOME Desktop Development GUI Library)
61
61
  - [glimmer-dsl-xml](https://github.com/AndyObtiva/glimmer-dsl-xml): Glimmer DSL for XML (& HTML)
62
62
  - [glimmer-dsl-css](https://github.com/AndyObtiva/glimmer-dsl-css): Glimmer DSL for CSS (Cascading Style Sheets)
63
63
 
@@ -82,6 +82,7 @@ Other [Glimmer](https://github.com/AndyObtiva/glimmer) DSL gems:
82
82
  - [Image Attribute](#image-attribute)
83
83
  - [Frame Padding](#frame-padding)
84
84
  - [Notebook Frame](#notebook-frame)
85
+ - [Menu Item Accelerator](#menu-item-accelerator)
85
86
  - [Icon Photo](#icon-photo)
86
87
  - [Root Background](#root-background)
87
88
  - [Toplevel Mac Style](#toplevel-mac-style)
@@ -120,10 +121,12 @@ Other [Glimmer](https://github.com/AndyObtiva/glimmer) DSL gems:
120
121
  - [Hello, Drag and Drop!](#hello-drag-and-drop)
121
122
  - [Hello, Built-in Dialog!](#hello-built-in-dialog)
122
123
  - [Hello, Separator!](#hello-separator)
124
+ - [Hello, Menu Bar!](#hello-menu-bar)
123
125
  - [Applications](#applications)
124
126
  - [Glimmer Tk Calculator](#glimmer-tk-calculator)
125
127
  - [Y3network Ruby UI](#y3network-ruby-ui)
126
128
  - [CryptoPunks GUI](#cryptopunks-gui)
129
+ - [Circule](#circule)
127
130
  - [Process](#process)
128
131
  - [Resources](#resources)
129
132
  - [Help](#help)
@@ -146,6 +149,13 @@ For example, on the Mac, you can:
146
149
  - Run: `rvm install 3.0.2 --enable-shared --enable-pthread --with-tk --with-tcl`
147
150
  - Run: `gem install tk -v0.4.0`
148
151
 
152
+ For example, on Windows, you can follow the [instructions over here](https://tkdocs.com/tutorial/install.html), specifically the following:
153
+ - Install Ruby+Devkit (including MSYS/MINGW toolchains) through Windows Installer: https://rubyinstaller.org/downloads/
154
+ - Install the ActiveTcl Windows package from [ActiveState.com](https://activestate.com)
155
+ - Follow this instruction: "First, Ruby needs to find the tcl86t.dll and tk86t.dll shared libraries. These are located in C:\ActiveTcl\bin. Make a copy of them somewhere Ruby can find them, e.g. C:\Ruby26\bin."
156
+ - Setup environment variables TCL_LIBRARY=C:\ActiveTcl\lib\tcl8.6 & TK_LIBRARY=C:\ActiveTcl\lib\tk8.6
157
+ - Run: `gem install tk -v0.4.0`
158
+
149
159
  Afterwards, if you open `irb`, you should be able to run `require 'tk'` successfully.
150
160
 
151
161
  ## Setup
@@ -161,7 +171,7 @@ gem install glimmer-dsl-tk
161
171
 
162
172
  Add the following to `Gemfile`:
163
173
  ```
164
- gem 'glimmer-dsl-tk', '~> 0.0.37'
174
+ gem 'glimmer-dsl-tk', '~> 0.0.38'
165
175
  ```
166
176
 
167
177
  And, then run:
@@ -285,10 +295,13 @@ keyword(args) | attributes | event bindings & callbacks
285
295
  `label` | `text`, `image` (optional keyword args: `subsample`, `zoom`, `from`, `to`, `shrink`, `compositingrule`), `compound` (`'center', 'top', 'bottom', 'left', 'right'`), `font` (`'default', 'text', 'fixed', 'menu', 'heading', 'caption', 'small_caption', 'icon', 'tooltip'`), `relief` (`'flat' (default), 'raised', 'sunken', 'solid', 'ridge', 'groove'`), `justify` (`'left', 'center', 'right'`), `foreground`, `background` | None
286
296
  `list` | `selectmode`, `selection` | None
287
297
  `message_box(type: , message: , detail: , title: , icon: , default: , parent: )` | None | None
298
+ `menu(label: nil) (label is nil if nested under root/toplevel for menu bar)` | None | None
299
+ `menu_item(style = :command, label: , underline: )` (style also can be `:radiobutton`, `:checkbutton`, or `:separator`) | `state`, `accelerator`, `selection` & `variable` (if `:radiobutton` or `:checkbutton`) | `command`
288
300
  `notebook` | None | None
289
301
  `radiobutton` | `text`, `variable` (Boolean), `image` (optional keyword args: `subsample`, `zoom`, `from`, `to`, `shrink`, `compositingrule`), `compound` (`'center', 'top', 'bottom', 'left', 'right'`), `value` (default: `text`) | `command {}`
290
- `root` | `title`, `iconphoto`, `background`, `alpha`, `fullscreen?`, `topmost?`, `transparent?`, `stackorder`, `winfo_screendepth`, `winfo_screenvisual`, `winfo_screenwidth`, `winfo_screenheight`, `winfo_pixels('li')`, `winfo_screen`, `wm_maxsize`, `state` (`'normal', 'iconic', 'withdrawn', 'icon', 'zoomed'`) | `'DELETE_WINDOW'`, `'OPEN_WINDOW'`
302
+ `root` | `title`, `iconphoto`, `background`, `alpha`, `escapable`, `fullscreen?`, `topmost?`, `transparent?`, `stackorder`, `winfo_screendepth`, `winfo_screenvisual`, `winfo_screenwidth`, `winfo_screenheight`, `winfo_pixels('li')`, `winfo_screen`, `wm_maxsize`, `state` (`'normal', 'iconic', 'withdrawn', 'icon', 'zoomed'`) | `'DELETE_WINDOW'`, `'OPEN_WINDOW'`
291
303
  `separator` | `orient` (`'horizontal' (default) or 'vertical'`) | None
304
+ `toplevel` | `title`, `iconphoto`, `background`, `alpha`, `escapable`, `fullscreen?`, `topmost?`, `transparent?`, `stackorder`, `winfo_screendepth`, `winfo_screenvisual`, `winfo_screenwidth`, `winfo_screenheight`, `winfo_pixels('li')`, `winfo_screen`, `wm_maxsize`, `state` (`'normal', 'iconic', 'withdrawn', 'icon', 'zoomed'`) | `'DELETE_WINDOW'`
292
305
  `text` | `value`, [many more attributes](https://tcl.tk/man/tcl8.6/TkCmd/text.htm#M116) | `'modified'`, `'selection'`, `'insert_mark_moved'` (alias: `'insert_mark_move', 'InsertMarkMove', 'InsertMarkMoved'`)
293
306
 
294
307
  Options for `get_open_file` and `get_multiple_open_file` include:
@@ -456,6 +469,10 @@ Frames have a padding of `15` all around by default to produce more user-friendl
456
469
 
457
470
  When nesting `frame` under `notebook`, you can pass a `:text` keyword argument to indicate the tab title.
458
471
 
472
+ #### Menu Item Accelerator
473
+
474
+ `menu_item` `accelerator` is automatically bound to the `command` set inside `menu_item` content (no need to do manual binding as per [Tk docs](https://tkdocs.com/tutorial/menus.html)).
475
+
459
476
  #### Icon Photo
460
477
 
461
478
  The `iconphoto` attribute on `root` is set to the Glimmer icon by default if no icon photo is supplied.
@@ -2920,6 +2937,203 @@ Glimmer app:
2920
2937
 
2921
2938
  ![glimmer dsl tk screenshot sample hello separator](images/glimmer-dsl-tk-screenshot-sample-hello-separator.png)
2922
2939
 
2940
+ ### Hello, Menu Bar!
2941
+
2942
+ Glimmer code (from [samples/hello/hello_menu_bar.rb](samples/hello/hello_menu_bar.rb)):
2943
+
2944
+ ```ruby
2945
+ require 'glimmer-dsl-tk'
2946
+
2947
+ include Glimmer
2948
+
2949
+ COLORS = [:white, :red, :yellow, :green, :blue, :magenta, :gray, :black]
2950
+
2951
+ Tk::Tile::Style.theme_use "classic" # this enables setting background on label just for demo purposes
2952
+
2953
+ root { |r|
2954
+ title 'Hello, Menu Bar!'
2955
+
2956
+ @label = label {
2957
+ grid row_weight: 1, column_weight: 1
2958
+ text 'Check Out The Menu Bar Above!'
2959
+ font size: 50
2960
+ anchor 'center'
2961
+ }
2962
+
2963
+ menu {
2964
+ menu(label: 'File', underline: 0) {
2965
+ menu_item(label: 'New', underline: 0) {
2966
+ accelerator 'Command+N'
2967
+
2968
+ on('command') do
2969
+ message_box(parent: r, title: 'New', message: 'New file created.')
2970
+ end
2971
+ }
2972
+ menu_item(label: 'Open...', underline: 0) {
2973
+ accelerator 'Command+O'
2974
+
2975
+ on('command') do
2976
+ message_box(parent: r, title: 'Open', message: 'Opening File...')
2977
+ end
2978
+ }
2979
+ menu(label: 'Open Recent', underline: 5) {
2980
+ menu_item(label: 'File 1') {
2981
+ on('command') do
2982
+ message_box(parent: r, title: 'File 1', message: 'File 1 Contents')
2983
+ end
2984
+ }
2985
+ menu_item(label: 'File 2') {
2986
+ on('command') do
2987
+ message_box(parent: r, title: 'File 2', message: 'File 2 Contents')
2988
+ end
2989
+ }
2990
+ }
2991
+ menu_item(:separator)
2992
+ menu_item(label: 'Exit', underline: 1) {
2993
+ on('command') do
2994
+ exit(0)
2995
+ end
2996
+ }
2997
+ }
2998
+ menu(label: 'Edit', underline: 0) {
2999
+ menu_item(label: 'Cut', underline: 2) {
3000
+ accelerator 'Command+X'
3001
+ }
3002
+ menu_item(label: 'Copy', underline: 0) {
3003
+ accelerator 'Command+C'
3004
+ }
3005
+ menu_item(label: 'Paste', underline: 0) {
3006
+ accelerator 'Command+V'
3007
+ }
3008
+ }
3009
+ menu(label: 'Options', underline: 0) {
3010
+ menu_item(:checkbutton, label: 'Enabled', underline: 0) {
3011
+ on('command') do
3012
+ @select_one_menu.children.each { |menu_item| menu_item.state = menu_item.state == 'disabled' ? 'normal' : 'disabled' }
3013
+ @select_multiple_menu.children.each { |menu_item| menu_item.state = menu_item.state == 'disabled' ? 'normal' : 'disabled' }
3014
+ end
3015
+ }
3016
+ @select_one_menu = menu(label: 'Select One', underline: 0) {
3017
+ menu_item(:radiobutton, label: 'Option 1') {
3018
+ state 'disabled'
3019
+ }
3020
+ menu_item(:radiobutton, label: 'Option 2') {
3021
+ state 'disabled'
3022
+ }
3023
+ menu_item(:radiobutton, label: 'Option 3') {
3024
+ state 'disabled'
3025
+ }
3026
+ }
3027
+ @select_multiple_menu = menu(label: 'Select Multiple', underline: 0) {
3028
+ menu_item(:checkbutton, label: 'Option 4') {
3029
+ state 'disabled'
3030
+ }
3031
+ menu_item(:checkbutton, label: 'Option 5') {
3032
+ state 'disabled'
3033
+ }
3034
+ menu_item(:checkbutton, label: 'Option 6') {
3035
+ state 'disabled'
3036
+ }
3037
+ }
3038
+ }
3039
+ menu(label: 'Format', underline: 0) {
3040
+ menu(label: 'Background Color', underline: 0) {
3041
+ COLORS.each { |color_style|
3042
+ menu_item(:radiobutton, label: color_style.to_s.split('_').map(&:capitalize).join(' ')) {
3043
+ on('command') do
3044
+ @label.background = color_style
3045
+ end
3046
+ }
3047
+ }
3048
+ }
3049
+ menu(label: 'Foreground Color', underline: 11) {
3050
+ COLORS.each { |color_style|
3051
+ menu_item(:radiobutton, label: color_style.to_s.split('_').map(&:capitalize).join(' ')) {
3052
+ on('command') do
3053
+ @label.foreground = color_style
3054
+ end
3055
+ }
3056
+ }
3057
+ }
3058
+ }
3059
+ menu(label: 'View', underline: 0) {
3060
+ menu_item(:radiobutton, label: 'Small', underline: 0) {
3061
+ accelerator 'Command+S'
3062
+
3063
+ on('command') do
3064
+ @label.font = {size: 25}
3065
+ end
3066
+ }
3067
+ menu_item(:radiobutton, label: 'Medium', underline: 0) {
3068
+ accelerator 'Command+M'
3069
+ selection true
3070
+
3071
+ on('command') do
3072
+ @label.font = {size: 50}
3073
+ end
3074
+ }
3075
+ menu_item(:radiobutton, label: 'Large', underline: 0) {
3076
+ accelerator 'Command+L'
3077
+
3078
+ on('command') do
3079
+ @label.font = {size: 75}
3080
+ end
3081
+ }
3082
+ }
3083
+ menu(label: 'Help', underline: 0) {
3084
+ menu_item(label: 'Manual', underline: 0) {
3085
+ accelerator 'Command+Shift+M'
3086
+
3087
+ on('command') do
3088
+ message_box(parent: r, title: 'Manual', message: 'Manual Contents')
3089
+ end
3090
+ }
3091
+ menu_item(label: 'Tutorial', underline: 0) {
3092
+ accelerator 'Command+Shift+T'
3093
+
3094
+ on('command') do
3095
+ message_box(parent: r, title: 'Tutorial', message: 'Tutorial Contents')
3096
+ end
3097
+ }
3098
+ menu_item(:separator)
3099
+ menu_item(label: 'Report an Issue...', underline: 0) {
3100
+ on('command') do
3101
+ message_box(parent: r, title: 'Report an Issue', message: 'Reporting an issue...')
3102
+ end
3103
+ }
3104
+ }
3105
+ }
3106
+ }.open
3107
+ ```
3108
+
3109
+ Run with [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed:
3110
+
3111
+ ```
3112
+ ruby -r glimmer-dsl-tk -e "require 'samples/hello/hello_menu_bar'"
3113
+ ```
3114
+
3115
+ Alternatively, run from cloned project without [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed:
3116
+
3117
+ ```
3118
+ ruby -r ./lib/glimmer-dsl-tk.rb samples/hello/hello_menu_bar.rb
3119
+ ```
3120
+
3121
+ Glimmer app:
3122
+
3123
+ ![glimmer dsl tk screenshot sample hello menu-bar](images/glimmer-dsl-tk-screenshot-sample-hello-menu-bar.png)
3124
+
3125
+ ![glimmer dsl tk screenshot sample hello menu-bar](images/glimmer-dsl-tk-screenshot-sample-hello-menu-bar-file.png)
3126
+
3127
+ ![glimmer dsl tk screenshot sample hello menu-bar](images/glimmer-dsl-tk-screenshot-sample-hello-menu-bar-edit.png)
3128
+
3129
+ ![glimmer dsl tk screenshot sample hello menu-bar](images/glimmer-dsl-tk-screenshot-sample-hello-menu-bar-options.png)
3130
+
3131
+ ![glimmer dsl tk screenshot sample hello menu-bar](images/glimmer-dsl-tk-screenshot-sample-hello-menu-bar-format.png)
3132
+
3133
+ ![glimmer dsl tk screenshot sample hello menu-bar](images/glimmer-dsl-tk-screenshot-sample-hello-menu-bar-view.png)
3134
+
3135
+ ![glimmer dsl tk screenshot sample hello menu-bar](images/glimmer-dsl-tk-screenshot-sample-hello-menu-bar-help.png)
3136
+
2923
3137
  ## Applications
2924
3138
 
2925
3139
  ### Glimmer Tk Calculator
@@ -2942,6 +3156,14 @@ https://github.com/AndyObtiva/cryptopunks-gui
2942
3156
 
2943
3157
  ![CryptoPunks GUI Screenshot](https://raw.githubusercontent.com/AndyObtiva/cryptopunks-gui/master/screenshots/cryptopunks-gui-screenshot.png)
2944
3158
 
3159
+ ### Circule
3160
+
3161
+ Generate an icon of overlapping circles derived from a hash.
3162
+
3163
+ https://gitlab.com/fjc/circule
3164
+
3165
+ [Demo Video](https://gitlab.com/fjc/circule/-/raw/master/circule-demo.mp4)
3166
+
2945
3167
  ## Process
2946
3168
 
2947
3169
  [Glimmer Process](https://github.com/AndyObtiva/glimmer/blob/master/PROCESS.md)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.37
1
+ 0.0.38
Binary file
@@ -0,0 +1,144 @@
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/tk/widget_proxy'
23
+
24
+ module Glimmer
25
+ module Tk
26
+ class MenuItemProxy < WidgetProxy
27
+ ACCELERATOR_MODIFIER_EVENT_MAP = {
28
+ 'Command' => 'Command',
29
+ 'Cmd' => 'Command',
30
+ 'Meta' => 'Command',
31
+ 'Option' => 'Option',
32
+ 'Opt' => 'Option',
33
+ 'Alt' => 'Option',
34
+ 'Shift' => 'Shift',
35
+ 'Ctrl' => 'Control',
36
+ 'Control' => 'Control',
37
+ }
38
+
39
+ attr_reader :options
40
+
41
+ def initialize(underscored_widget_name, parent_proxy, args, &block)
42
+ @options = args.last.is_a?(Hash) ? args.last : {}
43
+ super
44
+ end
45
+
46
+ def accelerator=(value)
47
+ @accelerator = value
48
+ @parent_proxy.tk.entryconfigure @options[:label], accelerator: value
49
+ root_parent_proxy.bind(accelerator_event) do |event|
50
+ @command_block&.call(event)
51
+ end
52
+ end
53
+
54
+ def accelerator
55
+ @accelerator
56
+ end
57
+
58
+ def accelerator_event
59
+ accelerator_parts = @accelerator.split('+')
60
+ accelerator_parts.map do |accelerator_part|
61
+ ACCELERATOR_MODIFIER_EVENT_MAP[accelerator_part.capitalize] || accelerator_part.downcase
62
+ end.join('-')
63
+ end
64
+
65
+ def state=(value)
66
+ @state = value
67
+ @parent_proxy.tk.entryconfigure @options[:label], :state => value
68
+ end
69
+
70
+ def state
71
+ @state
72
+ end
73
+
74
+ def command_block=(proc)
75
+ @command_block = proc
76
+ @parent_proxy.tk.entryconfigure @options[:label], command: @command_block
77
+ end
78
+
79
+ def handle_listener(listener_name, &listener)
80
+ case listener_name.to_s.downcase
81
+ when 'command'
82
+ self.command_block = listener
83
+ else
84
+ super
85
+ end
86
+ end
87
+
88
+ def command?
89
+ @args.first.nil? || @args.first == :command || @args.first.is_a?(Hash)
90
+ end
91
+
92
+ def radiobutton?
93
+ @args.first == :radiobutton
94
+ end
95
+
96
+ def checkbutton?
97
+ @args.first == :radiobutton
98
+ end
99
+
100
+ def separator?
101
+ @args.first == :separator
102
+ end
103
+
104
+ def variable(auto_create: true)
105
+ if @variable.nil? && auto_create
106
+ sibling_variable = sibling_radio_menu_items.map {|mi| mi.variable(auto_create: false)}.compact.first
107
+ @variable = sibling_variable.nil? ? ::TkVariable.new : sibling_variable
108
+ else
109
+ @variable
110
+ end
111
+ @variable
112
+ end
113
+
114
+ def selection=(value)
115
+ if value
116
+ variable.value = @options[:label]
117
+ # TODO handle image case where there is no label
118
+ elsif checkbutton?
119
+ variable.value = '__unchecked__'
120
+ end
121
+ end
122
+
123
+ def selection
124
+ variable.value == @options[:label]
125
+ end
126
+
127
+ private
128
+
129
+ def sibling_radio_menu_items
130
+ @parent_proxy.children.select {|child| child.is_a?(MenuItemProxy) && radiobutton? && child != self}
131
+ end
132
+
133
+ def build_widget
134
+ @args.prepend(:command) if @args.first.is_a?(Hash)
135
+ @args.append({}) if !@args.last.is_a?(Hash)
136
+ @args.last.merge!(variable: variable, value: @options[:label]) if radiobutton? || checkbutton?
137
+ case @parent_proxy
138
+ when MenuProxy
139
+ @parent_proxy.tk.add(*@args)
140
+ end
141
+ end
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,48 @@
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/tk/widget_proxy'
23
+
24
+ module Glimmer
25
+ module Tk
26
+ class MenuProxy < WidgetProxy
27
+ attr_reader :options
28
+
29
+ def initialize(underscored_widget_name, parent_proxy, args, &block)
30
+ @options = args.last.is_a?(Hash) ? args.last : {}
31
+ super
32
+ end
33
+
34
+ private
35
+
36
+ def build_widget
37
+ tk_widget_class = self.class.tk_widget_class_for(@keyword)
38
+ @tk = tk_widget_class.new(@parent_proxy.tk)
39
+ case @parent_proxy
40
+ when ToplevelProxy
41
+ @parent_proxy.tk['menu'] = @tk
42
+ when MenuProxy
43
+ @parent_proxy.tk.add(:cascade, {menu: @tk}.merge(@options))
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -47,22 +47,6 @@ module Glimmer
47
47
  Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::Tk::RootExpression.new, keyword, *args, &block)
48
48
  end
49
49
 
50
- def set_attribute(attribute, *args)
51
- case attribute.to_s
52
- when 'iconphoto'
53
- args[0..-1] = [image_argument(args)]
54
- super
55
- when 'resizable'
56
- if args.size == 1 && !args.first.is_a?(Array)
57
- self.resizable = [args.first]*2
58
- else
59
- super
60
- end
61
- else
62
- super
63
- end
64
- end
65
-
66
50
  def handle_listener(listener_name, &listener)
67
51
  case listener_name.to_s.upcase
68
52
  when 'WM_OPEN_WINDOW', 'OPEN_WINDOW'
@@ -50,6 +50,22 @@ module Glimmer
50
50
  %w[width height x y].include?(attribute.to_s) || super
51
51
  end
52
52
 
53
+ def set_attribute(attribute, *args)
54
+ case attribute.to_s
55
+ when 'iconphoto'
56
+ args[0..-1] = [image_argument(args)]
57
+ super
58
+ when 'resizable'
59
+ if args.size == 1 && !args.first.is_a?(Array)
60
+ self.resizable = [args.first]*2
61
+ else
62
+ super
63
+ end
64
+ else
65
+ super
66
+ end
67
+ end
68
+
53
69
  def width
54
70
  geometry.split(REGEX_GEOMETRY)[0].to_i
55
71
  end
@@ -77,8 +77,7 @@ module Glimmer
77
77
  @args = args
78
78
  @keyword = underscored_widget_name
79
79
  @block = block
80
- tk_widget_class = self.class.tk_widget_class_for(underscored_widget_name)
81
- @tk = tk_widget_class.new(@parent_proxy.tk, *args)
80
+ build_widget
82
81
  # a common widget initializer
83
82
  @parent_proxy.post_initialize_child(self)
84
83
  initialize_defaults
@@ -121,7 +120,7 @@ module Glimmer
121
120
  end
122
121
 
123
122
  def self.widget_exists?(underscored_widget_name)
124
- !!tk_widget_class_for(underscored_widget_name)
123
+ !!tk_widget_class_for(underscored_widget_name) || (Glimmer::Tk.constants.include?("#{underscored_widget_name.camelcase(:upper)}Proxy".to_sym) && Glimmer::Tk.const_get("#{underscored_widget_name.camelcase(:upper)}Proxy".to_sym).respond_to?(:new))
125
124
  end
126
125
 
127
126
  def tk_widget_has_attribute_setter?(attribute)
@@ -213,8 +212,8 @@ module Glimmer
213
212
  raise "#{self} cannot handle attribute #{attribute} with args #{args.inspect}"
214
213
  end
215
214
  rescue => e
216
- Glimmer::Config.logger.debug {"Failed to set attribute #{attribute} with args #{args.inspect}. Attempting to set through style instead..."}
217
- Glimmer::Config.logger.debug {e.full_message}
215
+ Glimmer::Config.logger.error {"Failed to set attribute #{attribute} with args #{args.inspect}. Attempting to set through style instead..."}
216
+ Glimmer::Config.logger.error {e.full_message}
218
217
  apply_style(attribute => args.first)
219
218
  end
220
219
  end
@@ -507,11 +506,16 @@ module Glimmer
507
506
 
508
507
  private
509
508
 
509
+ def build_widget
510
+ tk_widget_class = self.class.tk_widget_class_for(@keyword)
511
+ @tk = tk_widget_class.new(@parent_proxy.tk, *args)
512
+ end
513
+
510
514
  def initialize_defaults
511
515
  options = {}
512
516
  options[:sticky] = 'nsew'
513
517
  options[:column_weight] = 1 if @parent_proxy.children.count == 1
514
- grid(options) unless @tk.is_a?(::Tk::Toplevel)
518
+ grid(options) unless @tk.is_a?(::Tk::Toplevel) || @tk.is_a?(::Tk::Menu) || @tk.nil? # TODO refactor by adding a griddable? method that could be overriden by subclasses to consult for this call
515
519
  end
516
520
  end
517
521
  end
@@ -29,6 +29,9 @@ require 'puts_debuggerer' if ENV['pd'].to_s.downcase == 'true'
29
29
  require 'tk'
30
30
  require 'os'
31
31
  require 'facets/hash/symbolize_keys'
32
+ require 'facets/string/underscore'
33
+ require 'facets/string/camelcase'
34
+ require 'delegate'
32
35
 
33
36
  # Internal requires
34
37
  # require 'ext/glimmer/config'
@@ -40,3 +43,4 @@ Glimmer::Config.excluded_keyword_checkers << lambda do |method_symbol, *args|
40
43
  result = false
41
44
  result ||= method == 'load_iseq'
42
45
  end
46
+ ::TkOption.add '*tearOff', 0
@@ -0,0 +1,183 @@
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" # this enables setting background on label just for demo purposes
29
+
30
+ root { |r|
31
+ title 'Hello, Menu Bar!'
32
+
33
+ @label = label {
34
+ grid row_weight: 1, column_weight: 1
35
+ text 'Check Out The Menu Bar Above!'
36
+ font size: 50
37
+ anchor 'center'
38
+ }
39
+
40
+ menu {
41
+ menu(label: 'File', underline: 0) {
42
+ menu_item(label: 'New', underline: 0) {
43
+ accelerator 'Command+N'
44
+
45
+ on('command') do
46
+ message_box(parent: r, title: 'New', message: 'New file created.')
47
+ end
48
+ }
49
+ menu_item(label: 'Open...', underline: 0) {
50
+ accelerator 'Command+O'
51
+
52
+ on('command') do
53
+ message_box(parent: r, title: 'Open', message: 'Opening File...')
54
+ end
55
+ }
56
+ menu(label: 'Open Recent', underline: 5) {
57
+ menu_item(label: 'File 1') {
58
+ on('command') do
59
+ message_box(parent: r, title: 'File 1', message: 'File 1 Contents')
60
+ end
61
+ }
62
+ menu_item(label: 'File 2') {
63
+ on('command') do
64
+ message_box(parent: r, title: 'File 2', message: 'File 2 Contents')
65
+ end
66
+ }
67
+ }
68
+ menu_item(:separator)
69
+ menu_item(label: 'Exit', underline: 1) {
70
+ on('command') do
71
+ exit(0)
72
+ end
73
+ }
74
+ }
75
+ menu(label: 'Edit', underline: 0) {
76
+ menu_item(label: 'Cut', underline: 2) {
77
+ accelerator 'Command+X'
78
+ }
79
+ menu_item(label: 'Copy', underline: 0) {
80
+ accelerator 'Command+C'
81
+ }
82
+ menu_item(label: 'Paste', underline: 0) {
83
+ accelerator 'Command+V'
84
+ }
85
+ }
86
+ menu(label: 'Options', underline: 0) {
87
+ menu_item(:checkbutton, label: 'Enabled', underline: 0) {
88
+ on('command') do
89
+ @select_one_menu.children.each { |menu_item| menu_item.state = menu_item.state == 'disabled' ? 'normal' : 'disabled' }
90
+ @select_multiple_menu.children.each { |menu_item| menu_item.state = menu_item.state == 'disabled' ? 'normal' : 'disabled' }
91
+ end
92
+ }
93
+ @select_one_menu = menu(label: 'Select One', underline: 0) {
94
+ menu_item(:radiobutton, label: 'Option 1') {
95
+ state 'disabled'
96
+ }
97
+ menu_item(:radiobutton, label: 'Option 2') {
98
+ state 'disabled'
99
+ }
100
+ menu_item(:radiobutton, label: 'Option 3') {
101
+ state 'disabled'
102
+ }
103
+ }
104
+ @select_multiple_menu = menu(label: 'Select Multiple', underline: 0) {
105
+ menu_item(:checkbutton, label: 'Option 4') {
106
+ state 'disabled'
107
+ }
108
+ menu_item(:checkbutton, label: 'Option 5') {
109
+ state 'disabled'
110
+ }
111
+ menu_item(:checkbutton, label: 'Option 6') {
112
+ state 'disabled'
113
+ }
114
+ }
115
+ }
116
+ menu(label: 'Format', underline: 0) {
117
+ menu(label: 'Background Color', underline: 0) {
118
+ COLORS.each { |color_style|
119
+ menu_item(:radiobutton, label: color_style.to_s.split('_').map(&:capitalize).join(' ')) {
120
+ on('command') do
121
+ @label.background = color_style
122
+ end
123
+ }
124
+ }
125
+ }
126
+ menu(label: 'Foreground Color', underline: 11) {
127
+ COLORS.each { |color_style|
128
+ menu_item(:radiobutton, label: color_style.to_s.split('_').map(&:capitalize).join(' ')) {
129
+ on('command') do
130
+ @label.foreground = color_style
131
+ end
132
+ }
133
+ }
134
+ }
135
+ }
136
+ menu(label: 'View', underline: 0) {
137
+ menu_item(:radiobutton, label: 'Small', underline: 0) {
138
+ accelerator 'Command+S'
139
+
140
+ on('command') do
141
+ @label.font = {size: 25}
142
+ end
143
+ }
144
+ menu_item(:radiobutton, label: 'Medium', underline: 0) {
145
+ accelerator 'Command+M'
146
+ selection true
147
+
148
+ on('command') do
149
+ @label.font = {size: 50}
150
+ end
151
+ }
152
+ menu_item(:radiobutton, label: 'Large', underline: 0) {
153
+ accelerator 'Command+L'
154
+
155
+ on('command') do
156
+ @label.font = {size: 75}
157
+ end
158
+ }
159
+ }
160
+ menu(label: 'Help', underline: 0) {
161
+ menu_item(label: 'Manual', underline: 0) {
162
+ accelerator 'Command+Shift+M'
163
+
164
+ on('command') do
165
+ message_box(parent: r, title: 'Manual', message: 'Manual Contents')
166
+ end
167
+ }
168
+ menu_item(label: 'Tutorial', underline: 0) {
169
+ accelerator 'Command+Shift+T'
170
+
171
+ on('command') do
172
+ message_box(parent: r, title: 'Tutorial', message: 'Tutorial Contents')
173
+ end
174
+ }
175
+ menu_item(:separator)
176
+ menu_item(label: 'Report an Issue...', underline: 0) {
177
+ on('command') do
178
+ message_box(parent: r, title: 'Report an Issue', message: 'Reporting an issue...')
179
+ end
180
+ }
181
+ }
182
+ }
183
+ }.open
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.37
4
+ version: 0.0.38
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-06 00:00:00.000000000 Z
11
+ date: 2021-11-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: glimmer
@@ -235,6 +235,8 @@ files:
235
235
  - lib/glimmer/tk/frame_proxy.rb
236
236
  - lib/glimmer/tk/label_proxy.rb
237
237
  - lib/glimmer/tk/list_proxy.rb
238
+ - lib/glimmer/tk/menu_item_proxy.rb
239
+ - lib/glimmer/tk/menu_proxy.rb
238
240
  - lib/glimmer/tk/notebook_proxy.rb
239
241
  - lib/glimmer/tk/radiobutton_proxy.rb
240
242
  - lib/glimmer/tk/root_proxy.rb
@@ -258,6 +260,7 @@ files:
258
260
  - samples/hello/hello_label.rb
259
261
  - samples/hello/hello_list_multi_selection.rb
260
262
  - samples/hello/hello_list_single_selection.rb
263
+ - samples/hello/hello_menu_bar.rb
261
264
  - samples/hello/hello_message_box.rb
262
265
  - samples/hello/hello_notebook.rb
263
266
  - samples/hello/hello_radiobutton.rb