cyberarm_engine 0.19.0 → 0.19.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/.gitignore +8 -8
 - data/.rubocop.yml +7 -7
 - data/.travis.yml +5 -5
 - data/Gemfile +6 -6
 - data/LICENSE.txt +21 -21
 - data/README.md +74 -74
 - data/Rakefile +10 -10
 - data/bin/console +14 -14
 - data/bin/setup +8 -8
 - data/cyberarm_engine.gemspec +39 -39
 - data/lib/cyberarm_engine/animator.rb +219 -219
 - data/lib/cyberarm_engine/background.rb +179 -179
 - data/lib/cyberarm_engine/background_nine_slice.rb +142 -142
 - data/lib/cyberarm_engine/bounding_box.rb +150 -150
 - data/lib/cyberarm_engine/builtin/intro_state.rb +130 -130
 - data/lib/cyberarm_engine/cache/download_manager.rb +121 -121
 - data/lib/cyberarm_engine/cache.rb +4 -4
 - data/lib/cyberarm_engine/common.rb +113 -113
 - data/lib/cyberarm_engine/config_file.rb +46 -46
 - data/lib/cyberarm_engine/console/command.rb +157 -157
 - data/lib/cyberarm_engine/console/commands/help_command.rb +43 -43
 - data/lib/cyberarm_engine/console/subcommand.rb +99 -99
 - data/lib/cyberarm_engine/console.rb +248 -248
 - data/lib/cyberarm_engine/game_object.rb +248 -248
 - data/lib/cyberarm_engine/game_state.rb +97 -97
 - data/lib/cyberarm_engine/model/material.rb +21 -21
 - data/lib/cyberarm_engine/model/model_object.rb +131 -131
 - data/lib/cyberarm_engine/model/parser.rb +74 -74
 - data/lib/cyberarm_engine/model/parsers/collada_parser.rb +138 -138
 - data/lib/cyberarm_engine/model/parsers/wavefront_parser.rb +154 -154
 - data/lib/cyberarm_engine/model.rb +212 -212
 - data/lib/cyberarm_engine/model_cache.rb +31 -31
 - data/lib/cyberarm_engine/opengl/light.rb +50 -50
 - data/lib/cyberarm_engine/opengl/orthographic_camera.rb +46 -46
 - data/lib/cyberarm_engine/opengl/perspective_camera.rb +38 -38
 - data/lib/cyberarm_engine/opengl/renderer/bounding_box_renderer.rb +249 -249
 - data/lib/cyberarm_engine/opengl/renderer/g_buffer.rb +164 -164
 - data/lib/cyberarm_engine/opengl/renderer/opengl_renderer.rb +298 -298
 - data/lib/cyberarm_engine/opengl/renderer/renderer.rb +22 -22
 - data/lib/cyberarm_engine/opengl/shader.rb +406 -406
 - data/lib/cyberarm_engine/opengl/texture.rb +69 -69
 - data/lib/cyberarm_engine/opengl.rb +28 -28
 - data/lib/cyberarm_engine/ray.rb +56 -56
 - data/lib/cyberarm_engine/stats.rb +21 -21
 - data/lib/cyberarm_engine/text.rb +197 -197
 - data/lib/cyberarm_engine/timer.rb +23 -23
 - data/lib/cyberarm_engine/transform.rb +296 -296
 - data/lib/cyberarm_engine/ui/border_canvas.rb +102 -102
 - data/lib/cyberarm_engine/ui/dsl.rb +139 -139
 - data/lib/cyberarm_engine/ui/element.rb +488 -488
 - data/lib/cyberarm_engine/ui/elements/button.rb +97 -97
 - data/lib/cyberarm_engine/ui/elements/check_box.rb +54 -54
 - data/lib/cyberarm_engine/ui/elements/container.rb +256 -256
 - data/lib/cyberarm_engine/ui/elements/edit_box.rb +179 -179
 - data/lib/cyberarm_engine/ui/elements/edit_line.rb +263 -263
 - data/lib/cyberarm_engine/ui/elements/flow.rb +15 -15
 - data/lib/cyberarm_engine/ui/elements/image.rb +72 -72
 - data/lib/cyberarm_engine/ui/elements/list_box.rb +88 -82
 - data/lib/cyberarm_engine/ui/elements/progress.rb +51 -51
 - data/lib/cyberarm_engine/ui/elements/radio.rb +6 -6
 - data/lib/cyberarm_engine/ui/elements/slider.rb +104 -104
 - data/lib/cyberarm_engine/ui/elements/stack.rb +11 -11
 - data/lib/cyberarm_engine/ui/elements/text_block.rb +162 -162
 - data/lib/cyberarm_engine/ui/elements/toggle_button.rb +65 -65
 - data/lib/cyberarm_engine/ui/event.rb +54 -54
 - data/lib/cyberarm_engine/ui/gui_state.rb +256 -256
 - data/lib/cyberarm_engine/ui/style.rb +49 -49
 - data/lib/cyberarm_engine/ui/theme.rb +207 -207
 - data/lib/cyberarm_engine/vector.rb +293 -293
 - data/lib/cyberarm_engine/version.rb +4 -4
 - data/lib/cyberarm_engine/window.rb +120 -120
 - data/lib/cyberarm_engine.rb +71 -71
 - metadata +3 -3
 
| 
         @@ -1,162 +1,162 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            module CyberarmEngine
         
     | 
| 
       2 
     | 
    
         
            -
              class Element
         
     | 
| 
       3 
     | 
    
         
            -
                class TextBlock < Element
         
     | 
| 
       4 
     | 
    
         
            -
                  def initialize(text, options = {}, block = nil)
         
     | 
