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 +4 -4
- data/CHANGELOG.md +11 -0
- data/README.md +226 -4
- data/VERSION +1 -1
- data/glimmer-dsl-tk.gemspec +0 -0
- data/lib/glimmer/tk/menu_item_proxy.rb +144 -0
- data/lib/glimmer/tk/menu_proxy.rb +48 -0
- data/lib/glimmer/tk/root_proxy.rb +0 -16
- data/lib/glimmer/tk/toplevel_proxy.rb +16 -0
- data/lib/glimmer/tk/widget_proxy.rb +10 -6
- data/lib/glimmer-dsl-tk.rb +4 -0
- data/samples/hello/hello_menu_bar.rb +183 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5c6969620ced6ade48e45e36bd48909bfe282a412e2f57d8a201f398082c6836
|
4
|
+
data.tar.gz: d8d4bc858b5fdf7399b10d71922a2e12aaf1cbf0b4c8c0db4bf78416e025a5d0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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
|
[](http://badge.fury.io/rb/glimmer-dsl-tk)
|
4
4
|
[](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.
|
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
|

|
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
|
+

|
3124
|
+
|
3125
|
+

|
3126
|
+
|
3127
|
+

|
3128
|
+
|
3129
|
+

|
3130
|
+
|
3131
|
+

|
3132
|
+
|
3133
|
+

|
3134
|
+
|
3135
|
+

|
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
|

|
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.
|
1
|
+
0.0.38
|
data/glimmer-dsl-tk.gemspec
CHANGED
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
|
-
|
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.
|
217
|
-
Glimmer::Config.logger.
|
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
|
data/lib/glimmer-dsl-tk.rb
CHANGED
@@ -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.
|
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-
|
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
|