cyberarm_engine 0.22.0 → 0.24.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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/assets/shaders/fragment/g_buffer.glsl +30 -0
  3. data/assets/shaders/fragment/lighting.glsl +69 -0
  4. data/assets/shaders/include/light_struct.glsl +11 -0
  5. data/assets/shaders/include/material_struct.glsl +16 -0
  6. data/assets/shaders/vertex/g_buffer.glsl +28 -0
  7. data/assets/shaders/vertex/lighting.glsl +24 -0
  8. data/lib/cyberarm_engine/background_image.rb +1 -1
  9. data/lib/cyberarm_engine/builtin/intro_state.rb +3 -3
  10. data/lib/cyberarm_engine/common.rb +14 -2
  11. data/lib/cyberarm_engine/console.rb +10 -10
  12. data/lib/cyberarm_engine/game_object.rb +1 -1
  13. data/lib/cyberarm_engine/game_state.rb +4 -0
  14. data/lib/cyberarm_engine/gosu_ext/draw_arc.rb +98 -0
  15. data/lib/cyberarm_engine/gosu_ext/draw_circle.rb +31 -0
  16. data/lib/cyberarm_engine/gosu_ext/draw_path.rb +17 -0
  17. data/lib/cyberarm_engine/model.rb +7 -6
  18. data/lib/cyberarm_engine/notification.rb +83 -0
  19. data/lib/cyberarm_engine/notification_manager.rb +242 -0
  20. data/lib/cyberarm_engine/opengl/renderer/g_buffer.rb +1 -0
  21. data/lib/cyberarm_engine/opengl/renderer/opengl_renderer.rb +16 -10
  22. data/lib/cyberarm_engine/opengl/renderer/renderer.rb +12 -1
  23. data/lib/cyberarm_engine/opengl/shader.rb +2 -2
  24. data/lib/cyberarm_engine/opengl.rb +13 -1
  25. data/lib/cyberarm_engine/stats.rb +181 -10
  26. data/lib/cyberarm_engine/text.rb +3 -0
  27. data/lib/cyberarm_engine/ui/border_canvas.rb +2 -2
  28. data/lib/cyberarm_engine/ui/element.rb +74 -26
  29. data/lib/cyberarm_engine/ui/elements/container.rb +95 -25
  30. data/lib/cyberarm_engine/ui/elements/edit_line.rb +6 -0
  31. data/lib/cyberarm_engine/ui/elements/image.rb +2 -2
  32. data/lib/cyberarm_engine/ui/elements/progress.rb +5 -0
  33. data/lib/cyberarm_engine/ui/elements/slider.rb +6 -3
  34. data/lib/cyberarm_engine/ui/elements/text_block.rb +19 -1
  35. data/lib/cyberarm_engine/ui/gui_state.rb +53 -27
  36. data/lib/cyberarm_engine/ui/style.rb +2 -1
  37. data/lib/cyberarm_engine/vector.rb +35 -16
  38. data/lib/cyberarm_engine/version.rb +1 -1
  39. data/lib/cyberarm_engine/window.rb +40 -8
  40. data/lib/cyberarm_engine.rb +8 -2
  41. data/mrbgem.rake +29 -0
  42. metadata +15 -3
@@ -30,6 +30,8 @@ module CyberarmEngine
30
30
  @y = @style.y
31
31
  @z = @style.z
32
32
 
33
+ @old_width = 0
34
+ @old_height = 0
33
35
  @width = 0
34
36
  @height = 0
35
37
 
@@ -65,6 +67,8 @@ module CyberarmEngine
65
67
 
66
68
  set_border_thickness
67
69
  set_border_color
70
+
71
+ root.gui_state.request_repaint
68
72
  end
69
73
 
70
74
  def safe_style_fetch(*args)
@@ -166,10 +170,10 @@ module CyberarmEngine
166
170
  return if self.is_a?(ToolTip)
167
171
 