| 
       5 
     | 
    
         
            -
                    super(options, block)
         
     | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
       7 
     | 
    
         
            -
                    @text = Text.new(
         
     | 
| 
       8 
     | 
    
         
            -
                      text, font: @options[:font], z: @z, color: @options[:color],
         
     | 
| 
       9 
     | 
    
         
            -
                            size: @options[:text_size], shadow: @options[:text_shadow],
         
     | 
| 
       10 
     | 
    
         
            -
                            shadow_size: @options[:text_shadow_size],
         
     | 
| 
       11 
     | 
    
         
            -
                            shadow_color: @options[:text_shadow_color],
         
     | 
| 
       12 
     | 
    
         
            -
                            border: @options[:text_border],
         
     | 
| 
       13 
     | 
    
         
            -
                            border_size: @options[:text_border_size],
         
     | 
| 
       14 
     | 
    
         
            -
                            border_color: @options[:text_border_color]
         
     | 
| 
       15 
     | 
    
         
            -
                    )
         
     | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
       17 
     | 
    
         
            -
                    @raw_text = text
         
     | 
| 
       18 
     | 
    
         
            -
                  end
         
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
     | 
    
         
            -
                  def render
         
     | 
| 
       21 
     | 
    
         
            -
                    @text.draw
         
     | 
| 
       22 
     | 
    
         
            -
                  end
         
     | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
       24 
     | 
    
         
            -
                  def recalculate
         
     | 
| 
       25 
     | 
    
         
            -
                    unless @enabled
         
     | 
| 
       26 
     | 
    
         
            -
                      @text.color = @style.disabled[:color]
         
     | 
| 
       27 
     | 
    
         
            -
                    else
         
     | 
| 
       28 
     | 
    
         
            -
                      @text.color = @style.color
         
     | 
| 
       29 
     | 
    
         
            -
                    end
         
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
       31 
     | 
    
         
            -
                    @width  = 0
         
     | 
| 
       32 
     | 
    
         
            -
                    @height = 0
         
     | 
| 
       33 
     | 
    
         
            -
             
     | 
| 
       34 
     | 
    
         
            -
                    _width  = dimensional_size(@style.width,  :width)
         
     | 
| 
       35 
     | 
    
         
            -
                    _height = dimensional_size(@style.height, :height)
         
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
       37 
     | 
    
         
            -
                    handle_text_wrapping(_width)
         
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
                    @width  = _width  || @text.width.round
         
     | 
| 
       40 
     | 
    
         
            -
                    @height = _height || @text.height.round
         
     | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
       42 
     | 
    
         
            -
                    @text.y = @style.border_thickness_top + @style.padding_top + @y
         
     | 
| 
       43 
     | 
    
         
            -
                    @text.z = @z + 3
         
     | 
| 
       44 
     | 
    
         
            -
             
     | 
| 
       45 
     | 
    
         
            -
                    if (text_alignment = @options[:text_align])
         
     | 
| 
       46 
     | 
    
         
            -
                      case text_alignment
         
     | 
| 
       47 
     | 
    
         
            -
                      when :left
         
     | 
| 
       48 
     | 
    
         
            -
                        @text.x = @style.border_thickness_left + @style.padding_left + @x
         
     | 
| 
       49 
     | 
    
         
            -
                      when :center
         
     | 
| 
       50 
     | 
    
         
            -
                        @text.x = if @text.width <= outer_width
         
     | 
| 
       51 
     | 
    
         
            -
                                    @x + outer_width / 2 - @text.width / 2
         
     | 
| 
       52 
     | 
    
         
            -
                                  else # Act as left aligned
         
     | 
| 
       53 
     | 
    
         
            -
                                    @style.border_thickness_left + @style.padding_left + @x
         
     | 
| 
       54 
     | 
    
         
            -
                                  end
         
     | 
| 
       55 
     | 
    
         
            -
                      when :right
         
     | 
| 
       56 
     | 
    
         
            -
                        @text.x = @x + outer_width - (@text.width + @style.border_thickness_right + @style.padding_right)
         
     | 
| 
       57 
     | 
    
         
            -
                      end
         
     | 
| 
       58 
     | 
    
         
            -
                    end
         
     | 
| 
       59 
     | 
    
         
            -
             
     | 
| 
       60 
     | 
    
         
            -
                    update_background
         
     | 
| 
       61 
     | 
    
         
            -
                  end
         
     | 
| 
       62 
     | 
    
         
            -
             
     | 
| 
       63 
     | 
    
         
            -
                  def handle_text_wrapping(max_width)
         
     | 
| 
       64 
     | 
    
         
            -
                    max_width ||= @parent&.width
         
     | 
| 
       65 
     | 
    
         
            -
                    max_width ||= @x - (window.width + noncontent_width)
         
     | 
| 
       66 
     | 
    
         
            -
                    wrap_behavior = style.text_wrap
         
     | 
| 
       67 
     | 
    
         
            -
                    copy = @raw_text.to_s.dup
         
     | 
| 
       68 
     | 
    
         
            -
             
     | 
| 
       69 
     | 
    
         
            -
                    if line_width(copy[0]) <= max_width && line_width(copy) > max_width && wrap_behavior != :none
         
     | 
| 
       70 
     | 
    
         
            -
                      breaks = []
         
     | 
| 
       71 
     | 
    
         
            -
                      line_start = 0
         
     | 
| 
       72 
     | 
    
         
            -
                      line_end   = copy.length
         
     | 
| 
       73 
     | 
    
         
            -
             
     | 
| 
       74 
     | 
    
         
            -
                      while line_start != copy.length
         
     | 
| 
       75 
     | 
    
         
            -
                        if line_width(copy[line_start...line_end]) > max_width
         
     | 
