glimmer-dsl-swt 4.18.4.10 → 4.18.4.11

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f06f3cbda7f10f81702dcdff893c91f4b7e381d5e7309c34786993e7000d8fc0
4
- data.tar.gz: d08c04bababf1eb91a6a137ca725a082d66ec2479c71e0ef3f093dd472c68616
3
+ metadata.gz: cb72ad5f93c5c27a2f2ead87225e0ee045e2663e50b04346f5be6065fbf269c2
4
+ data.tar.gz: 394f955a01f7d5b568ae433dcab240f86b48749e5db428296299388ceaff5773
5
5
  SHA512:
6
- metadata.gz: 95fbd9e1be14bf90eb36fd92b6e0d86c3a4a3848c1451f1b17234a8fb3521e544c0893d423c04f32bf750c538b6972969407a8ab6fa84e6a3d9ff0181c3fb144
7
- data.tar.gz: 32ddd1acf980524c63fef1722ad1f006cf84d08bd1496b387cd0e6a180dd517b920fc458df34c58b2ac489f2c9b48b6a430a1891a21d9789219e965dc86c8f2b
6
+ metadata.gz: 18dd1f7062fdb14e063820d29168815df77b70f04275559fc812b605d2daf6053815b94579030a749cfc942188115150db093b0f0fc9863247177d112d165d90
7
+ data.tar.gz: c1809fda609b22045fd5872624cbc234b1353173522f2430767b8f36e4afd096063d5b4fe5fc41b0a24b0f96ec00d9fc0aada8df9537201d1d87fe8eebe26d59
data/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Change Log
2
2
 
3
+ ### 4.18.4.11
4
+
5
+ - Support creating images pixel by pixel with `image(width, height) {|x,y| [r, g, b]}` keyword, which takes a block with x, y coordinates based on the image width and height and returns a pixel foreground color per point
6
+ - Add proper indentation in code_text upon hitting ENTER
7
+ - Reset Canvas Shape DSL alpha value to 255 when not explicitly set on a shape (Apply in Hello, Canvas! Sample)
8
+ - Provide terse syntax for building canvas objects (autodetecting its width and height)
9
+ - Provide terse syntax for building `:image_double_buffered` canvas objects (autodetecting its width and height):
10
+ - Center mandelbrot where mouse is clicked upon zoom
11
+ - Fix issue with Mandelbrot sample off by one error on Cores selected via Menu
12
+ - Fix use of on_events in code_text widget with lines mode true
13
+
3
14
  ### 4.18.4.10
4
15
 
5
16
  - Hello, Progress Bar!
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 SWT 4.18.4.10
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 SWT 4.18.4.11
2
2
  ## JRuby Desktop Development GUI Framework