168
172
  if old_width != width || old_height != height
169
- (root&.gui_state || @gui_state).request_recalculate
170
- else
171
- stylize
173
+ root.gui_state.request_recalculate
172
174
  end
175
+
176
+ stylize
173
177
  end
174
178
 
175
179
  def default_events
@@ -194,7 +198,7 @@ module CyberarmEngine
194
198
  end
195
199
 
196
200
  def enter(_sender)
197
- @focus = false unless window.button_down?(Gosu::MsLeft)
201
+ @focus = false unless Gosu.button_down?(Gosu::MS_LEFT)
198
202
 
199
203
  if !@enabled
200
204
  update_styles(:disabled)
@@ -256,6 +260,8 @@ module CyberarmEngine
256
260
  end
257
261
 
258
262
  def enabled=(boolean)
263
+ root.gui_state.request_repaint if @enabled != boolean
264
+
259
265
  @enabled = boolean
260
266
 
261
267
  recalculate
@@ -267,6 +273,10 @@ module CyberarmEngine
267
273
  @enabled
268
274
  end
269
275
 
276
+ def focused?
277
+ @focus
278
+ end
279
+
270
280
  def visible?
271
281
  @visible
272
282
  end
@@ -278,18 +288,21 @@ module CyberarmEngine
278
288
  def toggle
279
289
  @visible = !@visible
280
290
  root.gui_state.request_recalculate
291
+ root.gui_state.request_repaint
281
292
  end
282
293
 
283
294
  def show
284
295
  bool = visible?
285
296
  @visible = true
286
297
  root.gui_state.request_recalculate unless bool
298
+ root.gui_state.request_repaint unless bool
287
299
  end
288
300
 
289
301
  def hide
290
302
  bool = visible?
291
303
  @visible = false
292
304
  root.gui_state.request_recalculate if bool
305
+ root.gui_state.request_repaint if bool
293
306
  end
294
307
 
295
308
  def draw
@@ -305,7 +318,8 @@ module CyberarmEngine
305
318
  end
306
319
 
307
320
  def debug_draw
308
- return if defined?(GUI_DEBUG_ONLY_ELEMENT) && self.class == GUI_DEBUG_ONLY_ELEMENT
321
+ # FIXME
322
+ return# if const_defined?(GUI_DEBUG_ONLY_ELEMENT) && self.class == GUI_DEBUG_ONLY_ELEMENT
309
323
 
