glimmer-dsl-tk 0.0.26 → 0.0.27

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: 23370b36e8a1902b5115b534e8d9510ff5660d9b5daa9bf31abec321976eb485
4
- data.tar.gz: ebb5477ba30c249375d96f81747f250ea45ea14b20bc0420b373c9a36b0d79fc
3
+ metadata.gz: 73b915eb9db0314df3594942c5c4a1205d3ae63a923f01e4dee9f3ee03c75ac0
4
+ data.tar.gz: 31f1293d6d56d4966207a00b2aa453775adc51ab86aaf71f4dc40bfa5e0dabda
5
5
  SHA512:
6
- metadata.gz: 7249831c8104e32a6cab14341757932acb621e8de027ff6b698e6f017361959b27174b8ecd1d9a6ea3aa428a93a4392a57ceee2d7c7f08f4513eddf95129a051
7
- data.tar.gz: 7cafb57cb7fc10656d70d101cc32e8e0e18e6636ff34ed4c2056b8f8dbc9ec428205f96643792adaf939c2fc0789974f11be4718e6f443fca74bf4c6aee6c21a
6
+ metadata.gz: 965f7054d8cad79a9aeed46dd189c8db263d3447b965afccf6a2bc4e5376b95fed6b21cd119e23110ea8c140ae9b4c07cbd0927087dacacb70641bb7afe2d341
7
+ data.tar.gz: c26996ed08d930161da7cf0814753fcffdba7339be1eea84135f5e3f1fac64abcdf1efc24daf1b23859d197b117f4de62c34a78d678823c3ea68edbf91a1dd11
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Change Log
2
2
 
3
+ ## 0.0.27
4
+
5
+ - Improve Hello, Text! (toolbar buttons: bold, italic, underline)
6
+ - Set correct `wrap 'word'` attribute for `text` widget in Hello, Text!
7
+ - Default `text` widget to `wrap = 'none'`
8
+ - Default `text` widget to `font = {family: 'Courier New'}`
9
+ - Fix issue with unbolding text in `text` widget when selecting multiple lines with an empty line
10
+
3
11
  ## 0.0.26
4
12
 
5
13
  - Ensure spinbox data-binding updates on text key changes (without incrementing/decrementing)
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.26
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.27
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)
@@ -10,11 +10,9 @@
10
10
 
