zori_widget.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701
  1. #include "zori.h"
  2. #include "zori_widget.h"
  3. #include "zori_registry.h"
  4. #include "zori_style.h"
  5. #include "zori_screen.h"
  6. #include "monolog.h"
  7. #include "draw.h"
  8. bool zori_widget_is_type(struct zori_widget * widget, zori_widget_type type) {
  9. if(!widget) return false;
  10. return (type) == widget->type;
  11. }
  12. bool zori_widget_is_type_predicate(struct zori_widget * widget, void * extra) {
  13. zori_widget_type * type_ptr = extra;
  14. if(!type_ptr) return false;
  15. return zori_widget_is_type(widget, (*type_ptr));
  16. }
  17. struct zori_widget *
  18. zori_widget_get_parent_of_type(struct zori_widget * widget,
  19. zori_widget_type type) {
  20. return zori_widget_find_parent(widget, zori_widget_is_type_predicate, &type);
  21. }
  22. struct zori_screen * zori_widget_get_screen(struct zori_widget * widget) {
  23. struct zori_widget * screen_widget = zori_widget_get_parent_of_type(widget, ZORI_WIDGET_TYPE_SCREEN);
  24. return zori_widget_to_screen(screen_widget);
  25. }
  26. /** Returns whether or not a widget will even handle an event in the first place.
  27. * For example, a hidden widget won't draw, and a disabled widget won't
  28. * accept any system events, and a NULL widget doesn't accept events at all.. */
  29. int zori_widget_accepts_event(struct zori_widget * widget, union zori_event * event) {
  30. if (!widget) return 0;
  31. switch(event->any.type) {
  32. case ZORI_EVENT_DRAW:
  33. return zori_widget_visible(widget);
  34. default:
  35. return zori_widget_active(widget);
  36. }
  37. }
  38. /** Raises an event on the widget itself only. */
  39. int zori_widget_self_raise_event(struct zori_widget * widget,
  40. union zori_event * event) {
  41. enum zori_handle_result result;
  42. if (zori_widget_accepts_event(widget, event)) {
  43. event->any.widget = widget;
  44. return zori_handlers_handle(&widget->handlers, event);
  45. }
  46. /* If the event is not accepted, it is NOT passed on to the child widgets. */
  47. return ZORI_HANDLE_DONE;
  48. }
  49. /* Raises an event on the widget, and if necessary, propagates it on to it's
  50. * children automatically and recursively. */
  51. int
  52. zori_widget_raise_event(struct zori_widget * widget, union zori_event * event) {
  53. if (!widget) return ZORI_HANDLE_DONE;
  54. enum zori_handle_result result =
  55. zori_widget_self_raise_event(widget, event);
  56. if (zori_propagate_event_p(result)) {
  57. enum zori_handle_result sub;
  58. size_t index;
  59. for (index = 0; index < miao_size(&widget->children); index++) {
  60. struct zori_widget * child = miao_unsafe_get(&widget->children, index);
  61. event->any.widget = child;
  62. sub = zori_widget_raise_event(child, event);
  63. if (sub == ZORI_HANDLE_DONE) {
  64. result = ZORI_HANDLE_DONE;
  65. break;
  66. }
  67. }
  68. }
  69. return result;
  70. }
  71. int zori_widget_raise_system_event
  72. (struct zori_widget * widget, zori_system_event * sysev) {
  73. union zori_event event;
  74. event.sys.any.type = sysev->type;
  75. event.sys.any.widget = widget;
  76. event.sys.ev = sysev;
  77. return zori_widget_raise_event(widget, &event);
  78. }
  79. int zori_widget_raise_draw_event(struct zori_widget * widget) {
  80. union zori_event event;
  81. event.draw.any.type = ZORI_EVENT_DRAW;
  82. event.draw.any.widget = widget;
  83. return zori_widget_raise_event(widget, &event);
  84. }
  85. int zori_widget_raise_overdraw_event(struct zori_widget * widget) {
  86. union zori_event event;
  87. event.draw.any.type = ZORI_EVENT_OVERDRAW;
  88. event.draw.any.widget = widget;
  89. return zori_widget_raise_event(widget, &event);
  90. }
  91. int zori_widget_raise_done_event(struct zori_widget * widget) {
  92. union zori_event event;
  93. event.done.any.type = ZORI_EVENT_DONE;
  94. event.done.any.widget = widget;
  95. return zori_widget_raise_event(widget, &event);
  96. }
  97. int zori_widget_raise_free_event(struct zori_widget * widget) {
  98. union zori_event event;
  99. event.free.any.type = ZORI_EVENT_FREE;
  100. event.free.any.widget = widget;
  101. return zori_widget_raise_event(widget, &event);
  102. }
  103. int zori_widget_raise_update_event
  104. (struct zori_widget * widget, double dt) {
  105. union zori_event event;
  106. event.update.any.type = ZORI_EVENT_DONE;
  107. event.update.any.widget = widget;
  108. event.update.dt = dt;
  109. return zori_widget_raise_event(widget, &event);
  110. }
  111. int zori_widget_raise_action_event
  112. (struct zori_widget * widget) {
  113. union zori_event event;
  114. event.action.any.type = ZORI_EVENT_ACTION;
  115. event.action.any.widget = widget;
  116. return zori_widget_raise_event(widget, &event);
  117. }
  118. int zori_widget_raise_internal_action_event
  119. (struct zori_widget * widget) {
  120. union zori_event event;
  121. event.action.any.type = ZORI_INTERNAL_EVENT_ACTION;
  122. event.action.any.widget = widget;
  123. return zori_widget_raise_event(widget, &event);
  124. }
  125. int zori_widget_raise_close_event
  126. (struct zori_widget * widget, struct zori_widget * from) {
  127. union zori_event event;
  128. event.close.any.type = ZORI_EVENT_CLOSE;
  129. event.close.any.widget = widget;
  130. event.close.from = from;
  131. return zori_widget_raise_event(widget, &event);
  132. }
  133. int zori_widget_compare(const void * v1, const void * v2) {
  134. const struct zori_widget * w1 = v1, * w2 = v2;
  135. return (w2->id - w1->id);
  136. }
  137. struct zori_handler * zori_widget_add_handler
  138. (struct zori_widget * widget, zori_event_type type, zori_handler_func * handler, void * data) {
  139. if ((!widget) || (!handler)) return NULL;
  140. return zori_handlers_add(&widget->handlers, type, handler, data);
  141. }
  142. struct zori_handler * zori_widget_add_handlers
  143. (struct zori_widget * widget, struct zori_handler * handlers, size_t amount) {
  144. size_t i;
  145. for (i = 0; i < amount; i++) {
  146. struct zori_handler * handler = handlers + i;
  147. if (!zori_widget_add_handler(widget, handler->type, handler->handler, handler->data)) return NULL;
  148. }
  149. return handlers + amount - 1;
  150. }
  151. /* Gets the style to use for a marked widget. Looks up a screen widget and then
  152. * looks for the cursor t determine this. */
  153. struct zori_style * zori_widget_get_mark_style(struct zori_widget * widget) {
  154. struct zori_screen * screen = zori_widget_get_screen(widget);
  155. if (!screen) return &widget->style;
  156. return &(screen->cursors.keyjoy.target_style);
  157. }
  158. /* Gets the style to use for a hovered widget. Looks up a screen widget and then
  159. * looks for the cursor t determine this. */
  160. struct zori_style * zori_widget_get_hover_style(struct zori_widget * widget) {
  161. struct zori_screen * screen = zori_widget_get_screen(widget);
  162. if (!screen) return &widget->style;
  163. return &(screen->cursors.mouse.target_style);
  164. }
  165. void zori_widget_free(struct zori_widget * widget);
  166. struct zori_widget * zori_widget_done(struct zori_widget * widget) {
  167. size_t index;
  168. struct zori_widget * aid, * next;
  169. if (!widget) return widget;
  170. for (index = 0; index < miao_size(&widget->children); index ++) {
  171. struct zori_widget * child = miao_unsafe_get(&widget->children, index);
  172. zori_widget_free(child);
  173. }
  174. if (widget->destroy) {
  175. widget->destroy(widget);
  176. }
  177. miao_done(&widget->handlers);
  178. miao_done(&widget->children);
  179. return widget;
  180. }
  181. void zori_widget_free(struct zori_widget * widget) {
  182. if (widget) {
  183. zori_registry_remove(zori_get_registry(), widget->id);
  184. }
  185. zori_widget_done(widget);
  186. free(widget);
  187. }
  188. struct zori_widget *
  189. zori_widget_add_child(struct zori_widget * parent, struct zori_widget * child) {
  190. if (parent) {
  191. miao_push((&parent->children), child);
  192. child->parent = parent;
  193. }
  194. return child;
  195. }
  196. zori_id
  197. zori_widget_margins_(struct zori_widget * widget, int left, int top, int right, int bottom) {
  198. if (!widget) return ZORI_ID_EINVAL;
  199. widget->outer = widget->box;
  200. widget->outer.at.x -= left;
  201. widget->outer.at.y -= top;
  202. widget->outer.size.x += (left + right);
  203. widget->outer.size.y += (top + bottom);
  204. return widget->id;
  205. }
  206. zori_id
  207. zori_widget_margin_(struct zori_widget * widget, int size) {
  208. return zori_widget_margins_(widget, size, size, size, size);
  209. }
  210. /* Draws a widget's frame based on it's style. If the background bitmap is set
  211. * then that is used, otherwise, the background color is used, including a border
  212. * if needed. */
  213. void zori_widget_draw_background(struct zori_widget * widget) {
  214. float dx, dy, dw, dh;
  215. struct zori_style * style = &widget->style;
  216. dx = rebox_x(&widget->box);
  217. dy = rebox_y(&widget->box);
  218. dw = rebox_w(&widget->box);
  219. dh = rebox_h(&widget->box);
  220. if (zori_widget_hover(widget)) {
  221. style = zori_widget_get_hover_style(widget);
  222. }
  223. if (zori_widget_marked(widget)) {
  224. style = zori_widget_get_mark_style(widget);
  225. }
  226. if (style->back.image) {
  227. zori_bitmap * background = style->back.image;
  228. image_blitscale9(background, dx, dy, dw, dh, -1, -1);
  229. } else {
  230. zori_color fillco = style->back.color;
  231. zori_color bordco = style->border.color;
  232. int thick = style->border.size;
  233. draw_frame(dx, dy, dw, dh, thick, bordco, fillco);
  234. }
  235. }
  236. enum zori_handle_result
  237. zori_widget_must_draw_children(struct zori_widget * widget) {
  238. float dx = rebox_x(&widget->box);
  239. float dy = rebox_y(&widget->box);
  240. if (zori_widget_visible(widget)) {
  241. draw_roundbox(dx, dy, 10, 10, 3, 3, al_map_rgb(64,16,255), 3);
  242. return ZORI_HANDLE_PASS;
  243. }
  244. draw_roundbox(dx, dy, 10, 10, 3, 3, al_map_rgb(255,16,64), 3);
  245. return ZORI_HANDLE_DONE;
  246. }
  247. int zori_widget_visible(struct zori_widget * widget) {
  248. return widget && ((widget->flags & ZORI_FLAG_HIDDEN) != ZORI_FLAG_HIDDEN);
  249. }
  250. int zori_widget_active(struct zori_widget * widget) {
  251. return widget && ((widget->flags & ZORI_FLAG_DISABLED) != ZORI_FLAG_DISABLED);
  252. }
  253. int zori_widget_active_(struct zori_widget * widget, int set) {
  254. if (set) {
  255. widget->flags = widget->flags & (~ZORI_FLAG_DISABLED);
  256. } else {
  257. widget->flags = widget->flags | ZORI_FLAG_DISABLED;
  258. }
  259. return zori_widget_active(widget);
  260. }
  261. int zori_widget_visible_(struct zori_widget * widget, int set) {
  262. if (set) {
  263. widget->flags = widget->flags & (~ZORI_FLAG_HIDDEN);
  264. } else {
  265. widget->flags = widget->flags | ZORI_FLAG_HIDDEN;
  266. }
  267. return zori_widget_active(widget);
  268. }
  269. int zori_widget_hover(struct zori_widget * widget) {
  270. return widget && ((widget->flags & ZORI_FLAG_HOVERED) == ZORI_FLAG_HOVERED);
  271. }
  272. int zori_widget_hover_(struct zori_widget * widget, int set) {
  273. if (set) {
  274. widget->flags = widget->flags | ZORI_FLAG_HOVERED;
  275. } else {
  276. widget->flags = widget->flags & (~ZORI_FLAG_HOVERED);
  277. }
  278. return zori_widget_hover(widget);
  279. }
  280. int zori_widget_marked(struct zori_widget * widget) {
  281. return widget && ((widget->flags & ZORI_FLAG_MARKED) == ZORI_FLAG_MARKED);
  282. }
  283. int zori_widget_marked_(struct zori_widget * widget, int set) {
  284. if (set) {
  285. widget->flags = widget->flags | ZORI_FLAG_MARKED;
  286. } else {
  287. widget->flags = widget->flags & (~ZORI_FLAG_MARKED);
  288. }
  289. return zori_widget_marked(widget);
  290. }
  291. int zori_widget_ready(struct zori_widget * widget) {
  292. return widget && ((widget->flags & ZORI_FLAG_READY) == ZORI_FLAG_READY);
  293. }
  294. int zori_widget_ready_(struct zori_widget * widget, int set) {
  295. if (set) {
  296. widget->flags = widget->flags | ZORI_FLAG_READY;
  297. } else {
  298. widget->flags = widget->flags & (~ZORI_FLAG_READY);
  299. }
  300. return zori_widget_ready(widget);
  301. }
  302. int zori_xy_inside_widget_p(struct zori_widget * widget, double x, double y) {
  303. return (rebox_coordinates_inside_p(&widget->box, x, y));
  304. }
  305. /* Registers an event handler for a widget. */
  306. zori_id zori_register(zori_id id, zori_event_type type, zori_handler_func handler, void * extra);
  307. zori_font * zori_widget_font(struct zori_widget * widget) {
  308. return widget->style.text.font;
  309. }
  310. zori_color zori_widget_forecolor(struct zori_widget * widget) {
  311. return widget->style.text.color;
  312. }
  313. zori_color zori_widget_backcolor(struct zori_widget * widget) {
  314. return widget->style.back.color;
  315. }
  316. int zori_widget_h(struct zori_widget * widget) {
  317. return widget->box.size.y;
  318. }
  319. int zori_widget_w(struct zori_widget * widget) {
  320. return widget->box.size.x;
  321. }
  322. int zori_widget_x(struct zori_widget * widget) {
  323. return widget->box.at.x;
  324. }
  325. int zori_widget_y(struct zori_widget * widget) {
  326. return widget->box.at.y;
  327. }
  328. /* Gets amount of child widgets of this widget, 0 if none, -1 on error.*/
  329. int zori_widget_count_children(struct zori_widget * widget) {
  330. if (!widget) return -1;
  331. return miao_size(&widget->children);
  332. }
  333. /* Returns the index-th child of his widget, or NULL on error or if no such child exists. */
  334. struct zori_widget * zori_widget_get_child(struct zori_widget * widget, int index) {
  335. int count = zori_widget_count_children(widget);
  336. if (count < 1) return NULL;
  337. if (index < 0) return NULL;
  338. if (index >= count) return NULL;
  339. return miao_unsafe_get(&widget->children, index);
  340. }
  341. zori_id
  342. zori_widget_paddings_(struct zori_widget * widget, int left, int top, int right, int bottom) {
  343. if (!widget) return ZORI_ID_EINVAL;
  344. widget->inner = widget->box;
  345. widget->inner.at.x += left;
  346. widget->inner.at.y += top;
  347. widget->inner.size.x -= (left + right);
  348. widget->inner.size.y -= (top + bottom);
  349. return widget->id;
  350. }
  351. zori_id
  352. zori_widget_padding_(struct zori_widget * widget, int size) {
  353. return zori_widget_paddings_(widget, size, size, size, size);
  354. }
  355. zori_font * zori_widget_text_font(struct zori_widget * widget) {
  356. struct zori_style * style;
  357. if (!widget) {
  358. style = zori_get_default_style();
  359. } else {
  360. style = & widget->style;
  361. }
  362. return style->text.font;
  363. }
  364. struct zori_widget * zori_widget_init
  365. ( struct zori_widget * widget,
  366. zori_widget_type type,
  367. zori_id id,
  368. struct zori_widget * parent,
  369. zori_rebox * box, struct zori_style * style) {
  370. if (!widget) return NULL;
  371. struct zori_style * default_style = zori_get_default_style();
  372. miao_init(&widget->children);
  373. miao_init(&widget->handlers);
  374. widget->destroy = NULL;
  375. widget->z = 0;
  376. widget->flags = 0;
  377. widget->type = type;
  378. widget->id = ( (id < 0) ? zori_get_unused_id() : id);
  379. if (style) {
  380. widget->style = *style;
  381. if (!widget->style.text.font) {
  382. widget->style.text.font = default_style->text.font;
  383. }
  384. } else if (parent) {
  385. widget->style = parent->style;
  386. } else {
  387. widget->style = *default_style;
  388. }
  389. if (box) {
  390. widget->box = *box;
  391. } else if (parent) {
  392. widget->box = parent->box;
  393. } else {
  394. widget->box = rebox_make(0, 0, ZORI_WIDGET_DEFAULT_W, ZORI_WIDGET_DEFAULT_H);
  395. }
  396. zori_widget_margin_(widget, ZORI_MARGIN_DEFAULT);
  397. zori_widget_padding_(widget, ZORI_PADDING_DEFAULT);
  398. zori_widget_add_child(parent, widget);
  399. zori_registry_add(zori_get_registry(), widget->id, widget);
  400. return widget;
  401. }
  402. struct zori_widget *
  403. zori_widget_initall(struct zori_widget * widget, zori_widget_type type, int id,
  404. struct zori_widget * parent, zori_rebox * box, struct zori_style * style,
  405. struct zori_handler * handlers, size_t amount) {
  406. if (zori_widget_init(widget, type, id, parent, box, style)) {
  407. zori_widget_add_handlers(widget, handlers, amount);
  408. }
  409. return widget;
  410. }
  411. /* Lets the widget handle an event and bubbles it on to it's children
  412. * recursively depending on the need to do that. */
  413. void zori_widget_handle_event(struct zori_widget * widget, union zori_event * event) {
  414. zori_widget_raise_event(widget, event);
  415. }
  416. /* Returns the first parent or super-parent of this widget for which
  417. * predicate() returns true.
  418. */
  419. struct zori_widget *
  420. zori_widget_find_parent(struct zori_widget * widget,
  421. bool (*predicate)(struct zori_widget * parent, void * extra),
  422. void * extra
  423. ) {
  424. struct zori_widget * parent;
  425. if (!widget) return NULL;
  426. parent = widget->parent;
  427. while (parent) {
  428. if (predicate(parent, extra)) return parent;
  429. if (parent == parent->parent) {
  430. LOG_ERROR("GUI setup not correct. Parent/child loop in widget %p.", widget);
  431. return NULL;
  432. }
  433. parent = parent->parent;
  434. }
  435. return NULL;
  436. }
  437. int zori_mark_widget(struct zori_widget * widget) {
  438. struct zori_screen * screen = zori_widget_get_screen(widget);
  439. if (screen) {
  440. screen->cursors.keyjoy.p = widget->box.at;
  441. }
  442. return ZORI_HANDLE_DONE;
  443. }
  444. zori_id zori_widget_set_int_result(struct zori_widget * widget, int value) {
  445. if (widget) {
  446. widget->result.value.integer = value;
  447. widget->result.type = ZORI_RESULT_TYPE_INTEGER;
  448. widget->result.ready = widget->id;
  449. return widget->id;
  450. }
  451. return ZORI_ID_EINVAL;
  452. }
  453. zori_id zori_widget_set_string_result(struct zori_widget * widget,
  454. zori_string * value) {
  455. if (widget) {
  456. widget->result.value.string = value;
  457. widget->result.type = ZORI_RESULT_TYPE_STRING;
  458. widget->result.ready = widget->id;
  459. return widget->id;
  460. }
  461. return ZORI_ID_EINVAL;
  462. }
  463. zori_id zori_widget_set_closed_result(struct zori_widget * widget, int value) {
  464. if (widget) {
  465. widget->result.value.closed = value;
  466. widget->result.type = ZORI_RESULT_TYPE_CLOSED;
  467. widget->result.ready = widget->id;
  468. return widget->id;
  469. }
  470. return ZORI_ID_EINVAL;
  471. }
  472. zori_id zori_set_mark_style(zori_id id, struct zori_style style) {
  473. struct zori_widget * widget = zori_get_widget(id);
  474. struct zori_screen * screen = zori_widget_get_screen(widget);
  475. if (screen) {
  476. screen->cursors.keyjoy.style = style;
  477. return id;
  478. } else {
  479. return ZORI_ID_EINVAL;
  480. }
  481. }
  482. zori_id zori_set_hover_style(zori_id id, struct zori_style style) {
  483. struct zori_widget * widget = zori_get_widget(id);
  484. struct zori_screen * screen = zori_widget_get_screen(widget);
  485. if (screen) {
  486. screen->cursors.mouse.style = style;
  487. return id;
  488. } else {
  489. return ZORI_ID_EINVAL;
  490. }
  491. }
  492. /* Moves the widget by the offset (dx, dy). Does not move it's children. */
  493. void zori_widget_move_self_by(struct zori_widget * widget, int dx, int dy) {
  494. int index, stop;
  495. widget->box.at.x += dx;
  496. widget->box.at.y += dy;
  497. widget->inner.at.x += dx;
  498. widget->inner.at.y += dy;
  499. widget->outer.at.x += dx;
  500. widget->outer.at.y += dy;
  501. }
  502. /* Moves resizes the widget by (dw, dh). Does not resize it's children.
  503. * Margin and paddding are resized also by dw and dh;
  504. */
  505. void zori_widget_resize_self_by(struct zori_widget * widget, int dw, int dh) {
  506. int index, stop;
  507. widget->box.size.x += dw;
  508. widget->box.size.y += dh;
  509. widget->inner.size.x += dw;
  510. widget->inner.size.y += dh;
  511. widget->outer.size.x += dw;
  512. widget->outer.size.y += dh;
  513. }
  514. /* Moves the widget by the offset (dx, dy). It's children will be moved as well recursively
  515. * keeping the offset */
  516. void zori_widget_move_by(struct zori_widget * widget, int dx, int dy) {
  517. int index, stop;
  518. zori_widget_move_self_by(widget, dx, dy);
  519. stop = zori_widget_count_children(widget);
  520. for (index= 0 ; index < stop; index ++) {
  521. struct zori_widget * child = zori_widget_get_child(widget, index);
  522. zori_widget_move_by(child, dx, dy);
  523. }
  524. }
  525. /* Moves the widget to (x, y). It's children will be moved as well recursively
  526. * keeping the offset */
  527. void zori_widget_move_to(struct zori_widget * widget, int x, int y) {
  528. int dx = widget->box.at.x - x;
  529. int dy = widget->box.at.y - y;
  530. zori_widget_move_by(widget, dx, dy);
  531. }
  532. /* Moves the widget to (x, y). Doesn't move children. */
  533. void zori_widget_move_self_to(struct zori_widget * widget, int x, int y) {
  534. int dx = widget->box.at.x - x;
  535. int dy = widget->box.at.y - y;
  536. zori_widget_move_self_by(widget, dx, dy);
  537. }
  538. /* Resizes the widget to (w, h). Doesn't resize children. Margins and padding will be
  539. * resized accordingly. */
  540. void zori_widget_resize_self_to(struct zori_widget * widget, int w, int h) {
  541. int dw = widget->box.size.x - w;
  542. int dh = widget->box.size.y - h;
  543. zori_widget_resize_self_by(widget, dw, dh);
  544. }
  545. /* Makes the widget fit itself to all direct children.
  546. * Does not resize nor move the children.
  547. */
  548. void zori_widget_fit_to_children(struct zori_widget * widget) {
  549. int index, stop;
  550. int min_x = 640;
  551. int min_y = 480;
  552. int min_w = 0;
  553. int min_h = 0;
  554. struct zori_screen * screen = zori_widget_get_screen(widget);
  555. if (screen) {
  556. min_x = screen->widget.box.size.x;
  557. min_y = screen->widget.box.size.y;
  558. }
  559. stop = zori_widget_count_children(widget);
  560. for (index= 0 ; index < stop; index ++) {
  561. struct zori_widget * child = zori_widget_get_child(widget, index);
  562. if (child->outer.at.x < min_x) {
  563. min_x = child->outer.at.x;
  564. }
  565. if (child->outer.at.y < min_y) {
  566. min_y = child->outer.at.y;
  567. }
  568. if ((child->outer.size.x) > min_w) {
  569. min_w = child->outer.size.x;
  570. }
  571. if ((child->outer.size.y) > min_h) {
  572. min_h = child->outer.size.y;
  573. }
  574. }
  575. zori_widget_move_self_to(widget, min_x, min_y);
  576. zori_widget_resize_self_to(widget, min_w, min_h);
  577. }