310
324
  Gosu.draw_line(
311
325
  x, y, @debug_color,
@@ -330,6 +344,7 @@ module CyberarmEngine
330
344
  end
331
345
 
332
346
  def update
347
+ recalculate_if_size_changed
333
348
  end
334
349
 
335
350
  def button_down(id)
@@ -399,10 +414,14 @@ module CyberarmEngine
399
414
  end
400
415
 
401
416
  def scroll_width
402
- @children.sum(&:outer_width)
417
+ return @cached_scroll_width if @cached_scroll_width && is_a?(Container)
418
+
419
+ @cached_scroll_width = @children.sum(&:outer_width)
403
420
  end
404
421
 
405
422
  def scroll_height
423
+ return @cached_scroll_height if @cached_scroll_height && is_a?(Container)
424
+
406
425
  if is_a?(CyberarmEngine::Element::Flow)
407
426
  return 0 if @children.size.zero?
408
427
 
@@ -423,41 +442,39 @@ module CyberarmEngine
423
442
 
424
443
  pairs_ << a_ unless pairs_.last == a_
425
444
 
426
- pairs_.sum { |pair| pair.map(&:outer_height).max } + @style.padding_bottom + @style.border_thickness_bottom
445
+ @cached_scroll_height = pairs_.sum { |pair| + @style.padding_top + @style.border_thickness_top + pair.map(&:outer_height).max } + @style.padding_bottom + @style.border_thickness_bottom
427
446
  else
428
- @children.sum(&:outer_height) + @style.padding_bottom + @style.border_thickness_bottom
447
+ @cached_scroll_height = @style.padding_top + @style.border_thickness_top + @children.sum(&:outer_height) + @style.padding_bottom + @style.border_thickness_bottom
429
448
  end
430
449
  end
431
450
 
432
451
  def max_scroll_width
433
- scroll_width - outer_width
452
+ (scroll_width - outer_width).positive? ? scroll_width - outer_width : scroll_width
434
453
  end
435
454
 
436
455
  def max_scroll_height
437
- scroll_height - outer_height
456
+ (scroll_height - outer_height).positive? ? scroll_height - outer_height : scroll_height
438
457
  end
439
458
 
440
459
  def dimensional_size(size, dimension)
441
460
  raise "dimension must be either :width or :height" unless %i[width height].include?(dimension)
442
461
 
443
- new_size = if size.is_a?(Numeric) && size.between?(0.0, 1.0)
444
- (@parent.send(:"content_#{dimension}") * size).floor - send(:"noncontent_#{dimension}").floor
445
- else
446
- size
462
+ new_size = if size.is_a?(Float) && size.between?(0.0, 1.0)
463
+ (@parent.send(:"content_#{dimension}") * size).floor - send(:"noncontent_#{dimension}").floor
464
+ else
465
+ size
466
+ end
467
+
468
+ # Handle fill behavior
469
+ if @parent && @style.fill &&
470
+ (dimension == :width && @parent.is_a?(Flow) ||
471
+ dimension == :height && @parent.is_a?(Stack))
472
+ new_size = space_available_width - noncontent_width if dimension == :width && @parent.is_a?(Flow)
473
+ new_size = space_available_height - noncontent_height if dimension == :height && @parent.is_a?(Stack)
447
474
  end
448
475
 
449
- if @parent && @style.fill # Handle fill behavior
450
- if dimension == :width && @parent.is_a?(Flow)
451
- return space_available_width - noncontent_width
452
-
453
- elsif dimension == :height && @parent.is_a?(Stack)
454
- return space_available_height - noncontent_height
455
- end
456
-
457
- else # Handle min_width/height and max_width/height
458
- return @style.send(:"min_#{dimension}") if @style.send(:"min_#{dimension}") && new_size.to_f < @style.send(:"min_#{dimension}")
459
- return @style.send(:"max_#{dimension}") if @style.send(:"max_#{dimension}") && new_size.to_f > @style.send(:"max_#{dimension}")
460
- end
476
+ return @style.send(:"min_#{dimension}") if @style.send(:"min_#{dimension}") && new_size.to_f < @style.send(:"min_#{dimension}")
477
+ return @style.send(:"max_#{dimension}") if @style.send(:"max_#{dimension}") && new_size.to_f > @style.send(:"max_#{dimension}")
461
478
 
462
479
  new_size
463
480
  end
@@ -479,6 +496,8 @@ module CyberarmEngine
479
496
  end
480
497
 
481
498
  def background=(_background)
499
+ root.gui_state.request_repaint
500
+
482
501
  @style.background_canvas.background = _background
483
502
  update_background
484
503
  end
@@ -497,6 +516,8 @@ module CyberarmEngine
497
516
  end
498
517
 
499
518
  def background_nine_slice=(_image_path)
519
+ root.gui_state.request_repaint
520
+
500
521
  @style.background_nine_slice_canvas.image = _image_path
501
522
  update_background_nine_slice
502
523
  end
@@ -521,6 +542,8 @@ module CyberarmEngine
521
542
  end
522
543
 
523
544
  def background_image=(image_path)
545
+ root.gui_state.request_repaint
546
+
524
547
  @style.background_image = image_path.is_a?(Gosu::Image) ? image_path : get_image(image_path)
525
548
  update_background_image
526
549
  end
@@ -538,6 +561,15 @@ module CyberarmEngine
538
561
  @style.background_image_canvas.image = @style.background_image
539
562
  end
540
563
 
564
+ def recalculate_if_size_changed
565
+ if !is_a?(ToolTip) && (@old_width != width || @old_height != height)
566
+ root.gui_state.request_recalculate
567
+
568
+ @old_width = width
569
+ @old_height = height
570
+ end
571
+ end
572
+
541
573
  def root
542
574
  return self if is_root?
543
575
 
@@ -558,6 +590,22 @@ module CyberarmEngine
558
590
  @gui_state != nil
559
591
  end
560
592
 
593
+ def child_of?(element)
594
+ return element == self if is_root?
595
+ return false unless element.is_a?(Container)
596
+ return true if element.children.find { |child| child == self }
597
+
598
+ element.children.find { |child| child.child_of?(element) if child.is_a?(Container) }
599
+ end
600
+
601
+ def parent_of?(element)
602
+ return false if element == self
603
+ return false unless is_a?(Container)
604
+ return true if @children.find { |child| child == element }
605
+
606
+ @children.find { |child| child.parent_of?(element) if child.is_a?(Container) }
607
+ end
608
+
561
609
  def focus(_)
562
610
  warn "#{self.class}#focus was not overridden!"
563
611
 
@@ -20,7 +20,10 @@ module CyberarmEngine
20
20
  @gui_state = options.delete(:gui_state)
21
21
  super
22
22
 
23
+ @last_scroll_position = Vector.new(0, 0)
23
24
  @scroll_position = Vector.new(0, 0)
25
+ @scroll_target_position = Vector.new(0, 0)
26
+ @scroll_chunk = 120
24
27
  @scroll_speed = 40
25
28
 
26
29
  @text_color = options[:color]
@@ -33,13 +36,17 @@ module CyberarmEngine
33
36
  def build
34
37
  @block.call(self) if @block
35
38
 
36
- root.gui_state.request_recalculate
39
+ root.gui_state.request_recalculate_for(self)
37
40
  end
38
41
 
39
42
  def add(element)
40
43
  @children << element
41
44
 
42
- root.gui_state.request_recalculate
45
+ root.gui_state.request_recalculate_for(self)
46
+ end
47
+
48
+ def remove(element)
49
+ root.gui_state.request_recalculate_for(self) if @children.delete(element)
43
50
  end
44
51
 
45
52
  def clear(&block)
@@ -52,7 +59,7 @@ module CyberarmEngine
52
59
 
53
60
  CyberarmEngine::Element::Container.current_container = old_container
54
61
 
55
- root.gui_state.request_recalculate
62
+ root.gui_state.request_recalculate_for(self)
56
63
  end
57
64
 
58
65
  def append(&block)
@@ -63,7 +70,7 @@ module CyberarmEngine
63
70
 
64
71
  CyberarmEngine::Element::Container.current_container = old_container
65
72
 
66
- root.gui_state.request_recalculate
73
+ root.gui_state.request_recalculate_for(self)
67
74
  end
68
75
 
69
76
  def render
@@ -73,7 +80,9 @@ module CyberarmEngine
73
80
  content_width + 1,
74
81
  content_height + 1
75
82
  ) do