11
11
  [Glimmer](https://github.com/AndyObtiva/glimmer) DSL for [Tk](https://www.tcl.tk/) enables desktop development with [Glimmer](https://github.com/AndyObtiva/glimmer) in [Ruby](https://github.com/ruby/ruby).
12
12
 
13
- [Tcl/Tk](https://www.tcl.tk/) has recently improved by gaining native looking themed widgets on Mac, Windows, and Linux in [Tk version 8.5](https://www.tcl.tk/software/tcltk/8.5.html#:~:text=Highlights%20of%20Tk%208.5&text=Font%20rendering%3A%20Now%20uses%20anti,and%20window%20layout%2C%20and%20more.).
13
+ [Tcl/Tk](https://www.tcl.tk/) has recently improved by gaining native looking themed widgets on Mac, Windows, and Linux in [Tk version 8.5](https://www.tcl.tk/software/tcltk/8.5.html#:~:text=Highlights%20of%20Tk%208.5&text=Font%20rendering%3A%20Now%20uses%20anti,and%20window%20layout%2C%20and%20more.). Additionally, [Ruby](https://www.ruby-lang.org/en/) 3.0 Ractor (formerly known as [Guilds](https://olivierlacan.com/posts/concurrency-in-ruby-3-with-guilds/)) supports truly parallel multi-threading, making both [MRI](https://github.com/ruby/ruby) and [Tk](https://www.tcl.tk/) finally viable for support in [Glimmer](https://github.com/AndyObtiva/glimmer) (Ruby Desktop Development GUI Library) as an alternative to [JRuby on SWT](https://github.com/AndyObtiva/glimmer-dsl-swt).
14
14
 
15
- Additionally, [Ruby](https://www.ruby-lang.org/en/) 3.0 Ractor (formerly known as [Guilds](https://olivierlacan.com/posts/concurrency-in-ruby-3-with-guilds/)) supports truly parallel multi-threading, making both [MRI](https://github.com/ruby/ruby) and [Tk](https://www.tcl.tk/) finally viable for support in [Glimmer](https://github.com/AndyObtiva/glimmer) (Ruby Desktop Development GUI Library) as an alternative to [JRuby on SWT](https://github.com/AndyObtiva/glimmer-dsl-swt).
16
-
17
- The trade-off is that while [SWT](https://www.eclipse.org/swt/) provides a plethora of high quality reusable widgets for the Enterprise (such as [Nebula](https://www.eclipse.org/nebula/)), [Tk](https://www.tcl.tk/) enables very fast app startup time and a small memory footprint via [MRI Ruby](https://www.ruby-lang.org/en/).
15
+ The trade-off is that while [SWT](https://www.eclipse.org/swt/) provides a plethora of high quality reusable widgets for the Enterprise (such as [Nebula](https://github.com/AndyObtiva/glimmer-cw-nebula)), [Tk](https://www.tcl.tk/) enables very fast app startup time and a small memory footprint via [MRI Ruby](https://www.ruby-lang.org/en/).
18
16
 
19
17
  [Glimmer DSL for Tk](https://github.com/AndyObtiva/glimmer-dsl-tk) aims to provide a DSL similar to the [Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt) to enable more productive desktop development in Ruby with:
20
18
  - Declarative DSL syntax that visually maps to the GUI widget hierarchy
@@ -76,11 +74,15 @@ Other [Glimmer](https://github.com/AndyObtiva/glimmer) DSL gems:
76
74
  - [Supported Widgets](#supported-widgets)
77
75
  - [Common Attributes](#common-attributes)
78
76
  - [Common Themed Widget States](#common-themed-widget-states)
77
+ - [Text Extra API Methods](#text-extra-api-methods)
79
78
  - [Smart Defaults and Conventions](#smart-defaults-and-conventions)
80
79
  - [Grid Layout](#grid-layout)
81
- - [Label/Button Image](#labelbutton-image)
80
+ - [Image Attribute](#image-attribute)
81
+ - [Frame Padding](#frame-padding)
82
82
  - [Notebook Frame](#notebook-frame)
83
83
  - [Icon Photo](#icon-photo)
84
+ - [Root Background](#root-background)
85
+ - [Text Defaults](#text-defaults)
84
86
  - [The Grid Geometry Manager](#the-grid-geometry-manager)
85
87
  - [Data-Binding](#data-binding)
86
88
  - [Label Data-Binding](#label-data-binding)
@@ -146,7 +148,7 @@ gem install glimmer-dsl-tk
146
148
 
147
149
  Add the following to `Gemfile`:
148
150
  ```
149
- gem 'glimmer-dsl-tk', '~> 0.0.26'
151
+ gem 'glimmer-dsl-tk', '~> 0.0.27'
150
152
  ```
151
153
 
152
154
  And, then run:
@@ -317,6 +319,59 @@ keyword(args) | attributes | event bindings & callbacks
317
319
  - `invalid?`
318
320
  - `hover?`
319
321
 
322
+ #### Text Extra API Methods
323
+
324
+ [Glimmer DSL for Tk](https://rubygems.org/gems/glimmer-dsl-tk) automatically provides a `text` attribute for the `text` widget that enables updating its content simply without worrying about whether to manually insert by index, delete, or append.
325
+
326
+ Also, the `text` widget is enhanced by [Glimmer DSL for Tk](https://rubygems.org/gems/glimmer-dsl-tk) to enable simpler manipulation of text options without dealing with [tags](https://tkdocs.com/tutorial/text.html) directly. Simply specify region to mutate and option/value or font_option/value, and [Glimmer DSL for Tk](https://rubygems.org/gems/glimmer-dsl-tk) takes care of the rest by automating work of adding/removing [tags](https://tkdocs.com/tutorial/text.html) behind the scenes.
327
+
328
+ - `add_format(region_start, region_end, option, value)`
329
+ - `remove_format(region_start, region_end, option, value)`
330
+ - `toggle_format(region_start, region_end, option, value)`
331
+ - `add_font_format(region_start, region_end, font_option, value)`
332
+ - `remove_font_format(region_start, region_end, font_option, value)`
333
+ - `toggle_font_format(region_start, region_end, font_option, value)`
334
+ - `add_selection_format(region_start, region_end, option, value)`
335
+ - `remove_selection_format(region_start, region_end, option, value)`
336
+ - `toggle_selection_format(region_start, region_end, option, value)`
337
+ - `add_selection_font_format(region_start, region_end, font_option, value)`
338
+ - `remove_selection_font_format(region_start, region_end, font_option, value)`
339
+ - `toggle_selection_font_format(region_start, region_end, font_option, value)`
340
+
341
+ Available options:
342
+
343
+ - `background`
344
+ - `bgstipple`
345
+ - `borderwidth`
346
+ - `elide`
347
+ - `fgstipple`
348
+ - `foreground`
349
+ - `justify`
350
+ - `lmargin1`
351
+ - `lmargin2`
352
+ - `offset`
353
+ - `overstrike`
354
+ - `relief`
355
+ - `rmargin`
356
+ - `spacing1`
357
+ - `spacing2`
358
+ - `spacing3`
359
+ - `tabs`
360
+ - `tabstyle`
361
+ - `underline`
362
+ - `wrap`
363
+
364
+ Available font options:
365
+
366
+ - `family` (default: `'Courier New'`)
367
+ - `size` (default: `13`)
368
+ - `weight` (default: `'normal'`) (e.g. `'bold'`)
369
+ - `slant` (default: `'roman'`) (e.g. `'italic`')
370
+ - `underline` (default: `false`)
371
+ - `overstrike` (default: `false`)
372
+
373
+ Check out the [Hello, Text!](#hello-text) sample for a good demonstration of the `text` widget.
374
+
320
375
  ### Smart Defaults and Conventions
321
376
 
322
377
  #### Event Bindings
@@ -331,9 +386,13 @@ Also, any widget that is the first in a series of siblings has `column_weight` a
331
386
 
332
387
  To override that behavior, you may set alternative `grid` keyword args if needed (e.g. `grid sticky: '', column_weight: 0` disables the smart defaults).
333
388
 
334
- #### Label/Button Image
389
+ #### Image Attribute
335
390
 
336
- Label and Button `image` attribute can accept image path directly as an alternative to `TkPhotoImage` object in addition to key values for automatic processing of image (`subsample`, `zoom`, `from`, `to`, `shrink`, `compositingrule`)
391
+ Widget `image` attribute (e.g. `label` `image`) can accept image path directly as an alternative to `TkPhotoImage` object in addition to key values for automatic processing of image (`subsample`, `zoom`, `from`, `to`, `shrink`, `compositingrule`)
392
+
393
+ #### Frame Padding
394
+
395
+ Frames have a padding of `15` all around by default to produce more user-friendly graphical user interfaces.
337
396
 
338
397
  #### Notebook Frame
339
398
 
@@ -367,6 +426,12 @@ root {
367
426
 
368
427
  `root` `background` color attribute is automatically set to `'#ececec'` on the Mac to avoid having a non-native-looking light-colored background.
369
428
 
429
+ #### Text Defaults
430
+
431
+ `text` widget has these defaults:
432
+ - `wrap = 'none'`
433
+ - `font = {family: 'Courier New'}`
434
+
370
435
  ## The Grid Geometry Manager
371
436
 
372
437
  The Grid Geometry Manager is supported via the `grid` keyword just as per the [Tk documentation](https://tkdocs.com/tutorial/grid.html), except by nesting under the widget it concerns.
@@ -520,24 +585,6 @@ It automatically handles all the Tk plumbing behind the scenes.
520
585
 
521
586
  More details can be found in [Hello, Spinbox!](#hello-spinbox) sample below.
522
587
 
523
- ### Text Data-Binding
524
-
525
- Example:
526
-
527
- This assumes a `Person` model with a `address` attribute.
528
-
529
- ```ruby
530
- text {
531
- text <=> [person, :address]
532
- }
533
- ```
534
-
535
- That code binds the text content of `text` to the `address` attribute on the `person` model.
536
-
537
- It automatically handles all the Tk plumbing behind the scenes (including fine-grained inserts and deletes, abstracting them all away).
538
-
539
- More details can be found in [Glimmer Meta-Sample](#samples) below.
540
-
541
588
  ### Checkbutton Data-Binding
542
589
 
543
590
  Example:
@@ -1636,8 +1683,6 @@ Glimmer app:
1636
1683
 
1637
1684
  ### Hello, Text!
1638
1685
 
1639
- [Glimmer DSL for Tk](https://rubygems.org/gems/glimmer-dsl-tk) automatically provides a `text` attribute for the `text` widget that enables updating its content simply without worrying about whether to manually insert by index, delete, or append.
1640
-
1641
1686
  Glimmer code (from [samples/hello/hello_text.rb](samples/hello/hello_text.rb)):
1642
1687
 
1643
1688
  ```ruby
@@ -1674,14 +1719,44 @@ class HelloText
1674
1719
  frame {
1675
1720
  grid row: 0, column: 0
1676
1721
 
1722
+ button {
1723
+ grid row: 0, column: 0, column_weight: 0
1724
+ text 'B'
1725
+ style font: {weight: 'bold'}
1726
+
1727
+ on('command') do
1728
+ @text.toggle_selection_font_format('weight', 'bold')
1729
+ end
1730
+ }
1731
+
1732
+ button {
1733
+ grid row: 0, column: 1, column_weight: 0
1734
+ text 'I'
1735
+ style font: {slant: 'italic'}
1736
+
1737
+ on('command') do
1738
+ @text.toggle_selection_font_format('slant', 'italic')
1739
+ end
1740
+ }
1741
+
1742
+ button {
1743
+ grid row: 0, column: 2, column_weight: 0
1744
+ text 'U'
1745
+ style font: {underline: true}
1746
+
1747
+ on('command') do
1748
+ @text.toggle_selection_font_format('underline', true)
1749
+ end
1750
+ }
1751
+
1677
1752
  combobox {
1678
- grid row: 0, column: 0, column_weight: 1
1753
+ grid row: 0, column: 4, column_weight: 1
1679
1754
  readonly true
1680
1755
  text <=> [self, :foreground, after_write: ->(value) { @text.add_selection_format('foreground', value == FOREGROUND_PROMPT ? 'black' : value) }]
1681
1756
  }
1682
1757
 
1683
1758
  combobox {
1684
- grid row: 0, column: 1, column_weight: 1
1759
+ grid row: 0, column: 5, column_weight: 1
1685
1760
  readonly true
1686
1761
  text <=> [self, :background, after_write: ->(value) { @text.add_selection_format('background', value == BACKGROUND_PROMPT ? 'black' : value) }]
1687
1762
  }
@@ -1689,6 +1764,7 @@ class HelloText
1689
1764
 
1690
1765
  @text = text {
1691
1766
  grid row: 1, column: 0, row_weight: 1
1767
+ wrap 'word'
1692
1768
  text <<~MULTI_LINE_STRING
1693
1769
  According to the National Post, a heavy metal-loving high school principal in Canada will be allowed to keep her job, days after a public campaign to oust her made headlines around the globe.
1694
1770
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.26
1
+ 0.0.27
Binary file
@@ -100,7 +100,7 @@ module Glimmer
100
100
 
101
101
  tag_names.select do |tag_name|
102
102
  @tk.tag_ranges(tag_name).any? do |range|
103
- if range.first.to_f <= region_start.to_f && range.last.to_f >= region_end.to_f
103
+ if text_index_less_than_or_equal_to_other_text_index?(range.first, region_start) && text_index_greater_than_or_equal_to_other_text_index?(range.last, region_end)
104
104
  @tk.tag_cget(tag_name, option) == value
105
105
  end
106
106
  end
@@ -120,7 +120,7 @@ module Glimmer
120
120
  @tk.tag_ranges(tag_name).any? do |range|
121
121
  if range.first.to_f.between?(region_start.to_f, region_end.to_f) or
122
122
  range.last.to_f.between?(region_start.to_f, region_end.to_f) or
123
- (range.first.to_f <= region_start.to_f && range.last.to_f >= region_end.to_f)
123
+ (text_index_less_than_or_equal_to_other_text_index?(range.first, region_start) && text_index_greater_than_or_equal_to_other_text_index?(range.last, region_end))
124
124
  @tk.tag_cget(tag_name, option) == value
125
125
  end
126
126
  end
@@ -141,44 +141,207 @@ module Glimmer
141
141
  add_format(region_start, region_end, option, value)
142
142
  end
143
143
  end
144
+
145
+ # TODO Algorithm for font option formatting
146
+ # for a region, grab all the latest tags for each subregion as well as the widget font for subregions without a tag
147
+ # for each part of the region covered by a tag, augment its font with new font option (or remove if that is what is needed)
148
+ # Once add and remove are implemented, implement toggle
149
+ # Also, there is a need for a method that checks if a font option value applies to an entire region (to decide which way to toggle with toggle method)
150
+ def applied_font_format?(region_start, region_end, font_option, value)
151
+ applied_font_format_tags_and_regions(region_start, region_end).all? do |tag, region_start, region_end|
152
+ if tag.nil?
153
+ @tk.font.send(font_option) == value
154
+ else
155
+ @tk.tag_cget(tag, 'font').send(font_option) == value
156
+ end
157
+ end
158
+ end
159
+
160
+ def applied_font_format_tags_and_regions(region_start, region_end)
161
+ lines = text.split("\n")
162
+ tags_and_regions = []
163
+ all_tag_names = @tk.tag_names - ['sel']
164
+ (region_start.to_i..region_end.to_i).each do |line_number|
165
+ start_character_index = 0
166
+ start_character_index = region_start.to_s.split('.').last.to_i if line_number == region_start.to_i
167
+ end_character_index = lines[line_number - 1].size
168
+ end_character_index = region_end.to_s.split('.').last.to_i if line_number == region_end.to_i
169
+ (start_character_index...end_character_index).each do |character_index|
170
+ text_index = "#{line_number}.#{character_index}"
171
+ # TODO reimplement the following using @tk.tag_names without arg since passing an arg seems broken and returns inaccurate results
172
+ region_tag = all_tag_names.reverse.find do |tag|
173
+ @tk.tag_cget(tag, 'font') && @tk.tag_ranges(tag).any? do |range_start, range_end|
174
+ text_index_less_than_or_equal_to_other_text_index?(range_start, text_index) && text_index_greater_than_or_equal_to_other_text_index?(range_end, text_index)
175
+ end
176
+ end
177
+ end_text_index = add_to_text_index(text_index, 1)
178
+ if tags_and_regions&.last && region_tag == tags_and_regions.last.first
179
+ tags_and_regions.last[2] = end_text_index
180
+ else
181
+ tags_and_regions << [region_tag, text_index, end_text_index]
182
+ end
183
+ end
184
+ end
185
+ tags_and_regions
186
+ end
187
+
188
+ def add_font_format(region_start, region_end, font_option, value)
189
+ applied_font_format_tags_and_regions(region_start, region_end).each do |tag, tag_region_start, tag_region_end|
190
+ if tag
191
+ bigger_region_tag = @tk.tag_ranges(tag).any? do |range_start, range_end|
192
+ text_index_less_than_other_text_index?(range_start, tag_region_start) || text_index_greater_than_other_text_index?(range_end, tag_region_end)
193
+ end
194
+ if bigger_region_tag
195
+ @tk.tag_ranges(tag).each do |range_start, range_end|
196
+ if text_index_less_than_other_text_index?(range_start, tag_region_start) && text_index_less_than_or_equal_to_other_text_index?(range_end, tag_region_end) && text_index_greater_than_or_equal_to_other_text_index?(range_end, tag_region_start)
197
+ font = @tk.tag_cget(tag, 'font')
198
+ remove_format(range_start, range_end, 'font', font)
199
+ add_format(range_start, tag_region_start, 'font', font)
200
+ font_clone = clone_font(font)
201
+ font_clone.send("#{font_option}=", value)
202
+ add_format(tag_region_start, tag_region_end, 'font', font_clone)
203
+ elsif text_index_greater_than_other_text_index?(range_end, tag_region_end) && text_index_greater_than_or_equal_to_other_text_index?(range_start, tag_region_start) && text_index_less_than_or_equal_to_other_text_index?(range_start, tag_region_end)
204
+ font = @tk.tag_cget(tag, 'font')
205
+ remove_format(range_start, range_end, 'font', font)
206
+ add_format(tag_region_end, range_end, 'font', font)
207
+ font_clone = clone_font(font)
208
+ font_clone.send("#{font_option}=", value)
209
+ add_format(tag_region_start, tag_region_end, 'font', font_clone)
210
+ elsif text_index_less_than_other_text_index?(range_start, tag_region_start) && text_index_greater_than_other_text_index?(range_end, tag_region_end)
211
+ font = @tk.tag_cget(tag, 'font')
212
+ remove_format(range_start, range_end, 'font', font)
213
+ add_format(range_start, tag_region_start, 'font', font)
214
+ remove_format(range_start, range_end, 'font', font)
215
+ add_format(tag_region_end, range_end, 'font', font)
216
+ font_clone = clone_font(font)
217
+ font_clone.send("#{font_option}=", value)
218
+ add_format(tag_region_start, tag_region_end, 'font', font_clone)
219
+ end
220
+ end
221
+ else
222
+ current_font = @tk.tag_cget(tag, 'font')
223
+ current_font.send("#{font_option}=", value)
224
+ end
225
+ else
226
+ add_format(tag_region_start, tag_region_end, 'font', default_font_attributes.merge(font_option => value))
227
+ end
228
+ end
229
+ end
230
+
231
+ def remove_font_format(region_start, region_end, font_option, value)
232
+ applied_font_format_tags_and_regions(region_start, region_end).each do |tag, tag_region_start, tag_region_end|
233
+ if tag
234
+ bigger_region_tag = @tk.tag_ranges(tag).any? do |range_start, range_end|
235
+ text_index_less_than_other_text_index?(range_start, tag_region_start) || text_index_greater_than_other_text_index?(range_end, tag_region_end)
236
+ end
237
+ if bigger_region_tag
238
+ @tk.tag_ranges(tag).each do |range_start, range_end|
239
+ if text_index_less_than_other_text_index?(range_start, tag_region_start) && text_index_less_than_or_equal_to_other_text_index?(range_end, tag_region_end) && text_index_greater_than_or_equal_to_other_text_index?(range_end, tag_region_start)
240
+ font = @tk.tag_cget(tag, 'font')
241
+ remove_format(range_start, range_end, 'font', font)
242
+ add_format(range_start, subtract_from_text_index(tag_region_start, 1), 'font', font)
243
+ font_clone = clone_font(font)
244
+ font_clone.send("#{font_option}=", default_for_font_option(font_option))
245
+ add_format(tag_region_start, tag_region_end, 'font', font_clone)
246
+ elsif text_index_greater_than_other_text_index?(range_end, tag_region_end) && text_index_greater_than_or_equal_to_other_text_index?(range_start, tag_region_start) && text_index_less_than_or_equal_to_other_text_index?(range_start, tag_region_end)
247
+ font = @tk.tag_cget(tag, 'font')
248
+ remove_format(range_start, range_end, 'font', font)
249
+ add_format(add_to_text_index(tag_region_end, 1), range_end, 'font', font)
250
+ font_clone = clone_font(font)
251
+ font_clone.send("#{font_option}=", default_for_font_option(font_option))
252
+ add_format(tag_region_start, tag_region_end, 'font', font_clone)
253
+ elsif text_index_less_than_other_text_index?(range_start, tag_region_start) && text_index_greater_than_other_text_index?(range_end, tag_region_end)
254
+ font = @tk.tag_cget(tag, 'font')
255
+ remove_format(range_start, range_end, 'font', font)
256
+ add_format(range_start, subtract_from_text_index(tag_region_start, 1), 'font', font)
257
+ remove_format(range_start, range_end, 'font', font)
258
+ add_format(add_to_text_index(tag_region_end, 1), range_end, 'font', font)
259
+ font_clone = clone_font(font)
260
+ font_clone.send("#{font_option}=", default_for_font_option(font_option))
261
+ add_format(tag_region_start, tag_region_end, 'font', font_clone)
262
+ end
263
+ end
264
+ else
265
+ current_font = @tk.tag_cget(tag, 'font')
266
+ current_font.send("#{font_option}=", default_for_font_option(font_option))
267
+ end
268
+ else
269
+ add_format(tag_region_start, tag_region_end, 'font', default_font_attributes.merge(font_option => default_for_font_option(font_option)))
270
+ end
271
+ end
272
+ end
273
+
274
+ # toggles option/value tag (removes if already applied)
275
+ def toggle_font_format(region_start, region_end, option, value)
276
+ if applied_font_format?(region_start, region_end, option, value)
277
+ remove_font_format(region_start, region_end, option, value)
278
+ else
279
+ add_font_format(region_start, region_end, option, value)
280
+ end
281
+ end
282
+
283
+ def default_for_font_option(font_option)
284
+ @tk.font.send(font_option)
285
+ end
286
+
287
+ def default_font_attributes
288
+ Hash[@tk.font.actual]
289
+ end
290
+
291
+ def add_to_text_index(text_index, addition)
292
+ text_index_parts = text_index.split('.')
293
+ line = text_index_parts.first
294
+ char_index = text_index_parts.last
295
+ char_index = char_index.to_i + addition
296
+ "#{line}.#{char_index}"
297
+ end
144
298
 
145
- # def applied_font_format?(region_start, region_end, option, value)
146
- # !applied_font_format_tags(region_start, region_end, option, value).empty?
147
- # end
148
- #
149
- # def applied_font_format_tags(region_start, region_end, option, value)
150
- # tag_names = @tk.tag_names - ['sel']
151
- #
152
- # tag_names.select do |tag_name|
153
- # @tk.tag_ranges(tag_name).any? do |range|
154
- # if range.first.to_f <= region_start.to_f && range.last.to_f >= region_end.to_f
155
- # @tk.tag_cget(tag_name, option) == value
156
- # end
157
- # end
158
- # end
159
- # end
160
- #
161
- # def add_font_format(region_start, region_end, option, value)
162
- # end
163
- #
164
- # def remove_font_format(region_start, region_end, option, value)
165
- # end
166
- #
167
- ### toggles option/value tag (removes if already applied)
168
- # def toggle_font_format(region_start, region_end, option, value)
169
- # if applied_font_format?(region_start, region_end, option, value)
170
- ### ensure removing from previous font combination (perhaps checking widget font too)
171
- # remove_font_format(region_start, region_end, option, value)
172
- # else
173
- ### ensure adding to previous font combination (perhaps checking widget font too)
174
- # add_font_format(region_start, region_end, option, value)
175
- # end
176
- # end
299
+ def subtract_from_text_index(text_index, subtraction)
300
+ add_to_text_index(text_index, -1 * subtraction)
301
+ end
302
+
303
+ def text_index_less_than_other_text_index?(region1, region2)
304
+ region1_parts = region1.to_s.split('.')
305
+ region2_parts = region2.to_s.split('.')
306
+ return true if region1_parts.first.to_i < region2_parts.first.to_i
307
+ return false if region1_parts.first.to_i > region2_parts.first.to_i
308
+ region1_parts.last.to_i < region2_parts.last.to_i
309
+ end
310
+
311
+ def text_index_less_than_or_equal_to_other_text_index?(region1, region2)
312
+ region1_parts = region1.to_s.split('.')
313
+ region2_parts = region2.to_s.split('.')
314
+ return true if region1_parts.first.to_i < region2_parts.first.to_i
315
+ return false if region1_parts.first.to_i > region2_parts.first.to_i
316
+ region1_parts.last.to_i <= region2_parts.last.to_i
317
+ end
318
+
319
+ def text_index_greater_than_other_text_index?(region1, region2)
320
+ region1_parts = region1.to_s.split('.')
321
+ region2_parts = region2.to_s.split('.')
322
+ return true if region1_parts.first.to_i > region2_parts.first.to_i
323
+ return false if region1_parts.first.to_i < region2_parts.first.to_i
324
+ region1_parts.last.to_i > region2_parts.last.to_i
325
+ end
326
+
327
+ def text_index_greater_than_or_equal_to_other_text_index?(region1, region2)
328
+ region1_parts = region1.to_s.split('.')
329
+ region2_parts = region2.to_s.split('.')
330
+ return true if region1_parts.first.to_i > region2_parts.first.to_i
331
+ return false if region1_parts.first.to_i < region2_parts.first.to_i
332
+ region1_parts.last.to_i >= region2_parts.last.to_i
333
+ end
334
+
335
+ def clone_font(font)
336
+ ::TkFont.new(Hash[font.actual])
337
+ end
177
338
 
178
339
  private
179
340
 
180
341
  def initialize_defaults
181
342
  super
343
+ self.font = {family: 'Courier New'}
344
+ self.wrap = 'none'
182
345
  self.padx = 5
183
346
  self.pady = 5
184
347
  end
@@ -34,7 +34,9 @@ module Glimmer
34
34
  begin
35
35
  class_name = "#{keyword.camelcase(:upper)}Proxy".to_sym
36
36
  Glimmer::Tk.const_get(class_name)
37
- rescue
37
+ rescue => e
38
+ Glimmer::Config.logger.debug {"Unable to instantiate custom class name for #{keyword} ... defaulting to Glimmer::Tk::WidgetProxy"}
39
+ Glimmer::Config.logger.debug {e.full_message}
38
40
  Glimmer::Tk::WidgetProxy
39
41
  end
40
42
  end
@@ -54,7 +56,7 @@ module Glimmer
54
56
  tk_widget_class = eval(tk_widget_name)
55
57
  break
56
58
  rescue RuntimeError, SyntaxError, NameError => e
57
- Glimmer::Config.logger.debug e.full_message
59
+ Glimmer::Config.logger.debug {e.full_message}
58
60
  end
59
61
  end
60
62
  tk_widget_class if tk_widget_class.respond_to?(:new)
@@ -104,6 +106,8 @@ module Glimmer
104
106
  @tk.send(attribute_setter(attribute), @tk.send(attribute))
105
107
  result = true
106
108
  rescue => e
109
+ Glimmer::Config.logger.debug { "No tk attribute setter for #{attribute}" }
110
+ Glimmer::Config.logger.debug { e.full_message }
107
111
  result = false
108
112
  end
109
113
  result
@@ -114,7 +118,8 @@ module Glimmer
114
118
  # TK Widget currently doesn't support respond_to? properly, so I have to resort to this trick for now
115
119
  @tk.send(attribute)
116
120
  true
117
- rescue
121
+ rescue => e
122
+ Glimmer::Config.logger.debug { "No tk attribute getter setter for #{attribute}" }
118
123
  false
119
124
  end
120
125
  end
@@ -125,7 +130,8 @@ module Glimmer
125
130
  begin
126
131
  @tk.tile_instate(attribute)
127
132
  true
128
- rescue
133
+ rescue => e
134
+ Glimmer::Config.logger.debug { "No tk state for #{attribute}" }
129
135
  false
130
136
  end
131
137
  else
@@ -247,7 +253,7 @@ module Glimmer
247
253
 
248
254
  def apply_style(options)
249
255
  @@style_number = 0 unless defined?(@@style_number)
250
- style = "style#{@@style_number}.#{@tk.class.name.split('::').last}"
256
+ style = "style#{@@style_number += 1}.#{@tk.class.name.split('::').last}"
251
257
  ::Tk::Tile::Style.configure(style, options)
252
258
  @tk.style = style
253
259
  end
@@ -52,14 +52,44 @@ class HelloText
52
52
  frame {
53
53
  grid row: 0, column: 0
54
54
 
55
+ button {
56
+ grid row: 0, column: 0, column_weight: 0
57
+ text 'B'
58
+ style font: {weight: 'bold'}
59
+
60
+ on('command') do
61
+ @text.toggle_selection_font_format('weight', 'bold')
62
+ end
63
+ }
64
+
65
+ button {
66
+ grid row: 0, column: 1, column_weight: 0
67
+ text 'I'
68
+ style font: {slant: 'italic'}
69
+
70
+ on('command') do
71
+ @text.toggle_selection_font_format('slant', 'italic')
72
+ end
73
+ }
74
+
75
+ button {
76
+ grid row: 0, column: 2, column_weight: 0
77
+ text 'U'
78
+ style font: {underline: true}
79
+
80
+ on('command') do
81
+ @text.toggle_selection_font_format('underline', true)
82
+ end
83
+ }
84
+
55
85
  combobox {
56
- grid row: 0, column: 0, column_weight: 1
86
+ grid row: 0, column: 4, column_weight: 1
57
87
  readonly true
58
88
  text <=> [self, :foreground, after_write: ->(value) { @text.add_selection_format('foreground', value == FOREGROUND_PROMPT ? 'black' : value) }]
59
89
  }
60
90
 
61
91
  combobox {
62
- grid row: 0, column: 1, column_weight: 1
92
+ grid row: 0, column: 5, column_weight: 1
63
93
  readonly true
64
94
  text <=> [self, :background, after_write: ->(value) { @text.add_selection_format('background', value == BACKGROUND_PROMPT ? 'black' : value) }]
65
95
  }
@@ -67,6 +97,7 @@ class HelloText
67
97
 
68
98
  @text = text {
69
99
  grid row: 1, column: 0, row_weight: 1
100
+ wrap 'word'
70
101
  text <<~MULTI_LINE_STRING
71
102
  According to the National Post, a heavy metal-loving high school principal in Canada will be allowed to keep her job, days after a public campaign to oust her made headlines around the globe.
72
103
 
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.26
4
+ version: 0.0.27
5
5
  platform: ruby
6
6
  authors:
7
7
  - AndyMaleh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-10-18 00:00:00.000000000 Z
11
+ date: 2021-10-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: glimmer
@@ -288,7 +288,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
288
288
  - !ruby/object:Gem::Version
289
289
  version: '0'
290
290
  requirements: []
291
- rubygems_version: 3.2.22
291
+ rubygems_version: 3.2.29
292
292
  signing_key:
293
293
  specification_version: 4
294
294
  summary: Glimmer DSL for Tk