| 
       76 
     | 
    
         
            -
                          line_end = ((line_end - line_start) / 2.0)
         
     | 
| 
       77 
     | 
    
         
            -
                          line_end = 1.0 if line_end <= 1
         
     | 
| 
       78 
     | 
    
         
            -
                        elsif line_end < copy.length && line_width(copy[line_start...line_end + 1]) < max_width
         
     | 
| 
       79 
     | 
    
         
            -
                          # To small, grow!
         
     | 
| 
       80 
     | 
    
         
            -
                          # TODO: find a more efficient way
         
     | 
| 
       81 
     | 
    
         
            -
                          line_end += 1
         
     | 
| 
       82 
     | 
    
         
            -
             
     | 
| 
       83 
     | 
    
         
            -
                        else # FOUND IT!
         
     | 
| 
       84 
     | 
    
         
            -
                          entering_line_end = line_end.floor
         
     | 
| 
       85 
     | 
    
         
            -
                          max_reach = line_end.floor - line_start < 63 ? line_end.floor - line_start : 63
         
     | 
| 
       86 
     | 
    
         
            -
                          reach = 0
         
     | 
| 
       87 
     | 
    
         
            -
             
     | 
| 
       88 
     | 
    
         
            -
                          if wrap_behavior == :word_wrap
         
     | 
| 
       89 
     | 
    
         
            -
                            max_reach.times do |i|
         
     | 
| 
       90 
     | 
    
         
            -
                              reach = i
         
     | 
| 
       91 
     | 
    
         
            -
                              break if copy[line_end.floor - i].to_s.match(/[[:punct:]]| /)
         
     | 
| 
       92 
     | 
    
         
            -
                            end
         
     | 
| 
       93 
     | 
    
         
            -
             
     | 
| 
       94 
     | 
    
         
            -
                            # puts "Max width: #{max_width}/#{line_width(@raw_text)} Reach: {#{reach}/#{max_reach}} Line Start: #{line_start}/#{line_end.floor} (#{copy.length}|#{@raw_text.length}) [#{entering_line_end}] '#{copy}' {#{copy[line_start...line_end]}}"
         
     | 
| 
       95 
     | 
    
         
            -
                            line_end = line_end.floor - reach + 1 if reach != max_reach # Add +1 to walk in front of punctuation
         
     | 
| 
       96 
     | 
    
         
            -
                          end
         
     | 
| 
       97 
     | 
    
         
            -
             
     | 
| 
       98 
     | 
    
         
            -
                          breaks << line_end.floor
         
     | 
| 
       99 
     | 
    
         
            -
                          line_start = line_end.floor
         
     | 
| 
       100 
     | 
    
         
            -
                          line_end = copy.length
         
     | 
| 
       101 
     | 
    
         
            -
             
     | 
| 
       102 
     | 
    
         
            -
                          break if entering_line_end == copy.length || reach == max_reach
         
     | 
| 
       103 
     | 
    
         
            -
                        end
         
     | 
| 
       104 
     | 
    
         
            -
                      end
         
     | 
| 
       105 
     | 
    
         
            -
             
     | 
| 
       106 
     | 
    
         
            -
                      breaks.each_with_index do |pos, index|
         
     | 
| 
       107 
     | 
    
         
            -
                        copy.insert(pos + index, "\n") if pos + index >= 0 && pos + index < copy.length
         
     | 
| 
       108 
     | 
    
         
            -
                      end
         
     | 
| 
       109 
     | 
    
         
            -
                    end
         
     | 
| 
       110 
     | 
    
         
            -
             
     | 
| 
       111 
     | 
    
         
            -
                    @text.text = copy
         
     | 
| 
       112 
     | 
    
         
            -
                  end
         
     | 
| 
       113 
     | 
    
         
            -
             
     | 
| 
       114 
     | 
    
         
            -
                  def line_width(text)
         
     | 
| 
       115 
     | 
    
         
            -
                    (@text.textobject.markup_width(text) + noncontent_width)
         
     | 
| 
       116 
     | 
    
         
            -
                  end
         
     | 
| 
       117 
     | 
    
         
            -
             
     | 
| 
       118 
     | 
    
         
            -
                  def value
         
     | 
| 
       119 
     | 
    
         
            -
                    @raw_text
         
     | 
| 
       120 
     | 
    
         
            -
                  end
         
     | 
| 
       121 
     | 
    
         
            -
             
     | 
| 
       122 
     | 
    
         
            -
                  def value=(value)
         
     | 
| 
       123 
     | 
    
         
            -
                    @raw_text = value.to_s.chomp
         
     | 
| 
       124 
     | 
    
         
            -
             
     | 
| 
       125 
     | 
    
         
            -
                    old_width = width
         
     | 
| 
       126 
     | 
    
         
            -
                    old_height = height
         
     | 
| 
       127 
     | 
    
         
            -
                    recalculate
         
     | 
| 
       128 
     | 
    
         
            -
             
     | 
| 
       129 
     | 
    
         
            -
                    root.gui_state.request_recalculate if old_width != width || old_height != height
         
     | 
| 
       130 
     | 
    
         
            -
             
     | 
| 
       131 
     | 
    
         
            -
                    publish(:changed, self.value)
         
     | 
| 
       132 
     | 
    
         
            -
                  end
         
     | 
| 
       133 
     | 
    
         
            -
                end
         
     | 
| 
       134 
     | 
    
         
            -
             
     | 
| 
       135 
     | 
    
         
            -
                class Banner < TextBlock
         
     | 
| 
       136 
     | 
    
         
            -
                end
         
     | 
| 
       137 
     | 
    
         
            -
             
     | 
