2 * Copyright Geoff Levand <geoff@infradead.org>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 #if defined(HAVE_CONFIG_H)
24 #include <linux/input.h>
27 #include "talloc/talloc.h"
28 #include "ui/common/ui-system.h"
32 static void pbt_item_draw_cb(twin_window_t *window)
34 struct pbt_item *item = pbt_item_from_window(window);
37 assert(window == item->window);
41 //pbt_dump_pixmap(window->pixmap);
43 if (pbt_item_is_selected(item) && item->menu->has_focus)
44 image = item->pixmap_active;
45 else if (pbt_item_is_selected(item) && !item->menu->has_focus)
46 image = item->pixmap_selected;
48 image = item->pixmap_idle;
50 pbt_image_draw(window->pixmap, image);
53 static twin_bool_t pbt_item_event_cb(twin_window_t *window,
56 struct pbt_item *item = pbt_item_from_window(window);
58 pbt_dump_event(pbt_item_name(item), window, event);
61 case TwinEventButtonDown:
63 item->on_execute(item);
65 case TwinEventButtonUp:
68 /* prevent window drag */
71 pbt_item_set_as_selected(item);
75 case TwinEventKeyDown:
76 switch(event->u.key.key) {
77 case (twin_keysym_t)XK_Return:
78 case (twin_keysym_t)KEY_ENTER:
80 item->on_execute(item);
82 case (twin_keysym_t)'e':
96 int pbt_item_editor(struct pbt_item *item)
102 struct pbt_item *pbt_item_create(struct pbt_menu *menu, const char *name,
103 unsigned int position, const char *icon_filename, const char *title,
107 struct pbt_item *item;
110 const struct pbt_menu_layout *layout = &menu->layout;
112 static const twin_argb32_t focus_color = 0x10404040;
120 DBGS("%d:%s (%s)\n", position, name, icon_filename);
122 item = talloc_zero(menu, struct pbt_item);
128 item->on_edit = pbt_item_editor;
130 pbt_menu_get_item_quad(menu, position, &q);
132 item->window = twin_window_create(menu->scr->tscreen,
133 TWIN_ARGB32, TwinWindowPlain,
134 q.x, q.y, q.width, q.height);
137 goto fail_window_create;
139 twin_window_set_name(item->window, name);
140 item->window->client_data = item;
141 item->window->draw = pbt_item_draw_cb;
142 item->window->event = pbt_item_event_cb;
144 item->pixmap_idle = twin_pixmap_create(TWIN_ARGB32, q.width, q.height);
145 assert(item->pixmap_idle);
147 item->pixmap_selected = twin_pixmap_create(TWIN_ARGB32, q.width,
149 assert(item->pixmap_selected);
151 item->pixmap_active = twin_pixmap_create(TWIN_ARGB32, q.width,
153 assert(item->pixmap_active);
155 if (!item->pixmap_idle || !item->pixmap_selected || !item->pixmap_active)
156 goto fail_pixmap_create;
158 twin_fill(item->pixmap_idle, 0x01000000, TWIN_SOURCE, 0, 0, q.width,
163 icon = pbt_icon_load(icon_filename);
168 src.source_kind = TWIN_PIXMAP;
171 twin_composite(item->pixmap_idle,
172 //0, (item->pixmap_idle->height - icon->height) / 2,
177 icon->width, icon->height);
181 path = twin_path_create();
185 twin_path_set_font_size(path,
186 twin_int_to_fixed(layout->title.font_size));
187 twin_path_set_font_style(path, TWIN_TEXT_UNHINTED);
190 twin_int_to_fixed(icon->width + layout->text_space),
191 twin_int_to_fixed(layout->title.font_size
192 + layout->text_space));
193 twin_path_utf8(path, title);
194 twin_paint_path(item->pixmap_idle, layout->title.color, path);
195 twin_path_empty(path);
199 twin_path_set_font_size(path,
200 twin_int_to_fixed(layout->text.font_size));
202 twin_int_to_fixed(icon->width + layout->text_space),
203 twin_int_to_fixed(layout->title.font_size
204 + layout->text.font_size
205 + layout->text_space));
206 twin_path_utf8(path, text);
207 twin_paint_path(item->pixmap_idle, layout->text.color, path);
208 twin_path_empty(path);
211 pbt_image_draw(item->pixmap_selected, item->pixmap_idle);
212 pbt_image_draw(item->pixmap_active, item->pixmap_idle);
215 static const struct pbt_border grey_border = {
220 .fill_color = 0xffe0e0e0,
223 //pbt_border_draw(item->pixmap_idle, &pbt_blue_debug_border);
224 pbt_border_draw(item->pixmap_selected, &grey_border);
225 pbt_border_draw(item->pixmap_active, &pbt_green_debug_border);
227 assert(!(stroke_width % 2));
229 /* pixmap_selected */
231 twin_path_rounded_rectangle(path,
232 twin_int_to_fixed(stroke_width / 2),
233 twin_int_to_fixed(stroke_width / 2),
234 twin_int_to_fixed(item->pixmap_selected->width - stroke_width),
235 twin_int_to_fixed(item->pixmap_selected->height - stroke_width),
236 twin_int_to_fixed(corner_rounding),
237 twin_int_to_fixed(corner_rounding));
239 twin_paint_stroke(item->pixmap_selected, focus_color, path,
240 twin_int_to_fixed(stroke_width));
242 twin_path_empty(path);
246 twin_path_rounded_rectangle(path, 0, 0,
247 twin_int_to_fixed(item->pixmap_active->width),
248 twin_int_to_fixed(item->pixmap_active->height),
249 twin_int_to_fixed(corner_rounding),
250 twin_int_to_fixed(corner_rounding));
252 twin_paint_path(item->pixmap_active, focus_color, path);
254 twin_path_empty(path); // FIXME: need it???
256 twin_path_destroy(path);
258 list_add_tail(menu->item_list, &item->list);
260 pbt_item_redraw(item);
270 void _pbt_dump_item(const struct pbt_item* item, const char *func, int line)
272 DBG("%s:%d: %p: %sselected, %sfocus\n", func, line, item,
273 (pbt_item_is_selected(item) ? "+" : "-"),
274 (item->menu->has_focus ? "+" : "-"));
278 * pbt_menu_get_item_quad - Return item coords relative to screen origin.
281 struct pbt_quad *pbt_menu_get_item_quad(const struct pbt_menu *menu,
282 unsigned int pos, struct pbt_quad *q)
284 const struct pbt_menu_layout *layout = &menu->layout;
286 q->x = menu->window->pixmap->x + layout->item_space;
288 q->width = menu->window->pixmap->width - 2 * layout->item_space;
290 q->y = menu->window->pixmap->y + layout->item_space
291 + pos * (layout->item_height + layout->item_space);
293 q->height = layout->item_height;
298 static void pbt_menu_draw_cb(twin_window_t *window)
300 struct pbt_menu *menu = pbt_menu_from_window(window);
301 twin_path_t *path = twin_path_create();
305 pbt_dump_pixmap(window->pixmap);
307 twin_fill(window->pixmap, menu->background_color, TWIN_SOURCE,
308 0, 0, window->pixmap->width, window->pixmap->height);
310 pbt_border_draw(window->pixmap, &menu->border);
312 twin_path_destroy(path);
315 static twin_bool_t pbt_menu_event_cb(twin_window_t *window,
318 struct pbt_menu *menu = pbt_menu_from_window(window);
321 pbt_dump_event(pbt_menu_name(menu), window, event);
323 switch(event->kind) {
324 case TwinEventButtonDown:
325 case TwinEventButtonUp:
326 case TwinEventMotion:
327 /* prevent window drag */
330 pbt_menu_set_focus(menu, 1);
333 if (!pbt_window_contains(window, event))
334 pbt_menu_set_focus(menu, 0);
336 case TwinEventKeyDown:
337 switch(event->u.key.key) {
338 case (twin_keysym_t)XK_Up:
339 case (twin_keysym_t)KEY_UP:
340 i = list_prev_entry(menu->item_list, menu->selected,
343 pbt_item_set_as_selected(i);
345 case (twin_keysym_t)XK_Down:
346 case (twin_keysym_t)KEY_DOWN:
347 i = list_next_entry(menu->item_list, menu->selected,
350 pbt_item_set_as_selected(i);
352 case (twin_keysym_t)XK_Left:
353 case (twin_keysym_t)KEY_LEFT:
355 pbt_menu_set_focus(menu, 0);
356 pbt_menu_set_focus(menu->parent, 1);
360 case (twin_keysym_t)XK_Right:
361 case (twin_keysym_t)KEY_RIGHT:
362 if (menu->selected->sub_menu) {
363 pbt_menu_set_focus(menu, 0);
364 pbt_menu_set_focus(menu->selected->sub_menu, 1);
366 DBGS("no sub_menu\n");
369 return pbt_item_event_cb(menu->selected->window, event);
378 struct pbt_menu *pbt_menu_create(void *talloc_ctx, const char *name,
379 struct pbt_scr *scr, struct pbt_menu *parent, const struct pbt_quad *q,
380 const struct pbt_menu_layout *layout)
382 struct pbt_menu *menu;
388 menu = talloc_zero(talloc_ctx, struct pbt_menu);
394 menu->parent = parent;
395 menu->layout = *layout;
397 menu->item_list = talloc(menu, struct list);
398 list_init(menu->item_list);
400 menu->window = twin_window_create(scr->tscreen, TWIN_ARGB32,
401 TwinWindowPlain, q->x, q->y,
402 q->width, q->height);
407 DBGS("window = %p\n", menu->window);
409 twin_window_set_name(menu->window, name);
411 menu->background_color = 0x01000000; //FIXME: what value???
413 menu->window->draw = pbt_menu_draw_cb;
414 menu->window->event = pbt_menu_event_cb;
415 menu->window->client_data = menu;
417 pbt_dump_pixmap(menu->window->pixmap);
419 pbt_menu_redraw(menu);
429 void pbt_menu_set_focus(struct pbt_menu *menu, int focus)
431 DBGS("%s(%p): %d -> %d\n", pbt_menu_name(menu), menu, menu->has_focus,
434 assert(menu->selected);
436 if (!menu->has_focus == !focus)
439 menu->has_focus = !!focus;
441 /* Route key events to menu with focus. */
444 menu->scr->tscreen->active = menu->window->pixmap;
446 pbt_item_redraw(menu->selected);
449 void pbt_menu_hide(struct pbt_menu *menu)
451 struct pbt_item *item;
456 list_for_each_entry(menu->item_list, item, list) {
458 pbt_menu_hide(item->sub_menu);
460 twin_window_hide(item->window);
461 //twin_window_queue_paint(item->window);
464 twin_window_hide(menu->window);
465 //twin_window_queue_paint(menu->window);
468 void pbt_menu_show(struct pbt_menu *menu, int hide)
470 struct pbt_item *item;
475 twin_window_show(menu->window);
476 pbt_menu_redraw(menu);
478 list_for_each_entry(menu->item_list, item, list) {
479 twin_window_show(item->window);
480 pbt_item_redraw(item);
482 if (item->sub_menu) {
483 if (pbt_item_is_selected(item))
484 pbt_menu_show(item->sub_menu, hide);
486 pbt_menu_hide(item->sub_menu);
491 void pbt_menu_set_selected(struct pbt_menu *menu, struct pbt_item *item)
493 struct pbt_item *last_selected;
497 DBGS("%s(%p): %s(%p) -> %s(%p)\n", pbt_menu_name(menu), menu,
498 (menu->selected ? pbt_menu_name(menu) : "none"),
499 menu->selected, pbt_item_name(item), item);
501 if (menu->selected == item)
504 last_selected = menu->selected;
505 menu->selected = item;
508 pbt_menu_hide(last_selected->sub_menu);
509 pbt_item_redraw(last_selected);
512 pbt_item_redraw(item);
513 pbt_menu_show(item->sub_menu, 0);