76
- @children.each(&:draw)
83
+ Gosu.translate(@scroll_position.x, @scroll_position.y) do
84
+ @children.each(&:draw)
85
+ end
77
86
  end
78
87
  end
79
88
 
@@ -86,35 +95,74 @@ module CyberarmEngine
86
95
  end
87
96
 
88
97
  def update
98
+ update_scroll
89
99
  @children.each(&:update)
90
100
  end
91
101
 
92
102
  def hit_element?(x, y)
93
103
  return unless hit?(x, y)
94
104
 
105
+ # Offset child hit point by scroll position/offset
106
+ child_x = x - @scroll_position.x
107
+ child_y = y - @scroll_position.y
108
+
95
109
  @children.reverse_each do |child|
96
110
  next unless child.visible?
97
111
 
98
112
  case child
99
113
  when Container
100
- if element = child.hit_element?(x, y)
114
+ if element = child.hit_element?(child_x, child_y)
101
115
  return element
102
116
  end
103
117
  else
104
- return child if child.hit?(x, y)
118
+ return child if child.hit?(child_x, child_y)
105
119
  end
106
120
  end
107
121
 
108
122
  self if hit?(x, y)
109
123
  end
110
124
 
125
+ def update_child_element_visibity(child)
126
+ child.element_visible = child.x >= (@x - @scroll_position.x) - child.width && child.x <= (@x - @scroll_position.x) + width &&
127
+ child.y >= (@y - @scroll_position.y) - child.height && child.y <= (@y - @scroll_position.y) + height
128
+ end
129
+
130
+ def update_scroll
131
+ dt = window.dt > 1 ? 1.0 : window.dt
132
+
133
+ scroll_x_diff = (@scroll_target_position.x - @scroll_position.x)
134
+ scroll_y_diff = (@scroll_target_position.y - @scroll_position.y)
135
+
136
+ @scroll_position.x += (scroll_x_diff * @scroll_speed * 0.25 * dt).round
137
+ @scroll_position.y += (scroll_y_diff * @scroll_speed * 0.25 * dt).round
138
+
139
+ @scroll_position.x = @scroll_target_position.x if scroll_x_diff.abs < 1.0
140
+ @scroll_position.y = @scroll_target_position.y if scroll_y_diff.abs < 1.0
141
+
142
+ # Scrolled PAST top
143
+ if @scroll_position.y > 0
144
+ @scroll_target_position.y = 0
145
+
146
+ # Scrolled PAST bottom
147
+ elsif @scroll_position.y.abs > max_scroll_height
148
+ @scroll_target_position.y = -max_scroll_height
149
+ end
150
+
151
+ if @last_scroll_position != @scroll_position
152
+ @children.each { |child| update_child_element_visibity(child) }
153
+ root.gui_state.request_repaint
154
+ end
155
+
156
+ @last_scroll_position.x = @scroll_position.x
157
+ @last_scroll_position.y = @scroll_position.y
158
+ end
159
+
111
160
  def recalculate