| 
       138 
     | 
    
         
            -
                class Title < TextBlock
         
     | 
| 
       139 
     | 
    
         
            -
                end
         
     | 
| 
       140 
     | 
    
         
            -
             
     | 
| 
       141 
     | 
    
         
            -
                class Subtitle < TextBlock
         
     | 
| 
       142 
     | 
    
         
            -
                end
         
     | 
| 
       143 
     | 
    
         
            -
             
     | 
| 
       144 
     | 
    
         
            -
                class Tagline < TextBlock
         
     | 
| 
       145 
     | 
    
         
            -
                end
         
     | 
| 
       146 
     | 
    
         
            -
             
     | 
| 
       147 
     | 
    
         
            -
                class Caption < TextBlock
         
     | 
| 
       148 
     | 
    
         
            -
                end
         
     | 
| 
       149 
     | 
    
         
            -
             
     | 
| 
       150 
     | 
    
         
            -
                class Para < TextBlock
         
     | 
| 
       151 
     | 
    
         
            -
                end
         
     | 
| 
       152 
     | 
    
         
            -
             
     | 
| 
       153 
     | 
    
         
            -
                class Inscription < TextBlock
         
     | 
| 
       154 
     | 
    
         
            -
                end
         
     | 
| 
       155 
     | 
    
         
            -
             
     | 
| 
       156 
     | 
    
         
            -
                class ToolTip < TextBlock
         
     | 
| 
       157 
     | 
    
         
            -
                end
         
     | 
| 
       158 
     | 
    
         
            -
             
     | 
| 
       159 
     | 
    
         
            -
                class Link < TextBlock
         
     | 
| 
       160 
     | 
    
         
            -
                end
         
     | 
| 
       161 
     | 
    
         
            -
              end
         
     | 
| 
       162 
     | 
    
         
            -
            end
         
     | 
| 
      
 1 
     | 
    
         
            +
            module CyberarmEngine
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Element
         
     | 
| 
      
 3 
     | 
    
         
            +
                class TextBlock < Element
         
     | 
| 
      
 4 
     | 
    
         
            +
                  def initialize(text, options = {}, block = nil)
         
     | 
| 
      
 5 
     | 
    
         
            +
                    super(options, block)
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                    @text = Text.new(
         
     | 
| 
      
 8 
     | 
    
         
            +
                      text, font: @options[:font], z: @z, color: @options[:color],
         
     | 
| 
      
 9 
     | 
    
         
            +
                            size: @options[:text_size], shadow: @options[:text_shadow],
         
     | 
| 
      
 10 
     | 
    
         
            +
                            shadow_size: @options[:text_shadow_size],
         
     | 
| 
      
 11 
     | 
    
         
            +
                            shadow_color: @options[:text_shadow_color],
         
     | 
| 
      
 12 
     | 
    
         
            +
                            border: @options[:text_border],
         
     | 
| 
      
 13 
     | 
    
         
            +
                            border_size: @options[:text_border_size],
         
     | 
| 
      
 14 
     | 
    
         
            +
                            border_color: @options[:text_border_color]
         
     | 
| 
      
 15 
     | 
    
         
            +
                    )
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                    @raw_text = text
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  def render
         
     | 
| 
      
 21 
     | 
    
         
            +
                    @text.draw
         
     | 
| 
      
 22 
     | 
    
         
            +
                  end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                  def recalculate
         
     | 
| 
      
 25 
     | 
    
         
            +
                    unless @enabled
         
     | 
| 
      
 26 
     | 
    
         
            +
                      @text.color = @style.disabled[:color]
         
     | 
| 
      
 27 
     | 
    
         
            +
                    else
         
     | 
| 
      
 28 
     | 
    
         
            +
                      @text.color = @style.color
         
     | 
| 
      
 29 
     | 
    
         
            +
                    end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                    @width  = 0
         
     | 
| 
      
 32 
     | 
    
         
            +
                    @height = 0
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                    _width  = dimensional_size(@style.width,  :width)
         
     | 
| 
      
 35 
     | 
    
         
            +
                    _height = dimensional_size(@style.height, :height)
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                    handle_text_wrapping(_width)
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                    @width  = _width  || @text.width.round
         
     | 
| 
      
 40 
     | 
    
         
            +
                    @height = _height || @text.height.round
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                    @text.y = @style.border_thickness_top + @style.padding_top + @y
         
     | 
| 
      
 43 
     | 
    
         
            +
                    @text.z = @z + 3
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                    if (text_alignment = @options[:text_align])
         
     | 
| 
      
 46 
     | 
    
         
            +
                      case text_alignment
         
     | 
| 
      
 47 
     | 
    
         
            +
                      when :left
         
     | 
| 
      
 48 
     | 
    
         
            +
                        @text.x = @style.border_thickness_left + @style.padding_left + @x
         
     | 
| 
      
 49 
     | 
    
         
            +
                      when :center
         
     | 
| 
      
 50 
     | 
    
         
            +
                        @text.x = if @text.width <= outer_width
         
     | 
| 
      
 51 
     | 
    
         
            +
                                    @x + outer_width / 2 - @text.width / 2
         
     | 
| 
      
 52 
     | 
    
         
            +
                                  else # Act as left aligned
         
     | 
| 
      
 53 
     | 
    
         
            +
                                    @style.border_thickness_left + @style.padding_left + @x
         
     | 
| 
      
 54 
     | 
    
         
            +
                                  end
         
     | 
| 
      
 55 
     | 
    
         
            +
                      when :right
         
     | 
| 
      
 56 
     | 
    
         
            +
                        @text.x = @x + outer_width - (@text.width + @style.border_thickness_right + @style.padding_right)
         
     | 
