341 lines
8.0 KiB
C
341 lines
8.0 KiB
C
/*
|
|
* File : box.c
|
|
* This file is part of RT-Thread RTOS
|
|
* COPYRIGHT (C) 2006 - 2009, 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
|
|
* 2009-10-16 Bernard first version
|
|
*/
|
|
#include <rtgui/dc.h>
|
|
#include <rtgui/widgets/box.h>
|
|
|
|
static void _rtgui_box_constructor(rtgui_box_t *box)
|
|
{
|
|
/* init widget and set event handler */
|
|
rtgui_widget_set_event_handler(RTGUI_WIDGET(box), rtgui_box_event_handler);
|
|
|
|
RTGUI_WIDGET(box)->flag |= RTGUI_WIDGET_FLAG_TRANSPARENT;
|
|
rtgui_widget_set_event_handler(RTGUI_WIDGET(box), rtgui_box_event_handler);
|
|
|
|
/* set proper of control */
|
|
box->orientation = RTGUI_HORIZONTAL;
|
|
box->border_size = RTGUI_BORDER_DEFAULT_WIDTH;
|
|
}
|
|
|
|
rtgui_type_t *rtgui_box_type_get(void)
|
|
{
|
|
static rtgui_type_t *box_type = RT_NULL;
|
|
|
|
if (!box_type)
|
|
{
|
|
box_type = rtgui_type_create("box", RTGUI_CONTAINER_TYPE,
|
|
sizeof(rtgui_box_t), RTGUI_CONSTRUCTOR(_rtgui_box_constructor), RT_NULL);
|
|
}
|
|
|
|
return box_type;
|
|
}
|
|
|
|
rt_bool_t rtgui_box_event_handler(rtgui_widget_t* widget, rtgui_event_t* event)
|
|
{
|
|
struct rtgui_box* box = (struct rtgui_box*)widget;
|
|
|
|
RT_ASSERT(box != RT_NULL);
|
|
|
|
switch (event->type)
|
|
{
|
|
case RTGUI_EVENT_RESIZE:
|
|
/* re-layout */
|
|
rtgui_box_layout(box);
|
|
break;
|
|
|
|
default:
|
|
return rtgui_container_event_handler(RTGUI_WIDGET(box), event);
|
|
}
|
|
|
|
return RT_FALSE;
|
|
}
|
|
|
|
struct rtgui_box* rtgui_box_create(int orientation, rtgui_rect_t* rect)
|
|
{
|
|
struct rtgui_box* box;
|
|
|
|
box = (struct rtgui_box*) rtgui_widget_create (RTGUI_BOX_TYPE);
|
|
if (box != RT_NULL)
|
|
{
|
|
/* set proper of control */
|
|
rtgui_widget_set_rect(RTGUI_WIDGET(box), rect);
|
|
box->orientation = orientation;
|
|
}
|
|
|
|
return box;
|
|
}
|
|
|
|
void rtgui_box_append(struct rtgui_box* box, rtgui_widget_t* widget)
|
|
{
|
|
/* put to box's children list */
|
|
rtgui_container_add_child(RTGUI_CONTAINER(box), widget);
|
|
}
|
|
|
|
static void rtgui_box_layout_vertical(rtgui_box_t* box)
|
|
{
|
|
rtgui_list_t *node;
|
|
rt_int32_t box_width;
|
|
rt_int32_t space_count;
|
|
rt_int32_t next_x, next_y;
|
|
rt_int32_t total_height, space_height;
|
|
struct rtgui_event_resize size_event;
|
|
|
|
/* prepare the resize event */
|
|
RTGUI_EVENT_RESIZE_INIT(&size_event);
|
|
|
|
/* find spaces */
|
|
space_count = 0;
|
|
total_height = 0;
|
|
space_height = 0;
|
|
|
|
rtgui_list_foreach(node, &(RTGUI_CONTAINER(box)->children))
|
|
{
|
|
rtgui_widget_t* widget = rtgui_list_entry(node, struct rtgui_widget, sibling);
|
|
if (widget->align & RTGUI_ALIGN_STRETCH) space_count ++;
|
|
else total_height += widget->mini_height;
|
|
}
|
|
|
|
/* calculate the height for each spaces */
|
|
if (space_count != 0)
|
|
{
|
|
space_height = (rtgui_rect_height(RTGUI_WIDGET(box)->extent) - total_height - (box->border_size << 1)) / space_count;
|
|
}
|
|
|
|
/* init (x, y) and box width */
|
|
next_x = RTGUI_WIDGET(box)->extent.x1 + box->border_size;
|
|
next_y = RTGUI_WIDGET(box)->extent.y1 + box->border_size;
|
|
box_width = rtgui_rect_width(RTGUI_WIDGET(box)->extent) - (box->border_size << 1);
|
|
|
|
/* layout each widget */
|
|
rtgui_list_foreach(node, &(RTGUI_CONTAINER(box)->children))
|
|
{
|
|
rtgui_rect_t *rect;
|
|
rtgui_widget_t* widget = rtgui_list_entry(node, struct rtgui_widget, sibling);
|
|
|
|
/* get extent of widget */
|
|
rect = &(widget->extent);
|
|
|
|
/* reset rect */
|
|
rtgui_rect_moveto(rect, -rect->x1, -rect->y1);
|
|
rect->x2 = widget->mini_width;
|
|
rect->y2 = widget->mini_height;
|
|
|
|
/* left in default */
|
|
rtgui_rect_moveto(rect, next_x, next_y);
|
|
|
|
if (widget->align & RTGUI_ALIGN_EXPAND)
|
|
{
|
|
/* expand on horizontal */
|
|
rect->x2 = rect->x1 + (rt_int16_t)box_width;
|
|
}
|
|
if (widget->align & RTGUI_ALIGN_CENTER_VERTICAL)
|
|
{
|
|
/* center */
|
|
rt_uint32_t mid;
|
|
|
|
mid = box_width - rtgui_rect_width(*rect);
|
|
mid = mid /2;
|
|
|
|
rect->x1 = next_x + mid;
|
|
rect->x2 = next_x + box_width - mid;
|
|
}
|
|
else if (widget->align & RTGUI_ALIGN_RIGHT)
|
|
{
|
|
/* right */
|
|
rect->x1 = next_x + box_width - rtgui_rect_width(*rect);
|
|
rect->x2 = next_x + box_width;
|
|
}
|
|
|
|
if (widget->align & RTGUI_ALIGN_STRETCH)
|
|
{
|
|
rect->y2 = rect->y1 + space_height;
|
|
}
|
|
|
|
/* process resize event */
|
|
size_event.x = rect->x1;
|
|
size_event.y = rect->y1;
|
|
size_event.w = rect->x2 - rect->x1;
|
|
size_event.h = rect->y2 - rect->y1;
|
|
widget->event_handler(widget, &size_event.parent);
|
|
|
|
/* point to next height */
|
|
next_y = rect->y2;
|
|
}
|
|
}
|
|
|
|
static void rtgui_box_layout_horizontal(rtgui_box_t* box)
|
|
{
|
|
rtgui_list_t *node;
|
|
rt_int32_t box_height;
|
|
rt_int32_t space_count;
|
|
rt_int32_t next_x, next_y;
|
|
rt_int32_t total_width, space_width;
|
|
struct rtgui_event_resize size_event;
|
|
|
|
/* prepare the resize event */
|
|
RTGUI_EVENT_RESIZE_INIT(&size_event);
|
|
|
|
/* find spaces */
|
|
space_count = 0;
|
|
total_width = 0;
|
|
space_width = 0;
|
|
|
|
rtgui_list_foreach(node, &(RTGUI_CONTAINER(box)->children))
|
|
{
|
|
rtgui_widget_t* widget = rtgui_list_entry(node, struct rtgui_widget, sibling);
|
|
if (widget->align & RTGUI_ALIGN_STRETCH) space_count ++;
|
|
else total_width += widget->mini_width;
|
|
}
|
|
|
|
if (space_count != 0)
|
|
{
|
|
/* calculate the height for each spaces */
|
|
space_width = (rtgui_rect_width(RTGUI_WIDGET(box)->extent) - total_width) / space_count;
|
|
}
|
|
|
|
/* init (x, y) and box height */
|
|
next_x = RTGUI_WIDGET(box)->extent.x1 + box->border_size;
|
|
next_y = RTGUI_WIDGET(box)->extent.y1 + box->border_size;
|
|
box_height = rtgui_rect_height(RTGUI_WIDGET(box)->extent) - (box->border_size << 1);
|
|
|
|
/* layout each widget */
|
|
rtgui_list_foreach(node, &(RTGUI_CONTAINER(box)->children))
|
|
{
|
|
rtgui_rect_t *rect;
|
|
rtgui_widget_t* widget = rtgui_list_entry(node, struct rtgui_widget, sibling);
|
|
|
|
/* get extent of widget */
|
|
rect = &(widget->extent);
|
|
|
|
/* reset rect */
|
|
rtgui_rect_moveto(rect, -rect->x1, -rect->y1);
|
|
rect->x2 = widget->mini_width;
|
|
rect->y2 = widget->mini_height;
|
|
|
|
/* top in default */
|
|
rtgui_rect_moveto(rect, next_x, next_y);
|
|
|
|
if (widget->align & RTGUI_ALIGN_EXPAND)
|
|
{
|
|
/* expand on vertical */
|
|
rect->y2 = rect->y1 + box_height;
|
|
}
|
|
if (widget->align & RTGUI_ALIGN_CENTER_HORIZONTAL)
|
|
{
|
|
/* center */
|
|
rt_uint32_t mid;
|
|
|
|
mid = box_height - rtgui_rect_height(*rect);
|
|
mid = mid /2;
|
|
|
|
rect->y1 = next_y + mid;
|
|
rect->y2 = next_y + box_height - mid;
|
|
}
|
|
else if (widget->align & RTGUI_ALIGN_RIGHT)
|
|
{
|
|
/* right */
|
|
rect->y1 = next_y + box_height - rtgui_rect_height(*rect);
|
|
rect->y2 = next_y + box_height;
|
|
}
|
|
|
|
if (widget->align & RTGUI_ALIGN_STRETCH)
|
|
{
|
|
rect->x2 = rect->x1 + space_width;
|
|
}
|
|
|
|
/* process resize event */
|
|
size_event.x = rect->x1;
|
|
size_event.y = rect->y1;
|
|
size_event.w = rect->x2 - rect->x1;
|
|
size_event.h = rect->y2 - rect->y1;
|
|
widget->event_handler(widget, &size_event.parent);
|
|
|
|
/* point to next width */
|
|
next_x = rect->x2;
|
|
}
|
|
}
|
|
|
|
void rtgui_box_layout(rtgui_box_t* box)
|
|
{
|
|
RT_ASSERT(box != RT_NULL);
|
|
|
|
if (box->orientation & RTGUI_VERTICAL)
|
|
{
|
|
rtgui_box_layout_vertical(box);
|
|
}
|
|
else
|
|
{
|
|
rtgui_box_layout_horizontal(box);
|
|
}
|
|
|
|
/* update box and its children clip */
|
|
if (!RTGUI_WIDGET_IS_HIDE(RTGUI_WIDGET(box)))
|
|
{
|
|
rtgui_widget_update_clip(RTGUI_WIDGET(box));
|
|
}
|
|
}
|
|
|
|
rt_uint32_t rtgui_box_get_width(rtgui_box_t* box)
|
|
{
|
|
rtgui_list_t *node;
|
|
rt_uint32_t width;
|
|
|
|
width = 0;
|
|
rtgui_list_foreach(node, &(RTGUI_CONTAINER(box)->children))
|
|
{
|
|
rtgui_widget_t* widget = rtgui_list_entry(node, struct rtgui_widget, sibling);
|
|
rt_uint32_t widget_width;
|
|
|
|
widget_width = rtgui_rect_width(widget->extent);
|
|
if (box->orientation & RTGUI_VERTICAL)
|
|
{
|
|
/* get the max width */
|
|
if (width < widget_width) width = widget_width;
|
|
}
|
|
else
|
|
{
|
|
/* get the total width */
|
|
width += widget_width;
|
|
}
|
|
}
|
|
|
|
return width;
|
|
}
|
|
|
|
rt_uint32_t rtgui_box_get_height(rtgui_box_t* box)
|
|
{
|
|
rtgui_list_t *node;
|
|
rt_uint32_t height;
|
|
|
|
height = 0;
|
|
rtgui_list_foreach(node, &(RTGUI_CONTAINER(box)->children))
|
|
{
|
|
rtgui_widget_t* widget = rtgui_list_entry(node, struct rtgui_widget, sibling);
|
|
rt_uint32_t widget_height;
|
|
|
|
widget_height = rtgui_rect_height(widget->extent);
|
|
if (box->orientation & RTGUI_HORIZONTAL)
|
|
{
|
|
/* get the max height */
|
|
if (height < widget_height) height = widget_height;
|
|
}
|
|
else
|
|
{
|
|
/* get the total height */
|
|
height += widget_height;
|
|
}
|
|
}
|
|
|
|
return height;
|
|
}
|