widget.rb 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. module Zori
  2. # A widget may have sub-widgets
  3. module Widget
  4. include Graphic
  5. include State
  6. # Position of the widget.
  7. attr_reader :x
  8. attr_reader :y
  9. attr_reader :z
  10. # Dimensions of the widget.
  11. attr_reader :w
  12. attr_reader :h
  13. # Style of the widget
  14. attr_reader :style
  15. # Capabilities of the widget
  16. attr_reader :can
  17. # State of the widget
  18. attr_reader :state
  19. # Parent of a widget
  20. attr_accessor :parent
  21. def initialize(params={}, &block)
  22. super(params, &block)
  23. @action = block
  24. @components = []
  25. @x = params[:x] || 0
  26. @y = params[:y] || 0
  27. @w = params[:w] || 640
  28. @h = params[:h] || 480
  29. self.init_graph
  30. @z = params[:z] || 0
  31. @style = Zori::Style.default.dup
  32. # deep copy the default style
  33. @can = Zori::Capability.new
  34. @state = :active
  35. @parent = nil
  36. # Widget is active
  37. # @action = action
  38. end
  39. # Helper dimension, equal to x + w
  40. def left
  41. @x + @w
  42. end
  43. # Helper dimension, equal to y + h
  44. def bottom
  45. @y + @h
  46. end
  47. # Called when an event comes in from the Eruta engine.
  48. # Tries every component of this widget in order and stops if a truthy
  49. # value is returned. Finally calls handle_event on self in case
  50. # no component handles the event.
  51. def on_event(*data)
  52. return false if disabled? || hidden?
  53. if @components
  54. @components.each do | component |
  55. res = component.on_event(*data)
  56. return res if res
  57. end
  58. end
  59. res = handle_event(*data)
  60. end
  61. # The widget's own event handler will try to call a method named on_eventname
  62. def handle_event(*args)
  63. type = args.shift
  64. return false unless type
  65. method = "on_#{type}".to_sym
  66. # Try direct handler call.
  67. if self.respond_to?(method)
  68. return self.send(method, *args)
  69. else
  70. return nil
  71. end
  72. end
  73. # Adds a component to this widget
  74. # Will try to send a on_component event with
  75. def <<(component)
  76. component.parent = self
  77. @components << component
  78. self.on_event(:component, component)
  79. end
  80. # Checks if the coordinates are inside the main rectange of the widget.
  81. def inside?(x, y)
  82. return (x >= @x) && (x <= (@x + w)) && (y >= @y) && (y <= (@y + h))
  83. end
  84. # Makes the widget fit all direct children with the given margins
  85. def fit_children(margin_x = 20, margin_y = 20)
  86. min_x, min_y, = 640, 480 # XXX get this from somewhere...
  87. max_y, max_x = 0, 0
  88. @components.each do | child |
  89. min_x = child.x if child.x < min_x
  90. min_y = child.y if child.y < min_y
  91. max_x = child.left if child.left > max_x
  92. max_y = child.bottom if child.bottom > max_y
  93. end
  94. @x = min_x - margin_x
  95. @y = min_y - margin_y
  96. @w = max_x - min_x + margin_x * 2
  97. @h = max_y - min_y + margin_y * 2
  98. on_resize
  99. end
  100. # Adds a menu to this widget as a child widget
  101. def make_menu(x, y, w, h, heading, &block)
  102. menu = Zori::Menu.new(:x => x, :y => y, :w => w, :h => h, :heading => heading, &block)
  103. self << menu
  104. return menu
  105. end
  106. # Adds a button to this widget as a child widget
  107. def make_button(x, y, w, h, heading, &block)
  108. button = Zori::Button.new(:x => x, :y => y, :w => w, :h => h, :heading => heading, &block)
  109. self << button
  110. return button
  111. end
  112. # Adds a longtext to this widget as a child widget
  113. def make_longtext(x, y, w, h, text, &block)
  114. lt = Zori::LongText.new(:x => x, :y => y, :w => w, :h => h, :text => text,
  115. &block)
  116. self << lt
  117. return lt
  118. end
  119. # Triggers the widget and call its action block
  120. def trigger
  121. return @action.call if @action
  122. return nil
  123. end
  124. end
  125. end