| 
      
 57 
     | 
    
         
            +
                      end
         
     | 
| 
      
 58 
     | 
    
         
            +
                    end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                    update_background
         
     | 
| 
      
 61 
     | 
    
         
            +
                  end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                  def handle_text_wrapping(max_width)
         
     | 
| 
      
 64 
     | 
    
         
            +
                    max_width ||= @parent&.width
         
     | 
| 
      
 65 
     | 
    
         
            +
                    max_width ||= @x - (window.width + noncontent_width)
         
     | 
| 
      
 66 
     | 
    
         
            +
                    wrap_behavior = style.text_wrap
         
     | 
| 
      
 67 
     | 
    
         
            +
                    copy = @raw_text.to_s.dup
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                    if line_width(copy[0]) <= max_width && line_width(copy) > max_width && wrap_behavior != :none
         
     | 
| 
      
 70 
     | 
    
         
            +
                      breaks = []
         
     | 
| 
      
 71 
     | 
    
         
            +
                      line_start = 0
         
     | 
| 
      
 72 
     | 
    
         
            +
                      line_end   = copy.length
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                      while line_start != copy.length
         
     | 
| 
      
 75 
     | 
    
         
            +
                        if line_width(copy[line_start...line_end]) > max_width
         
     | 
| 
      
 76 
     | 
    
         
            +
                          line_end = ((line_end - line_start) / 2.0)
         
     | 
| 
      
 77 
     | 
    
         
            +
                          line_end = 1.0 if line_end <= 1
         
     | 
| 
      
 78 
     | 
    
         
            +
                        elsif line_end < copy.length && line_width(copy[line_start...line_end + 1]) < max_width
         
     | 
| 
      
 79 
     | 
    
         
            +
                          # To small, grow!
         
     | 
| 
      
 80 
     | 
    
         
            +
                          # TODO: find a more efficient way
         
     | 
| 
      
 81 
     | 
    
         
            +
                          line_end += 1
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                        else # FOUND IT!
         
     | 
| 
      
 84 
     | 
    
         
            +
                          entering_line_end = line_end.floor
         
     | 
| 
      
 85 
     | 
    
         
            +
                          max_reach = line_end.floor - line_start < 63 ? line_end.floor - line_start : 63
         
     | 
| 
      
 86 
     | 
    
         
            +
                          reach = 0
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                          if wrap_behavior == :word_wrap
         
     | 
| 
      
 89 
     | 
    
         
            +
                            max_reach.times do |i|
         
     | 
| 
      
 90 
     | 
    
         
            +
                              reach = i
         
     | 
| 
      
 91 
     | 
    
         
            +
                              break if copy[line_end.floor - i].to_s.match(/[[:punct:]]| /)
         
     | 
| 
      
 92 
     | 
    
         
            +
                            end
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
                            # puts "Max width: #{max_width}/#{line_width(@raw_text)} Reach: {#{reach}/#{max_reach}} Line Start: #{line_start}/#{line_end.floor} (#{copy.length}|#{@raw_text.length}) [#{entering_line_end}] '#{copy}' {#{copy[line_start...line_end]}}"
         
     | 
| 
      
 95 
     | 
    
         
            +
                            line_end = line_end.floor - reach + 1 if reach != max_reach # Add +1 to walk in front of punctuation
         
     | 
| 
      
 96 
     | 
    
         
            +
                          end
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
                          breaks << line_end.floor
         
     | 
| 
      
 99 
     | 
    
         
            +
                          line_start = line_end.floor
         
     | 
| 
      
 100 
     | 
    
         
            +
                          line_end = copy.length
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                          break if entering_line_end == copy.length || reach == max_reach
         
     | 
| 
      
 103 
     | 
    
         
            +
                        end
         
     | 
| 
      
 104 
     | 
    
         
            +
                      end
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
                      breaks.each_with_index do |pos, index|
         
     | 
| 
      
 107 
     | 
    
         
            +
                        copy.insert(pos + index, "\n") if pos + index >= 0 && pos + index < copy.length
         
     | 
| 
      
 108 
     | 
    
         
            +
                      end
         
     | 
| 
      
 109 
     | 
    
         
            +
                    end
         
     | 
| 
      
 110 
     | 
    
         
            +
             
     | 
| 
      
 111 
     | 
    
         
            +
                    @text.text = copy
         
     | 
| 
      
 112 
     | 
    
         
            +
                  end
         
     | 
| 
      
 113 
     | 
    
         
            +
             
     | 
| 
      
 114 
     | 
    
         
            +
                  def line_width(text)
         
     | 
| 
      
 115 
     | 
    
         
            +
                    (@text.textobject.markup_width(text) + noncontent_width)
         
     | 
| 
      
 116 
     | 
    
         
            +
                  end
         
     | 
| 
      
 117 
     | 
    
         
            +
             
     | 
| 
      
 118 
     | 
    
         
            +
                  def value
         
     | 
| 
      
 119 
     | 
    
         
            +
                    @raw_text
         
     | 
| 
      
 120 
     | 
    
         
            +
                  end
         
     | 
| 
      
 121 
     | 
    
         
            +
             
     | 
| 
      
 122 
     | 
    
         
            +
                  def value=(value)
         
     | 
| 
      
 123 
     | 
    
         
            +
                    @raw_text = value.to_s.chomp
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
      
 125 
     | 
    
         
            +
                    old_width = width
         
     | 
| 
      
 126 
     | 
    
         
            +
                    old_height = height
         
     | 
| 
      
 127 
     | 
    
         
            +
                    recalculate
         
     | 
| 
      
 128 
     | 
    
         
            +
             
     | 
