PageRenderTime 448ms CodeModel.GetById 101ms app.highlight 209ms RepoModel.GetById 123ms app.codeStats 0ms

/apps/designer/ftk_app_designer.c

http://ftk.googlecode.com/
C | 676 lines | 524 code | 121 blank | 31 comment | 111 complexity | 52c3162198ba0aebe602da722605f2b9 MD5 | raw file
  1/*
  2 * File: ftk_app_designer.c
  3 * Author:  Li XianJing <xianjimli@hotmail.com>
  4 * Brief: ui designer app.
  5 *
  6 * Copyright (c) 2009 - 2011  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 * 2011-09-27 Li XianJing <xianjimli@hotmail.com> created
 29 *
 30 */
 31
 32#include "open.h"
 33#include "save.h"
 34#include "widgets_info.h"
 35#include "widget_editor.h"
 36#include "ftk_popup_menu.h"
 37#include "ftk_app_designer.h"
 38
 39typedef struct _PrivInfo
 40{
 41	FtkBitmap* icon;
 42}PrivInfo;
 43
 44typedef struct _Info
 45{
 46	int last_x;
 47	int last_y;
 48	int ctrl_down;
 49	int alt_down;
 50	int mouse_down;
 51	FtkWidget* selected_widget;
 52}Info;
 53
 54static Ret designer_on_event(void* ctx, void* data);
 55static Ret designer_on_prepare_options_menu(void* ctx, FtkWidget* menu_panel);
 56
 57static Info* info_create(void)
 58{
 59	Info* info = FTK_NEW(Info);
 60	
 61	return info;
 62}
 63
 64static void info_destroy(void* data)
 65{
 66	FTK_FREE(data);
 67	
 68	return;
 69}
 70
 71static FtkBitmap* ftk_app_designer_get_icon(FtkApp* thiz)
 72{
 73	DECL_PRIV(thiz, priv);
 74	return_val_if_fail(priv != NULL, NULL);
 75	
 76	if(priv->icon != NULL) return priv->icon;
 77
 78	priv->icon = ftk_app_load_bitmap(thiz, "designer", "designer");
 79
 80	return priv->icon;
 81}
 82
 83static const char* ftk_app_designer_get_name(FtkApp* thiz)
 84{
 85	return _("Designer");
 86}
 87
 88static Ret designer_init(FtkWidget* win)
 89{
 90	ftk_widget_set_user_data(win, info_destroy, info_create());
 91	ftk_widget_set_event_listener(win, designer_on_event, win);
 92	ftk_app_window_set_on_prepare_options_menu(win, designer_on_prepare_options_menu, win);
 93	
 94	ftk_widget_show(win, 1);
 95
 96	return RET_OK;
 97}
 98
 99static Ret designer_on_new(void* ctx, void* item)
