glimmer-dsl-libui 0.7.8 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,22 +1,24 @@
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 LibUI 0.7.8
2
- ## Prerequisite-Free Ruby Desktop Development GUI Library
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 LibUI ([Fukuoka Award Winning](http://www.digitalfukuoka.jp/topics/187?locale=ja))
2
+ ## Prerequisite-Free Ruby Desktop Development Cross-Platform Native GUI Library
3
3
  ### The Quickest Way From Zero To GUI
4
4
  [![Gem Version](https://badge.fury.io/rb/glimmer-dsl-libui.svg)](http://badge.fury.io/rb/glimmer-dsl-libui)
5
5
  [![Join the chat at https://gitter.im/AndyObtiva/glimmer](https://badges.gitter.im/AndyObtiva/glimmer.svg)](https://gitter.im/AndyObtiva/glimmer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
6
6
 
7
+ **[If You Liked Shoes, You'll Love Glimmer!](https://github.com/AndyObtiva/glimmer#faq)**
8
+
7
9
  (**[Fukuoka Ruby Award Competition 2022 Special Award Winner](https://andymaleh.blogspot.com/2022/02/glimmer-dsl-for-libui-wins-fukuoka-ruby.html)** [[Award Announcement]](http://www.digitalfukuoka.jp/topics/187?locale=ja))
8
10
 
9
11
  (**[***RubyConf 2022 Talk - Building Native GUI Apps in Ruby***](https://andymaleh.blogspot.com/2023/02/rubyconf-2022-talk-video-for-building.html)**)
10
12
 
11
13
  [**(Ruby Rogues Podcast Interview - Desktop Apps in Ruby ft. Andy)**](https://andymaleh.blogspot.com/2022/05/ruby-rogues-podcast-interview-desktop.html)
12
14
 
13
- [Glimmer](https://github.com/AndyObtiva/glimmer) DSL for [LibUI](https://github.com/libui-ng/libui-ng) is a prerequisite-free [MRI Ruby](https://www.ruby-lang.org) desktop development GUI (Graphical User Interface) library. No need to pre-install any prerequisites. Just install the [gem](https://rubygems.org/gems/glimmer-dsl-libui) and have platform-independent native GUI that just works!
15
+ [Glimmer](https://github.com/AndyObtiva/glimmer) DSL for [LibUI](https://github.com/libui-ng/libui-ng) is a [Fukuoka Award Winning](http://www.digitalfukuoka.jp/topics/187?locale=ja) prerequisite-free [MRI Ruby](https://www.ruby-lang.org) desktop development cross-platform native GUI (Graphical User Interface) library. No need to pre-install any prerequisites. Just install the [gem](https://rubygems.org/gems/glimmer-dsl-libui) and have cross-platform native GUI that just works on Mac, Windows, and Linux!
14
16
 
15
17
  Mac | Windows | Linux
16
18
  ----|---------|------
17
19
  ![glimmer-dsl-libui-mac-control-gallery.png](images/glimmer-dsl-libui-mac-control-gallery.png) | ![glimmer-dsl-libui-windows-control-gallery.png](images/glimmer-dsl-libui-windows-control-gallery.png) | ![glimmer-dsl-libui-linux-control-gallery.png](images/glimmer-dsl-libui-linux-control-gallery.png)
18
20
 
19
- [LibUI](https://github.com/libui-ng/libui-ng) is a relatively new C GUI library that renders native controls on every platform (similar to [SWT](https://www.eclipse.org/swt/), but without the heavy weight of the [Java Virtual Machine](https://www.java.com/en/)).
21
+ [LibUI](https://github.com/libui-ng/libui-ng) is a relatively new C GUI library that renders native controls on every platform (similar to [SWT](https://www.eclipse.org/swt/), but without the heavy weight of the [Java Virtual Machine](https://www.java.com/en/)). Applications built with Glimmer DSL for LibUI will provide the familiar native look, feel, and behavior of GUI on Mac, Windows, and Linux.
20
22
 
21
23
  The main trade-off in using [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) as opposed to [Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt) or [Glimmer DSL for Tk](https://github.com/AndyObtiva/glimmer-dsl-tk) is the fact that [SWT](https://www.eclipse.org/swt/) and [Tk](https://www.tcl.tk/) are more mature than mid-alpha [libui](https://github.com/libui-ng/libui-ng) as GUI toolkits. Still, if there is only a need to build a small simple application, [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) could be a good convenient choice due to having zero prerequisites (beyond Ruby and the dependencies included in the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui)). Also, just like [Glimmer DSL for Tk](https://github.com/AndyObtiva/glimmer-dsl-tk), its apps start instantly and have a small memory footprint. [LibUI](https://github.com/kojix2/LibUI) is a promising new GUI toolkit that might prove quite worthy in the future.
22
24
 
@@ -335,26 +337,18 @@ Mac | Windows | Linux
335
337
 
336
338
  NOTE: [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) is regularly catching up with changes in the C [libui-ng](https://github.com/libui-ng/libui-ng) library API and in beta mode. The C [libui-ng](https://github.com/libui-ng/libui-ng) is still mid-alpha, which is why [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) cannot be declared v1.0.0 yet. Please help make better by contributing, adopting for small or low risk projects, and providing feedback. The more feedback and issues you report the better.
337
339
 
338
- **[Glimmer](https://rubygems.org/gems/glimmer) DSL Comparison Table:**
339
- DSL | Platforms | Native? | Vector Graphics? | Pros | Cons | Prereqs
340
- ----|-----------|---------|------------------|------|------|--------
341
- [Glimmer DSL for SWT (JRuby Desktop Development GUI Framework)](https://github.com/AndyObtiva/glimmer-dsl-swt) | Mac / Windows / Linux | Yes | Yes (Canvas Shape DSL) | Very Mature / Scaffolding / Native Executable Packaging / Custom Widgets | Slow JRuby Startup Time / Heavy Memory Footprint | Java / JRuby
342
- [Glimmer DSL for Opal (Pure Ruby Web GUI and Auto-Webifier of Desktop Apps)](https://github.com/AndyObtiva/glimmer-dsl-opal) | All Web Browsers | No | Yes (Canvas Shape DSL) | Simpler than All JavaScript Technologies / Auto-Webify Desktop Apps | Setup Process / Only Rails 5 Support for Now | Rails
343
- [Glimmer DSL for LibUI (Prerequisite-Free Ruby Desktop Development GUI Library)](https://github.com/AndyObtiva/glimmer-dsl-libui) | Mac / Windows / Linux | Yes | Yes (Area API) | Fast Startup Time / Light Memory Footprint | LibUI is an Incomplete Mid-Alpha Only | None Other Than MRI Ruby
344
- [Glimmer DSL for Tk (Ruby Tk Desktop Development GUI Library)](https://github.com/AndyObtiva/glimmer-dsl-tk) | Mac / Windows / Linux | Some Native-Themed Widgets (Not Truly Native) | Yes (Canvas) | Fast Startup Time / Light Memory Footprint | Complicated Setup / Widgets Do Not Look Truly Native, Espcially on Linux | ActiveTcl / MRI Ruby
345
- [Glimmer DSL for GTK (Ruby-GNOME Desktop Development GUI Library)](https://github.com/AndyObtiva/glimmer-dsl-gtk) | Mac / Windows / Linux | Only on Linux | Yes (Cairo) | Complete Access to GNOME Features on Linux (Forte) | Not Native on Mac and Windows | None Other Than MRI Ruby on Linux / Brew Packages on Mac / MSYS & MING Toolchains on Windows / MRI Ruby
346
- [Glimmer DSL for FX (FOX Toolkit Ruby Desktop Development GUI Library)](https://github.com/AndyObtiva/glimmer-dsl-fx) | Mac (requires XQuartz) / Windows / Linux | No | Yes (Canvas) | No Prerequisites on Windows (Forte Since Binaries Are Included Out of The Box) | Widgets Do Not Look Native / Mac Usage Obtrusively Starts XQuartz | None Other Than MRI Ruby on Windows / XQuarts on Mac / MRI Ruby
347
- [Glimmer DSL for JFX (JRuby JavaFX Desktop Development GUI Library)](https://github.com/AndyObtiva/glimmer-dsl-jfx) | Mac / Windows / Linux | No | Yes (javafx.scene.shape and javafx.scene.canvas) | Rich in Custom Widgets | Slow JRuby Startup Time / Heavy Memory Footprint / Widgets Do Not Look Native | Java / JRuby / JavaFX SDK
348
- [Glimmer DSL for Swing (JRuby Swing Desktop Development GUI Library)](https://github.com/AndyObtiva/glimmer-dsl-swing) | Mac / Windows / Linux | No | Yes (Java2D) | Very Mature | Slow JRuby Startup Time / Heavy Memory Footprint / Widgets Do Not Look Native | Java / JRuby
349
- [Glimmer DSL for XML (& HTML)](https://github.com/AndyObtiva/glimmer-dsl-xml) | All Web Browsers | No | Yes (SVG) | Programmable / Lighter-weight Than Actual XML | XML Elements Are Sometimes Not Well-Named (Many Types of Input) | None
350
- [Glimmer DSL for CSS](https://github.com/AndyObtiva/glimmer-dsl-css) | All Web Browsers | No | Yes | Programmable | CSS Is Over-Engineered / Too Many Features To Learn | None
340
+ Learn more about the differences between various [Glimmer](https://github.com/AndyObtiva/glimmer) DSLs by looking at the **[Glimmer DSL Comparison Table](https://github.com/AndyObtiva/glimmer#glimmer-dsl-comparison-table)**.
351
341
 
352
342
  ## Table of Contents
353
343
 
354
344
  - [Glimmer DSL for LibUI](#)
355
- - [Glimmer GUI DSL Concepts](#glimmer-gui-dsl-concepts)
345
+ - [Setup](#setup)
356
346
  - [Usage](#usage)
347
+ - [Experimentation Usage](#experimentation-usage)
348
+ - [Prototyping Usage](#prototyping-usage)
349
+ - [Serious Usage](#serious-usage)
357
350
  - [Girb (Glimmer IRB)](#girb-glimmer-irb)
351
+ - [Glimmer GUI DSL Concepts](#glimmer-gui-dsl-concepts)
358
352
  - [API](#api)
359
353
  - [Supported Keywords](#supported-keywords)
360
354
  - [Common Control Properties](#common-control-properties)
@@ -373,9 +367,12 @@ DSL | Platforms | Native? | Vector Graphics? | Pros | Cons | Prereqs
373
367
  - [Area Listeners](#area-listeners)
374
368
  - [Area Methods/Attributes](#area-methods-attributes)
375
369
  - [Area Transform Matrix](#area-transform-matrix)
370
+ - [Area Composite Shape](#area-composite-shape)
376
371
  - [Area Animation](#area-animation)
377
372
  - [Smart Defaults and Conventions](#smart-defaults-and-conventions)
378
- - [Custom Keywords](#custom-keywords)
373
+ - [Custom Controls](#custom-controls)
374
+ - [Method-Based Custom Controls](#method-based-custom-controls)
375
+ - [Class-Based Custom Controls](#class-based-custom-controls)
379
376
  - [Observer Pattern](#observer-pattern)
380
377
  - [Data-Binding](#data-binding)
381
378
  - [Bidirectional (Two-Way) Data-Binding](#bidirectional-two-way-data-binding)
@@ -409,6 +406,197 @@ DSL | Platforms | Native? | Vector Graphics? | Pros | Cons | Prereqs
409
406
  - [Contributors](#contributors)
410
407
  - [License](#license)
411
408
 
409
+ ## Setup
410
+
411
+ Install [glimmer-dsl-libui](https://rubygems.org/gems/glimmer-dsl-libui) gem directly into a [maintained Ruby version](https://www.ruby-lang.org/en/downloads/):
412
+
413
+ ```
414
+ gem install glimmer-dsl-libui
415
+ ```
416
+
417
+ Or install via Bundler `Gemfile`:
418
+
419
+ ```ruby
420
+ gem 'glimmer-dsl-libui', '~> 0.9.0'
421
+ ```
422
+
423
+ Test that installation worked by running the [Glimmer Meta-Example](#examples):
424
+
425
+ ```
426
+ glimmer examples
427
+ ```
428
+
429
+ Or alternatively, run using the explicit Ruby command:
430
+
431
+ ```
432
+ ruby -r glimmer-dsl-libui -e "require 'examples/meta_example'"
433
+ ```
434
+
435
+ Mac | Windows | Linux
436
+ ----|---------|------
437
+ ![glimmer-dsl-libui-mac-meta-example.png](images/glimmer-dsl-libui-mac-meta-example.png) | ![glimmer-dsl-libui-windows-meta-example.png](images/glimmer-dsl-libui-windows-meta-example.png) | ![glimmer-dsl-libui-linux-meta-example.png](images/glimmer-dsl-libui-linux-meta-example.png)
438
+
439
+ ## Usage
440
+
441
+ Require [glimmer-dsl-libui](https://rubygems.org/gems/glimmer-dsl-libui) (whether through a Ruby `require` statement or `Bundler`) and then include the `Glimmer` or `Glimmer::LibUI::Application` module to enable access to the Glimmer GUI DSL in one of multiple approaches.
442
+
443
+ ### Experimentation Usage
444
+
445
+ For experimenting and learning, add `include Glimmer` into the top-level main object and start using the Glimmer GUI DSL directly.
446
+
447
+ Example including `Glimmer` at the top-level scope just for some prototyping/demoing/testing (you may copy/paste in [`girb`](#girb-glimmer-irb)):
448
+
449
+ ```ruby
450
+ require 'glimmer-dsl-libui'
451
+
452
+ include Glimmer
453
+
454
+ window('hello world', 300, 200) {
455
+ button('Button') {
456
+ on_clicked do
457
+ puts 'Button Clicked'
458
+ end
459
+ }
460
+ }.show
461
+ ```
462
+
463
+ ![usage mac](images/glimmer-dsl-libui-mac-usage.png)
464
+
465
+ ### Prototyping Usage
466
+
467
+ For prototyping, add `include Glimmer` into an actual class and start using the Glimmer GUI DSL in instance methods.
468
+
469
+ Example including `Glimmer` and manually implementing the `#launch` method (you may copy/paste in [`girb`](#girb-glimmer-irb)):
470
+
471
+ ```ruby
472
+ require 'glimmer-dsl-libui'
473
+
474
+ class SomeGlimmerApp
475
+ include Glimmer
476
+
477
+ def launch
478
+ window('hello world', 300, 200) {
479
+ button('Button') {
480
+ on_clicked do
481
+ puts 'Button Clicked'
482
+ end
483
+ }
484
+ }.show
485
+ end
486
+ end
487
+
488
+ SomeGlimmerApp.new.launch
489
+ ```
490
+
491
+ ![usage mac](images/glimmer-dsl-libui-mac-usage.png)
492
+
493
+ ### Serious Usage
494
+
495
+ For more serious usage, add `include Glimmer::LibUI::Application` into an actual class (it automatically includes the `Glimmer` module) to conveniently declare the GUI underneath a `body` block (with the option of implementing `before_body` and `after_body` hooks) and take advantage of the inherited `SomeClass::launch` method implementation that automatically calls `window.show` for you.
496
+
497
+ Example including `Glimmer::LibUI::Application` (you may copy/paste in [`girb`](#girb-glimmer-irb)):
498
+
499
+ ```ruby
500
+ require 'glimmer-dsl-libui'
501
+
502
+ class SomeGlimmerApp
503
+ include Glimmer::LibUI::Application
504
+
505
+ body {
506
+ window('hello world', 300, 200) {
507
+ button('Button') {
508
+ on_clicked do
509
+ puts 'Button Clicked'
510
+ end
511
+ }
512
+ }
513
+ }
514
+ end
515
+
516
+ SomeGlimmerApp.launch
517
+ ```
518
+
519
+ ![usage mac](images/glimmer-dsl-libui-mac-usage.png)
520
+
521
+ (note: `Glimmer::LibUI::Application` is an alias for `Glimmer::LibUI::CustomWindow` since that is what it represents)
522
+
523
+ If you are new to [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui), check out the [Glimmer GUI DSL Concepts](#glimmer-gui-dsl-concepts), [Glimmer Command](#glimmer-command), [Girb](#girb-glimmer-irb) and [Examples](#examples) to quickly learn through copy/paste. You may refer to the [API](#api) later on once you have gotten your feet wet with [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) and need more detailed reference information.
524
+
525
+
526
+ ## Glimmer Command
527
+
528
+ The `glimmer` command allows you to conveniently:
529
+ - Run Glimmer DSL for LibUI applications (via `glimmer [app_path]`)
530
+ - Run Glimmer DSL for LibUI included examples (via `glimmer examples`, which brings up the [Glimmer Meta-Example](https://github.com/AndyObtiva/glimmer-dsl-libui/blob/master/examples/meta_example.rb))
531
+
532
+ You can bring up usage instructions by running the `glimmer` command without arguments:
533
+
534
+ ```
535
+ glimmer
536
+ ```
537
+
538
+ ```
539
+ % bin/glimmer
540
+ Glimmer DSL for LibUI (Prerequisite-Free Ruby Desktop Development Cross-Platform Native GUI Library) - Ruby Gem: glimmer-dsl-libui v0.8.0
541
+
542
+ Usage: glimmer [--bundler] [--pd] [--quiet] [--debug] [--log-level=VALUE] [[ENV_VAR=VALUE]...] [[-ruby-option]...] (application.rb or task[task_args])
543
+
544
+ Runs Glimmer applications and tasks.
545
+
546
+ When applications are specified, they are run using Ruby,
547
+ automatically preloading the glimmer-dsl-libui Ruby gem.
548
+
549
+ Optionally, extra Glimmer options, Ruby options, and/or environment variables may be passed in.
550
+
551
+ Glimmer options:
552
+ - "--bundler=GROUP" : Activates gems in Bundler default group in Gemfile
553
+ - "--pd=BOOLEAN" : Requires puts_debuggerer to enable pd method
554
+ - "--quiet=BOOLEAN" : Does not announce file path of Glimmer application being launched
555
+ - "--debug" : Displays extra debugging information and enables debug logging
556
+ - "--log-level=VALUE" : Sets Glimmer's Ruby logger level ("ERROR" / "WARN" / "INFO" / "DEBUG"; default is none)
557
+
558
+ Tasks are run via rake. Some tasks take arguments in square brackets (surround with double-quotes if using Zsh).
559
+
560
+ Available tasks are below (if you do not see any, please add `require 'glimmer/rake_task'` to Rakefile and rerun or run rake -T):
561
+
562
+ Select a Glimmer task to run: (Press ↑/↓ arrow to move, Enter to select and letters to filter)
563
+ ‣ glimmer examples # Brings up the Glimmer Meta-Sample app to allow browsing, running, and viewing code of Glimmer samples
564
+ glimmer list:gems:customcontrol[query] # List Glimmer custom control gems available at rubygems.org (query is optional) [alt: list:gems:cc]
565
+ glimmer list:gems:customshape[query] # List Glimmer custom shape gems available at rubygems.org (query is optional) [alt: list:gems:cs]
566
+ glimmer list:gems:customwindow[query] # List Glimmer custom window gems available at rubygems.org (query is optional) [alt: list:gems:cw]
567
+ glimmer list:gems:dsl[query] # List Glimmer DSL gems available at rubygems.org (query is optional)
568
+ glimmer run[app_path] # Runs Glimmer app or custom window gem in the current directory, unless app_path is specified, then runs it instead (app_path is optional)
569
+ glimmer scaffold[app_name] # Scaffold Glimmer application directory structure to build a new app
570
+ glimmer scaffold:customcontrol[name,namespace] # Scaffold Glimmer::UI::CustomControl subclass (part of a view) under app/views (namespace is optional) [alt: scaffold:cc]
571
+ glimmer scaffold:customshape[name,namespace] # Scaffold Glimmer::UI::CustomShape subclass (part of a view) under app/views (namespace is optional) [alt: scaffold:cs]
572
+ glimmer scaffold:customwindow[name,namespace] # Scaffold Glimmer::UI::CustomWindow subclass (full window view) under app/views (namespace is optional) [alt: scaffold:cw]
573
+ glimmer scaffold:gem:customcontrol[name,namespace] # Scaffold Glimmer::UI::CustomControl subclass (part of a view) under its own Ruby gem project (namespace is required) [alt: scaffold:gem:cc]
574
+ glimmer scaffold:gem:customshape[name,namespace] # Scaffold Glimmer::UI::CustomShape subclass (part of a view) under its own Ruby gem project (namespace is required) [alt: scaffold:gem:cs]
575
+ glimmer scaffold:gem:customwindow[name,namespace] # Scaffold Glimmer::UI::CustomWindow subclass (full window view) under its own Ruby gem + app project (namespace is required) [alt: scaffold:gem:cw]
576
+ ```
577
+
578
+ On Mac and Linux, it brings up a TUI (Text-based User Interface) for interactive navigation and execution of Glimmer tasks (courtesy of [rake-tui](https://github.com/AndyObtiva/rake-tui)).
579
+
580
+ On Windows and ARM64 machines, it simply lists the available Glimmer tasks at the end (courtsey of [rake](https://github.com/ruby/rake)).
581
+
582
+ Note: If you encounter an issue running the `glimmer` command, run `bundle exec glimmer` instead.
583
+
584
+ ## Girb (Glimmer IRB)
585
+
586
+ You can run the `girb` command (`bin/girb` if you cloned the project locally) to do some quick and dirty experimentation and learning:
587
+
588
+ ```
589
+ girb
590
+ ```
591
+
592
+ This gives you `irb` with the `glimmer-dsl-libui` gem loaded and the `Glimmer` module mixed into the main object for easy experimentation with GUI.
593
+
594
+ ![glimmer-dsl-libui-girb.png](images/glimmer-dsl-libui-girb.png)
595
+
596
+ For a more advanced code editing tool, check out the [Meta-Example (The Example of Examples)](#examples).
597
+
598
+ Gotcha: On the Mac, when you close a window opened in `girb`, it remains open until you enter `exit` or open another GUI window.
599
+
412
600
  ## Glimmer GUI DSL Concepts
413
601
 
414
602
  The Glimmer GUI DSL provides object-oriented declarative hierarchical syntax for [LibUI](https://github.com/kojix2/LibUI) that:
@@ -532,115 +720,6 @@ window('hello world', 300, 200) {
532
720
  end
533
721
  }.show
534
722
  ```
535
-
536
- ## Usage
537
-
538
- Install [glimmer-dsl-libui](https://rubygems.org/gems/glimmer-dsl-libui) gem directly into a [maintained Ruby version](https://www.ruby-lang.org/en/downloads/):
539
-
540
- ```
541
- gem install glimmer-dsl-libui
542
- ```
543
-
544
- Or install via Bundler `Gemfile`:
545
-
546
- ```ruby
547
- gem 'glimmer-dsl-libui', '~> 0.7.8'
548
- ```
549
-
550
- Test that installation worked by running the [Meta-Example](#examples):
551
-
552
- ```
553
- ruby -r glimmer-dsl-libui -e "require 'examples/meta_example'"
554
- ```
555
-
556
- Mac | Windows | Linux
557
- ----|---------|------
558
- ![glimmer-dsl-libui-mac-meta-example.png](images/glimmer-dsl-libui-mac-meta-example.png) | ![glimmer-dsl-libui-windows-meta-example.png](images/glimmer-dsl-libui-windows-meta-example.png) | ![glimmer-dsl-libui-linux-meta-example.png](images/glimmer-dsl-libui-linux-meta-example.png)
559
-
560
- Now to use [glimmer-dsl-libui](https://rubygems.org/gems/glimmer-dsl-libui), add `require 'glimmer-dsl-libui'` at the top.
561
-
562
- Afterwards, `include Glimmer` into the top-level main object for testing or into an actual class for serious usage.
563
-
564
- Alternatively, `include Glimmer::LibUI::Application` to conveniently declare the GUI `body` and run via the `::launch` method (`Glimmer::LibUI::Application` is an alias for `Glimmer::LibUI::CustomWindow` since that is what it represents).
565
-
566
- Example including `Glimmer::LibUI::Application` (you may copy/paste in [`girb`](#girb-glimmer-irb)):
567
-
568
- ```ruby
569
- require 'glimmer-dsl-libui'
570
-
571
- class SomeGlimmerApp
572
- include Glimmer::LibUI::Application
573
-
574
- body {
575
- window('hello world', 300, 200) {
576
- button('Button') {
577
- on_clicked do
578
- puts 'Button Clicked'
579
- end
580
- }
581
- }
582
- }
583
- end
584
-
585
- SomeGlimmerApp.launch
586
- ```
587
-
588
- Example including `Glimmer` and manually implementing the `#launch` method (you may copy/paste in [`girb`](#girb-glimmer-irb)):
589
-
590
- ```ruby
591
- require 'glimmer-dsl-libui'
592
-
593
- class SomeGlimmerApp
594
- include Glimmer
595
-
596
- def launch
597
- window('hello world', 300, 200) {
598
- button('Button') {
599
- on_clicked do
600
- puts 'Button Clicked'
601
- end
602
- }
603
- }.show
604
- end
605
- end
606
-
607
- SomeGlimmerApp.new.launch
608
- ```
609
-
610
- Example including `Glimmer` at the top-level scope just for some prototyping/demoing/testing (you may copy/paste in [`girb`](#girb-glimmer-irb)):
611
-
612
- ```ruby
613
- require 'glimmer-dsl-libui'
614
-
615
- include Glimmer
616
-
617
- window('hello world', 300, 200) {
618
- button('Button') {
619
- on_clicked do
620
- puts 'Button Clicked'
621
- end
622
- }
623
- }.show
624
- ```
625
-
626
- If you are new to [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui), check out [Girb](#girb-glimmer-irb) and [Examples](#examples) to quickly learn through copy/paste. You may refer to the [API](#api) later on once you have gotten your feet wet with [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) and need more detailed reference information.
627
-
628
- ## Girb (Glimmer IRB)
629
-
630
- You can run the `girb` command (`bin/girb` if you cloned the project locally) to do some quick and dirty experimentation and learning:
631
-
632
- ```
633
- girb
634
- ```
635
-
636
- This gives you `irb` with the `glimmer-dsl-libui` gem loaded and the `Glimmer` module mixed into the main object for easy experimentation with GUI.
637
-
638
- ![glimmer-dsl-libui-girb.png](images/glimmer-dsl-libui-girb.png)
639
-
640
- For a more advanced code editing tool, check out the [Meta-Example (The Example of Examples)](#examples).
641
-
642
- Gotcha: On the Mac, when you close a window opened in `girb`, it remains open until you enter `exit` or open another GUI window.
643
-
644
723
  ## API
645
724
 
646
725
  Any control returned by a [Glimmer GUI DSL](#glimmer-gui-dsl-concepts) keyword declaration can be introspected for its properties and updated via object-oriented attributes (standard Ruby `attr`/`attr=` or `set_attr`).
@@ -773,7 +852,7 @@ Keyword(Args) | Properties | Listeners
773
852
 
774
853
  All operations that could normally be called on `LibUI` can also be called on `Glimmer::LibUI`, but some have enhancements as detailed below.
775
854
 
776
- - `Glimmer::LibUI::queue_main(&block)`: queues an operation to be run on the main event loop at the earliest opportunity possible
855
+ - `Glimmer::LibUI::queue_main(&block)`: queues an operation to be run on the main event loop at the earliest opportunity possible. When writing multi-threaded code, it is required to wrap all code interacting with GUI objects (like `window` or `button`) from another `Thread` with `Glimmer::LibUI::queue_main { ... }`. See [Glimmer Meta-Example](https://github.com/AndyObtiva/glimmer-dsl-libui/blob/master/examples/meta_example.rb) for an example of using `Glimmer::LibUI::queue_main { ... }` inside another `Thread`.
777
856
  - `Glimmer::LibUI::timer(time_in_seconds=0.1, repeat: true, &block)`: calls block after time_in_seconds has elapsed, repeating indefinitely unless repeat is `false` or an `Integer` for finite number of repeats. Block can return `false` or `true` to override next repetition.
778
857
 
779
858
  There are additional useful `Glimmer::LibUI` operations that are not found in `LibUI`, which mostly help if you would like to do advanced lower level [LibUI](https://github.com/kojix2/LibUI) programming:
@@ -1563,6 +1642,170 @@ You can set a `matrix`/`transform` on `area` directly to conveniently apply to a
1563
1642
 
1564
1643
  Note that `area`, `path`, and nested shapes are all truly declarative, meaning they do not care about the ordering of calls to `fill`, `stroke`, and `transform`. Furthermore, any transform that is applied is reversed at the end of the block, so you never have to worry about the ordering of `transform` calls among different paths. You simply set a transform on the `path`s that need it and it is guaranteed to be called before all its content is drawn, and then undone afterwards to avoid affecting later paths. Matrix `transform` can be set on an entire `area` too, applying to all nested `path`s.
1565
1644
 
1645
+ #### Area Composite Shape
1646
+
1647
+ If you would like to build a composite shape that contains smaller sub-shapes, which would all get treated as a single unit,
1648
+ you can use the `shape` (or `composite_shape`) keyword, and wrap all the sub-shapes within the composite `shape`.
1649
+
1650
+ If you specify the `fill`, `stroke`, and `transform` at the `shape` level, they will get inherited by all sub-shapes that do not
1651
+ specify values for `fill`, `stroke`, or `transform` (though if they do, they override their parent's value).
1652
+
1653
+ When you use the `include?(x, y)` or `contain?(x, y)` method on a composite `shape`, it automatically includes all its aggregated shapes
1654
+ in the inclusion or containment check using the corresponding [PerfectShape](https://github.com/AndyObtiva/perfect-shape) object.
1655
+
1656
+ Example of a `cube` method-based custom shape built using the composite `shape` keyword:
1657
+
1658
+ ![glimmer-dsl-libui-mac-basic-composite-shape.gif](/images/glimmer-dsl-libui-mac-basic-composite-shape.gif)
1659
+
1660
+ ```ruby
1661
+ require 'glimmer-dsl-libui'
1662
+
1663
+ class BasicCompositeShape
1664
+ include Glimmer::LibUI::Application
1665
+
1666
+ body {
1667
+ window {
1668
+ title 'Basic Composite Shape'
1669
+ content_size 200, 225
1670
+
1671
+ @area = area {
1672
+ rectangle(0, 0, 200, 225) {
1673
+ fill :white
1674
+ }
1675
+
1676
+ 7.times do |n|
1677
+ x_location = (rand*125).to_i%200 + (rand*15).to_i
1678
+ y_location = (rand*125).to_i%200 + (rand*15).to_i
1679
+ shape_color = [rand*125 + 130, rand*125 + 130, rand*125 + 130]
1680
+ shape_size = 20+n
1681
+
1682
+ cube(
1683
+ location_x: x_location,
1684
+ location_y: y_location,
1685
+ rectangle_width: shape_size*2,
1686
+ rectangle_height: shape_size,
1687
+ cube_height: shape_size*2,
1688
+ background_color: shape_color,
1689
+ line_thickness: 2
1690
+ ) { |the_shape|
1691
+ on_mouse_up do |area_mouse_event|
1692
+ # Change color on mouse up without dragging
1693
+ if @drag_shape.nil?
1694
+ background_color = [rand(255), rand(255), rand(255)]
1695
+ the_shape.fill = background_color
1696
+ end
1697
+ end
1698
+
1699
+ on_mouse_drag_start do |area_mouse_event|
1700
+ @drag_shape = the_shape
1701
+ @drag_x = area_mouse_event[:x]
1702
+ @drag_y = area_mouse_event[:y]
1703
+ end
1704
+
1705
+ on_mouse_drag do |area_mouse_event|
1706
+ if @drag_shape && @drag_x && @drag_y
1707
+ drag_distance_width = area_mouse_event[:x] - @drag_x
1708
+ drag_distance_height = area_mouse_event[:y] - @drag_y
1709
+ @drag_shape.x += drag_distance_width
1710
+ @drag_shape.y += drag_distance_height
1711
+ @drag_x = area_mouse_event[:x]
1712
+ @drag_y = area_mouse_event[:y]
1713
+ end
1714
+ end
1715
+
1716
+ on_mouse_drop do |area_mouse_event|
1717
+ @drag_shape = nil
1718
+ @drag_x = nil
1719
+ @drag_y = nil
1720
+ end
1721
+ }
1722
+ end
1723
+
1724
+ # this general area on_mouse_drag listener is needed to ensure that dragging a shape
1725
+ # outside of its boundaries would still move the dragged shape
1726
+ on_mouse_drag do |area_mouse_event|
1727
+ if @drag_shape && @drag_x && @drag_y
1728
+ drag_distance_width = area_mouse_event[:x] - @drag_x
1729
+ drag_distance_height = area_mouse_event[:y] - @drag_y
1730
+ @drag_shape.x += drag_distance_width
1731
+ @drag_shape.y += drag_distance_height
1732
+ @drag_x = area_mouse_event[:x]
1733
+ @drag_y = area_mouse_event[:y]
1734
+ end
1735
+ end
1736
+
1737
+ on_mouse_drop do |area_mouse_event|
1738
+ @drag_shape = nil
1739
+ @drag_x = nil
1740
+ @drag_y = nil
1741
+ end
1742
+ }
1743
+ }
1744
+ }
1745
+
1746
+ # method-based custom shape using `shape` keyword as a composite shape containing nested shapes
1747
+ # that are declared with relative positioning
1748
+ def cube(location_x: 0,
1749
+ location_y: 0,
1750
+ rectangle_width: nil,
1751
+ rectangle_height: nil,
1752
+ cube_height: nil,
1753
+ background_color: :brown,
1754
+ line_thickness: 1,
1755
+ &content_block)
1756
+ default_size = 28
1757
+ rectangle_width ||= rectangle_height || cube_height || default_size
1758
+ rectangle_height ||= rectangle_width || cube_height || default_size
1759
+ cube_height ||= rectangle_width || rectangle_height || default_size
1760
+ foreground_color = [0, 0, 0, thickness: line_thickness]
1761
+
1762
+ # the shape keyword (alias for composite_shape) enables building a composite shape that is treated as one shape
1763
+ # like a cube containing polygons, a polyline, a rectangle, and a line
1764
+ # with the fill and stroke colors getting inherited by all children that do not specify them
1765
+ shape(location_x, location_y) { |the_shape|
1766
+ fill background_color
1767
+ stroke foreground_color
1768
+
1769
+ bottom = polygon(0, cube_height + rectangle_height / 2.0,
1770
+ rectangle_width / 2.0, cube_height,
1771
+ rectangle_width, cube_height + rectangle_height / 2.0,
1772
+ rectangle_width / 2.0, cube_height + rectangle_height) {
1773
+ # inherits fill property from parent shape if not set
1774
+ # inherits stroke property from parent shape if not set
1775
+ }
1776
+ body = rectangle(0, rectangle_height / 2.0, rectangle_width, cube_height) {
1777
+ # inherits fill property from parent shape if not set
1778
+ # stroke is overridden to ensure a different value from parent
1779
+ stroke thickness: 0
1780
+ }
1781
+ polyline(0, rectangle_height / 2.0 + cube_height,
1782
+ 0, rectangle_height / 2.0,
1783
+ rectangle_width, rectangle_height / 2.0,
1784
+ rectangle_width, rectangle_height / 2.0 + cube_height) {
1785
+ # inherits stroke property from parent shape if not set
1786
+ }
1787
+ top = polygon(0, rectangle_height / 2.0,
1788
+ rectangle_width / 2.0, 0,
1789
+ rectangle_width, rectangle_height / 2.0,
1790
+ rectangle_width / 2.0, rectangle_height) {
1791
+ # inherits fill property from parent shape if not set
1792
+ # inherits stroke property from parent shape if not set
1793
+ }
1794
+ line(rectangle_width / 2.0, cube_height + rectangle_height,
1795
+ rectangle_width / 2.0, rectangle_height) {
1796
+ # inherits stroke property from parent shape if not set
1797
+ }
1798
+
1799
+ content_block&.call(the_shape)
1800
+ }
1801
+ end
1802
+ end
1803
+
1804
+ BasicCompositeShape.launch
1805
+
1806
+
1807
+ ```
1808
+
1566
1809
  #### Area Animation
1567
1810
 
1568
1811
  If you need to animate `area` vector graphics, you just have to use the [`Glimmer::LibUI::timer`](#libui-operations) method along with making changes to shape attributes.
@@ -1696,17 +1939,21 @@ SpinnerExample.new.launch
1696
1939
  - Colors may be passed in as a hash of `:r`, `:g`, `:b`, `:a`, or `:red`, `:green`, `:blue`, `:alpha`, or [X11](https://en.wikipedia.org/wiki/X11_color_names) color like `:skyblue`, or 6-char hex or 3-char hex (as `Integer` or `String` with or without `0x` prefix)
1697
1940
  - Color alpha value defaults to `1.0` when not specified.
1698
1941
 
1699
- ### Custom Keywords
1942
+ ### Custom Controls
1700
1943
 
1701
- Custom keywords can be defined to represent custom controls (components) that provide new features or act as composites of [existing controls](#supported-keywords) that need to be reused multiple times in an application or across multiple applications. Custom keywords save a lot of development time, improving productivity and maintainability immensely.
1944
+ Custom controls can be defined to represent custom controls (components) that provide new features or act as composites of [existing controls](#supported-keywords) that need to be reused multiple times in an application or across multiple applications. Custom controls save a lot of development time, improving productivity and maintainability immensely.
1702
1945
 
1703
1946
  For example, you can define a custom `address_view` control as an aggregate of multiple `label` controls to reuse multiple times as a standard address View, displaying street, city, state, and zip code.
1704
1947
 
1705
- There are two ways to define custom keywords:
1948
+ There are two ways to define custom controls:
1706
1949
  - Method-Based: simply define a method representing the custom control you want (e.g. `address_view`) with any arguments needed (e.g. `address(address_model)`).
1707
1950
  - Class-Based: define a class matching the camelcased name of the custom control by convention (e.g. the `address_view` custom control keyword would have a class called `AddressView`) and `include Glimmer::LibUI::CustomControl`. Classes add the benefit of being able to distribute the custom controls into separate files and reuse externally from multiple places or share via Ruby gems.
1708
1951
 
1709
- It is OK to use the terms "custom keyword" and "custom control" synonymously though "custom keyword" is a broader term that covers things other than controls too like custom shapes (e.g. `cylinder`), custom attributed strings (e.g. `alternating_color_string`), and custom transforms (`isometric_transform`).
1952
+ It is OK to use the terms "custom control" and "custom keyword" synonymously though "custom keyword" is a broader term that covers things other than controls too like custom shapes (e.g. `cylinder`), custom attributed strings (e.g. `alternating_color_string`), and custom transforms (`isometric_transform`).
1953
+
1954
+ #### Method-Based Custom Controls
1955
+
1956
+ Simply define a method representing the custom control you want (e.g. `address_view`) with any arguments needed (e.g. `address(address_model)`).
1710
1957
 
1711
1958
  Example that defines `form_field`, `address_form`, `label_pair`, and `address_view` keywords (you may copy/paste in [`girb`](#girb-glimmer-irb)):
1712
1959
 
@@ -1805,7 +2052,9 @@ window('Method-Based Custom Keyword') {
1805
2052
 
1806
2053
  ![glimmer-dsl-libui-mac-method-based-custom-keyword.png](images/glimmer-dsl-libui-mac-method-based-custom-keyword.png)
1807
2054
 
1808
- You can also define Custom Window keywords, that is custom controls with `window` being the body root. These are also known as Applications. To define a Custom Window, you `include Glimmer::LibUI::CustomWindow` or `include Glimmer:LibUI::Application` and then you can invoke the `::launch` method on the class.
2055
+ #### Class-Based Custom Controls
2056
+
2057
+ Define a class matching the camelcased name of the custom control by convention (e.g. the `address_view` custom control keyword would have a class called `AddressView`) and `include Glimmer::LibUI::CustomControl`. Classes add the benefit of being able to distribute the custom controls into separate files and reuse externally from multiple places or share via Ruby gems.
1809
2058
 
1810
2059
  Example (you may copy/paste in [`girb`](#girb-glimmer-irb)):
1811
2060
 
@@ -1935,11 +2184,13 @@ ClassBasedCustomControls.launch
1935
2184
 
1936
2185
  ![glimmer-dsl-libui-mac-method-based-custom-keyword.png](images/glimmer-dsl-libui-mac-method-based-custom-keyword.png)
1937
2186
 
2187
+ You can also define Custom Window keywords, that is custom controls with `window` being the body root. These are also known as Applications. To define a Custom Window, you `include Glimmer::LibUI::CustomWindow` or `include Glimmer:LibUI::Application` and then you can invoke the `::launch` method on the class.
2188
+
1938
2189
  The [`area`](#area-api) control can be utilized to build non-native custom controls from scratch by leveraging vector graphics, formattable text, keyboard events, and mouse events. This is demonstrated in the [Area-Based Custom Controls](/docs/examples/GLIMMER-DSL-LIBUI-ADVANCED-EXAMPLES.md#area-based-custom-controls) example.
1939
2190
 
1940
- Defining custom keywords enables unlimited extension of the [Glimmer GUI DSL](#glimmer-gui-dsl). The sky is the limit on what can be done with custom keywords as a result. You can compose new visual vocabulary to build applications in any domain from higher concepts rather than [mere standard controls](#supported-keywords). For example, in a traffic signaling app, you could define `street`, `light_signal`, `traffic_sign`, and `car` as custom keywords and build your application from these concepts directly, saving enormous time and achieving much higher productivity.
2191
+ Defining custom controls enables unlimited extension of the [Glimmer GUI DSL](#glimmer-gui-dsl). The sky is the limit on what can be done with custom controls as a result. You can compose new visual vocabulary to build applications in any domain from higher concepts rather than [mere standard controls](#supported-keywords). For example, in a traffic signaling app, you could define `street`, `light_signal`, `traffic_sign`, and `car` as custom keywords and build your application from these concepts directly, saving enormous time and achieving much higher productivity.
1941
2192
 
1942
- Learn more from custom keyword usage in [Method-Based Custom Keyword](/docs/examples/GLIMMER-DSL-LIBUI-ADVANCED-EXAMPLES.md#method-based-custom-keyword), [Area-Based Custom Controls](/docs/examples/GLIMMER-DSL-LIBUI-ADVANCED-EXAMPLES.md#area-based-custom-controls), [Basic Scrolling Area](/docs/examples/GLIMMER-DSL-LIBUI-BASIC-EXAMPLES.md#basic-scrolling-area), [Histogram](/docs/examples/GLIMMER-DSL-LIBUI-ADVANCED-EXAMPLES.md#histogram), and [Tetris](/docs/examples/GLIMMER-DSL-LIBUI-ADVANCED-EXAMPLES.md#tetris) examples.
2193
+ Learn more from custom control usage in [Method-Based Custom Keyword](/docs/examples/GLIMMER-DSL-LIBUI-ADVANCED-EXAMPLES.md#method-based-custom-keyword), [Area-Based Custom Controls](/docs/examples/GLIMMER-DSL-LIBUI-ADVANCED-EXAMPLES.md#area-based-custom-controls), [Basic Scrolling Area](/docs/examples/GLIMMER-DSL-LIBUI-BASIC-EXAMPLES.md#basic-scrolling-area), [Histogram](/docs/examples/GLIMMER-DSL-LIBUI-ADVANCED-EXAMPLES.md#histogram), and [Tetris](/docs/examples/GLIMMER-DSL-LIBUI-ADVANCED-EXAMPLES.md#tetris) examples.
1943
2194
 
1944
2195
  ### Observer Pattern
1945
2196
 
@@ -2249,7 +2500,8 @@ Learn more from data-binding usage in [Login](/docs/examples/GLIMMER-DSL-LIBUI-A
2249
2500
  - `text` `string` `background` does not work on Windows due to an [issue in libui](https://github.com/andlabs/libui/issues/347).
2250
2501
  - `table` `progress_bar` column on Windows cannot be updated with a positive value if it started initially with `-1` (it ignores update to avoid crashing due to an issue in [libui](https://github.com/andlabs/libui) on Windows.
2251
2502
  - `radio_buttons` on Linux has an issue where it always selects the first item even if you did not set its `selected` value or set it to `-1` (meaning unselected). It works correctly on Mac and Windows.
2252
- - It seems that [libui](https://github.com/andlabs/libui) does not support nesting multiple `area` controls under a `grid` as only the first one shows up in that scenario. To workaround that limitation, use a `vertical_box` with nested `horizontal_box`s instead to include multiple `area`s in a GUI.
2503
+ - It seems that [libui](https://github.com/libui-ng/libui-ng) does not support nesting multiple `area` controls under a `grid` as only the first one shows up in that scenario. To workaround that limitation, use a `vertical_box` with nested `horizontal_box`s instead to include multiple `area`s in a GUI.
2504
+ - Both `multiline_entry` and `non_wrapping_multiline_entry` do not seem to play well with being nested in a `grid`. To get around the problem, I would use a combination of `vertical_box` and `horizontal_box`s instead.
2253
2505
  - As per the code of [examples/basic_transform.rb](/docs/examples/GLIMMER-DSL-LIBUI-BASIC-EXAMPLES.md#basic-transform), Windows requires different ordering of transforms than Mac and Linux.
2254
2506
  - `scrolling_area#scroll_to` does not seem to work on Windows and Linux, but works fine on Mac
2255
2507
 
@@ -2267,7 +2519,7 @@ To learn more about the [LibUI](https://github.com/kojix2/LibUI) API exposed thr
2267
2519
 
2268
2520
  I am documenting options for packaging, which I have not tried myself, but figured they would still be useful to add to the README.md until I can expand further effort into supporting packaging.
2269
2521
 
2270
- For Windows, the [LibUI](https://github.com/kojix2/LibUI) project recommends [OCRA](https://github.com/larsch/ocra) (One-Click Ruby Application), which builds Windows executables from Ruby source.
2522
+ For Windows, the [LibUI](https://github.com/kojix2/LibUI) project recommends [OCRA](https://github.com/larsch/ocra) (One-Click Ruby Application), which builds Windows executables from Ruby source. And, there is a newer fork of the project that supports newer versions of Ruby called [OCRAN](https://github.com/Largo/ocran).
2271
2523
 
2272
2524
  For Mac, consider [Platypus](https://github.com/sveinbjornt/Platypus) (builds a native Mac app from a Ruby script)
2273
2525
 
@@ -2275,6 +2527,8 @@ For Linux, simply package your app as a [Ruby Gem](https://guides.rubygems.org/w
2275
2527
 
2276
2528
  Also, there is a promising project called [ruby-packer](https://github.com/pmq20/ruby-packer) that supports all platforms.
2277
2529
 
2530
+ Last but not least, Ruby recently supported WASM, including the ability to [package a Ruby application as a WASI application](https://github.com/ruby/ruby.wasm#quick-example-how-to-package-your-ruby-application-as-a-wasi-application).
2531
+
2278
2532
  ## Glimmer Style Guide
2279
2533
 
2280
2534
  **1 - Control arguments are always wrapped by parentheses.**
@@ -2683,6 +2937,12 @@ https://github.com/kojix2/htsgrid
2683
2937
 
2684
2938
  ![hts grid screenshot](https://raw.githubusercontent.com/AndyObtiva/htsgrid/main/screenshot-00.png)
2685
2939
 
2940
+ ### Electric Avenue
2941
+
2942
+ This is built as an exploratory software prototype by [Ari Brown](https://github.com/seydar) (closed source software).
2943
+
2944
+ ![Electric Avenue](https://user-images.githubusercontent.com/16188/260890040-b4b28429-1789-4cdd-a708-45a2bd62b70f.png)
2945
+
2686
2946
  ## Process
2687
2947
 
2688
2948
  [Glimmer Process](https://github.com/AndyObtiva/glimmer/blob/master/PROCESS.md)