| 
      
 129 
     | 
    
         
            +
                    root.gui_state.request_recalculate if old_width != width || old_height != height
         
     | 
| 
      
 130 
     | 
    
         
            +
             
     | 
| 
      
 131 
     | 
    
         
            +
                    publish(:changed, self.value)
         
     | 
| 
      
 132 
     | 
    
         
            +
                  end
         
     | 
| 
      
 133 
     | 
    
         
            +
                end
         
     | 
| 
      
 134 
     | 
    
         
            +
             
     | 
| 
      
 135 
     | 
    
         
            +
                class Banner < TextBlock
         
     | 
| 
      
 136 
     | 
    
         
            +
                end
         
     | 
| 
      
 137 
     | 
    
         
            +
             
     | 
| 
      
 138 
     | 
    
         
            +
                class Title < TextBlock
         
     | 
| 
      
 139 
     | 
    
         
            +
                end
         
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
      
 141 
     | 
    
         
            +
                class Subtitle < TextBlock
         
     | 
| 
      
 142 
     | 
    
         
            +
                end
         
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
      
 144 
     | 
    
         
            +
                class Tagline < TextBlock
         
     | 
| 
      
 145 
     | 
    
         
            +
                end
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
                class Caption < TextBlock
         
     | 
| 
      
 148 
     | 
    
         
            +
                end
         
     | 
| 
      
 149 
     | 
    
         
            +
             
     | 
| 
      
 150 
     | 
    
         
            +
                class Para < TextBlock
         
     | 
| 
      
 151 
     | 
    
         
            +
                end
         
     | 
| 
      
 152 
     | 
    
         
            +
             
     | 
| 
      
 153 
     | 
    
         
            +
                class Inscription < TextBlock
         
     | 
| 
      
 154 
     | 
    
         
            +
                end
         
     | 
| 
      
 155 
     | 
    
         
            +
             
     | 
| 
      
 156 
     | 
    
         
            +
                class ToolTip < TextBlock
         
     | 
| 
      
 157 
     | 
    
         
            +
                end
         
     | 
| 
      
 158 
     | 
    
         
            +
             
     | 
| 
      
 159 
     | 
    
         
            +
                class Link < TextBlock
         
     | 
| 
      
 160 
     | 
    
         
            +
                end
         
     | 
| 
      
 161 
     | 
    
         
            +
              end
         
     | 
| 
      
 162 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -1,65 +1,65 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            module CyberarmEngine
         
     | 
| 
       2 
     | 
    
         
            -
              class Element
         
     | 
| 
       3 
     | 
    
         
            -
                class ToggleButton < Button
         
     | 
| 
       4 
     | 
    
         
            -
                  attr_reader :toggled, :value
         
     | 
| 
       5 
     | 
    
         
            -
             
     | 
| 
       6 
     | 
    
         
            -
                  def initialize(options, block = nil)
         
     | 
| 
       7 
     | 
    
         
            -
                    if options.dig(:theme, :ToggleButton, :checkmark_image)
         
     | 
| 
       8 
     | 
    
         
            -
                      options[:theme][:ToggleButton][:image_width] ||= options[:theme][:Label][:text_size]
         
     | 
| 
       9 
     | 
    
         
            -
                      super(get_image(options.dig(:theme, :ToggleButton, :checkmark_image)), options, block)
         
     | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
       11 
     | 
    
         
            -
                      @_image = @image
         
     | 
| 
       12 
     | 
    
         
            -
                    else
         
     | 
| 
       13 
     | 
    
         
            -
                      super(options[:checkmark], options, block)
         
     | 
| 
       14 
     | 
    
         
            -
                    end
         
     | 
| 
       15 
     | 
    
         
            -
             
     | 
| 
       16 
     | 
    
         
            -
                    @value = options[:checked] || false
         
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
     | 
    
         
            -
                    if @value
         
     | 
| 
       19 
     | 
    
         
            -
                      @image = @_image if @_image
         
     | 
| 
       20 
     | 
    
         
            -
                      @raw_text = @options[:checkmark]
         
     | 
| 
       21 
     | 
    
         
            -
                    else
         
     | 
| 
       22 
     | 
    
         
            -
                      @image = nil
         
     | 
| 
       23 
     | 
    
         
            -
                      @raw_text = ""
         
     | 
| 
       24 
     | 
    
         
            -
                    end
         
     | 
| 
       25 
     | 
    
         
            -
                  end
         
     | 
| 
       26 
     | 
    
         
            -
             
     | 
| 
       27 
     | 
    
         
            -
                  def clicked_left_mouse_button(_sender, _x, _y)
         
     | 
| 
       28 
     | 
    
         
            -
                    self.value = !@value
         
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
       30 
     | 
    
         
            -
                    @block.call(self) if @block
         
     | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
       32 
     | 
    
         
            -
                    :handled
         
     | 
| 
       33 
     | 
    
         
            -
                  end
         
     | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
       35 
     | 
    
         
            -
                  def recalculate
         
     | 
| 
       36 
     | 
    
         
            -
                    super
         
     | 
| 
       37 
     | 
    
         
            -
                    return if @image
         
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
                    _width  = dimensional_size(@style.width,  :width)
         
     | 
| 
       40 
     | 
    
         
            -
                    _height = dimensional_size(@style.height, :height)
         
     | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
       42 
     | 
    
         
            -
                    @width  = _width  || @text.textobject.text_width(@options[:checkmark])
         
     | 
| 
       43 
     | 
    
         
            -
                    @height = _height || @text.height
         
     | 
| 
       44 
     | 
    
         
            -
             
     | 
| 
       45 
     | 
    
         
            -
                    update_background
         
     | 