112
161
  @current_position = Vector.new(@style.margin_left + @style.padding_left, @style.margin_top + @style.padding_top)
113
- @current_position += @scroll_position
114
162
 
115
163
  return unless visible?
116
164
 
117
- Stats.increment(:gui_recalculations_last_frame, 1)
165
+ Stats.frame.increment(:gui_recalculations)
118
166
 
119
167
  stylize
120
168
 
@@ -122,6 +170,12 @@ module CyberarmEngine
122
170
 
123
171
  layout
124
172
 
173
+ old_width = @width
174
+ old_height = @height
175
+
176
+ @cached_scroll_width = nil
177
+ @cached_scroll_height = nil
178
+
125
179
  if is_root?
126
180
  @width = @style.width = window.width
127
181
  @height = @style.height = window.height
@@ -169,15 +223,30 @@ module CyberarmEngine
169
223
  child.recalculate
170
224
  child.reposition # TODO: Implement top,bottom,left,center, and right positioning
171
225
 
172
- Stats.increment(:gui_recalculations_last_frame, 1)
226
+ Stats.frame.increment(:gui_recalculations)
173
227
 
174
- child.element_visible = child.x >= @x - child.width && child.x <= @x + width &&
175
- child.y >= @y - child.height && child.y <= @y + height
228
+ update_child_element_visibity(child)
176
229
  end
177
230
 
178
231
  # puts "TOOK: #{Gosu.milliseconds - s}ms to recalculate #{self.class}:0x#{self.object_id.to_s(16)}"
179
232
 
180
233
  update_background
