box.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. /*
  2. * File : box.c
  3. * This file is part of RT-Thread RTOS
  4. * COPYRIGHT (C) 2006 - 2009, RT-Thread Development Team
  5. *
  6. * The license and distribution terms for this file may be
  7. * found in the file LICENSE in this distribution or at
  8. * http://www.rt-thread.org/license/LICENSE
  9. *
  10. * Change Logs:
  11. * Date Author Notes
  12. * 2009-10-16 Bernard first version
  13. */
  14. #include <rtgui/dc.h>
  15. #include <rtgui/widgets/box.h>
  16. static void _rtgui_box_constructor(rtgui_box_t *box)
  17. {
  18. /* init widget and set event handler */
  19. rtgui_widget_set_event_handler(RTGUI_WIDGET(box), rtgui_box_event_handler);
  20. RTGUI_WIDGET(box)->flag |= RTGUI_WIDGET_FLAG_TRANSPARENT;
  21. rtgui_widget_set_event_handler(RTGUI_WIDGET(box), rtgui_box_event_handler);
  22. /* set proper of control */
  23. box->orientation = RTGUI_HORIZONTAL;
  24. box->border_size = RTGUI_BORDER_DEFAULT_WIDTH;
  25. }
  26. rtgui_type_t *rtgui_box_type_get(void)
  27. {
  28. static rtgui_type_t *box_type = RT_NULL;
  29. if (!box_type)
  30. {
  31. box_type = rtgui_type_create("box", RTGUI_CONTAINER_TYPE,
  32. sizeof(rtgui_box_t), RTGUI_CONSTRUCTOR(_rtgui_box_constructor), RT_NULL);
  33. }
  34. return box_type;
  35. }
  36. rt_bool_t rtgui_box_event_handler(rtgui_widget_t* widget, rtgui_event_t* event)
  37. {
  38. struct rtgui_box* box = (struct rtgui_box*)widget;
  39. RT_ASSERT(box != RT_NULL);
  40. switch (event->type)
  41. {
  42. case RTGUI_EVENT_RESIZE:
  43. /* re-layout */
  44. rtgui_box_layout(box);
  45. break;
  46. default:
  47. return rtgui_container_event_handler(RTGUI_WIDGET(box), event);
  48. }
  49. return RT_FALSE;
  50. }
  51. struct rtgui_box* rtgui_box_create(int orientation, rtgui_rect_t* rect)
  52. {
  53. struct rtgui_box* box;
  54. box = (struct rtgui_box*) rtgui_widget_create (RTGUI_BOX_TYPE);
  55. if (box != RT_NULL)
  56. {
  57. /* set proper of control */
  58. rtgui_widget_set_rect(RTGUI_WIDGET(box), rect);
  59. box->orientation = orientation;
  60. }
  61. return box;
  62. }
  63. void rtgui_box_append(struct rtgui_box* box, rtgui_widget_t* widget)
  64. {
  65. /* put to box's children list */
  66. rtgui_container_add_child(RTGUI_CONTAINER(box), widget);
  67. }
  68. static void rtgui_box_layout_vertical(rtgui_box_t* box)
  69. {
  70. rtgui_list_t *node;
  71. rt_int32_t box_width;
  72. rt_int32_t space_count;
  73. rt_int32_t next_x, next_y;
  74. rt_int32_t total_height, space_height;
  75. struct rtgui_event_resize size_event;
  76. /* prepare the resize event */
  77. RTGUI_EVENT_RESIZE_INIT(&size_event);
  78. /* find spaces */
  79. space_count = 0;
  80. total_height = 0;
  81. space_height = 0;
  82. rtgui_list_foreach(node, &(RTGUI_CONTAINER(box)->children))
  83. {
  84. rtgui_widget_t* widget = rtgui_list_entry(node, struct rtgui_widget, sibling);
  85. if (widget->align & RTGUI_ALIGN_STRETCH) space_count ++;
  86. else total_height += widget->mini_height;
  87. }
  88. /* calculate the height for each spaces */
  89. if (space_count != 0)
  90. {
  91. space_height = (rtgui_rect_height(RTGUI_WIDGET(box)->extent) - total_height - (box->border_size << 1)) / space_count;
  92. }
  93. /* init (x, y) and box width */
  94. next_x = RTGUI_WIDGET(box)->extent.x1 + box->border_size;
  95. next_y = RTGUI_WIDGET(box)->extent.y1 + box->border_size;
  96. box_width = rtgui_rect_width(RTGUI_WIDGET(box)->extent) - (box->border_size << 1);
  97. /* layout each widget */
  98. rtgui_list_foreach(node, &(RTGUI_CONTAINER(box)->children))
  99. {
  100. rtgui_rect_t *rect;
  101. rtgui_widget_t* widget = rtgui_list_entry(node, struct rtgui_widget, sibling);
  102. /* get extent of widget */
  103. rect = &(widget->extent);
  104. /* reset rect */
  105. rtgui_rect_moveto(rect, -rect->x1, -rect->y1);
  106. rect->x2 = widget->mini_width;
  107. rect->y2 = widget->mini_height;
  108. /* left in default */
  109. rtgui_rect_moveto(rect, next_x, next_y);
  110. if (widget->align & RTGUI_ALIGN_EXPAND)
  111. {
  112. /* expand on horizontal */
  113. rect->x2 = rect->x1 + (rt_int16_t)box_width;
  114. }
  115. if (widget->align & RTGUI_ALIGN_CENTER_VERTICAL)
  116. {
  117. /* center */
  118. rt_uint32_t mid;
  119. mid = box_width - rtgui_rect_width(*rect);
  120. mid = mid /2;
  121. rect->x1 = next_x + mid;
  122. rect->x2 = next_x + box_width - mid;
  123. }
  124. else if (widget->align & RTGUI_ALIGN_RIGHT)
  125. {
  126. /* right */
  127. rect->x1 = next_x + box_width - rtgui_rect_width(*rect);
  128. rect->x2 = next_x + box_width;
  129. }
  130. if (widget->align & RTGUI_ALIGN_STRETCH)
  131. {
  132. rect->y2 = rect->y1 + space_height;
  133. }
  134. /* process resize event */
  135. size_event.x = rect->x1;
  136. size_event.y = rect->y1;
  137. size_event.w = rect->x2 - rect->x1;
  138. size_event.h = rect->y2 - rect->y1;
  139. widget->event_handler(widget, &size_event.parent);
  140. /* point to next height */
  141. next_y = rect->y2;
  142. }
  143. }
  144. static void rtgui_box_layout_horizontal(rtgui_box_t* box)
  145. {
  146. rtgui_list_t *node;
  147. rt_int32_t box_height;
  148. rt_int32_t space_count;
  149. rt_int32_t next_x, next_y;
  150. rt_int32_t total_width, space_width;
  151. struct rtgui_event_resize size_event;
  152. /* prepare the resize event */
  153. RTGUI_EVENT_RESIZE_INIT(&size_event);
  154. /* find spaces */
  155. space_count = 0;
  156. total_width = 0;
  157. space_width = 0;
  158. rtgui_list_foreach(node, &(RTGUI_CONTAINER(box)->children))
  159. {
  160. rtgui_widget_t* widget = rtgui_list_entry(node, struct rtgui_widget, sibling);
  161. if (widget->align & RTGUI_ALIGN_STRETCH) space_count ++;
  162. else total_width += widget->mini_width;
  163. }
  164. if (space_count != 0)
  165. {
  166. /* calculate the height for each spaces */
  167. space_width = (rtgui_rect_width(RTGUI_WIDGET(box)->extent) - total_width) / space_count;
  168. }
  169. /* init (x, y) and box height */
  170. next_x = RTGUI_WIDGET(box)->extent.x1 + box->border_size;
  171. next_y = RTGUI_WIDGET(box)->extent.y1 + box->border_size;
  172. box_height = rtgui_rect_height(RTGUI_WIDGET(box)->extent) - (box->border_size << 1);
  173. /* layout each widget */
  174. rtgui_list_foreach(node, &(RTGUI_CONTAINER(box)->children))
  175. {
  176. rtgui_rect_t *rect;
  177. rtgui_widget_t* widget = rtgui_list_entry(node, struct rtgui_widget, sibling);
  178. /* get extent of widget */
  179. rect = &(widget->extent);
  180. /* reset rect */
  181. rtgui_rect_moveto(rect, -rect->x1, -rect->y1);
  182. rect->x2 = widget->mini_width;
  183. rect->y2 = widget->mini_height;
  184. /* top in default */
  185. rtgui_rect_moveto(rect, next_x, next_y);
  186. if (widget->align & RTGUI_ALIGN_EXPAND)
  187. {
  188. /* expand on vertical */
  189. rect->y2 = rect->y1 + box_height;
  190. }
  191. if (widget->align & RTGUI_ALIGN_CENTER_HORIZONTAL)
  192. {
  193. /* center */
  194. rt_uint32_t mid;
  195. mid = box_height - rtgui_rect_height(*rect);
  196. mid = mid /2;
  197. rect->y1 = next_y + mid;
  198. rect->y2 = next_y + box_height - mid;
  199. }
  200. else if (widget->align & RTGUI_ALIGN_RIGHT)
  201. {
  202. /* right */
  203. rect->y1 = next_y + box_height - rtgui_rect_height(*rect);
  204. rect->y2 = next_y + box_height;
  205. }
  206. if (widget->align & RTGUI_ALIGN_STRETCH)
  207. {
  208. rect->x2 = rect->x1 + space_width;
  209. }
  210. /* process resize event */
  211. size_event.x = rect->x1;
  212. size_event.y = rect->y1;
  213. size_event.w = rect->x2 - rect->x1;
  214. size_event.h = rect->y2 - rect->y1;
  215. widget->event_handler(widget, &size_event.parent);
  216. /* point to next width */
  217. next_x = rect->x2;
  218. }
  219. }
  220. void rtgui_box_layout(rtgui_box_t* box)
  221. {
  222. RT_ASSERT(box != RT_NULL);
  223. if (box->orientation & RTGUI_VERTICAL)
  224. {
  225. rtgui_box_layout_vertical(box);
  226. }
  227. else
  228. {
  229. rtgui_box_layout_horizontal(box);
  230. }
  231. /* update box and its children clip */
  232. if (!RTGUI_WIDGET_IS_HIDE(RTGUI_WIDGET(box)))
  233. {
  234. rtgui_widget_update_clip(RTGUI_WIDGET(box));
  235. }
  236. }
  237. rt_uint32_t rtgui_box_get_width(rtgui_box_t* box)
  238. {
  239. rtgui_list_t *node;
  240. rt_uint32_t width;
  241. width = 0;
  242. rtgui_list_foreach(node, &(RTGUI_CONTAINER(box)->children))
  243. {
  244. rtgui_widget_t* widget = rtgui_list_entry(node, struct rtgui_widget, sibling);
  245. rt_uint32_t widget_width;
  246. widget_width = rtgui_rect_width(widget->extent);
  247. if (box->orientation & RTGUI_VERTICAL)
  248. {
  249. /* get the max width */
  250. if (width < widget_width) width = widget_width;
  251. }
  252. else
  253. {
  254. /* get the total width */
  255. width += widget_width;
  256. }
  257. }
  258. return width;
  259. }
  260. rt_uint32_t rtgui_box_get_height(rtgui_box_t* box)
  261. {
  262. rtgui_list_t *node;
  263. rt_uint32_t height;
  264. height = 0;
  265. rtgui_list_foreach(node, &(RTGUI_CONTAINER(box)->children))
  266. {
  267. rtgui_widget_t* widget = rtgui_list_entry(node, struct rtgui_widget, sibling);
  268. rt_uint32_t widget_height;
  269. widget_height = rtgui_rect_height(widget->extent);
  270. if (box->orientation & RTGUI_HORIZONTAL)
  271. {
  272. /* get the max height */
  273. if (height < widget_height) height = widget_height;
  274. }
  275. else
  276. {
  277. /* get the total height */
  278. height += widget_height;
  279. }
  280. }
  281. return height;
  282. }