| 
       46 
     | 
    
         
            -
                  end
         
     | 
| 
       47 
     | 
    
         
            -
             
     | 
| 
       48 
     | 
    
         
            -
                  def value=(boolean)
         
     | 
| 
       49 
     | 
    
         
            -
                    @value = boolean
         
     | 
| 
       50 
     | 
    
         
            -
             
     | 
| 
       51 
     | 
    
         
            -
                    if boolean
         
     | 
| 
       52 
     | 
    
         
            -
                      @image = @_image if @_image
         
     | 
| 
       53 
     | 
    
         
            -
                      @raw_text = @options[:checkmark]
         
     | 
| 
       54 
     | 
    
         
            -
                    else
         
     | 
| 
       55 
     | 
    
         
            -
                      @image = nil
         
     | 
| 
       56 
     | 
    
         
            -
                      @raw_text = ""
         
     | 
| 
       57 
     | 
    
         
            -
                    end
         
     | 
| 
       58 
     | 
    
         
            -
             
     | 
| 
       59 
     | 
    
         
            -
                    recalculate
         
     | 
| 
       60 
     | 
    
         
            -
             
     | 
| 
       61 
     | 
    
         
            -
                    publish(:changed, @value)
         
     | 
| 
       62 
     | 
    
         
            -
                  end
         
     | 
| 
       63 
     | 
    
         
            -
                end
         
     | 
| 
       64 
     | 
    
         
            -
              end
         
     | 
| 
       65 
     | 
    
         
            -
            end
         
     | 
| 
      
 1 
     | 
    
         
            +
            module CyberarmEngine
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Element
         
     | 
| 
      
 3 
     | 
    
         
            +
                class ToggleButton < Button
         
     | 
| 
      
 4 
     | 
    
         
            +
                  attr_reader :toggled, :value
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                  def initialize(options, block = nil)
         
     | 
| 
      
 7 
     | 
    
         
            +
                    if options.dig(:theme, :ToggleButton, :checkmark_image)
         
     | 
| 
      
 8 
     | 
    
         
            +
                      options[:theme][:ToggleButton][:image_width] ||= options[:theme][:Label][:text_size]
         
     | 
| 
      
 9 
     | 
    
         
            +
                      super(get_image(options.dig(:theme, :ToggleButton, :checkmark_image)), options, block)
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                      @_image = @image
         
     | 
| 
      
 12 
     | 
    
         
            +
                    else
         
     | 
| 
      
 13 
     | 
    
         
            +
                      super(options[:checkmark], options, block)
         
     | 
| 
      
 14 
     | 
    
         
            +
                    end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                    @value = options[:checked] || false
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                    if @value
         
     | 
| 
      
 19 
     | 
    
         
            +
                      @image = @_image if @_image
         
     | 
| 
      
 20 
     | 
    
         
            +
                      @raw_text = @options[:checkmark]
         
     | 
| 
      
 21 
     | 
    
         
            +
                    else
         
     | 
| 
      
 22 
     | 
    
         
            +
                      @image = nil
         
     | 
| 
      
 23 
     | 
    
         
            +
                      @raw_text = ""
         
     | 
| 
      
 24 
     | 
    
         
            +
                    end
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                  def clicked_left_mouse_button(_sender, _x, _y)
         
     | 
| 
      
 28 
     | 
    
         
            +
                    self.value = !@value
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                    @block.call(self) if @block
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                    :handled
         
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                  def recalculate
         
     | 
| 
      
 36 
     | 
    
         
            +
                    super
         
     | 
| 
      
 37 
     | 
    
         
            +
                    return if @image
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                    _width  = dimensional_size(@style.width,  :width)
         
     | 
| 
      
 40 
     | 
    
         
            +
                    _height = dimensional_size(@style.height, :height)
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                    @width  = _width  || @text.textobject.text_width(@options[:checkmark])
         
     | 
| 
      
 43 
     | 
    
         
            +
                    @height = _height || @text.height
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                    update_background
         
     | 
| 
      
 46 
     | 
    
         
            +
                  end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                  def value=(boolean)
         
     | 
| 
      
 49 
     | 
    
         
            +
                    @value = boolean
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                    if boolean
         
     | 
| 
      
 52 
     | 
    
         
            +
                      @image = @_image if @_image
         
     | 
| 
      
 53 
     | 
    
         
            +
                      @raw_text = @options[:checkmark]
         
     | 
| 
      
 54 
     | 
    
         
            +
                    else
         
     | 
| 
      
 55 
     | 
    
         
            +
                      @image = nil
         
     | 
| 
      
 56 
     | 
    
         
            +
                      @raw_text = ""
         
     | 
| 
      
 57 
     | 
    
         
            +
                    end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                    recalculate
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                    publish(:changed, @value)
         
     | 
| 
      
 62 
     | 
    
         
            +
                  end
         
     | 
| 
      
 63 
     | 
    
         
            +
                end
         
     | 
| 
      
 64 
     | 
    
         
            +
              end
         
     | 
| 
      
 65 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -1,54 +1,54 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            module CyberarmEngine
         
     | 
| 
       2 
     | 
    
         
            -
              module Event # Gets included into Element
         
     | 
| 
       3 
     | 
    
         
            -
                def subscribe(event, method = nil, &block)
         
     | 
| 
       4 
     | 
    
         
            -
                  handler = method || block
         
     | 
| 
       5 
     | 
    
         
            -
                  @event_handler[event] << handler
         
     | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
       7 
     | 
    
         
            -
                  Subscription.new(self, event, handler)
         
     | 
| 
       8 
     | 
    
         
            -
                end
         
     | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
       10 
     | 
    
         
            -
                def unsubscribe(subscription)
         
     | 