234
+
235
+ # Fixes resized container scrolled past bottom
236
+ self.scroll_top = -@scroll_position.y
237
+ @scroll_target_position.y = @scroll_position.y
238
+
239
+ # NOTE: Experiment for removing need to explicitly call gui_state#recalculate at least 3 times for layout to layout...
240
+ if old_width != @width || old_height != @height
241
+ if @parent
242
+ root.gui_state.request_recalculate_for(@parent)
243
+ else
244
+ root.gui_state.request_recalculate
245
+ end
246
+ end
247
+
248
+ root.gui_state.request_repaint if @width != old_width || @height != old_height
249
+ recalculate_if_size_changed
181
250
  end
182
251
 
183
252
  def layout
@@ -237,11 +306,13 @@ module CyberarmEngine
237
306
  def mouse_wheel_up(sender, x, y)
238
307
  return unless @style.scroll
239
308
 
240
- if @scroll_position.y < 0
241
- @scroll_position.y += @scroll_speed
242
- @scroll_position.y = 0 if @scroll_position.y > 0
243
-
244
- root.gui_state.request_recalculate_for(self)
309
+ # Allow overscrolling UP, only if one can scroll DOWN
310
+ if height < scroll_height
311
+ if @scroll_target_position.y > 0
312
+ @scroll_target_position.y = @scroll_chunk
313
+ else
314
+ @scroll_target_position.y += @scroll_chunk
315
+ end
245
316
 
246
317
  return :handled
247
318
  end
@@ -252,14 +323,13 @@ module CyberarmEngine
252
323
 
253
324
  return unless height < scroll_height
254
325
 
255
- if @scroll_position.y.abs < max_scroll_height
256
- @scroll_position.y -= @scroll_speed
257
- @scroll_position.y = -max_scroll_height if @scroll_position.y.abs > max_scroll_height
258
-
259
- root.gui_state.request_recalculate_for(self)
260
-
261
- return :handled
326
+ if @scroll_target_position.y > 0
327
+ @scroll_target_position.y = -@scroll_chunk
328
+ else
329
+ @scroll_target_position.y -= @scroll_chunk
262
330
  end
331
+
332
+ return :handled
263
333
  end
264
334
 
265
335
  def scroll_top
@@ -278,7 +348,7 @@ module CyberarmEngine
278
348
  end
279
349
 
280
350
  def value
281
- @children.map { |c| c.class }.join(", ")
351
+ @children.map(&:class).join(", ")
282
352
  end
283
353
 
284
354
  def to_s
@@ -80,16 +80,22 @@ module CyberarmEngine
80
80
  @show_caret = true
81
81
  @caret_last_interval = Gosu.milliseconds
82
82
 
83
+ root.gui_state.request_repaint
84
+
83
85
  publish(:changed, value)
84
86
  end
85
87
 
86
88
  if @last_caret_position != @text_input.caret_pos
87
89
  @last_caret_position = @text_input.caret_pos
90
+ root.gui_state.request_repaint
91
+
88
92
  @show_caret = true
89
93
  @caret_last_interval = Gosu.milliseconds
90
94
  end
91
95
 
92
96
  if Gosu.milliseconds >= @caret_last_interval + @caret_interval
97
+ root.gui_state.request_repaint
98
+
93
99
  @caret_last_interval = Gosu.milliseconds
94
100
 
95
101
  @show_caret = !@show_caret
@@ -45,8 +45,8 @@ module CyberarmEngine
45
45
  @scale_y = 1
46
46
  end
47
47
 
48
- @width = _width || @image.width.floor * @scale_x
49
- @height = _height || @image.height.floor * @scale_y
48
+ @width = _width || (@image.width * @scale_x).floor
49
+ @height = _height || (@image.height * @scale_y).floor
50
50
 
51
51
  update_background
52
52
  end
@@ -52,6 +52,7 @@ module CyberarmEngine
52
52
  @marquee_animation_time = Gosu.milliseconds if @marquee_offset > range
53
53
 
54
54
  update_background
55
+ root.gui_state.request_repaint
55
56
  end
56
57
 
57
58
  def type=(type)
