PageRenderTime 892ms CodeModel.GetById 182ms app.highlight 548ms RepoModel.GetById 148ms app.codeStats 1ms

/src/ftk_combo_box.c

http://ftk.googlecode.com/
C | 362 lines | 261 code | 72 blank | 29 comment | 33 complexity | b0d320d4b3aae38210d379593c965d60 MD5 | raw file
  1/*
  2 * File: ftk_combo_box.c    
  3 * Author:  Li XianJing <xianjimli@hotmail.com>
  4 * Brief: combo_box control.  
  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 * 2010-01-28 Li XianJing <xianjimli@hotmail.com> created
 29 *
 30 */
 31
 32#include "ftk_globals.h"
 33#include "ftk_theme.h"
 34#include "ftk_entry.h"
 35#include "ftk_dialog.h"
 36#include "ftk_button.h"
 37#include "ftk_combo_box.h"
 38#include "ftk_list_view.h"
 39#include "ftk_list_model_default.h"
 40#include "ftk_list_render_default.h"
 41
 42typedef struct _ComboBoxPrivInfo
 43{
 44	FtkWidget* entry;
 45	FtkWidget* button;
 46	FtkListModel* model;
 47	int selected;
 48	FtkListener listener;
 49	void* listener_ctx;
 50}PrivInfo;
 51
 52static Ret ftk_combo_box_on_event(FtkWidget* thiz, FtkEvent* event)
 53{
 54	return RET_OK;
 55}
 56
 57static Ret ftk_combo_box_on_paint(FtkWidget* thiz)
 58{
 59	return RET_OK;
 60}
 61
 62static void ftk_combo_box_destroy(FtkWidget* thiz)
 63{
 64	
 65	DECL_PRIV0(thiz, priv);
 66
 67	if(priv != NULL)
 68	{
 69		ftk_list_model_unref(priv->model);
 70		priv->model = NULL;
 71		FTK_ZFREE(thiz->priv_subclass[0], sizeof(PrivInfo));
 72	}
 73
 74	return;
 75}
 76
 77static Ret ftk_popup_on_item_clicked(void* ctx, void* list)
 78{
 79	FtkListItemInfo* info = NULL;
 80	int i = ftk_list_view_get_selected((FtkWidget*)list);
 81	FtkListModel* model = ftk_list_view_get_model((FtkWidget*)list);
 82	Ret ret = RET_OK;
 83
 84	ftk_list_model_get_data(model, i, (void**)&info);
 85	if(info != NULL)
 86	{
 87	    FtkWidget* thiz = (FtkWidget*)info->user_data;
 88	    DECL_PRIV0(thiz, priv);
 89
 90		ftk_combo_box_set_text(thiz, info->text);
 91
 92		priv->selected = i;
 93
 94        ret = FTK_CALL_LISTENER(priv->listener, priv->listener_ctx, thiz);
 95
 96        priv->model->listener_ctx = NULL;
 97	}
 98	ftk_widget_unref((FtkWidget*)ctx);
 99
100	return ret;
101}
102
103static Ret ftk_combo_box_popup_rect(FtkWidget* thiz, int* x, int* y, int* w, int* h)
104{
105	int ox = 0;
106	int oy = 0;
107	int nr  = 0;
108	int width  = 0;
109	int height = 0;
110	DECL_PRIV0(thiz, priv);
111	FtkWidget* win = ftk_widget_toplevel(thiz);
112	int win_heigth = ftk_widget_height(win);
113	int margin = (FTK_H_MARGIN + FTK_DIALOG_BORDER)*2;
114
115	ox = ftk_widget_left_abs(thiz);
116	width = ftk_widget_width(thiz);
117	oy = ftk_widget_top_in_window(priv->entry) + ftk_widget_height(priv->entry);
118
119	height = ftk_list_model_get_total(priv->model) * FTK_POPUP_MENU_ITEM_HEIGHT + margin;
120	
121	if((height + oy) > win_heigth)
122	{
123		if(oy < (win_heigth)/2)
124		{
125			height = win_heigth - oy;
126			nr = (height - margin)/FTK_POPUP_MENU_ITEM_HEIGHT;
127			height = nr * FTK_POPUP_MENU_ITEM_HEIGHT + margin;
128		}
129		else
130		{
131			height = FTK_MIN(height, oy - ftk_widget_height(priv->entry));
132			nr = (height - margin)/FTK_POPUP_MENU_ITEM_HEIGHT;
133			height = nr * FTK_POPUP_MENU_ITEM_HEIGHT + margin;
134			oy = oy - height - ftk_widget_height(priv->entry);
135		}
136	}
137	oy += ftk_widget_top_abs(win);
138
139	*x = ox;
140	*y = oy;
141	*w = width;
142	*h = height;
143
144	return RET_OK;
145}
146
147static Ret button_drop_down_clicked(void* ctx, void* obj)
148{
149	int x = 0;
150	int y = 0;
151	int w = 200;
152	int h = 100;
153	FtkWidget* thiz  = (FtkWidget*)ctx;
154	DECL_PRIV0(thiz, priv);
155	FtkWidget* popup = NULL;
156	FtkWidget* list  = NULL;
157	FtkListRender* render = NULL; 
158
159	ftk_combo_box_popup_rect(thiz, &x, &y, &w, &h);
160
161	popup = ftk_dialog_create_ex(FTK_ATTR_POPUP, x, y, w, h);
162	
163	if(y < ftk_widget_top_abs(thiz))
164	{
165		ftk_window_set_animation_hint(popup, "combobox_up");
166	}
167	else
168	{
169		ftk_window_set_animation_hint(popup, "combobox_down");
170	}
171
172	ftk_dialog_hide_title(popup);
173	w = ftk_widget_width(popup) - FTK_DIALOG_BORDER * 2;
174	h = ftk_widget_height(popup) - FTK_DIALOG_BORDER * 2;
175	list = ftk_list_view_create(popup, 0, 0, w, h);
176	ftk_widget_show(list, 1);
177
178	render = ftk_list_render_default_create();
179	ftk_list_view_init(list, priv->model, render, FTK_POPUP_MENU_ITEM_HEIGHT);
180	ftk_list_view_set_clicked_listener(list, ftk_popup_on_item_clicked, popup);
181
182	ftk_widget_show_all(popup, 1);
183
184	return RET_OK;
185}
186
187FtkWidget* ftk_combo_box_create(FtkWidget* parent, int x, int y, int width, int height)
188{
189	FtkWidget* thiz = (FtkWidget*)FTK_ZALLOC(sizeof(FtkWidget));
190	
191	return_val_if_fail(thiz != NULL, NULL);
192
193	width = width < height ? (height << 1) : width;
194	thiz->priv_subclass[0] = (PrivInfo*)FTK_ZALLOC(sizeof(PrivInfo));
195	if(thiz->priv_subclass[0] != NULL)
196	{
197		int h = 0;
198		int w = 0;
199		FtkGc gc = {0};
200		DECL_PRIV0(thiz, priv);
201		thiz->on_event = ftk_combo_box_on_event;
202		thiz->on_paint = ftk_combo_box_on_paint;
203		thiz->destroy  = ftk_combo_box_destroy;
204
205		ftk_widget_init(thiz, FTK_COMBO_BOX, 0, x, y, width, height, FTK_ATTR_TRANSPARENT);
206		ftk_widget_append_child(parent, thiz);
207
208		priv->entry = ftk_entry_create(thiz, 0, 0, width-height, height);
209		h = ftk_widget_height(priv->entry);
210		w = ftk_widget_width(priv->entry);
211		ftk_widget_move_resize(priv->entry, 0, FTK_HALF(height-h), width - h, h);
212		ftk_widget_show(priv->entry, 1);
213
214		priv->button = ftk_button_create(thiz, width - h, FTK_HALF(height-h), h, h); 
215		ftk_button_set_clicked_listener(priv->button, button_drop_down_clicked, thiz);
216
217		ftk_widget_set_attr(priv->button, FTK_ATTR_BG_CENTER);
218		gc.mask = FTK_GC_BITMAP;
219		gc.bitmap = ftk_theme_load_image(ftk_default_theme(), "drop_down_normal"FTK_STOCK_IMG_SUFFIX);
220		ftk_widget_set_gc(priv->button, FTK_WIDGET_NORMAL, &gc);
221		ftk_gc_reset(&gc);
222		
223		gc.mask = FTK_GC_BITMAP;
224		gc.bitmap = ftk_theme_load_image(ftk_default_theme(), "drop_down_selected"FTK_STOCK_IMG_SUFFIX);
225		ftk_widget_set_gc(priv->button, FTK_WIDGET_FOCUSED, &gc);
226		ftk_gc_reset(&gc);
227		
228		gc.mask = FTK_GC_BITMAP;
229		gc.bitmap = ftk_theme_load_image(ftk_default_theme(), "drop_down_pressed"FTK_STOCK_IMG_SUFFIX);
230		ftk_widget_set_gc(priv->button, FTK_WIDGET_ACTIVE, &gc);
231		ftk_gc_reset(&gc);
232
233		ftk_widget_show(priv->button, 1);
234
235		ftk_widget_resize(thiz, width, h + (FTK_V_MARGIN << 1));
236
237		priv->model = ftk_list_model_default_create(10);
238
239		priv->selected = -1;
240	}
241	else
242	{
243		FTK_FREE(thiz);
244	}
245
246	return thiz;
247}
248
249const char* ftk_combo_box_get_text(FtkWidget* thiz)
250{
251	DECL_PRIV0(thiz, priv);
252	return_val_if_fail(thiz != NULL, NULL);
253
254	return ftk_entry_get_text(priv->entry);
255}
256
257Ret ftk_combo_box_set_text(FtkWidget* thiz, const char* text)
258{
259	DECL_PRIV0(thiz, priv);
260	return_val_if_fail(thiz != NULL && text != NULL, RET_FAIL);
261
262	return ftk_entry_set_text(priv->entry, text);	
263}
264
265FtkWidget* ftk_combo_box_get_entry(FtkWidget* thiz)
266{
267	DECL_PRIV0(thiz, priv);
268	return_val_if_fail(thiz != NULL, NULL);
269
270	return priv->entry;
271}
272
273int ftk_combo_box_get_selected(FtkWidget* thiz)
274{
275    DECL_PRIV0(thiz, priv);
276    return_val_if_fail(thiz != NULL, -1);
277
278    return priv->selected;
279}
280
281Ret ftk_combo_box_append(FtkWidget* thiz, FtkBitmap* icon, const char* text)
282{
283	DECL_PRIV0(thiz, priv);
284	FtkListItemInfo info = {0};
285	return_val_if_fail(thiz != NULL && text != NULL, RET_FAIL);
286
287	info.type = FTK_LIST_ITEM_NORMAL;
288	info.text = (char *)text;
289	info.left_icon = icon;
290	info.user_data = thiz;
291	
292	return ftk_list_model_add(priv->model, &info);
293}
294
295Ret ftk_combo_box_reset(FtkWidget* thiz)
296{
297    DECL_PRIV0(thiz, priv);
298    return_val_if_fail(thiz != NULL, RET_FAIL);
299
300    ftk_combo_box_set_text(thiz, " ");
301
302    priv->selected = -1;
303
304    return ftk_list_model_reset(priv->model);
305}
306
307Ret ftk_combo_box_remove(FtkWidget* thiz, size_t index)
308{
309    DECL_PRIV0(thiz, priv);
310    return_val_if_fail(thiz != NULL, RET_FAIL);
311
312    if(priv->selected == index)
313    {
314        ftk_combo_box_set_text(thiz, " ");
315
316        priv->selected = -1;
317    }
318
319    return ftk_list_model_remove(priv->model, index);
320}
321
322Ret ftk_combo_box_set_clicked_listener(FtkWidget* thiz, FtkListener listener, void* ctx)
323{
324    DECL_PRIV0(thiz, priv);
325    return_val_if_fail(thiz != NULL, RET_FAIL);
326
327    priv->listener_ctx = ctx;
328    priv->listener = listener;
329
330    return RET_OK;
331}
332
333int ftk_combo_box_get_item_nr(FtkWidget* thiz)
334{
335	DECL_PRIV0(thiz, priv);
336	return_val_if_fail(thiz != NULL, 0);
337
338	return ftk_list_model_get_total(priv->model);
339}
340
341Ret ftk_combo_box_get_item(FtkWidget* thiz, size_t index, const FtkBitmap** icon, const char** text)
342{
343	DECL_PRIV0(thiz, priv);
344	FtkListItemInfo* info = NULL;
345	return_val_if_fail(thiz != NULL, 0);
346
347	ftk_list_model_get_data(priv->model, index, (void**)&info);
348	if(info != NULL)
349	{
350		if(icon != NULL)
351		{
352			*icon = info->left_icon;
353		}
354
355		if(text != NULL)
356		{
357			*text = info->text;
358		}
359	}
360
361	return info != NULL ? RET_OK : RET_FAIL;
362}