| 
       11 
     | 
    
         
            -
                end
         
     | 
| 
       12 
     | 
    
         
            -
             
     | 
| 
       13 
     | 
    
         
            -
                def publish(event, *args)
         
     | 
| 
       14 
     | 
    
         
            -
                  raise ArgumentError, "#{self.class} does not handle #{event.inspect}" unless @event_handler.include?(event)
         
     | 
| 
       15 
     | 
    
         
            -
             
     | 
| 
       16 
     | 
    
         
            -
                  return unless enabled?
         
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
     | 
    
         
            -
                  was_handled = false
         
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
     | 
    
         
            -
                  was_handled = true if respond_to?(event) && (send(event, self, *args) == :handled)
         
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
       22 
     | 
    
         
            -
                  @event_handler[event].reverse_each do |handler|
         
     | 
| 
       23 
     | 
    
         
            -
                    if handler.call(self, *args) == :handled
         
     | 
| 
       24 
     | 
    
         
            -
                      was_handled = true
         
     | 
| 
       25 
     | 
    
         
            -
                      break
         
     | 
| 
       26 
     | 
    
         
            -
                    end
         
     | 
| 
       27 
     | 
    
         
            -
                  end
         
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
                  return :handled if was_handled
         
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
       31 
     | 
    
         
            -
                  parent.publish(event, *args) if parent
         
     | 
| 
       32 
     | 
    
         
            -
                  nil
         
     | 
| 
       33 
     | 
    
         
            -
                end
         
     | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
       35 
     | 
    
         
            -
                def event(event)
         
     | 
| 
       36 
     | 
    
         
            -
                  @event_handler ||= {}
         
     | 
| 
       37 
     | 
    
         
            -
                  @event_handler[event] ||= []
         
     | 
| 
       38 
     | 
    
         
            -
                end
         
     | 
| 
       39 
     | 
    
         
            -
              end
         
     | 
| 
       40 
     | 
    
         
            -
             
     | 
| 
       41 
     | 
    
         
            -
              class Subscription
         
     | 
| 
       42 
     | 
    
         
            -
                attr_reader :publisher, :event, :handler
         
     | 
| 
       43 
     | 
    
         
            -
             
     | 
| 
       44 
     | 
    
         
            -
                def initialize(publisher, event, handler)
         
     | 
| 
       45 
     | 
    
         
            -
                  @publisher = publisher
         
     | 
| 
       46 
     | 
    
         
            -
                  @event = event
         
     | 
| 
       47 
     | 
    
         
            -
                  @handler = handler
         
     | 
| 
       48 
     | 
    
         
            -
                end
         
     | 
| 
       49 
     | 
    
         
            -
             
     | 
| 
       50 
     | 
    
         
            -
                def unsubscribe
         
     | 
| 
       51 
     | 
    
         
            -
                  @publisher.unsubscribe(self)
         
     | 
| 
       52 
     | 
    
         
            -
                end
         
     | 
| 
       53 
     | 
    
         
            -
              end
         
     | 
| 
       54 
     | 
    
         
            -
            end
         
     | 
| 
      
 1 
     | 
    
         
            +
            module CyberarmEngine
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Event # Gets included into Element
         
     | 
| 
      
 3 
     | 
    
         
            +
                def subscribe(event, method = nil, &block)
         
     | 
| 
      
 4 
     | 
    
         
            +
                  handler = method || block
         
     | 
| 
      
 5 
     | 
    
         
            +
                  @event_handler[event] << handler
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                  Subscription.new(self, event, handler)
         
     | 
| 
      
 8 
     | 
    
         
            +
                end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                def unsubscribe(subscription)
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                def publish(event, *args)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  raise ArgumentError, "#{self.class} does not handle #{event.inspect}" unless @event_handler.include?(event)
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                  return unless enabled?
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                  was_handled = false
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  was_handled = true if respond_to?(event) && (send(event, self, *args) == :handled)
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                  @event_handler[event].reverse_each do |handler|
         
     | 
| 
      
 23 
     | 
    
         
            +
                    if handler.call(self, *args) == :handled
         
     | 
| 
      
 24 
     | 
    
         
            +
                      was_handled = true
         
     | 
| 
      
 25 
     | 
    
         
            +
                      break
         
     | 
| 
      
 26 
     | 
    
         
            +
                    end
         
     | 
| 
      
 27 
     | 
    
         
            +
                  end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                  return :handled if was_handled
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                  parent.publish(event, *args) if parent
         
     | 
| 
      
 32 
     | 
    
         
            +
                  nil
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                def event(event)
         
     | 
| 
      
 36 
     | 
    
         
            +
                  @event_handler ||= {}
         
     | 
| 
      
 37 
     | 
    
         
            +
                  @event_handler[event] ||= []
         
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
              end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
              class Subscription
         
     | 
| 
      
 42 
     | 
    
         
            +
                attr_reader :publisher, :event, :handler
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                def initialize(publisher, event, handler)
         
     | 
| 
      
 45 
     | 
    
         
            +
                  @publisher = publisher
         
     | 
| 
      
 46 
     | 
    
         
            +
                  @event = event
         
     | 
| 
      
 47 
     | 
    
         
            +
                  @handler = handler
         
     | 
| 
      
 48 
     | 
    
         
            +
                end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                def unsubscribe
         
     | 
| 
      
 51 
     | 
    
         
            +
                  @publisher.unsubscribe(self)
         
     | 
| 
      
 52 
     | 
    
         
            +
                end
         
     | 
| 
      
 53 
     | 
    
         
            +
              end
         
     | 
| 
      
 54 
     | 
    
         
            +
            end
         
     |