glimmer-dsl-libui 0.7.8 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.7.8
1
+ 0.9.0
data/bin/girb CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- # Copyright (c) 2020-2021 Andy Maleh
3
+ # Copyright (c) 2021-2023 Andy Maleh
4
4
  #
5
5
  # Permission is hereby granted, free of charge, to any person obtaining
6
6
  # a copy of this software and associated documentation files (the
data/bin/glimmer ADDED
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Copyright (c) 2021-2023 Andy Maleh
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining
6
+ # a copy of this software and associated documentation files (the
7
+ # "Software"), to deal in the Software without restriction, including
8
+ # without limitation the rights to use, copy, modify, merge, publish,
9
+ # distribute, sublicense, and/or sell copies of the Software, and to
10
+ # permit persons to whom the Software is furnished to do so, subject to
11
+ # the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be
14
+ # included in all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ require_relative '../lib/glimmer-dsl-libui'
25
+ require_relative '../lib/glimmer/launcher'
26
+
27
+ # Initialize launcher, consuming ARGV args that are for Glimmer only
28
+ launcher = Glimmer::Launcher.new(ARGV)
29
+
30
+ launcher.launch
@@ -25,6 +25,7 @@
25
25
  - [Basic Transform](#basic-transform)
26
26
  - [Basic Draw Text](#basic-draw-text)
27
27
  - [Basic Code Area](#basic-code-area)
28
+ - [Basic Composite Shape](#basic-composite-shape)
28
29
 
29
30
  ## Basic Window
30
31
 
@@ -2344,36 +2345,20 @@ Mac | Windows | Linux
2344
2345
 
2345
2346
  New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
2346
2347
 
2347
- ```ruby
2348
- require 'glimmer-dsl-libui'
2348
+ ## Basic Composite Shape
2349
2349
 
2350
- class BasicCodeArea
2351
- include Glimmer::LibUI::Application
2352
-
2353
- before_body do
2354
- @code = <<~CODE
2355
- # Greets target with greeting
2356
- def greet(greeting: 'Hello', target: 'World')
2357
-
2358
- puts "\#{greeting}, \#{target}!"
2359
- end
2360
-
2361
- greet
2362
- greet(target: 'Robert')
2363
- greet(greeting: 'Aloha')
2364
- greet(greeting: 'Aloha', target: 'Nancy')
2365
- greet(greeting: 'Howdy', target: 'Doodle')
2366
- CODE
2367
- end
2368
-
2369
- body {
2370
- window('Basic Code Area', 400, 300) {
2371
- margined true
2372
-
2373
- code_area(language: 'ruby', code: @code)
2374
- }
2375
- }
2376
- end
2350
+ [examples/basic_composite_shape.rb](/examples/basic_composite_shape.rb)
2351
+
2352
+ Run with this command from the root of the project if you cloned the project:
2377
2353
 
2378
- BasicCodeArea.launch
2379
2354
  ```
2355
+ ruby -r './lib/glimmer-dsl-libui' examples/basic_composite_shape.rb
2356
+ ```
2357
+
2358
+ Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
2359
+
2360
+ ```
2361
+ ruby -r glimmer-dsl-libui -e "require 'examples/basic_composite_shape.rb'"
2362
+ ```
2363
+
2364
+ ![glimmer-dsl-libui-mac-basic-composite-shape.gif](/images/glimmer-dsl-libui-mac-basic-composite-shape.gif)
@@ -0,0 +1,145 @@
1
+ require 'glimmer-dsl-libui'
2
+
3
+ class BasicCompositeShape
4
+ include Glimmer::LibUI::Application
5
+
6
+ body {
7
+ window {
8
+ title 'Basic Composite Shape'
9
+ content_size 200, 225
10
+
11
+ @area = area {
12
+ rectangle(0, 0, 200, 225) {
13
+ fill :white
14
+ }
15
+
16
+ 7.times do |n|
17
+ x_location = (rand*125).to_i%200 + (rand*15).to_i
18
+ y_location = (rand*125).to_i%200 + (rand*15).to_i
19
+ shape_color = [rand*125 + 130, rand*125 + 130, rand*125 + 130]
20
+ shape_size = 20+n
21
+
22
+ cube(
23
+ location_x: x_location,
24
+ location_y: y_location,
25
+ rectangle_width: shape_size*2,
26
+ rectangle_height: shape_size,
27
+ cube_height: shape_size*2,
28
+ background_color: shape_color,
29
+ line_thickness: 2
30
+ ) { |the_shape|
31
+ on_mouse_up do |area_mouse_event|
32
+ # Change color on mouse up without dragging
33
+ if @drag_shape.nil?
34
+ background_color = [rand(255), rand(255), rand(255)]
35
+ the_shape.fill = background_color
36
+ end
37
+ end
38
+
39
+ on_mouse_drag_start do |area_mouse_event|
40
+ @drag_shape = the_shape
41
+ @drag_x = area_mouse_event[:x]
42
+ @drag_y = area_mouse_event[:y]
43
+ end
44
+
45
+ on_mouse_drag do |area_mouse_event|
46
+ if @drag_shape && @drag_x && @drag_y
47
+ drag_distance_width = area_mouse_event[:x] - @drag_x
48
+ drag_distance_height = area_mouse_event[:y] - @drag_y
49
+ @drag_shape.x += drag_distance_width
50
+ @drag_shape.y += drag_distance_height
51
+ @drag_x = area_mouse_event[:x]
52
+ @drag_y = area_mouse_event[:y]
53
+ end
54
+ end
55
+
56
+ on_mouse_drop do |area_mouse_event|
57
+ @drag_shape = nil
58
+ @drag_x = nil
59
+ @drag_y = nil
60
+ end
61
+ }
62
+ end
63
+
64
+ # this general area on_mouse_drag listener is needed to ensure that dragging a shape
65
+ # outside of its boundaries would still move the dragged shape
66
+ on_mouse_drag do |area_mouse_event|
67
+ if @drag_shape && @drag_x && @drag_y
68
+ drag_distance_width = area_mouse_event[:x] - @drag_x
69
+ drag_distance_height = area_mouse_event[:y] - @drag_y
70
+ @drag_shape.x += drag_distance_width
71
+ @drag_shape.y += drag_distance_height
72
+ @drag_x = area_mouse_event[:x]
73
+ @drag_y = area_mouse_event[:y]
74
+ end
75
+ end
76
+
77
+ on_mouse_drop do |area_mouse_event|
78
+ @drag_shape = nil
79
+ @drag_x = nil
80
+ @drag_y = nil
81
+ end
82
+ }
83
+ }
84
+ }
85
+
86
+ # method-based custom shape using `shape` keyword as a composite shape containing nested shapes
87
+ # that are declared with relative positioning
88
+ def cube(location_x: 0,
89
+ location_y: 0,
90
+ rectangle_width: nil,
91
+ rectangle_height: nil,
92
+ cube_height: nil,
93
+ background_color: :brown,
94
+ line_thickness: 1,
95
+ &content_block)
96
+ default_size = 28
97
+ rectangle_width ||= rectangle_height || cube_height || default_size
98
+ rectangle_height ||= rectangle_width || cube_height || default_size
99
+ cube_height ||= rectangle_width || rectangle_height || default_size
100
+ foreground_color = [0, 0, 0, thickness: line_thickness]
101
+
102
+ # the shape keyword (alias for composite_shape) enables building a composite shape that is treated as one shape
103
+ # like a cube containing polygons, a polyline, a rectangle, and a line
104
+ # with the fill and stroke colors getting inherited by all children that do not specify them
105
+ shape(location_x, location_y) { |the_shape|
106
+ fill background_color
107
+ stroke foreground_color
108
+
109
+ bottom = polygon(0, cube_height + rectangle_height / 2.0,
110
+ rectangle_width / 2.0, cube_height,
111
+ rectangle_width, cube_height + rectangle_height / 2.0,
112
+ rectangle_width / 2.0, cube_height + rectangle_height) {
113
+ # inherits fill property from parent shape if not set
114
+ # inherits stroke property from parent shape if not set
115
+ }
116
+ body = rectangle(0, rectangle_height / 2.0, rectangle_width, cube_height) {
117
+ # inherits fill property from parent shape if not set
118
+ # stroke is overridden to ensure a different value from parent
119
+ stroke thickness: 0
120
+ }
121
+ polyline(0, rectangle_height / 2.0 + cube_height,
122
+ 0, rectangle_height / 2.0,
123
+ rectangle_width, rectangle_height / 2.0,
124
+ rectangle_width, rectangle_height / 2.0 + cube_height) {
125
+ # inherits stroke property from parent shape if not set
126
+ }
127
+ top = polygon(0, rectangle_height / 2.0,
128
+ rectangle_width / 2.0, 0,
129
+ rectangle_width, rectangle_height / 2.0,
130
+ rectangle_width / 2.0, rectangle_height) {
131
+ # inherits fill property from parent shape if not set
132
+ # inherits stroke property from parent shape if not set
133
+ }
134
+ line(rectangle_width / 2.0, cube_height + rectangle_height,
135
+ rectangle_width / 2.0, rectangle_height) {
136
+ # inherits stroke property from parent shape if not set
137
+ }
138
+
139
+ content_block&.call(the_shape)
140
+ }
141
+ end
142
+ end
143
+
144
+ BasicCompositeShape.launch
145
+
@@ -6,7 +6,7 @@ class ButtonCounter
6
6
  attr_accessor :count
7
7
 
8
8
  def initialize
9
- @count = 0
9
+ self.count = 0
10
10
  end
11
11
 
12
12
  def launch
Binary file
@@ -0,0 +1,26 @@
1
+ # Copyright (c) 2021-2023 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ # This Rakefile gets used from Glimmer::Launcher when the current directory for running the `glimmer` command
23
+ # does not have a Rakefile (e.g. during scaffolding).
24
+ # It is not needed when running from inside a scaffolded app or gem, or an app with a Rakefile that has
25
+ # `require 'glimmer/rake_task'`
26
+ require 'glimmer/rake_task'
@@ -33,8 +33,7 @@ module Glimmer
33
33
  end
34
34
 
35
35
  def interpret(parent, keyword, *args, &block)
36
- @@inverted_keyword_aliases = Glimmer::LibUI::ControlProxy::KEYWORD_ALIASES.invert unless defined?(@@inverted_keyword_aliases)
37
- keyword = @@inverted_keyword_aliases[keyword] || keyword
36
+ keyword = Glimmer::LibUI::ControlProxy::KEYWORD_ALIASES[keyword] || keyword
38
37
  Glimmer::LibUI::ControlProxy.create(keyword, parent, args, &block)
39
38
  end
40
39
 
@@ -42,6 +42,7 @@ module Glimmer
42
42
  end
43
43
 
44
44
  def interpret(parent, keyword, *args, &block)
45
+ keyword = Glimmer::LibUI::Shape::KEYWORD_ALIASES[keyword] || keyword
45
46
  args = [args] if args.size > 1 && Glimmer::LibUI::Shape.shape_class(keyword).parameters.size == 1
46
47
  Glimmer::LibUI::Shape.create(keyword, parent, args, &block)
47
48
  end
@@ -0,0 +1,231 @@
1
+ # Copyright (c) 2007-2023 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ if ARGV.include?('--bundler') && File.exist?(File.expand_path('./Gemfile'))
23
+ require 'bundler'
24
+ Bundler.setup(:default)
25
+ end
26
+ require 'fileutils'
27
+ require 'os'
28
+
29
+ module Glimmer
30
+ # Launcher of glimmer applications and main entry point for the `glimmer` command.
31
+ class Launcher
32
+ # TODO update the verbiage below for Glimmer DSL for LibUI
33
+ TEXT_USAGE = <<~MULTI_LINE_STRING
34
+ Glimmer DSL for LibUI (Prerequisite-Free Ruby Desktop Development Cross-Platform Native GUI Library) - Ruby Gem: glimmer-dsl-libui v#{File.read(File.expand_path('../../../VERSION', __FILE__))}
35
+ Usage: glimmer [--bundler] [--pd] [--quiet] [--debug] [--log-level=VALUE] [[ENV_VAR=VALUE]...] [[-ruby-option]...] (application.rb or task[task_args])
36
+
37
+ Runs Glimmer applications and tasks.
38
+
39
+ When applications are specified, they are run using Ruby,
40
+ automatically preloading the glimmer-dsl-libui Ruby gem.
41
+
42
+ Optionally, extra Glimmer options, Ruby options, and/or environment variables may be passed in.
43
+
44
+ Glimmer options:
45
+ - "--bundler=GROUP" : Activates gems in Bundler default group in Gemfile
46
+ - "--pd=BOOLEAN" : Requires puts_debuggerer to enable pd method
47
+ - "--quiet=BOOLEAN" : Does not announce file path of Glimmer application being launched
48
+ - "--debug" : Displays extra debugging information and enables debug logging
49
+ - "--log-level=VALUE" : Sets Glimmer's Ruby logger level ("ERROR" / "WARN" / "INFO" / "DEBUG"; default is none)
50
+
51
+ Tasks are run via rake. Some tasks take arguments in square brackets (surround with double-quotes if using Zsh).
52
+
53
+ Available tasks are below (if you do not see any, please add `require 'glimmer/rake_task'` to Rakefile and rerun or run rake -T):
54
+
55
+ MULTI_LINE_STRING
56
+
57
+ GLIMMER_LIB_GEM = 'glimmer-dsl-libui'
58
+ GLIMMER_LIB_LOCAL = File.expand_path(File.join('lib', "#{GLIMMER_LIB_GEM}.rb"))
59
+ GLIMMER_OPTIONS = %w[--log-level --quiet --bundler --pd]
60
+ GLIMMER_OPTION_ENV_VAR_MAPPING = {
61
+ '--log-level' => 'GLIMMER_LOGGER_LEVEL' ,
62
+ '--bundler' => 'GLIMMER_BUNDLER_SETUP' ,
63
+ '--pd' => 'PD' ,
64
+ }
65
+ REGEX_RAKE_TASK_WITH_ARGS = /^([^\[]+)\[?([^\]]*)\]?$/
66
+
67
+ class << self
68
+ def is_arm64?
69
+ host_cpu = OS.host_cpu.downcase
70
+ host_cpu.include?('aarch64') || host_cpu.include?('arm')
71
+ end
72
+
73
+ def glimmer_lib
74
+ unless @glimmer_lib
75
+ @glimmer_lib = GLIMMER_LIB_GEM
76
+ if File.exist?(GLIMMER_LIB_LOCAL)
77
+ @glimmer_lib = GLIMMER_LIB_LOCAL
78
+ puts "[DEVELOPMENT MODE] (detected #{@glimmer_lib})"
79
+ end
80
+ end
81
+ @glimmer_lib
82
+ end
83
+
84
+ def dev_mode?
85
+ glimmer_lib == GLIMMER_LIB_LOCAL
86
+ end
87
+
88
+ def glimmer_option_env_vars(glimmer_options)
89
+ GLIMMER_OPTION_ENV_VAR_MAPPING.reduce({}) do |hash, pair|
90
+ glimmer_options[pair.first] ? hash.merge(GLIMMER_OPTION_ENV_VAR_MAPPING[pair.first] => glimmer_options[pair.first]) : hash
91
+ end
92
+ end
93
+
94
+ def load_env_vars(env_vars)
95
+ env_vars.each do |key, value|
96
+ ENV[key] = value
97
+ end
98
+ end
99
+
100
+ def launch(application, ruby_options: [], env_vars: {}, glimmer_options: {})
101
+ ruby_options_string = ruby_options.join(' ') + ' ' if ruby_options.any?
102
+ env_vars = env_vars.merge(glimmer_option_env_vars(glimmer_options))
103
+ env_vars.each do |k,v|
104
+ ENV[k] = v
105
+ end
106
+ the_glimmer_lib = glimmer_lib
107
+ require 'puts_debuggerer' if the_glimmer_lib == GLIMMER_LIB_LOCAL
108
+ is_rake_task = !application.end_with?('.rb')
109
+ rake_tasks = []
110
+ if is_rake_task
111
+ load File.expand_path('./Rakefile') if File.exist?(File.expand_path('./Rakefile')) && caller.join("\n").include?('/bin/glimmer:')
112
+ require_relative 'rake_task'
113
+ rake_tasks = Rake.application.tasks.map(&:to_s).map {|t| t.sub('glimmer:', '')}
114
+
115
+ potential_rake_task_parts = application.match(REGEX_RAKE_TASK_WITH_ARGS)
116
+ application = potential_rake_task_parts[1]
117
+ rake_task_args = potential_rake_task_parts[2].split(',')
118
+ end
119
+ if rake_tasks.include?(application)
120
+ load_env_vars(glimmer_option_env_vars(glimmer_options))
121
+ rake_task = "glimmer:#{application}"
122
+ puts "Running Glimmer rake task: #{rake_task}" if ruby_options_string.to_s.include?('--debug')
123
+ Rake::Task[rake_task].invoke(*rake_task_args)
124
+ else
125
+ puts "Launching Glimmer Application: #{application}" if ruby_options_string.to_s.include?('--debug') || glimmer_options['--quiet'].to_s.downcase != 'true'
126
+ require the_glimmer_lib
127
+ load File.expand_path(application)
128
+ end
129
+ end
130
+ end
131
+
132
+ attr_reader :application_paths
133
+ attr_reader :env_vars
134
+ attr_reader :glimmer_options
135
+ attr_reader :ruby_options
136
+
137
+ def initialize(raw_options)
138
+ raw_options << '--quiet' if !caller.join("\n").include?('/bin/glimmer:') && !raw_options.join.include?('--quiet=')
139
+ raw_options << '--log-level=DEBUG' if raw_options.join.include?('--debug') && !raw_options.join.include?('--log-level=')
140
+ @application_path = extract_application_path(raw_options)
141
+ @env_vars = extract_env_vars(raw_options)
142
+ @glimmer_options = extract_glimmer_options(raw_options)
143
+ @ruby_options = raw_options
144
+ end
145
+
146
+ def launch
147
+ if @application_path.nil?
148
+ display_usage
149
+ else
150
+ launch_application
151
+ end
152
+ end
153
+
154
+ private
155
+
156
+ def launch_application
157
+ self.class.launch(
158
+ @application_path,
159
+ ruby_options: @ruby_options,
160
+ env_vars: @env_vars,
161
+ glimmer_options: @glimmer_options
162
+ )
163
+ end
164
+
165
+ def display_usage
166
+ puts TEXT_USAGE
167
+ display_tasks
168
+ end
169
+
170
+ def display_tasks
171
+ if OS.windows? || Launcher.is_arm64?
172
+ require 'rake'
173
+ Rake::TaskManager.record_task_metadata = true
174
+ require_relative 'rake_task'
175
+ tasks = Rake.application.tasks
176
+ task_lines = tasks.reject do |task|
177
+ task.comment.nil?
178
+ end.map do |task|
179
+ max_task_size = tasks.map(&:name_with_args).map(&:size).max + 1
180
+ task_name = task.name_with_args.sub('glimmer:', '')
181
+ line = "glimmer #{task_name.ljust(max_task_size)} # #{task.comment}"
182
+ end
183
+ puts task_lines.to_a
184
+ else
185
+ require 'rake-tui'
186
+ require 'tty-screen'
187
+ require_relative 'rake_task'
188
+ Rake::TUI.run(branding_header: nil, prompt_question: 'Select a Glimmer task to run:') do |task, tasks|
189
+ max_task_size = tasks.map(&:name_with_args).map(&:size).max + 1
190
+ task_name = task.name_with_args.sub('glimmer:', '')
191
+ line = "glimmer #{task_name.ljust(max_task_size)} # #{task.comment}"
192
+ bound = TTY::Screen.width - 6
193
+ line.size <= bound ? line : "#{line[0..(bound - 3)]}..."
194
+ end
195
+ end
196
+ end
197
+
198
+ # Extract application path (which can also be a rake task, basically a non-arg)
199
+ def extract_application_path(options)
200
+ application_path = options.detect do |option|
201
+ !option.start_with?('-') && !option.include?('=')
202
+ end.tap do
203
+ options.delete(application_path)
204
+ end
205
+ end
206
+
207
+ def extract_env_vars(options)
208
+ options.select do |option|
209
+ !option.start_with?('-') && option.include?('=')
210
+ end.each do |env_var|
211
+ options.delete(env_var)
212
+ end.reduce({}) do |hash, env_var_string|
213
+ match = env_var_string.match(/^([^=]+)=(.+)$/)
214
+ hash.merge(match[1] => match[2])
215
+ end
216
+ end
217
+
218
+ def extract_glimmer_options(options)
219
+ options.select do |option|
220
+ GLIMMER_OPTIONS.reduce(false) do |result, glimmer_option|
221
+ result || option.include?(glimmer_option)
222
+ end
223
+ end.each do |glimmer_option|
224
+ options.delete(glimmer_option)
225
+ end.reduce({}) do |hash, glimmer_option_string|
226
+ match = glimmer_option_string.match(/^([^=]+)=?(.+)?$/)
227
+ hash.merge(match[1] => (match[2] || 'true'))
228
+ end
229
+ end
230
+ end
231
+ end
@@ -129,6 +129,7 @@ module Glimmer
129
129
 
130
130
  def build_control
131
131
  @libui = ::LibUI::FFI::DrawMatrix.malloc
132
+ # TODO is there a way to free the memory allocated for this? Or does it get garbage collected automatically?
132
133
  if @args.empty?
133
134
  set_identity
134
135
  else
@@ -167,9 +167,9 @@ module Glimmer
167
167
  end
168
168
 
169
169
  def perfect_shape
170
- perfect_shape_dependencies = [draw_fill_mode, children]
171
- if perfect_shape_dependencies != @perfect_shape_dependencies
172
- draw_fill_mode, children = @perfect_shape_dependencies = perfect_shape_dependencies
170
+ the_perfect_shape_dependencies = perfect_shape_dependencies
171
+ if the_perfect_shape_dependencies != @perfect_shape_dependencies
172
+ draw_fill_mode, _ = @perfect_shape_dependencies = the_perfect_shape_dependencies
173
173
  shapes = children.map(&:perfect_shape)
174
174
  new_shapes = []
175
175
  shapes.each do |shape|
@@ -190,6 +190,10 @@ module Glimmer
190
190
  @perfect_shape
191
191
  end
192
192
 
193
+ def perfect_shape_dependencies
194
+ [draw_fill_mode, children.map(&:perfect_shape_dependencies)]
195
+ end
196
+
193
197
  private
194
198
 
195
199
  def build_control
@@ -35,10 +35,10 @@ module Glimmer
35
35
  end
36
36
 
37
37
  def create(keyword, parent, args, &block)
38
- widget_proxy_class(keyword).new(keyword, parent, args, &block).tap {|c| control_proxies << c}
38
+ control_proxy_class(keyword).new(keyword, parent, args, &block).tap {|c| control_proxies << c}
39
39
  end
40
40
 
41
- def widget_proxy_class(keyword)
41
+ def control_proxy_class(keyword)
42
42
  descendant_keyword_constant_map[keyword] || ControlProxy
43
43
  end
44
44
 
@@ -96,7 +96,7 @@ module Glimmer
96
96
  private
97
97
 
98
98
  def add_aliases_to_keyword_constant_map(keyword_constant_map)
99
- KEYWORD_ALIASES.each do |keyword, alias_keyword|
99
+ KEYWORD_ALIASES.each do |alias_keyword, keyword|
100
100
  keyword_constant_map[alias_keyword] = keyword_constant_map[keyword]
101
101
  end
102
102
  keyword_constant_map
@@ -106,8 +106,8 @@ module Glimmer
106
106
  include DataBindable
107
107
 
108
108
  KEYWORD_ALIASES = {
109
- 'msg_box' => 'message_box',
110
- 'msg_box_error' => 'message_box_error',
109
+ 'message_box' => 'msg_box',
110
+ 'message_box_error' => 'msg_box_error',
111
111
  }
112
112
 
113
113
  BOOLEAN_PROPERTIES = %w[
@@ -8,7 +8,7 @@ module Glimmer
8
8
 
9
9
  def_delegators :perfect_shape,
10
10
  :min_x, :min_y, :max_x, :max_y, :center_point, :center_x, :center_y
11
-
11
+
12
12
  # Returns if shape contains point on the inside when outline is false (default)
13
13
  # or if point is on the outline when outline is true
14
14
  # distance_tolerance is used when outline is true to enable a fuzz factor in
@@ -22,6 +22,7 @@ module Glimmer
22
22
  # or if shape includes point on the outline when stroked
23
23
  def include?(*point)
24
24
  if fill.empty?
25
+ # TODO check if distance_tolerance should be half the thickness in case it is checked against both sides of out and in
25
26
  contain?(*point, outline: true, distance_tolerance: ((stroke[:thickness] || 1) - 1))
26
27
  else
27
28
  contain?(*point)
@@ -60,6 +61,13 @@ module Glimmer
60
61
  def perfect_shape
61
62
  # No Op
62
63
  end
64
+
65
+ # Returns PerfectShape object dependencies to determine if the PerfectShape
66
+ # object changed or not for caching purposes.
67
+ # Every shape/path implements this uniquely for its own PerfectShape attribute dependencies
68
+ def perfect_shape_dependencies
69
+ # No Op
70
+ end
63
71
  end
64
72
  end
65
73
  end
@@ -51,21 +51,25 @@ module Glimmer
51
51
  end
52
52
 
53
53
  def perfect_shape
54
- perfect_shape_dependencies = [x_center, y_center, radius, start_angle, sweep, is_negative]
55
- if perfect_shape_dependencies != @perfect_shape_dependencies
56
- x_center, y_center, radius, start_angle, sweep, is_negative = @perfect_shape_dependencies = perfect_shape_dependencies
54
+ the_perfect_shape_dependencies = perfect_shape_dependencies
55
+ if the_perfect_shape_dependencies != @perfect_shape_dependencies
56
+ absolute_x_center, absolute_y_center, radius, start_angle, sweep, is_negative = @perfect_shape_dependencies = the_perfect_shape_dependencies
57
57
  sign = is_negative ? 1 : -1
58
58
  start = is_negative ? (360 - start_angle) : -1*start_angle
59
59
  extent = is_negative ? (360 - sweep) : -1*sweep
60
60
  @perfect_shape = PerfectShape::Arc.new(
61
61
  type: :open,
62
- center_x: x_center, center_y: y_center,
62
+ center_x: absolute_x_center, center_y: absolute_y_center,
63
63
  radius_x: radius, radius_y: radius,
64
64
  start: start, extent: extent
65
65
  )
66
66
  end
67
67
  @perfect_shape
68
68
  end
69
+
70
+ def perfect_shape_dependencies
71
+ [absolute_x_center, absolute_y_center, radius, start_angle, sweep, is_negative]
72
+ end
69
73
  end
70
74
  end
71
75
  end