layout_component.rb 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. ## $Id$
  2. ## ______ __ ___
  3. ## | ___| |.-----.--.--.| | .---.-.--.--.
  4. ## | ___| || -__|_ _|| |_| _ | | |
  5. ## |__| |__||_____|__.__||_____|___._|___ |
  6. ## |_____|
  7. ## Copyright (C) 2004 Ingo Ruhnke <grumbel@gmx.de>
  8. ##
  9. ## This program is free software: you can redistribute it and/or modify
  10. ## it under the terms of the GNU General Public License as published by
  11. ## the Free Software Foundation, either version 3 of the License, or
  12. ## (at your option) any later version.
  13. ##
  14. ## This program is distributed in the hope that it will be useful,
  15. ## but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. ## GNU General Public License for more details.
  18. ##
  19. ## You should have received a copy of the GNU General Public License
  20. ## along with this program. If not, see <http://www.gnu.org/licenses/>.
  21. require "sexpr.rb"
  22. # Helper class that holds all necesarry paramter to handle layouting,
  23. # could also extend Component instead
  24. class LayoutComponent
  25. attr_reader :component, :name, :size,:expand, :fill, :padding
  26. # use nil for width and height if it should be determined
  27. # automatically
  28. def initialize(component, child, params)
  29. @component = component
  30. @child = child
  31. @name = params[:name]
  32. @size = params[:size]
  33. @expand = params[:expand]
  34. @fill = params[:fill]
  35. @padding = params[:padding]
  36. end
  37. def get(name)
  38. if @child then
  39. return @child.get(name)
  40. else
  41. return nil
  42. end
  43. end
  44. def set_pos(x, y)
  45. if @component then
  46. @component.set_position(x, y)
  47. end
  48. end
  49. def set_size(width, height)
  50. if @component then
  51. @component.set_size(width, height)
  52. end
  53. if @child then
  54. @child.set_size(width, height)
  55. end
  56. end
  57. # Rearanges the layout to fit the current size
  58. def layout()
  59. if @child then
  60. return @child.layout()
  61. end
  62. end
  63. def LayoutComponent.create_from_sexpr(rect, sexpr, parent)
  64. create(sexpr.car().value(), rect, sexpr.cdr(), parent)
  65. end
  66. def LayoutComponent.create(type, rect, sexpr, parent)
  67. # puts "Create: #{type}"
  68. case type
  69. when :vbox
  70. return LayoutBox.new(type, rect, sexpr, parent)
  71. when :hbox
  72. return LayoutBox.new(type, rect, sexpr, parent)
  73. when :panel
  74. panel = Panel.new(rect, parent)
  75. return LayoutComponent.new(panel,
  76. LayoutBox.new(sexpr.get_value([:layout, '_'], :vbox),
  77. CL_Rect.new(0, 0, rect.get_width(), rect.get_height()),
  78. sexpr, panel),
  79. :name => sexpr.get_value([:name, '_'], nil),
  80. :size => sexpr.get_value([:size, '_'], nil),
  81. :expand => sexpr.get_value([:expand, '_'], true),
  82. :fill => sexpr.get_value([:fill, '_'], true),
  83. :padding => sexpr.get_value([:padding, '_'], 0))
  84. when :tab
  85. return TabComponent.new(rect, sexpr, parent)
  86. else
  87. return LayoutComponent.new(create_raw(type, rect, sexpr, parent),
  88. nil,
  89. :name => sexpr.get_value([:name, '_'], nil),
  90. :size => sexpr.get_value([:size, '_'], nil),
  91. :expand => sexpr.get_value([:expand, '_'], true),
  92. :fill => sexpr.get_value([:fill, '_'], true),
  93. :padding => sexpr.get_value([:padding, '_'], 0))
  94. end
  95. end
  96. def LayoutComponent.create_raw(type, rect, sexpr, parent)
  97. case type
  98. when :editormap
  99. return EditorMapComponent.new(rect, parent)
  100. when :menubar
  101. return CL_Menu.new_from_spec(sexpr.get_value(['spec', '_'], []),
  102. parent)
  103. when :button
  104. return CL_Button.new(rect,
  105. sexpr.get_value(['label', '_'], []),
  106. parent)
  107. when :label
  108. return CL_Label.new(CL_Point.new(rect.top, rect.left),
  109. sexpr.get_value(['label', '_'], []),
  110. parent)
  111. when :listbox
  112. return CL_ListBox.new(rect, parent)
  113. when :inputbox
  114. return CL_InputBox.new(rect, parent)
  115. when :radiobutton
  116. return CL_RadioButton.new(CL_Point.new(rect.left, rect.top),
  117. sexpr.get_value(['label', '_'], []),
  118. parent)
  119. when :radiogroup
  120. return CL_RadioGroup.new()
  121. when :checkbox
  122. return CL_CheckBox.new(CL_Point.new(rect.left, rect.top),
  123. sexpr.get_value(['label', '_'], []),
  124. parent)
  125. when :buttonpanel
  126. return ButtonPanel.new_from_spec(rect.left, rect.top, rect.get_width(), rect.get_height(), true,
  127. sexpr.get_value([:spec, '_'], []), parent)
  128. when :tileselector
  129. return TileSelector.new(rect, parent)
  130. when :objectselector
  131. return ObjectSelector.new(rect,
  132. sexpr.get_value([:objectwidth, '_'], 42),
  133. sexpr.get_value([:objectheight, '_'], 42),
  134. parent)
  135. when :minimap
  136. @minimap = Minimap.new(nil, rect, parent)
  137. else
  138. raise "Unknonwn Component type '#{type.inspect}'"
  139. end
  140. end
  141. end
  142. class TabComponent < LayoutComponent
  143. def initialize(rect, sexpr, parent)
  144. super(nil, nil,
  145. :name => sexpr.get_value([:name, '_'], nil),
  146. :size => sexpr.get_value([:size, '_'], nil),
  147. :expand => sexpr.get_value([:expand, '_'], true),
  148. :fill => sexpr.get_value([:fill, '_'], true),
  149. :padding => sexpr.get_value([:padding, '_'], 0))
  150. @childs = []
  151. sexpr.get(:components, SExpression.new()).each_pair() { |name, value|
  152. @childs.push(LayoutComponent.create(name, CL_Rect.new(0, 0, 256, 256), value, parent))
  153. }
  154. end
  155. def get(name)
  156. @childs.each() { |i|
  157. if i.name == name then
  158. return i
  159. end
  160. }
  161. return nil
  162. end
  163. def set_pos(x, y)
  164. @childs.each() { |i| i.set_pos(x, y) }
  165. end
  166. def set_size(width, height)
  167. @childs.each() { |i| i.set_size(width, height) }
  168. end
  169. # Rearanges the layout to fit the current size
  170. def layout()
  171. @childs.each() { |i| i.layout() }
  172. end
  173. end
  174. class LayoutBox < LayoutComponent
  175. def initialize(type, rect, sexpr, parent)
  176. super(nil, nil,
  177. :name => sexpr.get_value([:name, '_'], nil),
  178. :size => sexpr.get_value([:size, '_'], nil),
  179. :expand => sexpr.get_value([:expand, '_'], true),
  180. :fill => sexpr.get_value([:fill, '_'], true),
  181. :padding => sexpr.get_value([:padding, '_'], 0))
  182. @type = type # :vbox or :hbox
  183. @x = rect.left
  184. @y = rect.top
  185. @width = rect.get_width()
  186. @height = rect.get_height()
  187. @parent = parent
  188. @components = []
  189. @homogenus = false
  190. sexpr.get(:components, SExpression.new()).each_pair() { |name, value|
  191. @components.push(LayoutComponent.create(name, CL_Rect.new(0, 0, 256, 256), value, @parent))
  192. }
  193. layout()
  194. end
  195. def get(name)
  196. @components.each() { |i|
  197. if i.name == name then
  198. return i
  199. else
  200. a = i.get(name)
  201. if a then return a end
  202. end
  203. }
  204. return nil
  205. end
  206. def add(type, spec)
  207. @components.push([type, spec, nil])
  208. end
  209. def set_pos(x, y)
  210. @x = x
  211. @y = y
  212. layout()
  213. end
  214. def set_size(width, height)
  215. @width = width
  216. @height = height
  217. layout()
  218. end
  219. def layout()
  220. x = @x
  221. y = @y
  222. len = 0
  223. num = 0
  224. @components.each() { |component|
  225. if component.size then
  226. len += component.size
  227. else
  228. num += 1
  229. end
  230. }
  231. if @type == :vbox
  232. avlen = (@height - len) / num
  233. @components.each() { |component|
  234. component.set_pos(x + component.padding, y + component.padding)
  235. if component.size then
  236. component.set_size(@width - component.padding*2, component.size - component.padding*2)
  237. y += component.size
  238. else
  239. component.set_size(@width - component.padding*2, avlen - component.padding*2)
  240. y += avlen
  241. end
  242. }
  243. elsif @type == :hbox
  244. avlen = (@width - len) / num
  245. @components.each() { |component|
  246. component.set_pos(x + component.padding, y + component.padding)
  247. if component.size then
  248. component.set_size(component.size - component.padding*2, @height - component.padding*2)
  249. x += component.size
  250. else
  251. component.set_size(avlen - component.padding*2, @height - component.padding*2)
  252. x += avlen
  253. end
  254. }
  255. else
  256. raise "LayoutBox: Unknown type #{type}"
  257. end
  258. end
  259. end
  260. ## EOF ##