@@ -77,9 +78,13 @@ module CyberarmEngine
77
78
  def value=(decimal)
78
79
  raise "value must be number" unless decimal.is_a?(Numeric)
79
80
 
81
+ old_value = @fraction
82
+
80
83
  @fraction = decimal.clamp(0.0, 1.0)
81
84
  update_background
82
85
 
86
+ root.gui_state.request_repaint if @fraction != old_value
87
+
83
88
  publish(:changed, @fraction)
84
89
  @fraction
85
90
  end
@@ -33,7 +33,8 @@ module CyberarmEngine
33
33
  end
34
34
  end
35
35
 
36
- attr_reader :range, :step_size, :value
36
+ attr_reader :step_size, :value
37
+ attr_accessor :range, :step_size
37
38
 
38
39
  def initialize(options = {}, block = nil)
39
40
  super(options, block)
@@ -76,7 +77,7 @@ module CyberarmEngine
76
77
  def update
77
78
  super
78
79
 
79
- @tip = value.to_s
80
+ @tip = format("%.2f", value.to_f)
80
81
  @handle.tip = @tip
81
82
  end
82
83
 
@@ -87,7 +88,7 @@ module CyberarmEngine
87
88
  end
88
89
 
89
90
  def handle_dragged_to(x, _y)
90
- @ratio = ((x - @handle.width / 2) - @x) / (content_width - @handle.outer_width)
91
+ @ratio = ((x - @handle.width / 2.0) - @x) / (content_width - @handle.outer_width.to_f)
91
92
 
92
93
  self.value = @ratio.clamp(0.0, 1.0) * (@range.max - @range.min) + @range.min
93
94
  end
@@ -97,6 +98,8 @@ module CyberarmEngine
97
98
  position_handle
98
99
  @handle.recalculate
99
100
 
101
+ root.gui_state.request_repaint
102
+
100
103
  publish(:changed, @value)
101
104
  end
102
105
  end
@@ -18,6 +18,15 @@ module CyberarmEngine
18
18
  @raw_text = text
19
19
  end
20
20
 
21
+ def update
22
+ super
23
+
24
+ if @text.textobject.name != safe_style_fetch(:font)
25
+ set_font
26
+ root.gui_state.request_recalculate
27
+ end
28
+ end
29
+
21
30
  def render
22
31
  # Gosu.clip_to is too expensive to always use so check if we actually need it.
23
32
  if @text.width > width || @text.height > height
@@ -36,6 +45,9 @@ module CyberarmEngine
36
45
  @text.color = @style.color
37
46
  end
38
47
 
48
+ old_width = @width
49
+ old_height = @height
50
+
39
51
  @width = 0
40
52
  @height = 0
41
53
 
@@ -79,6 +91,9 @@ module CyberarmEngine
79
91
  end
80
92
 
81
93
  update_background
94
+
95
+ root.gui_state.request_repaint if @width != old_width || @height != old_height
96
+ recalculate_if_size_changed
82
97
  end
83
98
 
84
99
  def handle_text_wrapping(max_width)
@@ -151,7 +166,7 @@ module CyberarmEngine
151
166
  end
152
167
 
153
168
  def line_width(text)
154
- (@text.textobject.markup_width(text) + noncontent_width)
169
+ (@text.textobject.markup_width(text.to_s) + noncontent_width)
155
170
  end
156
171
 
157
172
  def value
@@ -159,6 +174,7 @@ module CyberarmEngine
159
174
  end
160
175
 
161
176
  def value=(value)
177
+ old_value = @raw_text
162
178
  @raw_text = value.to_s.chomp
163
179
 
164
180
  old_width = width
@@ -170,6 +186,8 @@ module CyberarmEngine
170
186
  recalculate
171
187
  end
172
188
 
189
+ root.gui_state.request_repaint if old_value != @raw_text
190
+
173
191
  publish(:changed, self.value)
174
192
  end
175
193
  end