PageRenderTime 951ms CodeModel.GetById 202ms app.highlight 566ms RepoModel.GetById 168ms app.codeStats 1ms

/src/ftk_widget.c

http://ftk.googlecode.com/
C | 1436 lines | 1036 code | 284 blank | 116 comment | 395 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/*
  26 * History:
  27 * ================================================================
  28 * 2009-10-03 Li XianJing <xianjimli@hotmail.com> created
  29 *
  30 */
  31
  32/**
  33 * SECTION:ftk_widget
  34 * @Short_description: Base class for all widgets
  35 * @Title: FtkWidget
  36 *
  37 * FtkWidget is the base class all widgets in FTK derive from. It manages the
  38 * widget lifecycle, states and style.
  39 */
  40
  41#include "ftk_theme.h"
  42#include "ftk_bitmap.h"
  43#include "ftk_widget.h"
  44#include "ftk_globals.h"
  45#include "ftk_canvas.h"
  46#include "ftk_window.h"
  47#include "ftk_util.h"
  48
  49struct _FtkWidgetInfo
  50{
  51	int id;
  52	int type;
  53	int top;
  54	int left;
  55	int width;
  56	int height;
  57	int visible;
  58	int hide_self;
  59	FtkWrapMode wrap_mode;
  60
  61	int painting;
  62	FtkCanvas* canvas;
  63	unsigned int attr;
  64	FtkWidgetState state;
  65	FtkGc gc[FTK_WIDGET_STATE_NR];
  66	void* user_data;
  67	char* text;
  68	size_t text_buff_length;
  69	FtkDestroy user_data_destroy;
  70
  71	FtkListener event_listener;
  72	void* event_listener_ctx;
  73};
  74
  75static int  ftk_widget_is_parent_visible(FtkWidget* thiz);
  76static void ftk_widget_validate_position_size(FtkWidget* thiz);
  77
  78/**
  79 * ftk_widget_init:
  80 * @thiz: a #FtkWidget
  81 * @type: a #FtkWidgetType 
  82 * @id: id of the widget.
  83 * @x: X position
  84 * @y: Y position
  85 * @width: width of the widget
  86 * @height: height of the widget
  87 * @attr: a #FtkWidgetAttr, attribute of the widget
  88 *
  89 * This function called by widget implementation to initialize a widget.
  90 *
  91 */
  92void ftk_widget_init(FtkWidget* thiz, int type, int id, int x, int y, 
  93	int width, int height, unsigned int attr)
  94{
  95	return_if_fail(thiz != NULL && thiz->priv == NULL);
  96
  97	thiz->ref = 1;
  98	thiz->priv = (FtkWidgetInfo*)FTK_ZALLOC(sizeof(FtkWidgetInfo));
  99
 100	if(thiz->priv != NULL)
 101	{
 102		FtkWidgetInfo* priv =  thiz->priv;
 103		int state = FTK_WIDGET_NORMAL;
 104
 105		priv->id     = id;
 106		priv->type   = type;
 107		priv->left   = x;
 108		priv->top    = y;
 109		priv->width  = width;
 110		priv->height = height;
 111		priv->attr |= attr;
 112		
 113		for(; state < FTK_WIDGET_STATE_NR; state++)
 114		{
 115			priv->gc[state].mask   = FTK_GC_BG | FTK_GC_FG | FTK_GC_FONT;
 116			priv->gc[state].font   = ftk_theme_get_font(ftk_default_theme(), (FtkWidgetType)type);
 117			priv->gc[state].fg     = ftk_theme_get_fg_color(ftk_default_theme(), (FtkWidgetType)type, (FtkWidgetState)state);
 118			priv->gc[state].bg     = ftk_theme_get_bg_color(ftk_default_theme(), (FtkWidgetType)type, (FtkWidgetState)state);
 119			priv->gc[state].bitmap = ftk_theme_get_bg(ftk_default_theme(), (FtkWidgetType)type, (FtkWidgetState)state);
 120
 121			if(priv->gc[state].bitmap != NULL) priv->gc[state].mask |= FTK_GC_BITMAP;
 122		}
 123	
 124		if(attr & FTK_ATTR_INSENSITIVE)
 125		{
 126			priv->state = FTK_WIDGET_INSENSITIVE;
 127		}
 128		else if(attr & FTK_ATTR_FOCUSED)
 129		{
 130			ftk_window_set_focus(ftk_widget_toplevel(thiz), thiz);
 131		}
 132	}
 133
 134	return;
 135
 136}
 137
 138/**
 139 * ftk_widget_type:
 140 * @thiz: a #FtkWidget
 141 *
 142 * Get the type of the widget.
 143 * 
 144 * Return value: #FtkWidgetType
 145 */
 146int ftk_widget_type(FtkWidget* thiz)
 147{
 148	return thiz != NULL && thiz->priv != NULL ? thiz->priv->type : 0;
 149}
 150
 151/**
 152 * ftk_widget_top:
 153 * @thiz: a #FtkWidget
 154 *
 155 * Get the Y position of the widget relative to its parent.
 156 * 
 157 */
 158int ftk_widget_top(FtkWidget* thiz)
 159{
 160	return thiz != NULL && thiz->priv != NULL ? thiz->priv->top : 0;
 161}
 162
 163/**
 164 * ftk_widget_left:
 165 * @thiz: a #FtkWidget
 166 *
 167 * Get the X position of the widget relative to its parent.
 168 * 
 169 */
 170int ftk_widget_left(FtkWidget* thiz)
 171{
 172	return thiz != NULL && thiz->priv != NULL ? thiz->priv->left : 0;
 173}
 174
 175/**
 176 * ftk_widget_top_abs:
 177 * @thiz: a #FtkWidget
 178 *
 179 * Get the absolute Y position of the widget.
 180 * 
 181 */
 182int ftk_widget_top_abs(FtkWidget* thiz)
 183{
 184	int top = 0;
 185	FtkWidget* iter = thiz;
 186
 187	for(; iter != NULL; iter = ftk_widget_parent(iter))
 188	{
 189		top += ftk_widget_top(iter);
 190	}
 191
 192	return top;
 193}
 194
 195/**
 196 * ftk_widget_left_abs:
 197 * @thiz: a #FtkWidget
 198 *
 199 * Get the absolute X position of the widget.
 200 * 
 201 */
 202int ftk_widget_left_abs(FtkWidget* thiz)
 203{
 204	int left = 0;
 205	FtkWidget* iter = thiz;
 206
 207	for(; iter != NULL; iter = ftk_widget_parent(iter))
 208	{
 209		left += ftk_widget_left(iter);
 210	}
 211
 212	return left;
 213}
 214
 215/**
 216 * ftk_widget_top_in_window:
 217 * @thiz: a #FtkWidget
 218 *
 219 * Get the absolute Y position of the widget in the window.
 220 * 
 221 */
 222int ftk_widget_top_in_window(FtkWidget* thiz)
 223{
 224	int top = 0;
 225	FtkWidget* iter = thiz;
 226
 227	for(; ftk_widget_parent(iter); iter = ftk_widget_parent(iter))
 228	{
 229		top += ftk_widget_top(iter);
 230	}
 231
 232	return top;
 233}
 234
 235/**
 236 * ftk_widget_left_in_window:
 237 * @thiz: a #FtkWidget
 238 *
 239 * Get the absolute X position of the widget in the window.
 240 * 
 241 */
 242int ftk_widget_left_in_window(FtkWidget* thiz)
 243{
 244	int left = 0;
 245	FtkWidget* iter = thiz;
 246
 247	for(; ftk_widget_parent(iter); iter = ftk_widget_parent(iter))
 248	{
 249		left += ftk_widget_left(iter);
 250	}
 251
 252	return left;
 253}
 254
 255int ftk_widget_width(FtkWidget* thiz)
 256{
 257	return thiz != NULL && thiz->priv != NULL ? thiz->priv->width : 0;
 258}
 259
 260int ftk_widget_height(FtkWidget* thiz)
 261{
 262	return thiz != NULL && thiz->priv != NULL ? thiz->priv->height : 0;
 263}
 264
 265int ftk_widget_is_insensitive(FtkWidget* thiz)
 266{
 267	return thiz != NULL && thiz->priv != NULL && thiz->priv->state == FTK_WIDGET_INSENSITIVE;
 268}
 269
 270int ftk_widget_is_visible(FtkWidget* thiz)
 271{
 272	return thiz != NULL && thiz->priv != NULL ? thiz->priv->visible: 0;
 273}
 274
 275int ftk_widget_is_focused(FtkWidget* thiz)
 276{
 277	return thiz != NULL && thiz->priv != NULL && thiz->priv->state == FTK_WIDGET_FOCUSED;
 278}
 279
 280int ftk_widget_is_active(FtkWidget* thiz)
 281{
 282	return thiz != NULL && thiz->priv != NULL && thiz->priv->state == FTK_WIDGET_ACTIVE;
 283}
 284
 285int ftk_widget_id(FtkWidget* thiz)
 286{
 287	return thiz != NULL && thiz->priv != NULL ? thiz->priv->id : 0;
 288}
 289
 290Ret ftk_widget_invalidate(FtkWidget* thiz)
 291{
 292	FtkRect rect = {0};
 293	if(!ftk_widget_is_visible(ftk_widget_toplevel(thiz)))
 294	{
 295		return RET_FAIL;
 296	}
 297	
 298	rect.y = ftk_widget_top_abs(thiz);
 299	rect.x = ftk_widget_left_abs(thiz);
 300	rect.width = ftk_widget_width(thiz);
 301	rect.height = ftk_widget_height(thiz);
 302
 303	return ftk_window_invalidate(ftk_widget_toplevel(thiz), &rect);
 304}
 305
 306Ret ftk_widget_invalidate_forcely(FtkWidget* thiz)
 307{
 308    FtkRect rect = {0};
 309
 310    thiz = ftk_widget_toplevel(thiz);
 311
 312    if(!ftk_widget_is_visible(thiz))
 313    {
 314        return RET_FAIL;
 315    }
 316
 317    rect.y = ftk_widget_top_abs(thiz);
 318    rect.x = ftk_widget_left_abs(thiz);
 319    rect.width = ftk_widget_width(thiz);
 320    rect.height = ftk_widget_height(thiz);
 321
 322    return ftk_window_invalidate(thiz, &rect);
 323}
 324
 325FtkWrapMode ftk_widget_get_wrap_mode(FtkWidget* thiz)
 326{
 327	return_val_if_fail(thiz != NULL && thiz->priv != NULL, FTK_WRAP_NONE);
 328
 329	return thiz->priv->wrap_mode;
 330}
 331
 332Ret ftk_widget_update(FtkWidget* thiz)
 333{
 334	return ftk_widget_update_rect(thiz, NULL);
 335}
 336
 337Ret ftk_widget_update_rect(FtkWidget* thiz, FtkRect* rect)
 338{
 339	FtkEvent event;
 340	FtkWidget* window = NULL;
 341	FtkWidgetInfo* priv = NULL;
 342	return_val_if_fail(thiz != NULL, RET_FAIL);
 343	window = ftk_widget_toplevel(thiz);
 344	return_val_if_fail(window != NULL, RET_FAIL);
 345
 346	priv =  thiz->priv;
 347	ftk_event_init(&event, FTK_EVT_UPDATE);
 348	if(rect == NULL)
 349	{
 350		event.u.rect.x = ftk_widget_left_abs(thiz);
 351		event.u.rect.y = ftk_widget_top_abs(thiz);
 352		event.u.rect.width = priv->width;
 353		event.u.rect.height = priv->height;
 354	}
 355	else
 356	{
 357		//ftk_logd("%s: x=%d y=%d w=%d h=%d\n", __func__, rect->x, rect->y, rect->width, rect->height);
 358		event.u.rect = *rect;
 359	}
 360
 361	return ftk_widget_event(window, &event);
 362}
 363
 364FtkCanvas* ftk_widget_canvas(FtkWidget* thiz)
 365{
 366	FtkWidget* toplevel = NULL;
 367	FtkCanvas* canvas = NULL;
 368	return_val_if_fail(thiz != NULL && thiz->priv != NULL, NULL);
 369	
 370	toplevel = ftk_widget_toplevel(thiz);
 371	canvas = toplevel->priv->canvas != NULL ? toplevel->priv->canvas : ftk_shared_canvas();
 372   	ftk_canvas_reset_gc(canvas, ftk_widget_get_gc(thiz));
 373
 374	return canvas;
 375}
 376
 377int ftk_widget_has_attr(FtkWidget* thiz, FtkWidgetAttr attr)
 378{
 379	return_val_if_fail(thiz != NULL && thiz->priv != NULL, 0);
 380
 381	return thiz->priv->attr & attr;
 382}
 383
 384FtkWidgetState ftk_widget_state(FtkWidget* thiz)
 385{
 386	return_val_if_fail(thiz != NULL && thiz->priv != NULL, FTK_WIDGET_NORMAL);
 387
 388	return thiz->priv->state;
 389}
 390
 391void* ftk_widget_user_data(FtkWidget* thiz)
 392{
 393	return_val_if_fail(thiz != NULL && thiz->priv != NULL, NULL);
 394
 395	return thiz->priv->user_data;
 396}
 397
 398const char* ftk_widget_get_text(FtkWidget* thiz)
 399{
 400	FtkEvent event;
 401	return_val_if_fail(thiz != NULL && thiz->priv != NULL, NULL);
 402	
 403	ftk_event_init(&event, FTK_EVT_GET_TEXT);
 404	if(ftk_widget_event(thiz, &event) == RET_REMOVE)
 405	{
 406		return (char*)event.u.extra;
 407	}
 408
 409	//return thiz->priv->text != NULL ? thiz->priv->text : "";
 410	return thiz->priv->text != NULL ? thiz->priv->text : NULL; 
 411}
 412
 413void ftk_widget_set_attr(FtkWidget* thiz, unsigned int attr)
 414{
 415	return_if_fail(thiz != NULL && thiz->priv != NULL);
 416
 417	thiz->priv->attr |= attr;
 418
 419	if(attr & FTK_ATTR_INSENSITIVE)
 420	{
 421		ftk_widget_set_insensitive(thiz, 1);
 422	}
 423	else if(attr & FTK_ATTR_FOCUSED)
 424	{
 425		ftk_window_set_focus(ftk_widget_toplevel(thiz), thiz);
 426	}
 427	else if(attr & FTK_ATTR_FULLSCREEN)
 428	{
 429		ftk_window_set_fullscreen(thiz, FTK_ATTR_FULLSCREEN);
 430	}
 431
 432	return;
 433}
 434
 435void ftk_widget_unset_attr(FtkWidget* thiz, FtkWidgetAttr attr)
 436{
 437	return_if_fail(thiz != NULL && thiz->priv != NULL);
 438
 439	thiz->priv->attr = (~attr) & thiz->priv->attr;
 440
 441	return;
 442}
 443
 444void ftk_widget_set_user_data(FtkWidget* thiz, FtkDestroy destroy, void* data)
 445{
 446	return_if_fail(thiz != NULL && thiz->priv != NULL);
 447
 448	if(thiz->priv->user_data != NULL && thiz->priv->user_data_destroy != NULL)
 449	{
 450		thiz->priv->user_data_destroy(thiz->priv->user_data);
 451	}
 452	thiz->priv->user_data = data;
 453	thiz->priv->user_data_destroy = destroy;
 454
 455	return;
 456}
 457
 458void ftk_widget_move(FtkWidget* thiz, int x, int y)
 459{
 460	FtkEvent event;
 461	return_if_fail(thiz != NULL && thiz->priv != NULL);
 462
 463	if(thiz->priv->left == x && thiz->priv->top  == y)
 464	{
 465		return;
 466	}
 467
 468	thiz->priv->left = x;
 469	thiz->priv->top  = y;
 470	ftk_widget_validate_position_size(thiz);
 471
 472	if(thiz->on_event != NULL)
 473	{
 474		ftk_event_init(&event, FTK_EVT_MOVE);
 475		event.widget = thiz;
 476		ftk_widget_event(thiz, &event);
 477	}
 478
 479    ftk_widget_invalidate_forcely(thiz);
 480
 481	return;
 482}
 483
 484void ftk_widget_resize(FtkWidget* thiz, int width, int height)
 485{
 486	FtkEvent event;
 487	return_if_fail(thiz != NULL && thiz->priv != NULL);
 488
 489	if(thiz->priv->width == width && thiz->priv->height == height)
 490	{
 491		return;
 492	}
 493
 494	thiz->priv->width = width;
 495	thiz->priv->height = height;
 496	ftk_widget_validate_position_size(thiz);
 497
 498	if(thiz->on_event != NULL)
 499	{
 500		ftk_event_init(&event, FTK_EVT_RESIZE);
 501		event.widget = thiz;
 502		ftk_widget_event(thiz, &event);
 503	}
 504
 505    ftk_widget_invalidate_forcely(thiz);
 506
 507	return;
 508}
 509
 510void ftk_widget_move_resize(FtkWidget* thiz, int x, int y, int width, int height)
 511{
 512	FtkEvent event;
 513	return_if_fail(thiz != NULL && thiz->priv != NULL);
 514	
 515	if(thiz->priv->left == x && thiz->priv->top  == y
 516		&& thiz->priv->width == width && thiz->priv->height == height)
 517	{
 518		return;
 519	}
 520
 521	thiz->priv->left = x;
 522	thiz->priv->top  = y;
 523	thiz->priv->width = width;
 524	thiz->priv->height = height;
 525	ftk_widget_validate_position_size(thiz);
 526	
 527	if(thiz->on_event != NULL)
 528	{
 529		ftk_event_init(&event, FTK_EVT_MOVE_RESIZE);
 530		event.widget = thiz;
 531		ftk_widget_event(thiz, &event);
 532	}
 533
 534    ftk_widget_invalidate_forcely(thiz);
 535
 536	return;
 537}
 538
 539void ftk_widget_set_type(FtkWidget* thiz, int type)
 540{
 541	return_if_fail(thiz != NULL && thiz->priv != NULL);
 542	thiz->priv->type = type;
 543
 544	return;
 545}
 546
 547void ftk_widget_set_insensitive(FtkWidget* thiz, int insensitive)
 548{
 549	return_if_fail(thiz != NULL && thiz->priv != NULL);
 550
 551	thiz->priv->state = insensitive ? FTK_WIDGET_INSENSITIVE : FTK_WIDGET_NORMAL;
 552
 553	return;
 554}
 555
 556static int  ftk_widget_is_parent_visible(FtkWidget* thiz)
 557{
 558	FtkWidget* parent = ftk_widget_parent(thiz);
 559	while(parent != NULL)
 560	{
 561		if(!ftk_widget_is_visible(parent))
 562		{
 563			return 0;
 564		}
 565
 566		parent = ftk_widget_parent(parent);
 567	}
 568
 569	return 1;
 570}
 571
 572void ftk_widget_show(FtkWidget* thiz, int visible)
 573{
 574	FtkEvent event;
 575	
 576	return_if_fail(thiz != NULL && thiz->priv != NULL);
 577	if(thiz->priv->visible == visible) return;
 578	
 579	if(thiz->priv->hide_self) return ; 
 580
 581	thiz->priv->visible = visible;
 582	ftk_event_init(&event, visible ? FTK_EVT_SHOW : FTK_EVT_HIDE);
 583
 584	ftk_widget_event(thiz, &event);
 585
 586	if(!ftk_widget_is_parent_visible(thiz))
 587	{
 588		return;
 589	}
 590
 591	//if(ftk_widget_parent(thiz) != NULL)
 592	//{
 593	//}
 594	if(visible)
 595	{
 596	    ftk_widget_invalidate(thiz);
 597	}
 598	else
 599	{
 600	    ftk_widget_invalidate_forcely(thiz);
 601	}
 602
 603	return;
 604}
 605
 606void ftk_widget_show_all(FtkWidget* thiz, int visible)
 607{
 608	return_if_fail(thiz != NULL && thiz->priv != NULL);
 609		
 610	if(thiz->children != NULL)
 611	{
 612		ftk_widget_show_all(thiz->children, visible);
 613	}
 614
 615	if(thiz->next != NULL)
 616	{
 617		ftk_widget_show_all(thiz->next, visible);
 618	}
 619
 620	ftk_widget_show(thiz, visible);
 621
 622	return;
 623}
 624
 625void ftk_widget_hide_self(FtkWidget* thiz, int hide)
 626{
 627	return_if_fail(thiz != NULL && thiz->priv != NULL);
 628	thiz->priv->hide_self = hide;
 629	return ;
 630}
 631
 632void ftk_widget_set_visible(FtkWidget* thiz, int visible)
 633{
 634	return_if_fail(thiz != NULL && thiz->priv != NULL);
 635	if(thiz->priv->visible == visible) return;
 636	
 637	thiz->priv->visible = visible;
 638
 639	return;
 640}
 641
 642void ftk_widget_set_focused(FtkWidget* thiz, int focused)
 643{	
 644	FtkEvent event;
 645	FtkWidgetState state = FTK_WIDGET_ACTIVE;
 646	return_if_fail(thiz != NULL && thiz->priv != NULL);
 647
 648	if(thiz->priv->state == FTK_WIDGET_INSENSITIVE)
 649	{
 650		return;
 651	}
 652
 653	state = focused ? FTK_WIDGET_FOCUSED : FTK_WIDGET_NORMAL;
 654	
 655	if(thiz->priv->state == state)
 656	{
 657		return;
 658	}
 659
 660	thiz->priv->state = state;
 661	ftk_event_init(&event, focused ? FTK_EVT_FOCUS_IN : FTK_EVT_FOCUS_OUT);
 662	event.widget = thiz;
 663	ftk_widget_event(thiz, &event);
 664
 665	if(!ftk_widget_is_parent_visible(thiz))
 666	{
 667		return;
 668	}
 669
 670	ftk_widget_invalidate(thiz);
 671
 672	return;
 673}
 674
 675void ftk_widget_set_active(FtkWidget* thiz, int active)
 676{	
 677	FtkWidgetState state = FTK_WIDGET_ACTIVE;
 678	return_if_fail(thiz != NULL && thiz->priv != NULL);
 679
 680	if(thiz->priv->state == FTK_WIDGET_INSENSITIVE)
 681	{
 682		return;
 683	}
 684
 685	state = active ? FTK_WIDGET_ACTIVE : FTK_WIDGET_FOCUSED;
 686	if(thiz->priv->state == state)
 687	{
 688		return;
 689	}
 690	
 691	thiz->priv->state = state;
 692	if(!ftk_widget_is_parent_visible(thiz))
 693	{
 694		return;
 695	}
 696
 697	ftk_widget_invalidate(thiz);
 698
 699	return;
 700}
 701
 702void ftk_widget_set_id(FtkWidget* thiz, int id)
 703{
 704	return_if_fail(thiz != NULL && thiz->priv != NULL);
 705	
 706	thiz->priv->id = id;
 707
 708	return;
 709}
 710
 711void ftk_widget_set_canvas(FtkWidget* thiz, FtkCanvas* canvas)
 712{
 713	return_if_fail(thiz != NULL && thiz->priv != NULL);
 714
 715	thiz->priv->canvas = canvas;
 716
 717	return;
 718}
 719
 720void ftk_widget_set_parent(FtkWidget* thiz, FtkWidget* parent)
 721{
 722	FtkEvent event;
 723	return_if_fail(thiz != NULL && thiz->priv != NULL);
 724
 725	if(thiz->parent != NULL && parent == NULL)
 726	{
 727		ftk_event_init(&event, FTK_EVT_REMOVE_CHILD);
 728		event.u.extra = thiz;
 729		ftk_widget_event(thiz->parent, &event);
 730	}
 731	thiz->parent = parent;
 732	if(parent != NULL)
 733	{
 734		ftk_event_init(&event, FTK_EVT_ADD_CHILD);
 735		event.u.extra = thiz;
 736		ftk_widget_event(parent, &event);
 737	}
 738
 739	ftk_widget_set_canvas(thiz, ftk_widget_canvas(ftk_widget_toplevel(parent)));
 740	
 741	return;
 742}
 743
 744static void ftk_widget_validate_position_size(FtkWidget* thiz)
 745{
 746	FtkWidgetInfo* priv = thiz->priv;
 747	FtkWidget* parent = thiz->parent;
 748
 749	if(parent != NULL)
 750	{
 751		int parent_w = ftk_widget_width(parent);
 752		int parent_h = ftk_widget_height(parent);
 753		
 754		// remove by wzw.random@gmail.com.
 755        // ???????????????
 756        // ??????????????????width?unsigned int??????0????????
 757        // ???width?height?????int??????????????
 758//		priv->width = (priv->width + 1) & 0xfffffffe;
 759//		priv->height = (priv->height + 1) & 0xfffffffe;
 760
 761		priv->left = (priv->left >= parent_w) ? (parent_w - 1) : priv->left;
 762		priv->top = (priv->top >= parent_h) ? (parent_h - 1) : priv->top;
 763		priv->width = (priv->left + priv->width) > parent_w ? (parent_w - priv->left) : priv->width;
 764		priv->height = (priv->height + priv->top) > parent_h ? (parent_h - priv->top) : priv->height;
 765
 766//		priv->width = priv->width & 0xfffffffe;
 767//		priv->height = priv->height & 0xfffffffe;
 768	}
 769
 770	return;
 771}
 772
 773void ftk_widget_append_child(FtkWidget* thiz, FtkWidget* child)
 774{
 775	return_if_fail(thiz != NULL && thiz->priv != NULL);
 776
 777	if(thiz->children == NULL)
 778	{
 779		thiz->children = child;
 780		ftk_widget_set_parent(child, thiz);
 781	}
 782	else
 783	{
 784		ftk_widget_append_sibling(thiz->children, child);
 785	}
 786
 787	ftk_widget_validate_position_size(child);
 788
 789	return;
 790}
 791
 792void ftk_widget_append_sibling(FtkWidget* thiz, FtkWidget* sibling)
 793{
 794	FtkWidget* iter = thiz;
 795	return_if_fail(thiz != NULL && sibling != NULL);
 796
 797	for(; iter->next != NULL; iter = iter->next);
 798
 799	iter->next = sibling;
 800	sibling->prev = iter;
 801
 802	ftk_widget_set_parent(sibling, ftk_widget_parent(thiz));
 803
 804	return;
 805}
 806
 807void ftk_widget_remove_child(FtkWidget* thiz, FtkWidget* child)
 808{
 809	FtkWidget* iter = thiz->children;
 810	return_if_fail(thiz != NULL && child != NULL);
 811
 812	if(iter == child)
 813	{
 814		thiz->children = child->next;
 815		if(thiz->children != NULL)
 816		{
 817			thiz->children->prev = NULL;
 818		}
 819
 820		child->prev = NULL;
 821		child->next = NULL;
 822		
 823		return;
 824	}
 825
 826	for(; iter != NULL; iter = iter->next)
 827	{
 828		if(iter == child)
 829		{
 830			if(child->prev != NULL)
 831			{
 832				child->prev->next = child->next;
 833			}
 834
 835			if(child->next != NULL)
 836			{
 837				child->next->prev = child->prev;
 838			}
 839
 840			child->prev = NULL;
 841			child->next = NULL;
 842
 843			return;
 844		}
 845	}
 846	
 847	return;
 848}
 849
 850FtkWidget* ftk_widget_toplevel(FtkWidget* thiz)
 851{
 852	FtkWidget* iter = thiz;
 853
 854	for(; ftk_widget_parent(iter) != NULL; iter = ftk_widget_parent(iter));
 855
 856	return iter;
 857}
 858
 859FtkWidget* ftk_widget_parent(FtkWidget* thiz)
 860{
 861	return thiz != NULL ? thiz->parent : NULL;
 862}
 863
 864FtkWidget* ftk_widget_prev(FtkWidget* thiz)
 865{
 866	return thiz != NULL ? thiz->prev : NULL;
 867}
 868
 869FtkWidget* ftk_widget_next(FtkWidget* thiz)
 870{
 871	return thiz != NULL ? thiz->next : NULL;
 872}
 873
 874FtkWidget* ftk_widget_child(FtkWidget* thiz)
 875{
 876	return thiz != NULL ? thiz->children : NULL;
 877}
 878
 879FtkWidget* ftk_widget_last_child(FtkWidget* thiz)
 880{
 881	FtkWidget* iter = NULL;
 882	return_val_if_fail(thiz != NULL && thiz->children != NULL, NULL);
 883
 884	for(iter = thiz->children; iter->next != NULL; iter = iter->next)
 885	{
 886	}
 887
 888	return iter;
 889}
 890
 891FtkWidget* ftk_widget_lookup(FtkWidget* thiz, int id)
 892{
 893	FtkWidget* iter = thiz;
 894	FtkWidget* widget = NULL;
 895	return_val_if_fail(thiz != NULL, NULL);
 896
 897	if(ftk_widget_id(thiz) == id) return iter;
 898
 899	iter = ftk_widget_child(thiz);
 900	for(; iter != NULL; iter = ftk_widget_next(iter))
 901	{
 902		if(ftk_widget_id(iter) == id) return iter;
 903		if((widget = ftk_widget_lookup(iter, id)) != NULL) return widget;
 904	}
 905
 906	return NULL;
 907}
 908
 909#if defined(FTK_OPTIMIZE_WIDGET_PAINT) && (FTK_OPTIMIZE_WIDGET_PAINT > 0)
 910static int ftk_rects_is_cross(const FtkRect *a, const FtkRect *b)
 911{
 912    int minx, maxx, miny, maxy;
 913
 914#define __ftk_min(a,b) (a) > (b) ? (b) : (a)
 915#define __ftk_max(a,b) (a) > (b) ? (a) : (b)
 916
 917    minx = __ftk_max(a->x, b->x);
 918    miny = __ftk_max(a->y, b->y);
 919
 920    maxx = __ftk_min(a->x + a->width  - 1, b->x + b->width  - 1);
 921    maxy = __ftk_min(a->y + a->height - 1, b->y + b->height - 1);
 922
 923    if (minx > maxx || miny > maxy)
 924    {
 925        return 0;
 926    }
 927
 928    return (maxx - minx) * (maxy - miny);
 929}
 930#endif /* FTK_OPTIMIZE_WIDGET_PAINT */
 931
 932void ftk_widget_paint(FtkWidget* thiz, FtkRect *rects, int rect_nr)
 933{
 934    FtkRect rect = {0};
 935
 936	if(!ftk_widget_is_parent_visible(thiz))
 937	{
 938		return;
 939	}
 940	
 941	/*If thiz is a window, we disable update first, until all sub-widgets are painted.*/
 942	if(ftk_widget_parent(thiz) == NULL)
 943	{
 944		ftk_window_disable_update(thiz);
 945	}
 946
 947    rect.x = ftk_widget_left_abs(thiz);
 948    rect.y = ftk_widget_top_abs(thiz);
 949    rect.width  = ftk_widget_width(thiz);
 950    rect.height = ftk_widget_height(thiz);
 951
 952#if defined(FTK_OPTIMIZE_WIDGET_PAINT) && (FTK_OPTIMIZE_WIDGET_PAINT > 0)
 953
 954    if (rect_nr > 0 && rects != NULL)
 955    {
 956        int i = 0;
 957
 958        for (i = 0; i < rect_nr; i++)
 959        {
 960            if (ftk_rects_is_cross(&rect, rects + i))
 961            {
 962                ftk_widget_paint_self(thiz, rects, rect_nr);
 963                break;
 964            }
 965        }
 966    }
 967    else
 968    {
 969        ftk_widget_paint_self(thiz, rects, rect_nr);
 970    }
 971
 972#else
 973
 974    ftk_widget_paint_self(thiz, rects, rect_nr);
 975
 976#endif
 977
 978	if(ftk_widget_next(thiz) != NULL)
 979	{
 980		ftk_widget_paint(ftk_widget_next(thiz), rects, rect_nr);
 981	}
 982
 983	/*If thiz is a window, now, do real updating.*/
 984	if(ftk_widget_parent(thiz) == NULL)
 985	{
 986		ftk_window_enable_update(thiz);
 987		
 988		ftk_window_update(thiz, &rect);
 989	}
 990
 991	return;
 992}
 993
 994void ftk_widget_set_font_size(FtkWidget* thiz, int font_size)
 995{
 996	char font_desc[64] = {0};
 997	ftk_snprintf(font_desc, sizeof(font_desc)-1, FONT_DESC_FMT, font_size, 0, 0, FTK_FONT);
 998
 999	ftk_widget_set_font(thiz, font_desc);
1000
1001	return;
1002}
1003
1004int  ftk_widget_get_font_size(FtkWidget* thiz)
1005{
1006	return_val_if_fail(thiz != NULL, 0);
1007
1008	return ftk_font_desc_get_size(ftk_widget_get_gc(thiz)->font);
1009}
1010
1011void ftk_widget_set_font(FtkWidget* thiz, const char* font_desc_str)
1012{
1013	FtkGc gc = {0};
1014	FtkFontDesc* font_desc = ftk_font_desc_create(font_desc_str);
1015
1016	gc.mask = FTK_GC_FONT;
1017	gc.font = font_desc;
1018
1019	if(gc.font != NULL)
1020	{
1021		int i = 0;
1022		for(i = 0; i < FTK_WIDGET_STATE_NR; i++)
1023		{
1024			ftk_widget_set_gc(thiz, (FtkWidgetState)i, &gc);
1025		}
1026	}
1027	ftk_gc_reset(&gc);
1028
1029	return;
1030}
1031
1032void    ftk_widget_set_gc(FtkWidget* thiz, FtkWidgetState state, FtkGc* gc)
1033{
1034	return_if_fail(thiz != NULL && state < FTK_WIDGET_STATE_NR && gc != NULL);
1035
1036	ftk_gc_copy(thiz->priv->gc+state, gc);
1037
1038	return;
1039}
1040
1041void    ftk_widget_reset_gc(FtkWidget* thiz, FtkWidgetState state, FtkGc* gc)
1042{
1043	return_if_fail(thiz != NULL && state < FTK_WIDGET_STATE_NR && gc != NULL);
1044
1045	ftk_gc_reset(thiz->priv->gc+state);
1046	ftk_gc_copy(thiz->priv->gc+state, gc);
1047
1048	return;
1049}
1050
1051void ftk_widget_set_text(FtkWidget* thiz, const char* text)
1052{
1053	FtkEvent event;
1054	return_if_fail(thiz != NULL && thiz->priv != NULL);
1055	
1056	ftk_event_init(&event, FTK_EVT_SET_TEXT);
1057	event.u.extra = (void*)text;
1058
1059	if(ftk_widget_event(thiz, &event) == RET_REMOVE)
1060	{
1061		return;
1062	}
1063
1064	if(thiz->priv->text != NULL 
1065		&& text != NULL 
1066		&& thiz->priv->text_buff_length > strlen(text))
1067	{
1068		ftk_strcpy(thiz->priv->text, text);
1069	}
1070	else
1071	{
1072		FTK_FREE(thiz->priv->text);
1073
1074		if(text != NULL)
1075		{
1076			thiz->priv->text = FTK_STRDUP(text);
1077			thiz->priv->text_buff_length = strlen(text) + 1;
1078		}
1079		else
1080		{
1081			thiz->priv->text_buff_length = 0;
1082		}
1083	}
1084
1085	ftk_widget_invalidate(thiz);
1086
1087	return;
1088}
1089
1090void ftk_widget_set_event_listener(FtkWidget* thiz, FtkListener listener, void* ctx)
1091{
1092	return_if_fail(thiz != NULL);
1093
1094	thiz->priv->event_listener = listener;
1095	thiz->priv->event_listener_ctx = ctx;
1096
1097	return;
1098}
1099
1100void ftk_widget_set_wrap_mode(FtkWidget* thiz, FtkWrapMode mode)
1101{
1102	return_if_fail(thiz != NULL && thiz->priv != NULL);
1103
1104	thiz->priv->wrap_mode = mode;
1105
1106	return;
1107}
1108
1109FtkGc* ftk_widget_get_gc(FtkWidget* thiz)
1110{
1111	return_val_if_fail(thiz != NULL && thiz->priv != NULL, NULL);
1112
1113	return thiz->priv->gc+thiz->priv->state;
1114}
1115
1116FtkWidget* ftk_widget_find_target_keyboard(FtkWidget* thiz, int x, int y)
1117{
1118    int left = ftk_widget_left_abs(thiz);
1119    int top  = ftk_widget_top_abs(thiz);
1120    int w    = ftk_widget_width(thiz);
1121    int h    = ftk_widget_height(thiz);
1122
1123    if(!ftk_widget_is_visible(thiz))
1124    {
1125        return NULL;
1126    }
1127
1128    if(x < left || y < top || (x > (left + w)) || (y > (top + h)))
1129    {
1130        return NULL;
1131    }
1132
1133    if(ftk_widget_type(thiz) == FTK_KEY_BOARD)
1134    {
1135        return thiz;
1136    }
1137    else
1138    {
1139        return NULL;
1140    }
1141}
1142
1143FtkWidget* ftk_widget_find_target(FtkWidget* thiz, int x, int y, int only_sensitive)
1144{
1145	FtkWidget* target = NULL;
1146	int left = ftk_widget_left_abs(thiz);
1147	int top  = ftk_widget_top_abs(thiz);
1148	int w    = ftk_widget_width(thiz);
1149	int h    = ftk_widget_height(thiz);
1150
1151	if(!ftk_widget_is_visible(thiz))
1152	{
1153		return NULL;
1154	}
1155
1156	if(x < left || y < top || (x > (left + w)) || (y > (top + h)))
1157	{
1158		return NULL;
1159	}
1160
1161    if(thiz->children != NULL)
1162    {
1163        FtkWidget* iter = thiz->children;
1164        while(iter != NULL)
1165        {
1166            if((target = ftk_widget_find_target_keyboard(iter, x, y)) != NULL)
1167            {
1168                return target;
1169            }
1170
1171            iter = ftk_widget_next(iter);
1172        }
1173    }
1174
1175	if(thiz->children != NULL)
1176	{
1177		FtkWidget* iter = thiz->children;
1178		while(iter != NULL)
1179		{
1180			if((target = ftk_widget_find_target(iter, x, y, only_sensitive)) != NULL)
1181			{
1182				return target;
1183			}
1184
1185			iter = ftk_widget_next(iter);
1186		}
1187	}
1188	
1189	if (only_sensitive && ftk_widget_is_insensitive(thiz))
1190	{
1191		return NULL;
1192	}
1193	else
1194	{
1195		return thiz;
1196	}
1197}
1198
1199void ftk_widget_destroy(FtkWidget* thiz)
1200{
1201	if(thiz != NULL)
1202	{
1203		int i = 0;
1204		if(thiz->destroy != NULL)
1205		{
1206			thiz->destroy(thiz);
1207		}
1208
1209		for(i = 0; i < FTK_WIDGET_STATE_NR; i++)
1210		{
1211			ftk_gc_reset(thiz->priv->gc+i);
1212		}
1213
1214		if(thiz->priv->user_data != NULL && thiz->priv->user_data_destroy != NULL)
1215		{
1216			thiz->priv->user_data_destroy(thiz->priv->user_data);
1217		}
1218
1219		FTK_FREE(thiz->priv->text);
1220		FTK_ZFREE(thiz->priv, sizeof(thiz->priv));
1221		FTK_ZFREE(thiz, sizeof(FtkWidget));
1222	}
1223
1224	return;
1225}
1226
1227void ftk_widget_ref(FtkWidget* thiz)
1228{
1229	if(thiz != NULL)
1230	{
1231		if(thiz->children != NULL)
1232		{
1233			ftk_widget_ref(thiz->children);
1234		}
1235
1236		if(thiz->next != NULL)
1237		{
1238			ftk_widget_ref(thiz->next);
1239		}
1240
1241		ftk_widget_ref_self(thiz);
1242	}
1243
1244	return;
1245}
1246
1247void ftk_widget_unref(FtkWidget* thiz)
1248{
1249	if(thiz != NULL)
1250	{
1251		if(ftk_widget_parent(thiz) == NULL)
1252		{
1253			if(thiz->ref == 1 && ftk_widget_is_visible(thiz))
1254			{
1255				ftk_widget_show(thiz, 0);
1256			}
1257		}
1258		if(thiz->children != NULL)
1259		{
1260			ftk_widget_unref(thiz->children);
1261		}
1262
1263		if(thiz->next != NULL)
1264		{
1265			ftk_widget_unref(thiz->next);
1266		}
1267
1268		ftk_widget_unref_self(thiz);
1269	}
1270
1271	return;
1272}
1273
1274static int ftk_widget_paint_called_by_parent(FtkWidget* thiz)
1275{
1276	FtkWidget* parent = thiz->parent;
1277	
1278	return parent != NULL ? parent->priv->painting : 0;
1279}
1280
1281Ret ftk_widget_paint_self(FtkWidget* thiz, FtkRect *rects, int rect_nr)
1282{
1283	return_val_if_fail(thiz != NULL && thiz->on_paint != NULL, RET_FAIL);
1284
1285	if(thiz->priv->width == 0 || thiz->priv->height == 0)
1286	{
1287		return RET_OK;
1288	}
1289
1290	if(ftk_widget_is_visible(thiz) && ftk_widget_is_parent_visible(thiz))
1291	{
1292        FtkGc gc = {0};
1293        FtkBitmap* bitmap = NULL;
1294        FtkWidget* parent = thiz->parent;
1295        FtkWidgetInfo* priv =  thiz->priv;
1296
1297        FTK_BEGIN_PAINT(x, y, width, height, canvas);
1298        bitmap = priv->gc[priv->state].bitmap;
1299        return_val_if_fail(canvas != NULL, RET_FAIL);
1300        return_val_if_fail(thiz->priv->width > 0 && thiz->priv->height > 0, RET_FAIL);
1301
1302        priv->painting++;
1303        assert(parent == NULL || ftk_widget_paint_called_by_parent(thiz));
1304
1305#if defined(FTK_OPTIMIZE_WIDGET_PAINT) && (FTK_OPTIMIZE_WIDGET_PAINT > 0)
1306
1307        if (rect_nr > 0 && rects != NULL && ftk_widget_parent(thiz) == NULL)
1308        {
1309            int i = 0;
1310            int j = 0;
1311
1312            for (i = 0; i < rect_nr; i++)
1313            {
1314                FtkWidget *child = thiz->children;
1315
1316                while(child != NULL)
1317                {
1318                    if(   ftk_widget_left_abs(child) == rects[i].x
1319                       && ftk_widget_top_abs(child)  == rects[i].y
1320                       && ftk_widget_width(child)    == rects[i].width
1321                       && ftk_widget_height(child)   == rects[i].height)
1322                    {
1323                        j++;
1324                        break;
1325                    }
1326
1327                    child = child->next;
1328                }
1329
1330                if(!ftk_widget_has_attr(thiz, FTK_ATTR_TRANSPARENT))
1331                {
1332                    gc.mask = FTK_GC_FG;
1333                    gc.fg = ftk_widget_get_gc(thiz)->bg;
1334                    ftk_canvas_reset_gc(canvas, &gc);
1335                    ftk_canvas_clear_rect(canvas, rects[i].x, rects[i].y, rects[i].width, rects[i].height);
1336                }
1337            }
1338
1339            if (j == rect_nr)
1340            {
1341                goto __paint_children;
1342            }
1343        }
1344#endif
1345
1346        if(!ftk_widget_has_attr(thiz, FTK_ATTR_TRANSPARENT))
1347        {
1348            gc.mask = FTK_GC_FG;
1349            gc.fg = ftk_widget_get_gc(thiz)->bg;
1350            ftk_canvas_reset_gc(canvas, &gc);
1351            ftk_canvas_clear_rect(canvas, x, y, width, height);
1352        }
1353
1354#if defined(FTK_OPTIMIZE_WIDGET_PAINT) && (FTK_OPTIMIZE_WIDGET_PAINT > 0)
1355        __paint_children:
1356#endif
1357        bitmap = priv->gc[priv->state].bitmap;
1358        if(bitmap != NULL)
1359        {
1360            if(ftk_widget_has_attr(thiz, FTK_ATTR_BG_CENTER))
1361            {
1362                ftk_canvas_draw_bg_image(canvas, bitmap, FTK_BG_CENTER, x, y, width, height);
1363            }
1364            else if(ftk_widget_has_attr(thiz, FTK_ATTR_BG_TILE))
1365            {
1366                ftk_canvas_draw_bg_image(canvas, bitmap, FTK_BG_TILE, x, y, width, height);
1367            }
1368            else if(ftk_widget_has_attr(thiz, FTK_ATTR_BG_FOUR_CORNER))
1369            {
1370                ftk_canvas_draw_bg_image(canvas, bitmap, FTK_BG_FOUR_CORNER, x, y, width, height);
1371            }
1372            else
1373            {
1374                ftk_canvas_draw_bg_image(canvas, bitmap, FTK_BG_NORMAL, x, y, width, height);
1375            }
1376        }
1377
1378        if(thiz->on_paint != NULL)
1379        {
1380            thiz->on_paint(thiz);
1381        }
1382
1383        if(thiz->children != NULL)
1384        {
1385            if (bitmap != NULL)
1386            {
1387                ftk_widget_paint(thiz->children, NULL, 0);
1388            }
1389            else
1390            {
1391                ftk_widget_paint(thiz->children, rects, rect_nr);
1392            }
1393        }
1394
1395        priv->painting--;
1396	}
1397	
1398	return RET_OK;
1399}
1400
1401void ftk_widget_ref_self(FtkWidget* thiz)
1402{
1403	return_if_fail(thiz != NULL);
1404	thiz->ref++;
1405
1406	return;
1407}
1408
1409void ftk_widget_unref_self(FtkWidget* thiz)
1410{
1411	return_if_fail(thiz != NULL);
1412
1413	thiz->ref--;
1414	if(thiz->ref == 0)
1415	{
1416		ftk_widget_destroy(thiz);
1417	}
1418
1419	return;
1420}
1421
1422Ret ftk_widget_event(FtkWidget* thiz, FtkEvent* event)
1423{
1424	Ret ret = RET_OK;
1425	return_val_if_fail(thiz != NULL && thiz->on_event != NULL && event != NULL, RET_FAIL);
1426	
1427	ret = FTK_CALL_LISTENER(thiz->priv->event_listener, thiz->priv->event_listener_ctx, event);
1428	
1429	if(ret == RET_REMOVE)
1430	{
1431		return RET_OK;
1432	}
1433
1434	return thiz->on_event(thiz, event);
1435}
1436