glimmer-dsl-tk 0.0.26 → 0.0.27
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +107 -31
- data/VERSION +1 -1
- data/glimmer-dsl-tk.gemspec +0 -0
- data/lib/glimmer/tk/text_proxy.rb +197 -34
- data/lib/glimmer/tk/widget_proxy.rb +11 -5
- data/samples/hello/hello_text.rb +33 -2
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 73b915eb9db0314df3594942c5c4a1205d3ae63a923f01e4dee9f3ee03c75ac0
|
4
|
+
data.tar.gz: 31f1293d6d56d4966207a00b2aa453775adc51ab86aaf71f4dc40bfa5e0dabda
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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
|
-
|
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
|
-
- [
|
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.
|
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
|
-
####
|
389
|
+
#### Image Attribute
|
335
390
|
|
336
|
-
|
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:
|
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:
|
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.
|
1
|
+
0.0.27
|
data/glimmer-dsl-tk.gemspec
CHANGED
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
|
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
|
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
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
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
|
data/samples/hello/hello_text.rb
CHANGED
@@ -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:
|
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:
|
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.
|
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-
|
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.
|
291
|
+
rubygems_version: 3.2.29
|
292
292
|
signing_key:
|
293
293
|
specification_version: 4
|
294
294
|
summary: Glimmer DSL for Tk
|