add listbox widget.
git-svn-id: https://rt-thread.googlecode.com/svn/trunk@694 bbd45198-f89e-11dd-88c7-29a3b14d5316
This commit is contained in:
parent
157bc5f263
commit
13c797f616
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* File : listbox.h
|
||||||
|
* This file is part of RTGUI in RT-Thread RTOS
|
||||||
|
* COPYRIGHT (C) 2010, RT-Thread Development Team
|
||||||
|
*
|
||||||
|
* The license and distribution terms for this file may be
|
||||||
|
* found in the file LICENSE in this distribution or at
|
||||||
|
* http://www.rt-thread.org/license/LICENSE
|
||||||
|
*
|
||||||
|
* Change Logs:
|
||||||
|
* Date Author Notes
|
||||||
|
* 2010-01-06 Bernard first version
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __RTGUI_LISTBOX_H__
|
||||||
|
#define __RTGUI_LISTBOX_H__
|
||||||
|
|
||||||
|
#include <rtgui/rtgui.h>
|
||||||
|
#include <rtgui/image.h>
|
||||||
|
#include <rtgui/rtgui_system.h>
|
||||||
|
#include <rtgui/widgets/widget.h>
|
||||||
|
|
||||||
|
struct rtgui_listbox_item
|
||||||
|
{
|
||||||
|
char* name;
|
||||||
|
rtgui_image_t *image;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Gets the type of a list box */
|
||||||
|
#define RTGUI_LISTBOX_TYPE (rtgui_listbox_type_get())
|
||||||
|
/** Casts the object to a filelist */
|
||||||
|
#define RTGUI_LISTBOX(obj) (RTGUI_OBJECT_CAST((obj), RTGUI_LISTBOX_TYPE, rtgui_listbox_t))
|
||||||
|
/** Checks if the object is a filelist box */
|
||||||
|
#define RTGUI_IS_LISTBOX(obj) (RTGUI_OBJECT_CHECK_TYPE((obj), RTGUI_LISTBOX_TYPE))
|
||||||
|
|
||||||
|
struct rtgui_listbox
|
||||||
|
{
|
||||||
|
struct rtgui_widget parent;
|
||||||
|
|
||||||
|
/* widget private data */
|
||||||
|
/* listbox item */
|
||||||
|
const struct rtgui_listbox_item* items;
|
||||||
|
|
||||||
|
/* item event handler */
|
||||||
|
void (*on_item)(rtgui_widget_t *widgets, struct rtgui_event* event);
|
||||||
|
|
||||||
|
/* total number of items */
|
||||||
|
rt_uint16_t items_count;
|
||||||
|
/* the number of item in a page */
|
||||||
|
rt_uint16_t page_items;
|
||||||
|
/* current item */
|
||||||
|
rt_uint16_t current_item;
|
||||||
|
};
|
||||||
|
typedef struct rtgui_listbox rtgui_listbox_t;
|
||||||
|
typedef void (*rtgui_onitem_func_t)(struct rtgui_widget* widget, rtgui_event_t *event);
|
||||||
|
|
||||||
|
rtgui_type_t *rtgui_listbox_type_get(void);
|
||||||
|
|
||||||
|
rtgui_listbox_t* rtgui_listbox_create(const struct rtgui_listbox_item* items, rt_uint16_t count,
|
||||||
|
rtgui_rect_t *rect);
|
||||||
|
void rtgui_listbox_destroy(rtgui_listbox_t* box);
|
||||||
|
|
||||||
|
rt_bool_t rtgui_listbox_event_handler(struct rtgui_widget* widget, struct rtgui_event* event);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,336 @@
|
||||||
|
/*
|
||||||
|
* File : listbox.c
|
||||||
|
* This file is part of RTGUI in RT-Thread RTOS
|
||||||
|
* COPYRIGHT (C) 2010, RT-Thread Development Team
|
||||||
|
*
|
||||||
|
* The license and distribution terms for this file may be
|
||||||
|
* found in the file LICENSE in this distribution or at
|
||||||
|
* http://www.rt-thread.org/license/LICENSE
|
||||||
|
*
|
||||||
|
* Change Logs:
|
||||||
|
* Date Author Notes
|
||||||
|
* 2010-01-06 Bernard first version
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <rtgui/rtgui_theme.h>
|
||||||
|
#include <rtgui/widgets/listbox.h>
|
||||||
|
|
||||||
|
#define LIST_MARGIN 5
|
||||||
|
|
||||||
|
static void _rtgui_listbox_constructor(struct rtgui_listbox *box)
|
||||||
|
{
|
||||||
|
/* set default widget rect and set event handler */
|
||||||
|
rtgui_widget_set_event_handler(RTGUI_WIDGET(box),rtgui_listbox_event_handler);
|
||||||
|
|
||||||
|
RTGUI_WIDGET(box)->flag |= RTGUI_WIDGET_FLAG_FOCUSABLE;
|
||||||
|
|
||||||
|
box->current_item = 0;
|
||||||
|
box->items_count = 0;
|
||||||
|
box->page_items = 0;
|
||||||
|
box->on_item = 0;
|
||||||
|
|
||||||
|
RTGUI_WIDGET_BACKGROUND(RTGUI_WIDGET(box)) = white;
|
||||||
|
RTGUI_WIDGET_TEXTALIGN(RTGUI_WIDGET(box)) = RTGUI_ALIGN_CENTER_VERTICAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rtgui_type_t *rtgui_listbox_type_get(void)
|
||||||
|
{
|
||||||
|
static rtgui_type_t *listbox_type = RT_NULL;
|
||||||
|
|
||||||
|
if (!listbox_type)
|
||||||
|
{
|
||||||
|
listbox_type = rtgui_type_create("listbox", RTGUI_WIDGET_TYPE,
|
||||||
|
sizeof(rtgui_listbox_t), RTGUI_CONSTRUCTOR(_rtgui_listbox_constructor), RT_NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return listbox_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rtgui_listbox_ondraw(struct rtgui_listbox* box)
|
||||||
|
{
|
||||||
|
struct rtgui_rect rect, item_rect;
|
||||||
|
struct rtgui_dc* dc;
|
||||||
|
rt_uint16_t page_index, index;
|
||||||
|
const struct rtgui_listbox_item* item;
|
||||||
|
|
||||||
|
dc = rtgui_dc_begin_drawing(RTGUI_WIDGET(box));
|
||||||
|
if (dc == RT_NULL) return;
|
||||||
|
|
||||||
|
rtgui_widget_get_rect(RTGUI_WIDGET(box), &rect);
|
||||||
|
rtgui_dc_fill_rect(dc, &rect);
|
||||||
|
|
||||||
|
rect.x2 -= 1; rect.y2 -= 1;
|
||||||
|
/* draw focused border */
|
||||||
|
if (RTGUI_WIDGET_IS_FOCUSED(RTGUI_WIDGET(box)))
|
||||||
|
rtgui_dc_draw_focus_rect(dc, &rect);
|
||||||
|
|
||||||
|
/* get item base rect */
|
||||||
|
item_rect = rect;
|
||||||
|
item_rect.x1 += 1; item_rect.x2 -= 1;
|
||||||
|
item_rect.y1 += 2;
|
||||||
|
item_rect.y2 = item_rect.y1 + (2 + rtgui_theme_get_selected_height());
|
||||||
|
|
||||||
|
/* get current page */
|
||||||
|
page_index = (box->current_item / box->page_items) * box->page_items;
|
||||||
|
for (index = 0; index < box->page_items; index ++)
|
||||||
|
{
|
||||||
|
if (page_index + index >= box->items_count) break;
|
||||||
|
|
||||||
|
item = &(box->items[page_index + index]);
|
||||||
|
|
||||||
|
if (page_index + index == box->current_item)
|
||||||
|
{
|
||||||
|
rtgui_theme_draw_selected(dc, &item_rect);
|
||||||
|
}
|
||||||
|
item_rect.x1 += LIST_MARGIN;
|
||||||
|
|
||||||
|
if (item->image != RT_NULL)
|
||||||
|
{
|
||||||
|
rtgui_image_blit(item->image, dc, &item_rect);
|
||||||
|
item_rect.x1 += item->image->w + 2;
|
||||||
|
}
|
||||||
|
/* draw text */
|
||||||
|
rtgui_dc_draw_text(dc, item->name, &item_rect);
|
||||||
|
|
||||||
|
if (item->image != RT_NULL)
|
||||||
|
item_rect.x1 -= (item->image->w + 2);
|
||||||
|
item_rect.x1 -= LIST_MARGIN;
|
||||||
|
|
||||||
|
/* move to next item position */
|
||||||
|
item_rect.y1 += (rtgui_theme_get_selected_height() + 2);
|
||||||
|
item_rect.y2 += (rtgui_theme_get_selected_height() + 2);
|
||||||
|
}
|
||||||
|
rtgui_dc_end_drawing(dc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rtgui_listbox_update_current(struct rtgui_listbox* box, rt_uint16_t old_item)
|
||||||
|
{
|
||||||
|
struct rtgui_dc* dc;
|
||||||
|
const struct rtgui_listbox_item* item;
|
||||||
|
rtgui_rect_t rect, item_rect;
|
||||||
|
|
||||||
|
if (old_item/box->page_items != box->current_item/box->page_items)
|
||||||
|
{
|
||||||
|
/* it's not a same page, update all */
|
||||||
|
rtgui_widget_update(RTGUI_WIDGET(box));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dc = rtgui_dc_begin_drawing(RTGUI_WIDGET(box));
|
||||||
|
if (dc == RT_NULL) return;
|
||||||
|
|
||||||
|
rtgui_widget_get_rect(RTGUI_WIDGET(box), &rect);
|
||||||
|
rect.x2 -= 1; rect.y2 -= 1;
|
||||||
|
|
||||||
|
item_rect = rect;
|
||||||
|
/* get old item's rect */
|
||||||
|
item_rect.x1 += 1; item_rect.x2 -= 1;
|
||||||
|
item_rect.y1 += 2;
|
||||||
|
item_rect.y1 += (old_item % box->page_items) * (2 + rtgui_theme_get_selected_height());
|
||||||
|
item_rect.y2 = item_rect.y1 + (2 + rtgui_theme_get_selected_height());
|
||||||
|
|
||||||
|
/* draw old item */
|
||||||
|
rtgui_dc_fill_rect(dc, &item_rect);
|
||||||
|
|
||||||
|
item_rect.x1 += LIST_MARGIN;
|
||||||
|
|
||||||
|
item = &(box->items[old_item]);
|
||||||
|
if (item->image != RT_NULL)
|
||||||
|
{
|
||||||
|
rtgui_image_blit(item->image, dc, &item_rect);
|
||||||
|
item_rect.x1 += item->image->w + 2;
|
||||||
|
}
|
||||||
|
rtgui_dc_draw_text(dc, item->name, &item_rect);
|
||||||
|
|
||||||
|
/* draw current item */
|
||||||
|
item_rect = rect;
|
||||||
|
/* get current item's rect */
|
||||||
|
item_rect.x1 += 1; item_rect.x2 -= 1;
|
||||||
|
item_rect.y1 += 2;
|
||||||
|
item_rect.y1 += (box->current_item % box->page_items) * (2 + rtgui_theme_get_selected_height());
|
||||||
|
item_rect.y2 = item_rect.y1 + (2 + rtgui_theme_get_selected_height());
|
||||||
|
|
||||||
|
/* draw current item */
|
||||||
|
rtgui_theme_draw_selected(dc, &item_rect);
|
||||||
|
|
||||||
|
item_rect.x1 += LIST_MARGIN;
|
||||||
|
|
||||||
|
item = &(box->items[box->current_item]);
|
||||||
|
if (item->image != RT_NULL)
|
||||||
|
{
|
||||||
|
rtgui_image_blit(item->image, dc, &item_rect);
|
||||||
|
item_rect.x1 += (item->image->w + 2);
|
||||||
|
}
|
||||||
|
rtgui_dc_draw_text(dc, item->name, &item_rect);
|
||||||
|
|
||||||
|
rtgui_dc_end_drawing(dc);
|
||||||
|
}
|
||||||
|
|
||||||
|
rt_bool_t rtgui_listbox_event_handler(struct rtgui_widget* widget, struct rtgui_event* event)
|
||||||
|
{
|
||||||
|
struct rtgui_listbox* box = RT_NULL;
|
||||||
|
|
||||||
|
box = RTGUI_LISTBOX(widget);
|
||||||
|
switch (event->type)
|
||||||
|
{
|
||||||
|
case RTGUI_EVENT_PAINT:
|
||||||
|
rtgui_listbox_ondraw(box);
|
||||||
|
return RT_FALSE;
|
||||||
|
|
||||||
|
case RTGUI_EVENT_RESIZE:
|
||||||
|
{
|
||||||
|
struct rtgui_event_resize* resize;
|
||||||
|
|
||||||
|
resize = (struct rtgui_event_resize*)event;
|
||||||
|
|
||||||
|
/* recalculate page items */
|
||||||
|
box->page_items = resize->h / (2 + rtgui_theme_get_selected_height());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RTGUI_EVENT_MOUSE_BUTTON:
|
||||||
|
{
|
||||||
|
rtgui_rect_t rect;
|
||||||
|
struct rtgui_event_mouse* emouse;
|
||||||
|
|
||||||
|
emouse = (struct rtgui_event_mouse*)event;
|
||||||
|
|
||||||
|
/* calculate selected item */
|
||||||
|
|
||||||
|
/* get physical extent information */
|
||||||
|
rtgui_widget_get_rect(widget, &rect);
|
||||||
|
rtgui_widget_rect_to_device(widget, &rect);
|
||||||
|
|
||||||
|
if (rtgui_rect_contains_point(&rect, emouse->x, emouse->y) == RT_EOK)
|
||||||
|
{
|
||||||
|
rt_uint16_t index;
|
||||||
|
index = (emouse->y - rect.y1) / (2 + rtgui_theme_get_selected_height());
|
||||||
|
|
||||||
|
/* set focus */
|
||||||
|
rtgui_widget_focus(widget);
|
||||||
|
{
|
||||||
|
struct rtgui_rect rect;
|
||||||
|
struct rtgui_dc* dc;
|
||||||
|
|
||||||
|
dc = rtgui_dc_begin_drawing(RTGUI_WIDGET(box));
|
||||||
|
if (dc != RT_NULL)
|
||||||
|
{
|
||||||
|
/* get widget rect */
|
||||||
|
rtgui_widget_get_rect(RTGUI_WIDGET(box), &rect);
|
||||||
|
/* update focus border */
|
||||||
|
rect.x2 -= 1; rect.y2 -= 1;
|
||||||
|
/* draw focused border */
|
||||||
|
if (RTGUI_WIDGET_IS_FOCUSED(RTGUI_WIDGET(box)))
|
||||||
|
rtgui_dc_draw_focus_rect(dc, &rect);
|
||||||
|
rtgui_dc_end_drawing(dc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((index < box->items_count) && (index < box->page_items))
|
||||||
|
{
|
||||||
|
rt_uint16_t old_item;
|
||||||
|
|
||||||
|
old_item = box->current_item;
|
||||||
|
|
||||||
|
/* set selected item */
|
||||||
|
box->current_item = (box->current_item/box->page_items) * box->page_items + index;
|
||||||
|
if (emouse->button & RTGUI_MOUSE_BUTTON_DOWN)
|
||||||
|
{
|
||||||
|
/* down event */
|
||||||
|
rtgui_listbox_update_current(box, old_item);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* up event */
|
||||||
|
if (box->on_item != RT_NULL)
|
||||||
|
{
|
||||||
|
box->on_item(RTGUI_WIDGET(box), RT_NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RTGUI_EVENT_KBD:
|
||||||
|
{
|
||||||
|
struct rtgui_event_kbd* ekbd = (struct rtgui_event_kbd*)event;
|
||||||
|
if (ekbd->type == RTGUI_KEYDOWN)
|
||||||
|
{
|
||||||
|
rt_uint16_t old_item;
|
||||||
|
|
||||||
|
old_item = box->current_item;
|
||||||
|
switch (ekbd->key)
|
||||||
|
{
|
||||||
|
case RTGUIK_LEFT:
|
||||||
|
if (box->current_item - box->page_items >= 0)
|
||||||
|
box->current_item -= box->page_items;
|
||||||
|
rtgui_listbox_update_current(box, old_item);
|
||||||
|
return RT_FALSE;
|
||||||
|
|
||||||
|
case RTGUIK_UP:
|
||||||
|
if (box->current_item > 0)
|
||||||
|
box->current_item --;
|
||||||
|
rtgui_listbox_update_current(box, old_item);
|
||||||
|
return RT_FALSE;
|
||||||
|
|
||||||
|
case RTGUIK_RIGHT:
|
||||||
|
if (box->current_item + box->page_items < box->items_count - 1)
|
||||||
|
box->current_item += box->page_items;
|
||||||
|
rtgui_listbox_update_current(box, old_item);
|
||||||
|
return RT_FALSE;
|
||||||
|
|
||||||
|
case RTGUIK_DOWN:
|
||||||
|
if (box->current_item < box->items_count - 1)
|
||||||
|
box->current_item ++;
|
||||||
|
rtgui_listbox_update_current(box, old_item);
|
||||||
|
return RT_FALSE;
|
||||||
|
|
||||||
|
case RTGUIK_RETURN:
|
||||||
|
if (box->on_item != RT_NULL)
|
||||||
|
{
|
||||||
|
box->on_item(RTGUI_WIDGET(box), RT_NULL);
|
||||||
|
}
|
||||||
|
return RT_FALSE;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return RT_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* use box event handler */
|
||||||
|
return rtgui_widget_event_handler(widget, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
rtgui_listbox_t* rtgui_listbox_create(const struct rtgui_listbox_item* items, rt_uint16_t count, rtgui_rect_t *rect)
|
||||||
|
{
|
||||||
|
struct rtgui_listbox* box = RT_NULL;
|
||||||
|
|
||||||
|
box = (struct rtgui_listbox*) rtgui_widget_create(RTGUI_LISTBOX_TYPE);
|
||||||
|
if (box != RT_NULL)
|
||||||
|
{
|
||||||
|
box->items = items;
|
||||||
|
box->items_count = count;
|
||||||
|
|
||||||
|
box->page_items = rtgui_rect_height(*rect) / (2 + rtgui_theme_get_selected_height());
|
||||||
|
rtgui_widget_set_rect(RTGUI_WIDGET(box), rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
return box;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rtgui_listbox_destroy(rtgui_listbox_t* box)
|
||||||
|
{
|
||||||
|
/* destroy box */
|
||||||
|
rtgui_widget_destroy(RTGUI_WIDGET(box));
|
||||||
|
}
|
||||||
|
|
||||||
|
void rtgui_listbox_set_onitem(rtgui_listbox_t* box, rtgui_onitem_func_t func)
|
||||||
|
{
|
||||||
|
RT_ASSERT(box != RT_NULL);
|
||||||
|
|
||||||
|
box->on_item = func;
|
||||||
|
}
|
Loading…
Reference in New Issue