/src/ftk_widget.c

http://ftk.googlecode.com/ · C · 1436 lines · 1036 code · 284 blank · 116 comment · 399 complexity · 05d2c3ccb1bbe217fdae8913936d58e1 MD5 · raw file

  1. /*
  2. * File: ftk_widget.c
  3. * Author: Li XianJing <xianjimli@hotmail.com>
  4. * Brief: widget
  5. *
  6. * Copyright (c) 2009 - 2010 Li XianJing <xianjimli@hotmail.com>
  7. *
  8. * Licensed under the Academic Free License version 2.1
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, write to the Free Software
  22. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  23. */
  24. /*
  25. * History:
  26. * ================================================================
  27. * 2009-10-03 Li XianJing <xianjimli@hotmail.com> created
  28. *
  29. */
  30. /**
  31. * SECTION:ftk_widget
  32. * @Short_description: Base class for all widgets
  33. * @Title: FtkWidget
  34. *
  35. * FtkWidget is the base class all widgets in FTK derive from. It manages the
  36. * widget lifecycle, states and style.
  37. */
  38. #include "ftk_theme.h"
  39. #include "ftk_bitmap.h"
  40. #include "ftk_widget.h"
  41. #include "ftk_globals.h"
  42. #include "ftk_canvas.h"
  43. #include "ftk_window.h"
  44. #include "ftk_util.h"
  45. struct _FtkWidgetInfo
  46. {
  47. int id;
  48. int type;
  49. int top;
  50. int left;
  51. int width;
  52. int height;
  53. int visible;
  54. int hide_self;
  55. FtkWrapMode wrap_mode;
  56. int painting;
  57. FtkCanvas* canvas;
  58. unsigned int attr;
  59. FtkWidgetState state;
  60. FtkGc gc[FTK_WIDGET_STATE_NR];
  61. void* user_data;
  62. char* text;
  63. size_t text_buff_length;
  64. FtkDestroy user_data_destroy;
  65. FtkListener event_listener;
  66. void* event_listener_ctx;
  67. };
  68. static int ftk_widget_is_parent_visible(FtkWidget* thiz);
  69. static void ftk_widget_validate_position_size(FtkWidget* thiz);
  70. /**
  71. * ftk_widget_init:
  72. * @thiz: a #FtkWidget
  73. * @type: a #FtkWidgetType
  74. * @id: id of the widget.
  75. * @x: X position
  76. * @y: Y position
  77. * @width: width of the widget
  78. * @height: height of the widget
  79. * @attr: a #FtkWidgetAttr, attribute of the widget
  80. *
  81. * This function called by widget implementation to initialize a widget.
  82. *
  83. */
  84. void ftk_widget_init(FtkWidget* thiz, int type, int id, int x, int y,
  85. int width, int height, unsigned int attr)
  86. {
  87. return_if_fail(thiz != NULL && thiz->priv == NULL);
  88. thiz->ref = 1;
  89. thiz->priv = (FtkWidgetInfo*)FTK_ZALLOC(sizeof(FtkWidgetInfo));
  90. if(thiz->priv != NULL)
  91. {
  92. FtkWidgetInfo* priv = thiz->priv;
  93. int state = FTK_WIDGET_NORMAL;
  94. priv->id = id;
  95. priv->type = type;
  96. priv->left = x;
  97. priv->top = y;
  98. priv->width = width;
  99. priv->height = height;
  100. priv->attr |= attr;
  101. for(; state < FTK_WIDGET_STATE_NR; state++)
  102. {
  103. priv->gc[state].mask = FTK_GC_BG | FTK_GC_FG | FTK_GC_FONT;
  104. priv->gc[state].font = ftk_theme_get_font(ftk_default_theme(), (FtkWidgetType)type);
  105. priv->gc[state].fg = ftk_theme_get_fg_color(ftk_default_theme(), (FtkWidgetType)type, (FtkWidgetState)state);
  106. priv->gc[state].bg = ftk_theme_get_bg_color(ftk_default_theme(), (FtkWidgetType)type, (FtkWidgetState)state);
  107. priv->gc[state].bitmap = ftk_theme_get_bg(ftk_default_theme(), (FtkWidgetType)type, (FtkWidgetState)state);
  108. if(priv->gc[state].bitmap != NULL) priv->gc[state].mask |= FTK_GC_BITMAP;
  109. }
  110. if(attr & FTK_ATTR_INSENSITIVE)
  111. {
  112. priv->state = FTK_WIDGET_INSENSITIVE;
  113. }
  114. else if(attr & FTK_ATTR_FOCUSED)
  115. {
  116. ftk_window_set_focus(ftk_widget_toplevel(thiz), thiz);
  117. }
  118. }
  119. return;
  120. }
  121. /**
  122. * ftk_widget_type:
  123. * @thiz: a #FtkWidget
  124. *
  125. * Get the type of the widget.
  126. *
  127. * Return value: #FtkWidgetType
  128. */
  129. int ftk_widget_type(FtkWidget* thiz)
  130. {
  131. return thiz != NULL && thiz->priv != NULL ? thiz->priv->type : 0;
  132. }
  133. /**
  134. * ftk_widget_top:
  135. * @thiz: a #FtkWidget
  136. *
  137. * Get the Y position of the widget relative to its parent.
  138. *
  139. */
  140. int ftk_widget_top(FtkWidget* thiz)
  141. {
  142. return thiz != NULL && thiz->priv != NULL ? thiz->priv->top : 0;
  143. }
  144. /**
  145. * ftk_widget_left:
  146. * @thiz: a #FtkWidget
  147. *
  148. * Get the X position of the widget relative to its parent.
  149. *
  150. */
  151. int ftk_widget_left(FtkWidget* thiz)
  152. {
  153. return thiz != NULL && thiz->priv != NULL ? thiz->priv->left : 0;
  154. }
  155. /**
  156. * ftk_widget_top_abs:
  157. * @thiz: a #FtkWidget
  158. *
  159. * Get the absolute Y position of the widget.
  160. *
  161. */
  162. int ftk_widget_top_abs(FtkWidget* thiz)
  163. {
  164. int top = 0;
  165. FtkWidget* iter = thiz;
  166. for(; iter != NULL; iter = ftk_widget_parent(iter))
  167. {
  168. top += ftk_widget_top(iter);
  169. }
  170. return top;
  171. }
  172. /**
  173. * ftk_widget_left_abs:
  174. * @thiz: a #FtkWidget
  175. *
  176. * Get the absolute X position of the widget.
  177. *
  178. */
  179. int ftk_widget_left_abs(FtkWidget* thiz)
  180. {
  181. int left = 0;
  182. FtkWidget* iter = thiz;
  183. for(; iter != NULL; iter = ftk_widget_parent(iter))
  184. {
  185. left += ftk_widget_left(iter);
  186. }
  187. return left;
  188. }
  189. /**
  190. * ftk_widget_top_in_window:
  191. * @thiz: a #FtkWidget
  192. *
  193. * Get the absolute Y position of the widget in the window.
  194. *
  195. */
  196. int ftk_widget_top_in_window(FtkWidget* thiz)
  197. {
  198. int top = 0;
  199. FtkWidget* iter = thiz;
  200. for(; ftk_widget_parent(iter); iter = ftk_widget_parent(iter))
  201. {
  202. top += ftk_widget_top(iter);
  203. }
  204. return top;
  205. }
  206. /**
  207. * ftk_widget_left_in_window:
  208. * @thiz: a #FtkWidget
  209. *
  210. * Get the absolute X position of the widget in the window.
  211. *
  212. */
  213. int ftk_widget_left_in_window(FtkWidget* thiz)
  214. {
  215. int left = 0;
  216. FtkWidget* iter = thiz;
  217. for(; ftk_widget_parent(iter); iter = ftk_widget_parent(iter))
  218. {
  219. left += ftk_widget_left(iter);
  220. }
  221. return left;
  222. }
  223. int ftk_widget_width(FtkWidget* thiz)
  224. {
  225. return thiz != NULL && thiz->priv != NULL ? thiz->priv->width : 0;
  226. }
  227. int ftk_widget_height(FtkWidget* thiz)
  228. {
  229. return thiz != NULL && thiz->priv != NULL ? thiz->priv->height : 0;
  230. }
  231. int ftk_widget_is_insensitive(FtkWidget* thiz)
  232. {
  233. return thiz != NULL && thiz->priv != NULL && thiz->priv->state == FTK_WIDGET_INSENSITIVE;
  234. }
  235. int ftk_widget_is_visible(FtkWidget* thiz)
  236. {
  237. return thiz != NULL && thiz->priv != NULL ? thiz->priv->visible: 0;
  238. }
  239. int ftk_widget_is_focused(FtkWidget* thiz)
  240. {
  241. return thiz != NULL && thiz->priv != NULL && thiz->priv->state == FTK_WIDGET_FOCUSED;
  242. }
  243. int ftk_widget_is_active(FtkWidget* thiz)
  244. {
  245. return thiz != NULL && thiz->priv != NULL && thiz->priv->state == FTK_WIDGET_ACTIVE;
  246. }
  247. int ftk_widget_id(FtkWidget* thiz)
  248. {
  249. return thiz != NULL && thiz->priv != NULL ? thiz->priv->id : 0;
  250. }
  251. Ret ftk_widget_invalidate(FtkWidget* thiz)
  252. {
  253. FtkRect rect = {0};
  254. if(!ftk_widget_is_visible(ftk_widget_toplevel(thiz)))
  255. {
  256. return RET_FAIL;
  257. }
  258. rect.y = ftk_widget_top_abs(thiz);
  259. rect.x = ftk_widget_left_abs(thiz);
  260. rect.width = ftk_widget_width(thiz);
  261. rect.height = ftk_widget_height(thiz);
  262. return ftk_window_invalidate(ftk_widget_toplevel(thiz), &rect);
  263. }
  264. Ret ftk_widget_invalidate_forcely(FtkWidget* thiz)
  265. {
  266. FtkRect rect = {0};
  267. thiz = ftk_widget_toplevel(thiz);
  268. if(!ftk_widget_is_visible(thiz))
  269. {
  270. return RET_FAIL;
  271. }
  272. rect.y = ftk_widget_top_abs(thiz);
  273. rect.x = ftk_widget_left_abs(thiz);
  274. rect.width = ftk_widget_width(thiz);
  275. rect.height = ftk_widget_height(thiz);
  276. return ftk_window_invalidate(thiz, &rect);
  277. }
  278. FtkWrapMode ftk_widget_get_wrap_mode(FtkWidget* thiz)
  279. {
  280. return_val_if_fail(thiz != NULL && thiz->priv != NULL, FTK_WRAP_NONE);
  281. return thiz->priv->wrap_mode;
  282. }
  283. Ret ftk_widget_update(FtkWidget* thiz)
  284. {
  285. return ftk_widget_update_rect(thiz, NULL);
  286. }
  287. Ret ftk_widget_update_rect(FtkWidget* thiz, FtkRect* rect)
  288. {
  289. FtkEvent event;
  290. FtkWidget* window = NULL;
  291. FtkWidgetInfo* priv = NULL;
  292. return_val_if_fail(thiz != NULL, RET_FAIL);
  293. window = ftk_widget_toplevel(thiz);
  294. return_val_if_fail(window != NULL, RET_FAIL);
  295. priv = thiz->priv;
  296. ftk_event_init(&event, FTK_EVT_UPDATE);
  297. if(rect == NULL)
  298. {
  299. event.u.rect.x = ftk_widget_left_abs(thiz);
  300. event.u.rect.y = ftk_widget_top_abs(thiz);
  301. event.u.rect.width = priv->width;
  302. event.u.rect.height = priv->height;
  303. }
  304. else
  305. {
  306. //ftk_logd("%s: x=%d y=%d w=%d h=%d\n", __func__, rect->x, rect->y, rect->width, rect->height);
  307. event.u.rect = *rect;
  308. }
  309. return ftk_widget_event(window, &event);
  310. }
  311. FtkCanvas* ftk_widget_canvas(FtkWidget* thiz)
  312. {
  313. FtkWidget* toplevel = NULL;
  314. FtkCanvas* canvas = NULL;
  315. return_val_if_fail(thiz != NULL && thiz->priv != NULL, NULL);
  316. toplevel = ftk_widget_toplevel(thiz);
  317. canvas = toplevel->priv->canvas != NULL ? toplevel->priv->canvas : ftk_shared_canvas();
  318. ftk_canvas_reset_gc(canvas, ftk_widget_get_gc(thiz));
  319. return canvas;
  320. }
  321. int ftk_widget_has_attr(FtkWidget* thiz, FtkWidgetAttr attr)
  322. {
  323. return_val_if_fail(thiz != NULL && thiz->priv != NULL, 0);
  324. return thiz->priv->attr & attr;
  325. }
  326. FtkWidgetState ftk_widget_state(FtkWidget* thiz)
  327. {
  328. return_val_if_fail(thiz != NULL && thiz->priv != NULL, FTK_WIDGET_NORMAL);
  329. return thiz->priv->state;
  330. }
  331. void* ftk_widget_user_data(FtkWidget* thiz)
  332. {
  333. return_val_if_fail(thiz != NULL && thiz->priv != NULL, NULL);
  334. return thiz->priv->user_data;
  335. }
  336. const char* ftk_widget_get_text(FtkWidget* thiz)
  337. {
  338. FtkEvent event;
  339. return_val_if_fail(thiz != NULL && thiz->priv != NULL, NULL);
  340. ftk_event_init(&event, FTK_EVT_GET_TEXT);
  341. if(ftk_widget_event(thiz, &event) == RET_REMOVE)
  342. {
  343. return (char*)event.u.extra;
  344. }
  345. //return thiz->priv->text != NULL ? thiz->priv->text : "";
  346. return thiz->priv->text != NULL ? thiz->priv->text : NULL;
  347. }
  348. void ftk_widget_set_attr(FtkWidget* thiz, unsigned int attr)
  349. {
  350. return_if_fail(thiz != NULL && thiz->priv != NULL);
  351. thiz->priv->attr |= attr;
  352. if(attr & FTK_ATTR_INSENSITIVE)
  353. {
  354. ftk_widget_set_insensitive(thiz, 1);
  355. }
  356. else if(attr & FTK_ATTR_FOCUSED)
  357. {
  358. ftk_window_set_focus(ftk_widget_toplevel(thiz), thiz);
  359. }
  360. else if(attr & FTK_ATTR_FULLSCREEN)
  361. {
  362. ftk_window_set_fullscreen(thiz, FTK_ATTR_FULLSCREEN);
  363. }
  364. return;
  365. }
  366. void ftk_widget_unset_attr(FtkWidget* thiz, FtkWidgetAttr attr)
  367. {
  368. return_if_fail(thiz != NULL && thiz->priv != NULL);
  369. thiz->priv->attr = (~attr) & thiz->priv->attr;
  370. return;
  371. }
  372. void ftk_widget_set_user_data(FtkWidget* thiz, FtkDestroy destroy, void* data)
  373. {
  374. return_if_fail(thiz != NULL && thiz->priv != NULL);
  375. if(thiz->priv->user_data != NULL && thiz->priv->user_data_destroy != NULL)
  376. {
  377. thiz->priv->user_data_destroy(thiz->priv->user_data);
  378. }
  379. thiz->priv->user_data = data;
  380. thiz->priv->user_data_destroy = destroy;
  381. return;
  382. }
  383. void ftk_widget_move(FtkWidget* thiz, int x, int y)
  384. {
  385. FtkEvent event;
  386. return_if_fail(thiz != NULL && thiz->priv != NULL);
  387. if(thiz->priv->left == x && thiz->priv->top == y)
  388. {
  389. return;
  390. }
  391. thiz->priv->left = x;
  392. thiz->priv->top = y;
  393. ftk_widget_validate_position_size(thiz);
  394. if(thiz->on_event != NULL)
  395. {
  396. ftk_event_init(&event, FTK_EVT_MOVE);
  397. event.widget = thiz;
  398. ftk_widget_event(thiz, &event);
  399. }
  400. ftk_widget_invalidate_forcely(thiz);
  401. return;
  402. }
  403. void ftk_widget_resize(FtkWidget* thiz, int width, int height)
  404. {
  405. FtkEvent event;
  406. return_if_fail(thiz != NULL && thiz->priv != NULL);
  407. if(thiz->priv->width == width && thiz->priv->height == height)
  408. {
  409. return;
  410. }
  411. thiz->priv->width = width;
  412. thiz->priv->height = height;
  413. ftk_widget_validate_position_size(thiz);
  414. if(thiz->on_event != NULL)
  415. {
  416. ftk_event_init(&event, FTK_EVT_RESIZE);
  417. event.widget = thiz;
  418. ftk_widget_event(thiz, &event);
  419. }
  420. ftk_widget_invalidate_forcely(thiz);
  421. return;
  422. }
  423. void ftk_widget_move_resize(FtkWidget* thiz, int x, int y, int width, int height)
  424. {
  425. FtkEvent event;
  426. return_if_fail(thiz != NULL && thiz->priv != NULL);
  427. if(thiz->priv->left == x && thiz->priv->top == y
  428. && thiz->priv->width == width && thiz->priv->height == height)
  429. {
  430. return;
  431. }
  432. thiz->priv->left = x;
  433. thiz->priv->top = y;
  434. thiz->priv->width = width;
  435. thiz->priv->height = height;
  436. ftk_widget_validate_position_size(thiz);
  437. if(thiz->on_event != NULL)
  438. {
  439. ftk_event_init(&event, FTK_EVT_MOVE_RESIZE);
  440. event.widget = thiz;
  441. ftk_widget_event(thiz, &event);
  442. }
  443. ftk_widget_invalidate_forcely(thiz);
  444. return;
  445. }
  446. void ftk_widget_set_type(FtkWidget* thiz, int type)
  447. {
  448. return_if_fail(thiz != NULL && thiz->priv != NULL);
  449. thiz->priv->type = type;
  450. return;
  451. }
  452. void ftk_widget_set_insensitive(FtkWidget* thiz, int insensitive)
  453. {
  454. return_if_fail(thiz != NULL && thiz->priv != NULL);
  455. thiz->priv->state = insensitive ? FTK_WIDGET_INSENSITIVE : FTK_WIDGET_NORMAL;
  456. return;
  457. }
  458. static int ftk_widget_is_parent_visible(FtkWidget* thiz)
  459. {
  460. FtkWidget* parent = ftk_widget_parent(thiz);
  461. while(parent != NULL)
  462. {
  463. if(!ftk_widget_is_visible(parent))
  464. {
  465. return 0;
  466. }
  467. parent = ftk_widget_parent(parent);
  468. }
  469. return 1;
  470. }
  471. void ftk_widget_show(FtkWidget* thiz, int visible)
  472. {
  473. FtkEvent event;
  474. return_if_fail(thiz != NULL && thiz->priv != NULL);
  475. if(thiz->priv->visible == visible) return;
  476. if(thiz->priv->hide_self) return ;
  477. thiz->priv->visible = visible;
  478. ftk_event_init(&event, visible ? FTK_EVT_SHOW : FTK_EVT_HIDE);
  479. ftk_widget_event(thiz, &event);
  480. if(!ftk_widget_is_parent_visible(thiz))
  481. {
  482. return;
  483. }
  484. //if(ftk_widget_parent(thiz) != NULL)
  485. //{
  486. //}
  487. if(visible)
  488. {
  489. ftk_widget_invalidate(thiz);
  490. }
  491. else
  492. {
  493. ftk_widget_invalidate_forcely(thiz);
  494. }
  495. return;
  496. }
  497. void ftk_widget_show_all(FtkWidget* thiz, int visible)
  498. {
  499. return_if_fail(thiz != NULL && thiz->priv != NULL);
  500. if(thiz->children != NULL)
  501. {
  502. ftk_widget_show_all(thiz->children, visible);
  503. }
  504. if(thiz->next != NULL)
  505. {
  506. ftk_widget_show_all(thiz->next, visible);
  507. }
  508. ftk_widget_show(thiz, visible);
  509. return;
  510. }
  511. void ftk_widget_hide_self(FtkWidget* thiz, int hide)
  512. {
  513. return_if_fail(thiz != NULL && thiz->priv != NULL);
  514. thiz->priv->hide_self = hide;
  515. return ;
  516. }
  517. void ftk_widget_set_visible(FtkWidget* thiz, int visible)
  518. {
  519. return_if_fail(thiz != NULL && thiz->priv != NULL);
  520. if(thiz->priv->visible == visible) return;
  521. thiz->priv->visible = visible;
  522. return;
  523. }
  524. void ftk_widget_set_focused(FtkWidget* thiz, int focused)
  525. {
  526. FtkEvent event;
  527. FtkWidgetState state = FTK_WIDGET_ACTIVE;
  528. return_if_fail(thiz != NULL && thiz->priv != NULL);
  529. if(thiz->priv->state == FTK_WIDGET_INSENSITIVE)
  530. {
  531. return;
  532. }
  533. state = focused ? FTK_WIDGET_FOCUSED : FTK_WIDGET_NORMAL;
  534. if(thiz->priv->state == state)
  535. {
  536. return;
  537. }
  538. thiz->priv->state = state;
  539. ftk_event_init(&event, focused ? FTK_EVT_FOCUS_IN : FTK_EVT_FOCUS_OUT);
  540. event.widget = thiz;
  541. ftk_widget_event(thiz, &event);
  542. if(!ftk_widget_is_parent_visible(thiz))
  543. {
  544. return;
  545. }
  546. ftk_widget_invalidate(thiz);
  547. return;
  548. }
  549. void ftk_widget_set_active(FtkWidget* thiz, int active)
  550. {
  551. FtkWidgetState state = FTK_WIDGET_ACTIVE;
  552. return_if_fail(thiz != NULL && thiz->priv != NULL);
  553. if(thiz->priv->state == FTK_WIDGET_INSENSITIVE)
  554. {
  555. return;
  556. }
  557. state = active ? FTK_WIDGET_ACTIVE : FTK_WIDGET_FOCUSED;
  558. if(thiz->priv->state == state)
  559. {
  560. return;
  561. }
  562. thiz->priv->state = state;
  563. if(!ftk_widget_is_parent_visible(thiz))
  564. {
  565. return;
  566. }
  567. ftk_widget_invalidate(thiz);
  568. return;
  569. }
  570. void ftk_widget_set_id(FtkWidget* thiz, int id)
  571. {
  572. return_if_fail(thiz != NULL && thiz->priv != NULL);
  573. thiz->priv->id = id;
  574. return;
  575. }
  576. void ftk_widget_set_canvas(FtkWidget* thiz, FtkCanvas* canvas)
  577. {
  578. return_if_fail(thiz != NULL && thiz->priv != NULL);
  579. thiz->priv->canvas = canvas;
  580. return;
  581. }
  582. void ftk_widget_set_parent(FtkWidget* thiz, FtkWidget* parent)
  583. {
  584. FtkEvent event;
  585. return_if_fail(thiz != NULL && thiz->priv != NULL);
  586. if(thiz->parent != NULL && parent == NULL)
  587. {
  588. ftk_event_init(&event, FTK_EVT_REMOVE_CHILD);
  589. event.u.extra = thiz;
  590. ftk_widget_event(thiz->parent, &event);
  591. }
  592. thiz->parent = parent;
  593. if(parent != NULL)
  594. {
  595. ftk_event_init(&event, FTK_EVT_ADD_CHILD);
  596. event.u.extra = thiz;
  597. ftk_widget_event(parent, &event);
  598. }
  599. ftk_widget_set_canvas(thiz, ftk_widget_canvas(ftk_widget_toplevel(parent)));
  600. return;
  601. }
  602. static void ftk_widget_validate_position_size(FtkWidget* thiz)
  603. {
  604. FtkWidgetInfo* priv = thiz->priv;
  605. FtkWidget* parent = thiz->parent;
  606. if(parent != NULL)
  607. {
  608. int parent_w = ftk_widget_width(parent);
  609. int parent_h = ftk_widget_height(parent);
  610. // remove by wzw.random@gmail.com.
  611. // ???????????????
  612. // ??????????????????width?unsigned int??????0????????
  613. // ???width?height?????int??????????????
  614. // priv->width = (priv->width + 1) & 0xfffffffe;
  615. // priv->height = (priv->height + 1) & 0xfffffffe;
  616. priv->left = (priv->left >= parent_w) ? (parent_w - 1) : priv->left;
  617. priv->top = (priv->top >= parent_h) ? (parent_h - 1) : priv->top;
  618. priv->width = (priv->left + priv->width) > parent_w ? (parent_w - priv->left) : priv->width;
  619. priv->height = (priv->height + priv->top) > parent_h ? (parent_h - priv->top) : priv->height;
  620. // priv->width = priv->width & 0xfffffffe;
  621. // priv->height = priv->height & 0xfffffffe;
  622. }
  623. return;
  624. }
  625. void ftk_widget_append_child(FtkWidget* thiz, FtkWidget* child)
  626. {
  627. return_if_fail(thiz != NULL && thiz->priv != NULL);
  628. if(thiz->children == NULL)
  629. {
  630. thiz->children = child;
  631. ftk_widget_set_parent(child, thiz);
  632. }
  633. else
  634. {
  635. ftk_widget_append_sibling(thiz->children, child);
  636. }
  637. ftk_widget_validate_position_size(child);
  638. return;
  639. }
  640. void ftk_widget_append_sibling(FtkWidget* thiz, FtkWidget* sibling)
  641. {
  642. FtkWidget* iter = thiz;
  643. return_if_fail(thiz != NULL && sibling != NULL);
  644. for(; iter->next != NULL; iter = iter->next);
  645. iter->next = sibling;
  646. sibling->prev = iter;
  647. ftk_widget_set_parent(sibling, ftk_widget_parent(thiz));
  648. return;
  649. }
  650. void ftk_widget_remove_child(FtkWidget* thiz, FtkWidget* child)
  651. {
  652. FtkWidget* iter = thiz->children;
  653. return_if_fail(thiz != NULL && child != NULL);
  654. if(iter == child)
  655. {
  656. thiz->children = child->next;
  657. if(thiz->children != NULL)
  658. {
  659. thiz->children->prev = NULL;
  660. }
  661. child->prev = NULL;
  662. child->next = NULL;
  663. return;
  664. }
  665. for(; iter != NULL; iter = iter->next)
  666. {
  667. if(iter == child)
  668. {
  669. if(child->prev != NULL)
  670. {
  671. child->prev->next = child->next;
  672. }
  673. if(child->next != NULL)
  674. {
  675. child->next->prev = child->prev;
  676. }
  677. child->prev = NULL;
  678. child->next = NULL;
  679. return;
  680. }
  681. }
  682. return;
  683. }
  684. FtkWidget* ftk_widget_toplevel(FtkWidget* thiz)
  685. {
  686. FtkWidget* iter = thiz;
  687. for(; ftk_widget_parent(iter) != NULL; iter = ftk_widget_parent(iter));
  688. return iter;
  689. }
  690. FtkWidget* ftk_widget_parent(FtkWidget* thiz)
  691. {
  692. return thiz != NULL ? thiz->parent : NULL;
  693. }
  694. FtkWidget* ftk_widget_prev(FtkWidget* thiz)
  695. {
  696. return thiz != NULL ? thiz->prev : NULL;
  697. }
  698. FtkWidget* ftk_widget_next(FtkWidget* thiz)
  699. {
  700. return thiz != NULL ? thiz->next : NULL;
  701. }
  702. FtkWidget* ftk_widget_child(FtkWidget* thiz)
  703. {
  704. return thiz != NULL ? thiz->children : NULL;
  705. }
  706. FtkWidget* ftk_widget_last_child(FtkWidget* thiz)
  707. {
  708. FtkWidget* iter = NULL;
  709. return_val_if_fail(thiz != NULL && thiz->children != NULL, NULL);
  710. for(iter = thiz->children; iter->next != NULL; iter = iter->next)
  711. {
  712. }
  713. return iter;
  714. }
  715. FtkWidget* ftk_widget_lookup(FtkWidget* thiz, int id)
  716. {
  717. FtkWidget* iter = thiz;
  718. FtkWidget* widget = NULL;
  719. return_val_if_fail(thiz != NULL, NULL);
  720. if(ftk_widget_id(thiz) == id) return iter;
  721. iter = ftk_widget_child(thiz);
  722. for(; iter != NULL; iter = ftk_widget_next(iter))
  723. {
  724. if(ftk_widget_id(iter) == id) return iter;
  725. if((widget = ftk_widget_lookup(iter, id)) != NULL) return widget;
  726. }
  727. return NULL;
  728. }
  729. #if defined(FTK_OPTIMIZE_WIDGET_PAINT) && (FTK_OPTIMIZE_WIDGET_PAINT > 0)
  730. static int ftk_rects_is_cross(const FtkRect *a, const FtkRect *b)
  731. {
  732. int minx, maxx, miny, maxy;
  733. #define __ftk_min(a,b) (a) > (b) ? (b) : (a)
  734. #define __ftk_max(a,b) (a) > (b) ? (a) : (b)
  735. minx = __ftk_max(a->x, b->x);
  736. miny = __ftk_max(a->y, b->y);
  737. maxx = __ftk_min(a->x + a->width - 1, b->x + b->width - 1);
  738. maxy = __ftk_min(a->y + a->height - 1, b->y + b->height - 1);
  739. if (minx > maxx || miny > maxy)
  740. {
  741. return 0;
  742. }
  743. return (maxx - minx) * (maxy - miny);
  744. }
  745. #endif /* FTK_OPTIMIZE_WIDGET_PAINT */
  746. void ftk_widget_paint(FtkWidget* thiz, FtkRect *rects, int rect_nr)
  747. {
  748. FtkRect rect = {0};
  749. if(!ftk_widget_is_parent_visible(thiz))
  750. {
  751. return;
  752. }
  753. /*If thiz is a window, we disable update first, until all sub-widgets are painted.*/
  754. if(ftk_widget_parent(thiz) == NULL)
  755. {
  756. ftk_window_disable_update(thiz);
  757. }
  758. rect.x = ftk_widget_left_abs(thiz);
  759. rect.y = ftk_widget_top_abs(thiz);
  760. rect.width = ftk_widget_width(thiz);
  761. rect.height = ftk_widget_height(thiz);
  762. #if defined(FTK_OPTIMIZE_WIDGET_PAINT) && (FTK_OPTIMIZE_WIDGET_PAINT > 0)
  763. if (rect_nr > 0 && rects != NULL)
  764. {
  765. int i = 0;
  766. for (i = 0; i < rect_nr; i++)
  767. {
  768. if (ftk_rects_is_cross(&rect, rects + i))
  769. {
  770. ftk_widget_paint_self(thiz, rects, rect_nr);
  771. break;
  772. }
  773. }
  774. }
  775. else
  776. {
  777. ftk_widget_paint_self(thiz, rects, rect_nr);
  778. }
  779. #else
  780. ftk_widget_paint_self(thiz, rects, rect_nr);
  781. #endif
  782. if(ftk_widget_next(thiz) != NULL)
  783. {
  784. ftk_widget_paint(ftk_widget_next(thiz), rects, rect_nr);
  785. }
  786. /*If thiz is a window, now, do real updating.*/
  787. if(ftk_widget_parent(thiz) == NULL)
  788. {
  789. ftk_window_enable_update(thiz);
  790. ftk_window_update(thiz, &rect);
  791. }
  792. return;
  793. }
  794. void ftk_widget_set_font_size(FtkWidget* thiz, int font_size)
  795. {
  796. char font_desc[64] = {0};
  797. ftk_snprintf(font_desc, sizeof(font_desc)-1, FONT_DESC_FMT, font_size, 0, 0, FTK_FONT);
  798. ftk_widget_set_font(thiz, font_desc);
  799. return;
  800. }
  801. int ftk_widget_get_font_size(FtkWidget* thiz)
  802. {
  803. return_val_if_fail(thiz != NULL, 0);
  804. return ftk_font_desc_get_size(ftk_widget_get_gc(thiz)->font);
  805. }
  806. void ftk_widget_set_font(FtkWidget* thiz, const char* font_desc_str)
  807. {
  808. FtkGc gc = {0};
  809. FtkFontDesc* font_desc = ftk_font_desc_create(font_desc_str);
  810. gc.mask = FTK_GC_FONT;
  811. gc.font = font_desc;
  812. if(gc.font != NULL)
  813. {
  814. int i = 0;
  815. for(i = 0; i < FTK_WIDGET_STATE_NR; i++)
  816. {
  817. ftk_widget_set_gc(thiz, (FtkWidgetState)i, &gc);
  818. }
  819. }
  820. ftk_gc_reset(&gc);
  821. return;
  822. }
  823. void ftk_widget_set_gc(FtkWidget* thiz, FtkWidgetState state, FtkGc* gc)
  824. {
  825. return_if_fail(thiz != NULL && state < FTK_WIDGET_STATE_NR && gc != NULL);
  826. ftk_gc_copy(thiz->priv->gc+state, gc);
  827. return;
  828. }
  829. void ftk_widget_reset_gc(FtkWidget* thiz, FtkWidgetState state, FtkGc* gc)
  830. {
  831. return_if_fail(thiz != NULL && state < FTK_WIDGET_STATE_NR && gc != NULL);
  832. ftk_gc_reset(thiz->priv->gc+state);
  833. ftk_gc_copy(thiz->priv->gc+state, gc);
  834. return;
  835. }
  836. void ftk_widget_set_text(FtkWidget* thiz, const char* text)
  837. {
  838. FtkEvent event;
  839. return_if_fail(thiz != NULL && thiz->priv != NULL);
  840. ftk_event_init(&event, FTK_EVT_SET_TEXT);
  841. event.u.extra = (void*)text;
  842. if(ftk_widget_event(thiz, &event) == RET_REMOVE)
  843. {
  844. return;
  845. }
  846. if(thiz->priv->text != NULL
  847. && text != NULL
  848. && thiz->priv->text_buff_length > strlen(text))
  849. {
  850. ftk_strcpy(thiz->priv->text, text);
  851. }
  852. else
  853. {
  854. FTK_FREE(thiz->priv->text);
  855. if(text != NULL)
  856. {
  857. thiz->priv->text = FTK_STRDUP(text);
  858. thiz->priv->text_buff_length = strlen(text) + 1;
  859. }
  860. else
  861. {
  862. thiz->priv->text_buff_length = 0;
  863. }
  864. }
  865. ftk_widget_invalidate(thiz);
  866. return;
  867. }
  868. void ftk_widget_set_event_listener(FtkWidget* thiz, FtkListener listener, void* ctx)
  869. {
  870. return_if_fail(thiz != NULL);
  871. thiz->priv->event_listener = listener;
  872. thiz->priv->event_listener_ctx = ctx;
  873. return;
  874. }
  875. void ftk_widget_set_wrap_mode(FtkWidget* thiz, FtkWrapMode mode)
  876. {
  877. return_if_fail(thiz != NULL && thiz->priv != NULL);
  878. thiz->priv->wrap_mode = mode;
  879. return;
  880. }
  881. FtkGc* ftk_widget_get_gc(FtkWidget* thiz)
  882. {
  883. return_val_if_fail(thiz != NULL && thiz->priv != NULL, NULL);
  884. return thiz->priv->gc+thiz->priv->state;
  885. }
  886. FtkWidget* ftk_widget_find_target_keyboard(FtkWidget* thiz, int x, int y)
  887. {
  888. int left = ftk_widget_left_abs(thiz);
  889. int top = ftk_widget_top_abs(thiz);
  890. int w = ftk_widget_width(thiz);
  891. int h = ftk_widget_height(thiz);
  892. if(!ftk_widget_is_visible(thiz))
  893. {
  894. return NULL;
  895. }
  896. if(x < left || y < top || (x > (left + w)) || (y > (top + h)))
  897. {
  898. return NULL;
  899. }
  900. if(ftk_widget_type(thiz) == FTK_KEY_BOARD)
  901. {
  902. return thiz;
  903. }
  904. else
  905. {
  906. return NULL;
  907. }
  908. }
  909. FtkWidget* ftk_widget_find_target(FtkWidget* thiz, int x, int y, int only_sensitive)
  910. {
  911. FtkWidget* target = NULL;
  912. int left = ftk_widget_left_abs(thiz);
  913. int top = ftk_widget_top_abs(thiz);
  914. int w = ftk_widget_width(thiz);
  915. int h = ftk_widget_height(thiz);
  916. if(!ftk_widget_is_visible(thiz))
  917. {
  918. return NULL;
  919. }
  920. if(x < left || y < top || (x > (left + w)) || (y > (top + h)))
  921. {
  922. return NULL;
  923. }
  924. if(thiz->children != NULL)
  925. {
  926. FtkWidget* iter = thiz->children;
  927. while(iter != NULL)
  928. {
  929. if((target = ftk_widget_find_target_keyboard(iter, x, y)) != NULL)
  930. {
  931. return target;
  932. }
  933. iter = ftk_widget_next(iter);
  934. }
  935. }
  936. if(thiz->children != NULL)
  937. {
  938. FtkWidget* iter = thiz->children;
  939. while(iter != NULL)
  940. {
  941. if((target = ftk_widget_find_target(iter, x, y, only_sensitive)) != NULL)
  942. {
  943. return target;
  944. }
  945. iter = ftk_widget_next(iter);
  946. }
  947. }
  948. if (only_sensitive && ftk_widget_is_insensitive(thiz))
  949. {
  950. return NULL;
  951. }
  952. else
  953. {
  954. return thiz;
  955. }
  956. }
  957. void ftk_widget_destroy(FtkWidget* thiz)
  958. {
  959. if(thiz != NULL)
  960. {
  961. int i = 0;
  962. if(thiz->destroy != NULL)
  963. {
  964. thiz->destroy(thiz);
  965. }
  966. for(i = 0; i < FTK_WIDGET_STATE_NR; i++)
  967. {
  968. ftk_gc_reset(thiz->priv->gc+i);
  969. }
  970. if(thiz->priv->user_data != NULL && thiz->priv->user_data_destroy != NULL)
  971. {
  972. thiz->priv->user_data_destroy(thiz->priv->user_data);
  973. }
  974. FTK_FREE(thiz->priv->text);
  975. FTK_ZFREE(thiz->priv, sizeof(thiz->priv));
  976. FTK_ZFREE(thiz, sizeof(FtkWidget));
  977. }
  978. return;
  979. }
  980. void ftk_widget_ref(FtkWidget* thiz)
  981. {
  982. if(thiz != NULL)
  983. {
  984. if(thiz->children != NULL)
  985. {
  986. ftk_widget_ref(thiz->children);
  987. }
  988. if(thiz->next != NULL)
  989. {
  990. ftk_widget_ref(thiz->next);
  991. }
  992. ftk_widget_ref_self(thiz);
  993. }
  994. return;
  995. }
  996. void ftk_widget_unref(FtkWidget* thiz)
  997. {
  998. if(thiz != NULL)
  999. {
  1000. if(ftk_widget_parent(thiz) == NULL)
  1001. {
  1002. if(thiz->ref == 1 && ftk_widget_is_visible(thiz))
  1003. {
  1004. ftk_widget_show(thiz, 0);
  1005. }
  1006. }
  1007. if(thiz->children != NULL)
  1008. {
  1009. ftk_widget_unref(thiz->children);
  1010. }
  1011. if(thiz->next != NULL)
  1012. {
  1013. ftk_widget_unref(thiz->next);
  1014. }
  1015. ftk_widget_unref_self(thiz);
  1016. }
  1017. return;
  1018. }
  1019. static int ftk_widget_paint_called_by_parent(FtkWidget* thiz)
  1020. {
  1021. FtkWidget* parent = thiz->parent;
  1022. return parent != NULL ? parent->priv->painting : 0;
  1023. }
  1024. Ret ftk_widget_paint_self(FtkWidget* thiz, FtkRect *rects, int rect_nr)
  1025. {
  1026. return_val_if_fail(thiz != NULL && thiz->on_paint != NULL, RET_FAIL);
  1027. if(thiz->priv->width == 0 || thiz->priv->height == 0)
  1028. {
  1029. return RET_OK;
  1030. }
  1031. if(ftk_widget_is_visible(thiz) && ftk_widget_is_parent_visible(thiz))
  1032. {
  1033. FtkGc gc = {0};
  1034. FtkBitmap* bitmap = NULL;
  1035. FtkWidget* parent = thiz->parent;
  1036. FtkWidgetInfo* priv = thiz->priv;
  1037. FTK_BEGIN_PAINT(x, y, width, height, canvas);
  1038. bitmap = priv->gc[priv->state].bitmap;
  1039. return_val_if_fail(canvas != NULL, RET_FAIL);
  1040. return_val_if_fail(thiz->priv->width > 0 && thiz->priv->height > 0, RET_FAIL);
  1041. priv->painting++;
  1042. assert(parent == NULL || ftk_widget_paint_called_by_parent(thiz));
  1043. #if defined(FTK_OPTIMIZE_WIDGET_PAINT) && (FTK_OPTIMIZE_WIDGET_PAINT > 0)
  1044. if (rect_nr > 0 && rects != NULL && ftk_widget_parent(thiz) == NULL)
  1045. {
  1046. int i = 0;
  1047. int j = 0;
  1048. for (i = 0; i < rect_nr; i++)
  1049. {
  1050. FtkWidget *child = thiz->children;
  1051. while(child != NULL)
  1052. {
  1053. if( ftk_widget_left_abs(child) == rects[i].x
  1054. && ftk_widget_top_abs(child) == rects[i].y
  1055. && ftk_widget_width(child) == rects[i].width
  1056. && ftk_widget_height(child) == rects[i].height)
  1057. {
  1058. j++;
  1059. break;
  1060. }
  1061. child = child->next;
  1062. }
  1063. if(!ftk_widget_has_attr(thiz, FTK_ATTR_TRANSPARENT))
  1064. {
  1065. gc.mask = FTK_GC_FG;
  1066. gc.fg = ftk_widget_get_gc(thiz)->bg;
  1067. ftk_canvas_reset_gc(canvas, &gc);
  1068. ftk_canvas_clear_rect(canvas, rects[i].x, rects[i].y, rects[i].width, rects[i].height);
  1069. }
  1070. }
  1071. if (j == rect_nr)
  1072. {
  1073. goto __paint_children;
  1074. }
  1075. }
  1076. #endif
  1077. if(!ftk_widget_has_attr(thiz, FTK_ATTR_TRANSPARENT))
  1078. {
  1079. gc.mask = FTK_GC_FG;
  1080. gc.fg = ftk_widget_get_gc(thiz)->bg;
  1081. ftk_canvas_reset_gc(canvas, &gc);
  1082. ftk_canvas_clear_rect(canvas, x, y, width, height);
  1083. }
  1084. #if defined(FTK_OPTIMIZE_WIDGET_PAINT) && (FTK_OPTIMIZE_WIDGET_PAINT > 0)
  1085. __paint_children:
  1086. #endif
  1087. bitmap = priv->gc[priv->state].bitmap;
  1088. if(bitmap != NULL)
  1089. {
  1090. if(ftk_widget_has_attr(thiz, FTK_ATTR_BG_CENTER))
  1091. {
  1092. ftk_canvas_draw_bg_image(canvas, bitmap, FTK_BG_CENTER, x, y, width, height);
  1093. }
  1094. else if(ftk_widget_has_attr(thiz, FTK_ATTR_BG_TILE))
  1095. {
  1096. ftk_canvas_draw_bg_image(canvas, bitmap, FTK_BG_TILE, x, y, width, height);
  1097. }
  1098. else if(ftk_widget_has_attr(thiz, FTK_ATTR_BG_FOUR_CORNER))
  1099. {
  1100. ftk_canvas_draw_bg_image(canvas, bitmap, FTK_BG_FOUR_CORNER, x, y, width, height);
  1101. }
  1102. else
  1103. {
  1104. ftk_canvas_draw_bg_image(canvas, bitmap, FTK_BG_NORMAL, x, y, width, height);
  1105. }
  1106. }
  1107. if(thiz->on_paint != NULL)
  1108. {
  1109. thiz->on_paint(thiz);
  1110. }
  1111. if(thiz->children != NULL)
  1112. {
  1113. if (bitmap != NULL)
  1114. {
  1115. ftk_widget_paint(thiz->children, NULL, 0);
  1116. }
  1117. else
  1118. {
  1119. ftk_widget_paint(thiz->children, rects, rect_nr);
  1120. }
  1121. }
  1122. priv->painting--;
  1123. }
  1124. return RET_OK;
  1125. }
  1126. void ftk_widget_ref_self(FtkWidget* thiz)
  1127. {
  1128. return_if_fail(thiz != NULL);
  1129. thiz->ref++;
  1130. return;
  1131. }
  1132. void ftk_widget_unref_self(FtkWidget* thiz)
  1133. {
  1134. return_if_fail(thiz != NULL);
  1135. thiz->ref--;
  1136. if(thiz->ref == 0)
  1137. {
  1138. ftk_widget_destroy(thiz);
  1139. }
  1140. return;
  1141. }
  1142. Ret ftk_widget_event(FtkWidget* thiz, FtkEvent* event)
  1143. {
  1144. Ret ret = RET_OK;
  1145. return_val_if_fail(thiz != NULL && thiz->on_event != NULL && event != NULL, RET_FAIL);
  1146. ret = FTK_CALL_LISTENER(thiz->priv->event_listener, thiz->priv->event_listener_ctx, event);
  1147. if(ret == RET_REMOVE)
  1148. {
  1149. return RET_OK;
  1150. }
  1151. return thiz->on_event(thiz, event);
  1152. }