100{
101	FtkWidget* win = NULL;
102	FtkWidget* old_win = (FtkWidget*)ctx;
103	
104	win = ftk_app_window_create();
105	ftk_widget_set_text(win, _("FTK UI Designer"));
106	ftk_window_set_animation_hint(win, "app_main_window");
107	designer_init(win);
108
109	if(old_win != NULL)
110	{
111		ftk_widget_unref(old_win);
112	}
113
114	return RET_OK;
115}
116
117static Ret designer_on_open_ok(void* ctx, FtkWidget* win)
118{
119	FtkWidget* old_win = (FtkWidget*)ctx;
120	
121	if(win != NULL)
122	{
123		designer_init(win);
124	}
125
126	ftk_widget_unref(old_win);
127
128	return RET_OK;
129}
130
131static Ret designer_on_open(void* ctx, void* item)
132{
133	ftk_widget_editor_open(ctx, designer_on_open_ok);
134
135	return RET_OK;
136}
137
138static Ret designer_on_save(void* ctx, void* item)
139{
140	FtkWidget* win = (FtkWidget*)ctx;
141
142	ftk_widget_editor_save(win);
143
144	return RET_OK;
145}
146
147static Ret designer_on_help(void* ctx, void* item)
148{
149	ftk_tips("Ctrl + UP|DOWN|LEFT|RIGHT: move widget.\n Alt + UP|DOWN|LEFT|RIGHT: resize widget\n <F5>: popup menu.\n");
150
151	return RET_OK;
152}
153
154static Ret designer_on_quit(void* ctx, void* item)
155{
156	FtkWidget* win = (FtkWidget*)ctx;
157
158	ftk_widget_unref(win);
159
160	return RET_OK;
161}
162
163static int designer_has_selected_widget(FtkWidget* win)
164{
165	Info* info = (Info*)ftk_widget_user_data(win);
166
167	return (info->selected_widget != NULL && info->selected_widget != win);
168}
169
170static Ret designer_on_duplicate(void* ctx, void* item)
171{
172	FtkWidget* widget = NULL;
173	FtkWidget* win = (FtkWidget*)ctx;
174	const WidgetInfo* widget_info = NULL; 
175	Info* info = (Info*)ftk_widget_user_data(win);
176	
177	if(!designer_has_selected_widget(win))
178	{
179		return RET_OK;
180	}
181
182	widget_info = widgets_info_find_by_type(ftk_widget_type(info->selected_widget));
183	return_val_if_fail(widget_info != NULL, RET_FAIL);
184
185	if(widget_info->is_leaf_widget)
186	{
187		widget = widget_info->create(
188			ftk_widget_parent(info->selected_widget),
189			ftk_widget_left(info->selected_widget),
190			ftk_widget_top(info->selected_widget) + ftk_widget_height(info->selected_widget),
191			ftk_widget_width(info->selected_widget),
192			ftk_widget_height(info->selected_widget));
193		ftk_widget_set_text(widget, ftk_widget_get_text(info->selected_widget));
194		ftk_widget_show(widget, 1);
195		ftk_widget_ref(widget);
196		/*TODO: duplicate listview/combobox/iconview*/
197	}
198
199	return RET_OK;
200}
201
202static Ret designer_on_insert(void* ctx, void* item)
203{
204	int x = 0;
205	int y = 0;
206	FtkWidget* parent = NULL;
207	FtkWidget* win = (FtkWidget*)ctx;
208	const WidgetInfo* widget_info = NULL; 
209	Info* info = (Info*)ftk_widget_user_data(win);
210	
211	parent = win;
212	if(designer_has_selected_widget(win))
213	{
214		widget_info = widgets_info_find_by_type(ftk_widget_type(info->selected_widget));
215		parent = widget_info->is_leaf_widget ? ftk_widget_parent(info->selected_widget) : info->selected_widget;
216	}
217
218	x = info->last_x - ftk_widget_left_abs(parent);
219	y = info->last_y - ftk_widget_top_abs(parent);
220	ftk_widget_editor_new(parent, x, y);
221	
222	return RET_OK;
223}
224
225static Ret designer_on_delete(void* ctx, void* item)
226{
227	FtkWidget* win = (FtkWidget*)ctx;
228	Info* info = (Info*)ftk_widget_user_data(win);
229	
230	if(designer_has_selected_widget(win))
231	{
232		ftk_widget_remove_child(ftk_widget_parent(info->selected_widget), info->selected_widget);
233		info->selected_widget = NULL;
234		ftk_widget_invalidate(win);
235	}
236
237	return RET_OK;
238}
239
240static Ret designer_on_prop(void* ctx, void* item)
241{
242	FtkWidget* parent = NULL;
243	FtkWidget* widget = NULL;
244	FtkWidget* win = (FtkWidget*)ctx;
245	Info* info = (Info*)ftk_widget_user_data(win);
246	
247	if(designer_has_selected_widget(win))
248	{
249		widget = info->selected_widget;
250		parent = ftk_widget_parent(info->selected_widget);
251	}
252	else
253	{
254		widget = win;
255		parent = win;
256	}
257
258	ftk_widget_editor_edit(parent, widget);
259
260	return RET_OK;
261}
262
263static Ret designer_on_special_prop(void* ctx, void* item)
264{
265	const WidgetInfo* widget_info = NULL; 
266	FtkWidget* win = (FtkWidget*)ctx;
267	Info* info = (Info*)ftk_widget_user_data(win);
268
269	if(designer_has_selected_widget(win))
270	{
271		widget_info = widgets_info_find_by_type(ftk_widget_type(info->selected_widget));
272		if(widget_info != NULL && widget_info->edit != NULL)
273		{
274			widget_info->edit(info->selected_widget);
275		}
276	}
277
278	return RET_OK;
279}
280
281typedef struct _MenuItem
282{
283	int need_selected_widget;
284	char* name;
285	const char* icon_file_name;
286	FtkListener on_clicked;
287}MenuItem;
288
289static const MenuItem s_menu_items[] =
290{
291	{0, "New", NULL,  designer_on_new},
292	{0, "Open", NULL, designer_on_open},
293	{0, "Save", NULL, designer_on_save},
294	{0, "Help", NULL, designer_on_help},
295	{0, "Quit", NULL, designer_on_quit}
296};
297
298static const MenuItem s_popup_menu_items[] =
299{
300	{0, "Insert",           NULL, designer_on_insert},
301	{1, "Duplicate",        NULL, designer_on_duplicate},
302	{1, "Delete",           NULL, designer_on_delete},
303	{0, "General property", NULL, designer_on_prop},
304	{1, "Special property", NULL, designer_on_special_prop},
305	{0, "Cancel",           NULL, NULL}
306};
307
308static Ret designer_on_popup_menu_item_clicked(void* ctx, void* data)
309{
310	FtkListItemInfo* info = data;
311	FtkListener on_clicked = (FtkListener)info->extra_user_data;
312
313	if(on_clicked != NULL)
314	{
315		on_clicked(ctx, NULL);
316	}
317
318	return RET_OK;
319}
320
321static Ret designer_on_popup_menu(void* ctx, void* obj)
322{
323	size_t i = 0;
324	int nr = 0;
325	int height = 0;
326	FtkBitmap* icon = NULL; 
327	FtkWidget* popup = NULL;
328	FtkListItemInfo infos;
329	FtkWidget* win = (FtkWidget*)ctx;
330
331	memset(&infos, 0x00, sizeof(infos));
332	icon = ftk_theme_load_image(ftk_default_theme(), "info"FTK_STOCK_IMG_SUFFIX); 
333
334	for(i = 0; i < FTK_ARRAY_SIZE(s_popup_menu_items); i++)
335	{
336		if(s_popup_menu_items[i].need_selected_widget && !designer_has_selected_widget(win))
337		{
338			continue;
339		}
340		nr++;
341	}
342
343	height = (nr + 1) * FTK_POPUP_MENU_ITEM_HEIGHT;
344	height = height < ftk_widget_height(win) ? height : ftk_widget_height(win);
345
346	popup = ftk_popup_menu_create(0, 0, 0, height, icon, _("Edit"));	
347
348	infos.state = 0;
349	infos.type = FTK_LIST_ITEM_NORMAL;
350	for(i = 0; i < FTK_ARRAY_SIZE(s_popup_menu_items); i++)
351	{
352		if(s_popup_menu_items[i].need_selected_widget && !designer_has_selected_widget(win))
353		{
354			continue;
355		}
356
357		infos.value = i;
358		infos.text = s_popup_menu_items[i].name;
359		infos.extra_user_data = s_popup_menu_items[i].on_clicked;
360		
361		ftk_popup_menu_add(popup, &infos);
362	}
363	ftk_bitmap_unref(icon);
364	
365	ftk_popup_menu_set_clicked_listener(popup, designer_on_popup_menu_item_clicked, ctx);
366	ftk_widget_show_all(popup, 1);
367
368	return RET_OK;
369}
370
371static Ret designer_on_prepare_options_menu(void* ctx, FtkWidget* menu_panel)
372{
373	size_t i = 0;
374	FtkWidget* item = NULL;
375	FtkWidget* win = (FtkWidget*)ctx;
376
377	for(i = 0; i < FTK_ARRAY_SIZE(s_menu_items); i++)	
378	{
379		item = ftk_menu_item_create(menu_panel);
380		ftk_widget_set_text(item, _(s_menu_items[i].name));
381		ftk_menu_item_set_clicked_listener(item, s_menu_items[i].on_clicked, win);
382		ftk_widget_show(item, 1);
383	}
384	
385	return RET_OK;
386}
387
388static Ret designer_move_widget(FtkWidget* widget, int x, int y, int w, int h)
389{
390	int parent_w = ftk_widget_width(ftk_widget_parent(widget));
391	int parent_h = ftk_widget_height(ftk_widget_parent(widget));
392	const WidgetInfo* widget_info = widgets_info_find_by_type(ftk_widget_type(widget));
393
394	return_val_if_fail(widget_info != NULL, RET_OK);
395
396	x = x >= 0 ? x : 0;
397	y = y >= 0 ? y : 0;
398
399	w = FTK_MAX(w, widget_info->min_width);
400	h = FTK_MAX(h, widget_info->min_height);
401
402	if((x + w) < parent_w && (y + h) < parent_h)
403	{
404		ftk_widget_move_resize(widget, x, y, w, h);
405	}
406
407	return RET_OK;
408}
409
410static  Ret designer_handle_direction_key(FtkWidget* win, int press, int code)
411{
412	int x = 0;
413	int y = 0;
414	int w = 0;
415	int h = 0;
416	Ret ret = RET_OK;
417	Info* info = (Info*)ftk_widget_user_data(win);
418
419	x = ftk_widget_left(info->selected_widget);
420	y = ftk_widget_top(info->selected_widget);
421	w = ftk_widget_width(info->selected_widget);
422	h = ftk_widget_height(info->selected_widget);
423	
424	switch(code)
425	{
426		case FTK_KEY_UP:
427		{
428			if(info->ctrl_down)
429			{
430				y--;
431			}
432
433			if(info->alt_down)
434			{
435				h--;
436			}
437
438			break;
439		}
440		case FTK_KEY_DOWN:
441		{
442			if(info->ctrl_down)
443			{
444				y++;
445			}
446
447			if(info->alt_down)
448			{
449				h++;
450			}
451
452			break;
453		}
454		case FTK_KEY_LEFT:
455		{
456			if(info->ctrl_down)
457			{
458				x--;
459			}
460
461			if(info->alt_down)
462			{
463				w--;
464			}
465
466			break;
467		}
468		case FTK_KEY_RIGHT:
469		{
470			if(info->ctrl_down)
471			{
472				x++;
473			}
474
475			if(info->alt_down)
476			{
477				w++;
478			}
479
480			break;
481		}
482		default:break; 
483	}
484
485	if(info->ctrl_down || info->alt_down)
486	{
487		designer_move_widget(info->selected_widget, x, y, w, h);
488		ret = RET_REMOVE;
489	}
490
491	return ret;
492}
493
494static Ret designer_on_key_event(FtkWidget* win, int press, int code)
495{
496	Ret ret = RET_OK;
497	Info* info = (Info*)ftk_widget_user_data(win);
498
499	/*XXX: Li XianJing 37 is the key code of left ctrl on my thinkpad, I dont know why.*/
500	if(code == FTK_KEY_LEFTCTRL || code == FTK_KEY_RIGHTCTRL || code == 37)
501	{
502		info->ctrl_down = press;
503
504		return RET_OK;
505	}
506
507	if(code == FTK_KEY_LEFTALT || code == FTK_KEY_RIGHTALT 
508		|| code == FTK_KEY_LEFTSHIFT || code == FTK_KEY_RIGHTSHIFT)
509	{
510		info->alt_down = press;
511
512		return RET_OK;
513	}
514
515	if(press)
516	{
517		if((info->ctrl_down || info->alt_down))
518		{
519			return RET_REMOVE;
520		}
521		else
522		{
523			return RET_OK;
524		}
525	}
526	else
527	{
528		if(code == FTK_KEY_F5)
529		{
530			designer_on_popup_menu(win, NULL);
531		}
532		else if(code == FTK_KEY_INSERT)
533		{
534			designer_on_insert(win, NULL);
535		}
536		else if(code == FTK_KEY_DELETE)
537		{
538			designer_on_delete(win, NULL);
539		}
540
541		if(!info->ctrl_down && !info->alt_down)
542		{
543			if(code == FTK_KEY_TAB || code == FTK_KEY_LEFT || code == FTK_KEY_UP || code == FTK_KEY_DOWN || code == FTK_KEY_RIGHT)
544			{
545				info->selected_widget = ftk_window_get_focus(win);
546			}
547			return RET_OK;
548		}
549	}
550	
551	if(!designer_has_selected_widget(win))
552	{
553		if(info->ctrl_down || info->alt_down)
554		{
555			return RET_REMOVE;
556		}
557		else
558		{
559			return RET_OK;
560		}
561	}
562
563	ret = designer_handle_direction_key(win, press, code);
564
565	return ret;
566}
567
568static Ret designer_on_mouse_event(FtkWidget* win, int press, int x, int y)
569{
570	Info* info = (Info*)ftk_widget_user_data(win);
571
572	if(press == 1)
573	{
574		info->last_x = x;
575		info->last_y = y;
576		info->mouse_down = 1;
577		info->selected_widget = ftk_widget_find_target(win, info->last_x, info->last_y, 0);
578	}
579	else if(press == 0)
580	{
581		info->mouse_down = 0;
582	}
583	else
584	{
585		int w = 0;
586		int h = 0;
587		int x_offset = x - info->last_x;
588		int y_offset = y - info->last_y;
589		
590		if(!designer_has_selected_widget(win) || !info->mouse_down)
591		{
592			return RET_OK;
593		}
594	
595		info->last_x = x;
596		info->last_y = y;
597		x = ftk_widget_left(info->selected_widget) + x_offset;
598		y = ftk_widget_top(info->selected_widget) + y_offset;
599		w = ftk_widget_width(info->selected_widget);
600		h = ftk_widget_height(info->selected_widget);
601
602		designer_move_widget(info->selected_widget, x, y, w, h);
603	}
604
605	return RET_OK;
606}
607
608static Ret designer_on_event(void* ctx, void* data)
609{
610	Ret ret = RET_OK;
611	FtkWidget* win = (FtkWidget*)ctx;
612	FtkEvent* event = (FtkEvent*)data;
613
614	if(event->type == FTK_EVT_MOUSE_LONG_PRESS)
615	{
616		ret = RET_REMOVE;
617		designer_on_popup_menu(win, NULL);
618	}
619	else if(event->type == FTK_EVT_KEY_DOWN)
620	{
621		ret = designer_on_key_event(win, 1, event->u.key.code);
622	}
623	else if(event->type == FTK_EVT_KEY_UP)
624	{
625		ret = designer_on_key_event(win, 0, event->u.key.code);
626	}
627	else if(event->type == FTK_EVT_MOUSE_DOWN)
628	{
629		ret = designer_on_mouse_event(win, 1, event->u.mouse.x, event->u.mouse.y);
630	}
631	else if(event->type == FTK_EVT_MOUSE_MOVE)
632	{
633		ret = designer_on_mouse_event(win, -1, event->u.mouse.x, event->u.mouse.y);
634	}
635	else if(event->type == FTK_EVT_MOUSE_UP)
636	{
637		ret = designer_on_mouse_event(win, 0, event->u.mouse.x, event->u.mouse.y);
638	}
639	
640	return ret;
641}
642
643static Ret ftk_app_designer_run(FtkApp* thiz, int argc, char* argv[])
644{
645	designer_on_new(NULL, NULL);
646
647	return RET_OK;
648}
649
650static void ftk_app_designer_destroy(FtkApp* thiz)
651{
652	if(thiz != NULL)
653	{
654		DECL_PRIV(thiz, priv);
655		ftk_bitmap_unref(priv->icon);
656		FTK_FREE(thiz);
657	}
658
659	return;
660}
661
662FtkApp* ftk_app_designer_create(void)
663{
664	FtkApp* thiz = FTK_ZALLOC(sizeof(FtkApp) + sizeof(PrivInfo));
665
666	if(thiz != NULL)
667	{
668		thiz->run  = ftk_app_designer_run;
669		thiz->get_icon = ftk_app_designer_get_icon;
670		thiz->get_name = ftk_app_designer_get_name;
671		thiz->destroy = ftk_app_designer_destroy;
672	}
673
674	return thiz;
675}
676