3
3
  [![Gem Version](https://badge.fury.io/rb/glimmer-dsl-swt.svg)](http://badge.fury.io/rb/glimmer-dsl-swt)
4
4
  [![Travis CI](https://travis-ci.com/AndyObtiva/glimmer-dsl-swt.svg?branch=master)](https://travis-ci.com/github/AndyObtiva/glimmer-dsl-swt)
@@ -342,7 +342,7 @@ jgem install glimmer-dsl-swt
342
342
 
343
343
  Or this command if you want a specific version:
344
344
  ```
345
- jgem install glimmer-dsl-swt -v 4.18.4.10
345
+ jgem install glimmer-dsl-swt -v 4.18.4.11
346
346
  ```
347
347
 
348
348
  `jgem` is JRuby's version of `gem` command.
@@ -360,7 +360,7 @@ Note: if you're using activerecord or activesupport, keep in mind that Glimmer u
360
360
 
361
361
  Add the following to `Gemfile`:
362
362
  ```
363
- gem 'glimmer-dsl-swt', '~> 4.18.4.10'
363
+ gem 'glimmer-dsl-swt', '~> 4.18.4.11'
364
364
  ```
365
365
 
366
366
  And, then run:
@@ -432,7 +432,7 @@ If you have a Glimmer app you would like referenced here, please mention in a Pu
432
432
 
433
433
  ### Connector
434
434
 
435
- [<img alt="Connector Logo" src="https://raw.githubusercontent.com/AndyObtiva/connector/master/package/linux/Connector.png" height=40 /> Connector](https://github.com/AndyObtiva/connector): A minimalist open-source web browser
435
+ [<img alt="Connector Logo" src="https://raw.githubusercontent.com/AndyObtiva/connector/master/package/linux/Connector.png" height=40 /> Connector](https://github.com/AndyObtiva/connector): A minimalist open-source multi-engine web browser
436
436
 
437
437
  ## Packaging & Distribution
438
438
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 4.18.4.10
1
+ 4.18.4.11
@@ -411,6 +411,10 @@ Although SWT Display is not technically a widget, it has similar APIs and DSL su
411
411
 
412
412
  [JRuby](https://www.jruby.org/) supports [truly parallel multi-threading](https://github.com/jruby/jruby/wiki/Concurrency-in-jruby) since it relies on the JVM (Java Virtual Machine). As such, it enables development of highly-interactive desktop applications that can do background work while the user is interacting with the GUI. However, any code that interacts with the GUI from a thread other than the main (first) GUI thread must do so only through sync_exec (if it is standard synchronous code) or async_exec.
413
413
 
414
+ Most of the time, you simply get away with Ruby [Threads](https://ruby-doc.org/core-2.5.7/Thread.html) and [Mutexes](https://ruby-doc.org/core-2.5.7/Mutex.html).
415
+
416
+ Otherwise, if you need more advanced concurrency, Glimmer includes the [concurrent-ruby gem](https://rubygems.org/gems/concurrent-ruby), which supports many helpful concurrency techniques such as [Thread Pools](http://ruby-concurrency.github.io/concurrent-ruby/master/file.thread_pools.html) (used in the [Mandelbrot Fractal](GLIMMER_SAMPLES.md#mandelbrot-fractal) sample).
417
+
414
418
  ##### async_exec
415
419
 
416
420
  `async_exec {}` is a Glimmer DSL keyword in addition to being a method on `display`. It accepts a block and when invoked, adds the block to the end of a queue of GUI events scheduled to run on the SWT event loop, executing asynchronously.
@@ -1411,6 +1415,106 @@ shell {
1411
1415
  }.open
1412
1416
  ```
1413
1417
 
1418
+ #### Shapes inside a Widget
1419
+
1420
+ Keep in mind that the Shape DSL can be used inside any widget, not just `canvas`. Unlike shapes on a `canvas`, which are standalone graphics, when included in a widget, which already has its own look and feel, shapes are used as a decorative add-on that complements its look by getting painted on top of it. For example, shapes were used to decorate `composite` blocks in the [Tetris](#tetris) sample to have a more bevel look. In summary, Shapes can be used in a hybrid approach (shapes inside a widget), not just standalone in a `canvas`.
1421
+
1422
+ #### Shapes inside an Image
1423
+
1424
+ You can build an image using the Canvas Shape DSL (including setting the icon of the application).
1425
+
1426
+ Example (you may copy/paste in [`girb`](GLIMMER_GIRB.md)):
1427
+
1428
+ ```
1429
+ include Glimmer
1430
+
1431
+ shell {
1432
+ text 'Image Shape DSL Example'
1433
+ label {
1434
+ bevel_constant = 20
1435
+ icon_block_size = 64
1436
+ icon_bevel_size = icon_block_size.to_f / 25.to_f
1437
+ icon_bevel_pixel_size = 0.16*icon_block_size.to_f
1438
+ icon_size = 8
1439
+ icon_pixel_size = icon_block_size * icon_size
1440
+ image(icon_pixel_size, icon_pixel_size) {
1441
+ icon_size.times { |row|
1442
+ icon_size.times { |column|
1443
+ colored = row >= 1 && column.between?(1, 6)
1444
+ color = colored ? color([:white, :red, :blue, :green, :yellow, :magenta, :cyan, :dark_blue].sample) : color(:white)
1445
+ x = column * icon_block_size
1446
+ y = row * icon_block_size
1447
+ rectangle(x, y, icon_block_size, icon_block_size) {
1448
+ background color
1449
+ }
1450
+ polygon(x, y, x + icon_block_size, y, x + icon_block_size - icon_bevel_pixel_size, y + icon_bevel_pixel_size, x + icon_bevel_pixel_size, y + icon_bevel_pixel_size) {
1451
+ background rgb(color.red + 4*bevel_constant, color.green + 4*bevel_constant, color.blue + 4*bevel_constant)
1452
+ }
1453
+ polygon(x + icon_block_size, y, x + icon_block_size - icon_bevel_pixel_size, y + icon_bevel_pixel_size, x + icon_block_size - icon_bevel_pixel_size, y + icon_block_size - icon_bevel_pixel_size, x + icon_block_size, y + icon_block_size) {
1454
+ background rgb(color.red - bevel_constant, color.green - bevel_constant, color.blue - bevel_constant)
1455
+ }
1456
+ polygon(x + icon_block_size, y + icon_block_size, x, y + icon_block_size, x + icon_bevel_pixel_size, y + icon_block_size - icon_bevel_pixel_size, x + icon_block_size - icon_bevel_pixel_size, y + icon_block_size - icon_bevel_pixel_size) {
1457
+ background rgb(color.red - 2*bevel_constant, color.green - 2*bevel_constant, color.blue - 2*bevel_constant)
1458
+ }
1459
+ polygon(x, y, x, y + icon_block_size, x + icon_bevel_pixel_size, y + icon_block_size - icon_bevel_pixel_size, x + icon_bevel_pixel_size, y + icon_bevel_pixel_size) {
1460
+ background rgb(color.red - bevel_constant, color.green - bevel_constant, color.blue - bevel_constant)
1461
+ }
1462
+ }
1463
+ }
1464
+ }
1465
+ }
1466
+ }.open
1467
+ ```
1468
+
1469
+ ![Image Shape DSL](/images/glimmer-example-image-shape-dsl.png)
1470
+
1471
+ Example setting the icon of the application (you may copy/paste in [`girb`](GLIMMER_GIRB.md)):
1472
+
1473
+ ```
1474
+ include Glimmer
1475
+
1476
+ shell {
1477
+ text 'Image Shape DSL Example'
1478
+ label {
1479
+ text 'Image Shape DSL Example'
1480
+ font height: 30
1481
+ }
1482
+ bevel_constant = 20
1483
+ icon_block_size = 64
1484
+ icon_bevel_size = icon_block_size.to_f / 25.to_f
1485
+ icon_bevel_pixel_size = 0.16*icon_block_size.to_f
1486
+ icon_size = 8
1487
+ icon_pixel_size = icon_block_size * icon_size
1488
+ image(icon_pixel_size, icon_pixel_size) {
1489
+ icon_size.times { |row|
1490
+ icon_size.times { |column|
1491
+ colored = row >= 1 && column.between?(1, 6)
1492
+ color = colored ? color([:white, :red, :blue, :green, :yellow, :magenta, :cyan, :dark_blue].sample) : color(:white)
1493
+ x = column * icon_block_size
1494
+ y = row * icon_block_size
1495
+ rectangle(x, y, icon_block_size, icon_block_size) {
1496
+ background color
1497
+ }
1498
+ polygon(x, y, x + icon_block_size, y, x + icon_block_size - icon_bevel_pixel_size, y + icon_bevel_pixel_size, x + icon_bevel_pixel_size, y + icon_bevel_pixel_size) {
1499
+ background rgb(color.red + 4*bevel_constant, color.green + 4*bevel_constant, color.blue + 4*bevel_constant)
1500
+ }
1501
+ polygon(x + icon_block_size, y, x + icon_block_size - icon_bevel_pixel_size, y + icon_bevel_pixel_size, x + icon_block_size - icon_bevel_pixel_size, y + icon_block_size - icon_bevel_pixel_size, x + icon_block_size, y + icon_block_size) {
1502
+ background rgb(color.red - bevel_constant, color.green - bevel_constant, color.blue - bevel_constant)
1503
+ }
1504
+ polygon(x + icon_block_size, y + icon_block_size, x, y + icon_block_size, x + icon_bevel_pixel_size, y + icon_block_size - icon_bevel_pixel_size, x + icon_block_size - icon_bevel_pixel_size, y + icon_block_size - icon_bevel_pixel_size) {
1505
+ background rgb(color.red - 2*bevel_constant, color.green - 2*bevel_constant, color.blue - 2*bevel_constant)
1506
+ }
1507
+ polygon(x, y, x, y + icon_block_size, x + icon_bevel_pixel_size, y + icon_block_size - icon_bevel_pixel_size, x + icon_bevel_pixel_size, y + icon_bevel_pixel_size) {
1508
+ background rgb(color.red - bevel_constant, color.green - bevel_constant, color.blue - bevel_constant)
1509
+ }
1510
+ }
1511
+ }
1512
+ }
1513
+ }.open
1514
+ ```
1515
+
1516
+ ![Image Shape DSL](/images/glimmer-example-image-shape-dsl-app-switcher-icon.png)
1517
+
1414
1518
  #### Pixel Graphics
1415
1519
 
1416
1520
  **(Early Alpha Feature)**
@@ -1440,6 +1544,21 @@ Result:
1440
1544
 
1441
1545
  ![glimmer example pixel graphics](/images/glimmer-example-pixel-graphics.png)
1442
1546
 
1547
+ If you are strictly dealing with pixels (no other shapes), you could even avoid the `pixel` keyword altogether and just provide direct foreground colors by passing a block that receives x, y coordinates:
1548
+
1549
+ ```ruby
1550
+ include Glimmer
1551
+
1552
+ shell {
1553
+ minimum_size 250, 265
1554
+ text 'Pixel Graphics Example'
1555
+
1556
+ canvas { |x, y|
1557
+ [y%255, x%255, (x+y)%255]
1558
+ }
1559
+ }.open
1560
+ ```
1561
+
1443
1562
  Remember that you could always default to direct SWT painting via [org.eclipse.swt.graphics.GC](https://help.eclipse.org/2020-12/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/swt/graphics/GC.html) too for even faster performance when needed in rare circumstances. Learn more at the [SWT Graphics Guide](https://www.eclipse.org/articles/Article-SWT-graphics/SWT_graphics.html) and [SWT Image Guide](https://www.eclipse.org/articles/Article-SWT-images/graphics-resources.html#Saving%20Images).
1444
1563
 
1445
1564
  Example of manually doing the same things as in the previous example without relying on the declarative Glimmer Shape DSL (you may copy/paste in [`girb`](GLIMMER_GIRB.md)):
@@ -1465,6 +1584,8 @@ shell {
1465
1584
  }.open
1466
1585
  ```
1467
1586
 
1587
+ (the code could be optimized further if you are repeating colors by simply reusing `Color` objects instead of re-constructing them)
1588
+
1468
1589
  The only downside with the approach above is that it repaints all pixels on repaints to the window (e.g. during window resize). To get around that, we can rely on a technique called **Image Double-Buffering**. That is to buffer the graphics on an Image first and then set it on the Canvas so that resizes of the shell dont cause a repaint of all the pixels. Additionally, this gives us the added benefit of being able to use the image as a Shell icon via its `image` property.
1469
1590
 
1470
1591
  Example (you may copy/paste in [`girb`](GLIMMER_GIRB.md)):
@@ -1501,127 +1622,80 @@ If you need a transparent background for the image, replace the image constructi
1501
1622
 
1502
1623
  That way, wherever you don't draw a point, you get transparency (seeing what is behind the image).
1503
1624
 
1504
- If you don't need a `shell` image icon and `pixel` performance is enough, you can automatically apply **Image Double-Buffering** with the `:image_double_buffered` SWT style (custom Glimmer style not available in SWT itself)
1505
-
1506
- Example (you may copy/paste in [`girb`](GLIMMER_GIRB.md)):
1625
+ Alternatively, with a very minor performance penalty, Glimmer enables you to build the image pixel by pixel with a friendly Ruby syntax by passing a block that takes the x and y coordinates and returns a foreground color rgb array or Color/ColorProxy object.
1507
1626
 
1508
1627
  ```ruby
1509
1628
  include Glimmer
1510
1629
 
1630
+ @the_image = image(250, 250) {|x, y|
1631
+ [y%255, x%255, (x+y)%255]
1632
+ }
1633
+
1511
1634
  shell {
1512
1635
  minimum_size 250, 265
1513
1636
  text 'Pixel Graphics Example'
1637
+ image @the_image
1514
1638
 
1515
- canvas(:image_double_buffered) {
1516
- 250.times {|y|
1517
- 250.times {|x|
1518
- pixel(x, y, foreground: [y%255, x%255, (x+y)%255])
1519
- }
1520
- }
1639
+ canvas {
1640
+ image @the_image
1521
1641
  }
1522
1642
  }.open
1523
1643
  ```
1524
1644
 
1525
- #### Shapes inside a Widget
1645
+ If you don't need a `shell` image (icon), you can nest the image directly under the canvas by passing in the `top_level` keyword to treat `image` as a top-level keyword (pretending it is built outside the shell).
1526
1646
 
1527
- Keep in mind that the Shape DSL can be used inside any widget, not just `canvas`. Unlike shapes on a `canvas`, which are standalone graphics, when included in a widget, which already has its own look and feel, shapes are used as a decorative add-on that complements its look by getting painted on top of it. For example, shapes were used to decorate `composite` blocks in the [Tetris](#tetris) sample to have a more bevel look. In summary, Shapes can be used in a hybrid approach (shapes inside a widget), not just standalone in a `canvas`.
1647
+ ```ruby
1648
+ include Glimmer
1528
1649
 
1529
- #### Shapes inside an Image
1650
+ shell {
1651
+ minimum_size 250, 265
1652
+ text 'Pixel Graphics Example'
1653
+
1654
+ canvas {
1655
+ image image(250, 250, top_level: true) {|x, y|
1656
+ [y%255, x%255, (x+y)%255]
1657
+ }
1658
+ }
1659
+ }.open
1660
+ ```
1530
1661
 
1531
- You can build an image using the Canvas Shape DSL (including setting the icon of the application).
1662
+ If you don't need a `shell` image (icon) and `pixel` performance is enough, you can automatically apply **Image Double-Buffering** with the `:image_double_buffered` SWT style (custom Glimmer style not available in SWT itself)
1532
1663
 
1533
1664
  Example (you may copy/paste in [`girb`](GLIMMER_GIRB.md)):
1534
1665
 
1535
- ```
1666
+ ```ruby
1536
1667
  include Glimmer
1537
1668
 
1538
1669
  shell {
1539
- text 'Image Shape DSL Example'
1540
- label {
1541
- bevel_constant = 20
1542
- icon_block_size = 64
1543
- icon_bevel_size = icon_block_size.to_f / 25.to_f
1544
- icon_bevel_pixel_size = 0.16*icon_block_size.to_f
1545
- icon_size = 8
1546
- icon_pixel_size = icon_block_size * icon_size
1547
- image(icon_pixel_size, icon_pixel_size) {
1548
- icon_size.times { |row|
1549
- icon_size.times { |column|
1550
- colored = row >= 1 && column.between?(1, 6)
1551
- color = colored ? color([:white, :red, :blue, :green, :yellow, :magenta, :cyan, :dark_blue].sample) : color(:white)
1552
- x = column * icon_block_size
1553
- y = row * icon_block_size
1554
- rectangle(x, y, icon_block_size, icon_block_size) {
1555
- background color
1556
- }
1557
- polygon(x, y, x + icon_block_size, y, x + icon_block_size - icon_bevel_pixel_size, y + icon_bevel_pixel_size, x + icon_bevel_pixel_size, y + icon_bevel_pixel_size) {
1558
- background rgb(color.red + 4*bevel_constant, color.green + 4*bevel_constant, color.blue + 4*bevel_constant)
1559
- }
1560
- polygon(x + icon_block_size, y, x + icon_block_size - icon_bevel_pixel_size, y + icon_bevel_pixel_size, x + icon_block_size - icon_bevel_pixel_size, y + icon_block_size - icon_bevel_pixel_size, x + icon_block_size, y + icon_block_size) {
1561
- background rgb(color.red - bevel_constant, color.green - bevel_constant, color.blue - bevel_constant)
1562
- }
1563
- polygon(x + icon_block_size, y + icon_block_size, x, y + icon_block_size, x + icon_bevel_pixel_size, y + icon_block_size - icon_bevel_pixel_size, x + icon_block_size - icon_bevel_pixel_size, y + icon_block_size - icon_bevel_pixel_size) {
1564
- background rgb(color.red - 2*bevel_constant, color.green - 2*bevel_constant, color.blue - 2*bevel_constant)
1565
- }
1566
- polygon(x, y, x, y + icon_block_size, x + icon_bevel_pixel_size, y + icon_block_size - icon_bevel_pixel_size, x + icon_bevel_pixel_size, y + icon_bevel_pixel_size) {
1567
- background rgb(color.red - bevel_constant, color.green - bevel_constant, color.blue - bevel_constant)
1568
- }
1569
- }
1670
+ minimum_size 250, 265
1671
+ text 'Pixel Graphics Example'
1672
+
1673
+ canvas(:image_double_buffered) {
1674
+ 250.times {|y|
1675
+ 250.times {|x|
1676
+ pixel(x, y, foreground: [y%255, x%255, (x+y)%255])
1570
1677
  }
1571
1678
  }
1572
1679
  }
1573
1680
  }.open
1574
1681
  ```
1575
1682
 
1576
- ![Image Shape DSL](/images/glimmer-example-image-shape-dsl.png)
1577
-
1578
- Example setting the icon of the application (you may copy/paste in [`girb`](GLIMMER_GIRB.md)):
1683
+ Of course, you could also take advantage of the pixel-less terser syntax:
1579
1684
 
1580
- ```
1685
+ ```ruby
1581
1686
  include Glimmer
1582
1687
 
1583
1688
  shell {
1584
- text 'Image Shape DSL Example'
1585
- label {
1586
- text 'Image Shape DSL Example'
1587
- font height: 30
1588
- }
1589
- bevel_constant = 20
1590
- icon_block_size = 64
1591
- icon_bevel_size = icon_block_size.to_f / 25.to_f
1592
- icon_bevel_pixel_size = 0.16*icon_block_size.to_f
1593
- icon_size = 8
1594
- icon_pixel_size = icon_block_size * icon_size
1595
- image(icon_pixel_size, icon_pixel_size) {
1596
- icon_size.times { |row|
1597
- icon_size.times { |column|
1598
- colored = row >= 1 && column.between?(1, 6)
1599
- color = colored ? color([:white, :red, :blue, :green, :yellow, :magenta, :cyan, :dark_blue].sample) : color(:white)
1600
- x = column * icon_block_size
1601
- y = row * icon_block_size
1602
- rectangle(x, y, icon_block_size, icon_block_size) {
1603
- background color
1604
- }
1605
- polygon(x, y, x + icon_block_size, y, x + icon_block_size - icon_bevel_pixel_size, y + icon_bevel_pixel_size, x + icon_bevel_pixel_size, y + icon_bevel_pixel_size) {
1606
- background rgb(color.red + 4*bevel_constant, color.green + 4*bevel_constant, color.blue + 4*bevel_constant)
1607
- }
1608
- polygon(x + icon_block_size, y, x + icon_block_size - icon_bevel_pixel_size, y + icon_bevel_pixel_size, x + icon_block_size - icon_bevel_pixel_size, y + icon_block_size - icon_bevel_pixel_size, x + icon_block_size, y + icon_block_size) {
1609
- background rgb(color.red - bevel_constant, color.green - bevel_constant, color.blue - bevel_constant)
1610
- }
1611
- polygon(x + icon_block_size, y + icon_block_size, x, y + icon_block_size, x + icon_bevel_pixel_size, y + icon_block_size - icon_bevel_pixel_size, x + icon_block_size - icon_bevel_pixel_size, y + icon_block_size - icon_bevel_pixel_size) {
1612
- background rgb(color.red - 2*bevel_constant, color.green - 2*bevel_constant, color.blue - 2*bevel_constant)
1613
- }
1614
- polygon(x, y, x, y + icon_block_size, x + icon_bevel_pixel_size, y + icon_block_size - icon_bevel_pixel_size, x + icon_bevel_pixel_size, y + icon_bevel_pixel_size) {
1615
- background rgb(color.red - bevel_constant, color.green - bevel_constant, color.blue - bevel_constant)
1616
- }
1617
- }
1618
- }
1689
+ minimum_size 250, 265
1690
+ text 'Pixel Graphics Example'
1691
+
1692
+ canvas(:image_double_buffered) { |x, y|
1693
+ [y%255, x%255, (x+y)%255]
1619
1694
  }
1620
1695
  }.open
1621
1696
  ```
1622
1697
 
1623
- ![Image Shape DSL](/images/glimmer-example-image-shape-dsl-app-switcher-icon.png)
1624
-
1698
+ As they say, there are many ways to skin a cat! This is in line with the Ruby way of providing more ways than one. Pick and choose the right tool for the job just like true software engineers.
1625
1699
 
1626
1700
  ### Canvas Transform DSL
1627
1701
 
@@ -2715,6 +2789,8 @@ To use, simply use `code_text` in place of the `text` or `styled_text` widget. I
2715
2789
  **lines**
2716
2790
  (default: `false`)
2717
2791
 
2792
+ **(BETA FEATURE)**
2793
+
2718
2794
  Shows line numbers when set to true.
2719
2795
 
2720
2796
  If set to a hash like `{width: 4}`, it sets the initial width of the line numbers lane in character count (default: 4)
@@ -2724,6 +2800,8 @@ Keep in mind that if the text grows and required a wider line numbers area, it g
2724
2800
  **theme**
2725
2801
  (default: `'glimmer'`)
2726
2802
 
2803
+ **(BETA FEATURE)**
2804
+
2727
2805
  Changes syntax color highlighting theme. Can be one of the following:
2728
2806
  - glimmer
2729
2807
  - github
@@ -2732,6 +2810,8 @@ Changes syntax color highlighting theme. Can be one of the following:
2732
2810
  **language**
2733
2811
  (default: `'ruby'`)
2734
2812
 
2813
+ **(BETA FEATURE)**
2814
+
2735
2815
  Sets the code language, which can be one of the following [rouge gem](#https://rubygems.org/gems/rouge) supported languages:
2736
2816
  - abap
2737
2817
  - actionscript
@@ -2941,10 +3021,13 @@ Sets the code language, which can be one of the following [rouge gem](#https://r
2941
3021
  **default_behavior**
2942
3022
  (default: true)
2943
3023
 
3024
+ **(BETA FEATURE)**
3025
+
2944
3026
  This adds some default keyboard shortcuts:
2945
3027
  - CMD+A (CTRL+A on Windows/Linux) to select all
2946
3028
  - CTRL+A on Mac to jump to beginning of line
2947
3029
  - CTRL+E on Mac to jump to end of line
3030
+ - Attempts to add proper indentation upon adding a new line when hitting ENTER (currently supporting Ruby only)
2948
3031
 
2949
3032
  If you prefer it to be vanilla with no default key event listeners, then pass the `default_behavior: false` option.
2950
3033
 
@@ -605,6 +605,10 @@ Hello, Cursor!
605
605
 
606
606
  This sample demonstrates the use of the `progress_bar` widget keyword.
607
607
 
608
+ It includes an `:indeterminate` progress bar on top, for cases when you could not calculate progress, but still want to inform the user there is an operation happening in the background.
609
+
610
+ Below it, there are a determinate `:horizontal` (default) progress bar and a `:vertical` progress bar.
611
+
608
612
  Code:
609
613
 
610
614
  [samples/hello/hello_progress_bar.rb](/samples/hello/hello_progress_bar.rb)
@@ -731,6 +735,12 @@ Code:
731
735
 
732
736
  ![Mandelbrot Fractal Zoom 5](/images/glimmer-mandelbrot-zoom5.png)
733
737
 
738
+ ![Mandelbrot Fractal View Menu](/images/glimmer-mandelbrot-menu-view.png)
739
+
740
+ ![Mandelbrot Fractal Cores Menu](/images/glimmer-mandelbrot-menu-cores.png)
741
+
742
+ ![Mandelbrot Fractal Help Menu](/images/glimmer-mandelbrot-menu-help.png)
743
+
734
744
  ### External Samples
735
745
 
736
746
  #### Glimmer Calculator
@@ -2,16 +2,16 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: glimmer-dsl-swt 4.18.4.10 ruby lib
5
+ # stub: glimmer-dsl-swt 4.18.4.11 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "glimmer-dsl-swt".freeze
9
- s.version = "4.18.4.10"
9
+ s.version = "4.18.4.11"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib".freeze]
13
13
  s.authors = ["AndyMaleh".freeze]
14
- s.date = "2021-02-16"
14
+ s.date = "2021-02-19"
15
15
  s.description = "Glimmer DSL for SWT (JRuby Desktop Development GUI Framework) is a native-GUI cross-platform desktop development library written in JRuby, an OS-threaded faster JVM version of Ruby. Glimmer's main innovation is a declarative Ruby DSL that enables productive and efficient authoring of desktop application user-interfaces by relying on the robust Eclipse SWT library. Glimmer additionally innovates by having built-in data-binding support, which greatly facilitates synchronizing the GUI with domain models, thus achieving true decoupling of object oriented components and enabling developers to solve business problems (test-first) without worrying about GUI concerns, or alternatively drive development GUI-first, and then write clean business models (test-first) afterwards. Not only does Glimmer provide a large set of GUI widgets, but it also supports drawing Canvas Graphics like Shapes and Animations. To get started quickly, Glimmer offers scaffolding options for Apps, Gems, and Custom Widgets. Glimmer also includes native-executable packaging support, sorely lacking in other libraries, thus enabling the delivery of desktop apps written in Ruby as truly native DMG/PKG/APP files on the Mac + App Store, MSI/EXE files on Windows, and Gem Packaged Shell Scripts on Linux.".freeze
16
16
  s.email = "andy.am@gmail.com".freeze
17
17
  s.executables = ["glimmer".freeze, "girb".freeze]
@@ -32,7 +32,7 @@ module Glimmer
32
32
  include_package 'org.eclipse.swt.widgets'
33
33
 
34
34
  def interpret(parent, keyword, *args, &block)
35
- Glimmer::SWT::ColorProxy.flyweight(*args)
35
+ Glimmer::SWT::ColorProxy.create(*args)
36
36
  end
37
37
  end
38
38
  end
@@ -46,11 +46,14 @@ module Glimmer
46
46
 
47
47
  def interpret(parent, keyword, *args, &block)
48
48
  options = args.last.is_a?(Hash) ? args.pop : {}
49
- UI::CustomWidget.for(keyword).new(parent, *args, options, &block)
49
+ UI::CustomWidget.for(keyword).new(parent, *args, options, &block).tap do |new_custom_widget|
50
+ new_custom_widget.body_root.paint_pixel_by_pixel(&block) if block&.parameters&.count == 2
51
+ end
50
52
  end
51
53
 
52
54
  def add_content(parent, &block)
53
55
  # TODO consider avoiding source_location
56
+ return if block&.parameters&.count == 2
54
57
  if block.source_location == parent.content&.__getobj__.source_location
55
58
  parent.content.call(parent) unless parent.content.called?
56
59
  else
@@ -40,11 +40,18 @@ module Glimmer
40
40
 
41
41
  def interpret(parent, keyword, *args, &block)
42
42
  options = args.last.is_a?(Hash) ? args.last : {}
43
+ coordinate_args = args.size == (options.empty? ? 2 : 3)
43
44
  args.unshift(parent) unless parent.nil? || options[:top_level]
44
- Glimmer::SWT::ImageProxy.new(*args, &block)
45
+ @create_pixel_by_pixel = coordinate_args && block&.parameters&.count == 2
46
+ if @create_pixel_by_pixel
47
+ Glimmer::SWT::ImageProxy.create_pixel_by_pixel(*args, &block)
48
+ else
49
+ Glimmer::SWT::ImageProxy.create(*args, &block)
50
+ end
45
51
  end
46
52
 
47
53
  def add_content(parent, &block)
54
+ return if @create_pixel_by_pixel || block&.parameters&.count == 2
48
55
  super
49
56
  parent.post_add_content
50
57
  end
@@ -40,10 +40,13 @@ module Glimmer
40
40
  end
41
41
 
42
42
  def interpret(parent, keyword, *args, &block)
43
- Glimmer::SWT::WidgetProxy.create(keyword, parent, args)
43
+ Glimmer::SWT::WidgetProxy.create(keyword, parent, args).tap do |new_widget_proxy|
44
+ new_widget_proxy.paint_pixel_by_pixel(&block) if block&.parameters&.count == 2
45
+ end
44
46
  end
45
47
 
46
48
  def add_content(parent, &block)
49
+ return if block&.parameters&.count == 2
47
50
  super
48
51
  parent.post_add_content
49
52
  parent.finish_add_content!
@@ -33,7 +33,7 @@ module Glimmer
33
33
  include_package 'org.eclipse.swt.graphics'
34
34
 
35
35
  class << self
36
- def flyweight(*args)
36
+ def create(*args)
37
37
  flyweight_color_proxies[args] ||= new(*args)
38
38
  end
39
39
 
@@ -64,6 +64,18 @@ module Glimmer
64
64
  respond_to?(method_name)
65
65
  end
66
66
 
67
+ def can_handle_observation_request?(observation_request)
68
+ @styled_text_proxy.can_handle_observation_request?(observation_request)
69
+ rescue
70
+ super
71
+ end
72
+
73
+ def handle_observation_request(observation_request, &block)
74
+ @styled_text_proxy.handle_observation_request(observation_request, &block)
75
+ rescue
76
+ super
77
+ end
78
+
67
79
  def root_block=(block)
68
80
  body_root.content(&block)
69
81
  end
@@ -153,6 +165,7 @@ module Glimmer
153
165
  top_margin 5
154
166
  right_margin 5
155
167
  bottom_margin 5
168
+ tabs 2
156
169
 
157
170
  if default_behavior
158
171
  on_key_pressed { |event|
@@ -166,6 +179,15 @@ module Glimmer
166
179
  jump_to_end_of_line
167
180
  end
168
181
  }
182
+ on_verify_text { |verify_event|
183
+ if verify_event.text == "\n"
184
+ line_index = verify_event.widget.get_line_at_offset(verify_event.widget.get_caret_offset)
185
+ line = verify_event.widget.get_line(line_index)
186
+ line_indent = line.match(/^([ ]*)/)[1].to_s.size
187
+ verify_event.text += ' '*line_indent
188
+ verify_event.text += ' '*2 if line.strip.end_with?('{') || line.strip.match(/do([ ]*[|][^|]*[|])?$/) || line.start_with?('class') || line.start_with?('module') || line.strip.start_with?('def')
189
+ end
190
+ }
169
191
  end
170
192
 
171
193
  on_modify_text { |event|
@@ -51,6 +51,50 @@ module Glimmer
51
51
  shapes.dup.each {|s| s.dispose(dispose_images: dispose_images, dispose_patterns: dispose_patterns) } if requires_shape_disposal?
52
52
  end
53
53
 
54
+ def paint_pixel_by_pixel(width = nil, height = nil, &each_pixel_color)
55
+ if @image_double_buffered
56
+ work = lambda do |paint_event|
57
+ width ||= swt_drawable.bounds.width
58
+ height ||= swt_drawable.bounds.height
59
+ @image_proxy_buffer ||= ImageProxy.create_pixel_by_pixel(width, height, &each_pixel_color)
60
+ @image_proxy_buffer.shape(self).paint(paint_event)
61
+ end
62
+ else
63
+ work = lambda do |paint_event_or_image|
64
+ the_gc = paint_event_or_image.gc
65
+ current_foreground = nil
66
+ width ||= swt_drawable.bounds.width
67
+ height ||= swt_drawable.bounds.height
68
+ height.times do |y|
69
+ width.times do |x|
70
+ new_foreground = each_pixel_color.call(x, y)
71
+ new_foreground = Glimmer::SWT::ColorProxy.create(new_foreground, ensure_bounds: false) unless new_foreground.is_a?(ColorProxy) || new_foreground.is_a?(Color)
72
+ new_foreground = new_foreground.swt_color if new_foreground.is_a?(Glimmer::SWT::ColorProxy)
73
+ the_gc.foreground = current_foreground = new_foreground unless new_foreground == current_foreground
74
+ the_gc.draw_point x, y
75
+ end
76
+ end
77
+ end
78
+ end
79
+ if respond_to?(:gc)
80
+ work.call(self)
81
+ else
82
+ on_swt_paint(&work)
83
+ end
84
+ end
85
+
86
+ def swt_drawable
87
+ swt_drawable = nil
88
+ if respond_to?(:swt_image)
89
+ swt_drawable = swt_image
90
+ elsif respond_to?(:swt_display)
91
+ swt_drawable = swt_display
92
+ elsif respond_to?(:swt_widget)
93
+ swt_drawable = swt_widget
94
+ end
95
+ swt_drawable
96
+ end
97
+
54
98
  def deregister_shape_painting
55
99
  @paint_listener_proxy&.deregister
56
100
  end
@@ -308,7 +308,11 @@ module Glimmer
308
308
  else
309
309
  @properties['background'] = [@parent.background] if fill? && !has_some_background?
310
310
  @properties['foreground'] = [@parent.foreground] if @parent.respond_to?(:foreground) && draw? && !has_some_foreground?
311
+ # TODO regarding alpha, make sure to reset it to parent stored alpha once we allow setting shape properties on parents directly without shapes
312
+ @properties['alpha'] ||= [255]
311
313
  @properties['font'] = [@parent.font] if @parent.respond_to?(:font) && draw? && !@properties.keys.map(&:to_s).include?('font')
314
+ # TODO regarding transform, make sure to reset it to parent stored alpha once we allow setting shape properties on parents directly without shapes
315
+ # Also do that with all future-added properties
312
316
  @properties['transform'] = [nil] if @parent.respond_to?(:transform) && !@properties.keys.map(&:to_s).include?('transform')
313
317
  @properties.each do |property, args|
314
318
  method_name = attribute_setter(property)
@@ -34,13 +34,24 @@ module Glimmer
34
34
  include Properties
35
35
 
36
36
  class << self
37
- def create(*args)
37
+ include_package 'org.eclipse.swt.graphics'
38
+
39
+ def create(*args, &content)
38
40
  if args.size == 1 && args.first.is_a?(ImageProxy)
39
41
  args.first
40
42
  else
41
- new(*args)
43
+ new(*args, &content)
42
44
  end
43
45
  end
46
+
47
+ def create_pixel_by_pixel(*args, &each_pixel_color)
48
+ image_proxy = create(*args)
49
+ options = args.last.is_a?(Hash) ? args.pop : {}
50
+ height = args[-1]
51
+ width = args[-2]
52
+ image_proxy.paint_pixel_by_pixel(width, height, &each_pixel_color)
53
+ image_proxy
54
+ end
44
55
  end
45
56
 
46
57
  include_package 'org.eclipse.swt.widgets'
@@ -88,7 +99,7 @@ module Glimmer
88
99
  # TODO consider adding a get_data/set_data method to conform with other SWT widgets
89
100
  @swt_image.singleton_class.define_method(:dispose) do
90
101
  proxy.clear_shapes
91
- super
102
+ super()
92
103
  end
93
104
  post_add_content if content.nil?
94
105
  end
@@ -55,7 +55,7 @@ class Mandelbrot
55
55
  end
56
56
 
57
57
  def processor_count
58
- @processor_count ||= Concurrent.processor_count
58
+ @processor_count ||= Concurrent.physical_processor_count
59
59
  end
60
60
  end
61
61
 
@@ -222,8 +222,8 @@ class MandelbrotFractal
222
222
  on_mouse_up { |mouse_event|
223
223
  if !@drag_detected
224
224
  origin = @scrolled_composite.origin
225
- @location_x = [[origin.x + mouse_event.x - @scrolled_composite.bounds.width / 2.0, 0].max, @scrolled_composite.bounds.width].min
226
- @location_y = [[origin.y + mouse_event.y - @scrolled_composite.bounds.height / 2.0, 0].max, @scrolled_composite.bounds.height].min
225
+ @location_x = mouse_event.x
226
+ @location_y = mouse_event.y
227
227
  if mouse_event.button == 1
228
228
  zoom_in
229
229
  elsif mouse_event.button > 2
@@ -265,7 +265,7 @@ class MandelbrotFractal
265
265
  menu {
266
266
  text '&Cores'
267
267
 
268
- Concurrent.processor_count.times {|n|
268
+ Concurrent.physical_processor_count.times {|n|
269
269
  processor_number = n + 1
270
270
  menu_item(:radio) {
271
271
  text "&#{processor_number}"
@@ -279,10 +279,10 @@ class MandelbrotFractal
279
279
  accelerator COMMAND, :alt, (processor_number - 20).to_s
280
280
  end
281
281
 
282
- selection true if processor_number == Concurrent.processor_count
282
+ selection true if processor_number == Concurrent.physical_processor_count
283
283
 
284
284
  on_widget_selected {
285
- Mandelbrot.processor_count = n
285
+ Mandelbrot.processor_count = processor_number
286
286
  }
287
287
  }
288
288
  }
@@ -316,21 +316,16 @@ class MandelbrotFractal
316
316
  width = the_mandelbrot.width
317
317
  height = the_mandelbrot.height
318
318
  pixels = the_mandelbrot.points
319
- new_mandelbrot_image = image(width, height, top_level: true) # invoke as a top-level parentless keyword to avoid nesting under any widget
320
- new_mandelbrot_image_gc = new_mandelbrot_image.gc
321
- current_foreground = nil
322
319
  Mandelbrot.work_in_progress = "Consuming Points To Build Image for Zoom #{mandelbrot_zoom}x"
323
- Mandelbrot.progress = Mandelbrot::PROGRESS_MAX
320
+ Mandelbrot.progress = Mandelbrot::PROGRESS_MAX + 1
324
321
  point_index = 0
325
322
  point_count = width*height
326
- height.times { |y|
327
- width.times { |x|
328
- new_foreground = color_palette[pixels[y][x]]
329
- new_mandelbrot_image_gc.foreground = current_foreground = new_foreground unless new_foreground == current_foreground
330
- new_mandelbrot_image_gc.draw_point x, y
331
- point_index += 1
332
- Mandelbrot.progress -= 1 if (Mandelbrot::PROGRESS_MAX - (point_index.to_f / point_count.to_f)*Mandelbrot::PROGRESS_MAX) < Mandelbrot.progress
333
- }
323
+ # invoke as a top-level parentless keyword to avoid nesting under any widget
324
+ new_mandelbrot_image = image(width, height, top_level: true) { |x, y|
325
+ point_index += 1
326
+ Mandelbrot.progress -= 1 if (Mandelbrot::PROGRESS_MAX - (point_index.to_f / point_count.to_f)*Mandelbrot::PROGRESS_MAX) < Mandelbrot.progress
327
+ pixel_color_index = pixels[y][x]
328
+ color_palette[pixel_color_index]
334
329
  }
335
330
  Mandelbrot.progress = 0
336
331
  flyweight_mandelbrot_images[mandelbrot_zoom] = new_mandelbrot_image
@@ -387,8 +382,9 @@ class MandelbrotFractal
387
382
  @canvas.set_size @mandelbrot_image.bounds.width, @mandelbrot_image.bounds.height
388
383
  @scrolled_composite.swt_widget.set_min_size(Point.new(@mandelbrot_image.bounds.width, @mandelbrot_image.bounds.height))
389
384
  if @location_x && @location_y
385
+ # center on mouse click location
390
386
  factor = (zoom / last_zoom)
391
- @scrolled_composite.set_origin(factor*@location_x, factor*@location_y)
387
+ @scrolled_composite.set_origin(factor*@location_x - @scrolled_composite.client_area.width/2.0, factor*@location_y - @scrolled_composite.client_area.height/2.0)
392
388
  @location_x = @location_y = nil
393
389
  end
394
390
  update_mandelbrot_shell_title!
@@ -404,7 +400,7 @@ class MandelbrotFractal
404
400
  Left-click to zoom in.
405
401
  Right-click to zoom out.
406
402
  Scroll or drag to pan.
407
- Lower cores to get more responsive interaction.
403
+ Adjust cores to get a more responsive interaction.
408
404
 
409
405
  Enjoy!
410
406
  MULTI_LINE_STRING
@@ -219,7 +219,7 @@ class MetaSampleApplication
219
219
  SampleDirectory.sample_directories.each { |sample_directory|
220
220
  expand_item {
221
221
  layout_data(:fill, :fill, true, true)
222
- text " #{sample_directory.name} Samples"
222
+ text " #{sample_directory.name} Samples (#{sample_directory.samples.count})"
223
223
 
224
224
  radio_group { |radio_group_proxy|
225
225
  row_layout(:vertical) {
@@ -46,7 +46,7 @@ class HelloCombo
46
46
  text 'Hello, Combo!'
47
47
 
48
48
  combo(:read_only) {
49
- selection bind(person, :country)
49
+ selection bind(person, :country) # also binds to country_options by convention
50
50
  }
51
51
 
52
52
  button {
@@ -59,7 +59,7 @@ class HelloListMultiSelection
59
59
  text 'Hello, List Multi Selection!'
60
60
 
61
61
  list(:multi) {
62
- selection bind(person, :provinces)
62
+ selection bind(person, :provinces) # also binds to provinces_options by convention
63
63
  }
64
64
 
65
65
  button {
@@ -44,7 +44,7 @@ class HelloListSingleSelection
44
44
  text 'Hello, List Single Selection!'
45
45
 
46
46
  list {
47
- selection bind(person, :country)
47
+ selection bind(person, :country) # also binds to country_options by convention
48
48
  }
49
49
 
50
50
  button {
@@ -110,6 +110,8 @@ class HelloProgressBar
110
110
  # (killing is not dangerous since it is only a thread about updating progress)
111
111
  @current_thread&.kill
112
112
  @current_thread = Thread.new {
113
+ # GUI updates must happen in sync_exec calls.
114
+ # Alternatively, add `sync_exec: true` to all the updated property `bind(...)` statements above
113
115
  sync_exec { @progress_model.selection = @progress_model.minimum }
114
116
  (@progress_model.minimum..@progress_model.maximum).to_a.each do |n|
115
117
  sync_exec {
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: glimmer-dsl-swt
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.18.4.10
4
+ version: 4.18.4.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - AndyMaleh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-02-16 00:00:00.000000000 Z
11
+ date: 2021-02-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement