container.c 9.4 KB
Newer Older
B
bernard.xiong 已提交
1 2 3 4 5 6 7 8 9 10 11 12
/*
 * File      : container.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
13
 * 2010-09-24     Bernard      fix container destroy issue
B
bernard.xiong 已提交
14
 */
15 16
#include <rtgui/dc.h>
#include <rtgui/rtgui_system.h>
17
#include <rtgui/rtgui_app.h>
B
bernard.xiong 已提交
18
#include <rtgui/widgets/container.h>
19
#include <rtgui/widgets/window.h>
B
bernard.xiong 已提交
20 21 22

static void _rtgui_container_constructor(rtgui_container_t *container)
{
23 24 25
    /* init container */
    rtgui_object_set_event_handler(RTGUI_OBJECT(container),
                                   rtgui_container_event_handler);
26

27 28
    rtgui_list_init(&(container->children));
    container->layout_box = RT_NULL;
29

30
    RTGUI_WIDGET(container)->flag |= RTGUI_WIDGET_FLAG_FOCUSABLE;
B
bernard.xiong 已提交
31 32 33 34
}

static void _rtgui_container_destructor(rtgui_container_t *container)
{
35
    rtgui_container_destroy_children(container);
36

37 38
    if (container->layout_box != RT_NULL)
        rtgui_object_destroy(RTGUI_OBJECT(container->layout_box));
B
bernard.xiong 已提交
39 40
}

41
DEFINE_CLASS_TYPE(container, "container",
42 43 44 45
                  RTGUI_WIDGET_TYPE,
                  _rtgui_container_constructor,
                  _rtgui_container_destructor,
                  sizeof(struct rtgui_container));
46
RTM_EXPORT(_rtgui_container);
B
bernard.xiong 已提交
47

48
rt_bool_t rtgui_container_dispatch_event(rtgui_container_t *container, rtgui_event_t *event)
B
bernard.xiong 已提交
49
{
50 51
    /* handle in child widget */
    struct rtgui_list_node *node;
B
bernard.xiong 已提交
52

53 54 55 56
    rtgui_list_foreach(node, &(container->children))
    {
        struct rtgui_widget *w;
        w = rtgui_list_entry(node, struct rtgui_widget, sibling);
B
bernard.xiong 已提交
57

58 59 60 61
        if (RTGUI_OBJECT(w)->event_handler &&
                RTGUI_OBJECT(w)->event_handler(RTGUI_OBJECT(w), event) == RT_TRUE)
            return RT_TRUE;
    }
B
bernard.xiong 已提交
62

63
    return RT_FALSE;
B
bernard.xiong 已提交
64
}
65
RTM_EXPORT(rtgui_container_dispatch_event);
B
bernard.xiong 已提交
66

67 68 69 70
/* broadcast means that the return value of event handlers will be ignored. The
 * events will always reach every child.*/
rt_bool_t rtgui_container_broadcast_event(struct rtgui_container *container, struct rtgui_event *event)
{
71
    struct rtgui_list_node *node;
72

73 74 75 76
    rtgui_list_foreach(node, &(container->children))
    {
        struct rtgui_widget *w;
        w = rtgui_list_entry(node, struct rtgui_widget, sibling);
77

78 79 80
        if (RTGUI_OBJECT(w)->event_handler)
            RTGUI_OBJECT(w)->event_handler(RTGUI_OBJECT(w), event);
    }
81

82
    return RT_FALSE;
83
}
84
RTM_EXPORT(rtgui_container_broadcast_event);
85

86
rt_bool_t rtgui_container_dispatch_mouse_event(rtgui_container_t *container, struct rtgui_event_mouse *event)
B
bernard.xiong 已提交
87
{
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
    /* handle in child widget */
    struct rtgui_list_node *node;
    struct rtgui_widget *old_focus;

    old_focus = RTGUI_WIDGET(container)->toplevel->focused_widget;

    rtgui_list_foreach(node, &(container->children))
    {
        struct rtgui_widget *w;
        w = rtgui_list_entry(node, struct rtgui_widget, sibling);
        if (rtgui_rect_contains_point(&(w->extent),
                                      event->x, event->y) == RT_EOK)
        {
            if ((old_focus != w) && RTGUI_WIDGET_IS_FOCUSABLE(w))
                rtgui_widget_focus(w);
            if (RTGUI_OBJECT(w)->event_handler &&
                    RTGUI_OBJECT(w)->event_handler(RTGUI_OBJECT(w),
                                                   (rtgui_event_t *)event) == RT_TRUE)
                return RT_TRUE;
        }
    }

    return RT_FALSE;
B
bernard.xiong 已提交
111
}
112
RTM_EXPORT(rtgui_container_dispatch_mouse_event);
B
bernard.xiong 已提交
113

114
rt_bool_t rtgui_container_event_handler(struct rtgui_object *object, struct rtgui_event *event)
B
bernard.xiong 已提交
115
{
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
    struct rtgui_container *container;
    struct rtgui_widget    *widget;

    RT_ASSERT(object != RT_NULL);
    RT_ASSERT(event != RT_NULL);

    container = RTGUI_CONTAINER(object);
    widget    = RTGUI_WIDGET(object);

    switch (event->type)
    {
    case RTGUI_EVENT_PAINT:
    {
        struct rtgui_dc *dc;
        struct rtgui_rect rect;

        dc = rtgui_dc_begin_drawing(widget);
        if (dc == RT_NULL)
            return RT_FALSE;
        rtgui_widget_get_rect(widget, &rect);

        /* fill container with background */
        rtgui_dc_fill_rect(dc, &rect);

        /* paint on each child */
        rtgui_container_dispatch_event(container, event);

        rtgui_dc_end_drawing(dc);
    }
    break;

    case RTGUI_EVENT_KBD:
        break;

    case RTGUI_EVENT_MOUSE_BUTTON:
    case RTGUI_EVENT_MOUSE_MOTION:
        /* handle in child widget */
        return rtgui_container_dispatch_mouse_event(container,
                (struct rtgui_event_mouse *)event);

    case RTGUI_EVENT_SHOW:
        rtgui_widget_onshow(RTGUI_OBJECT(container), event);
        rtgui_container_dispatch_event(container, event);
        break;
    case RTGUI_EVENT_HIDE:
        rtgui_widget_onhide(RTGUI_OBJECT(container), event);
        rtgui_container_dispatch_event(container, event);
        break;
    case RTGUI_EVENT_COMMAND:
        rtgui_container_dispatch_event(container, event);
        break;

    case RTGUI_EVENT_UPDATE_TOPLVL:
        /* call parent handler */
        rtgui_widget_onupdate_toplvl(object, event);
        /* update the children */
        rtgui_container_broadcast_event(container, event);
        break;

    case RTGUI_EVENT_RESIZE:
        /* re-layout container */
        rtgui_container_layout(container);
        break;

    default:
        /* call parent widget event handler */
        return rtgui_widget_event_handler(RTGUI_OBJECT(widget), event);
    }

    return RT_FALSE;
B
bernard.xiong 已提交
186
}
187
RTM_EXPORT(rtgui_container_event_handler);
B
bernard.xiong 已提交
188

189
rtgui_container_t *rtgui_container_create(void)
190
{
191
    struct rtgui_container *container;
192

193 194 195
    /* allocate container */
    container = (struct rtgui_container *) rtgui_widget_create(RTGUI_CONTAINER_TYPE);
    return container;
196
}
197
RTM_EXPORT(rtgui_container_create);
198

199
void rtgui_container_destroy(rtgui_container_t *container)
200
{
201
    rtgui_widget_destroy(RTGUI_WIDGET(container));
202
}
203
RTM_EXPORT(rtgui_container_destroy);
204

B
bernard.xiong 已提交
205 206 207 208 209
/*
 * This function will add a child to a container widget
 * Note: this function will not change the widget layout
 * the layout is the responsibility of layout widget, such as box.
 */
210
void rtgui_container_add_child(rtgui_container_t *container, rtgui_widget_t *child)
B
bernard.xiong 已提交
211
{
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
    RT_ASSERT(container != RT_NULL);
    RT_ASSERT(child != RT_NULL);

    /* set parent and toplevel widget */
    child->parent = RTGUI_WIDGET(container);
    /* put widget to parent's children list */
    rtgui_list_append(&(container->children), &(child->sibling));

    /* update children toplevel */
    if (RTGUI_WIDGET(container)->toplevel != RT_NULL &&
            RTGUI_IS_WIN(RTGUI_WIDGET(container)->toplevel))
    {
        struct rtgui_event_update_toplvl eup;
        RTGUI_EVENT_UPDATE_TOPLVL_INIT(&eup);
        eup.toplvl = RTGUI_WIDGET(container)->toplevel;
        rtgui_container_broadcast_event(container, (struct rtgui_event *)&eup);
    }
B
bernard.xiong 已提交
229
}
230
RTM_EXPORT(rtgui_container_add_child);
B
bernard.xiong 已提交
231 232

/* remove a child to widget */
233
void rtgui_container_remove_child(rtgui_container_t *container, rtgui_widget_t *child)
B
bernard.xiong 已提交
234
{
235 236
    RT_ASSERT(container != RT_NULL);
    RT_ASSERT(child != RT_NULL);
B
bernard.xiong 已提交
237

238
    rtgui_widget_unfocus(child);
B
bernard.xiong 已提交
239

240 241
    /* remove widget from parent's children list */
    rtgui_list_remove(&(container->children), &(child->sibling));
B
bernard.xiong 已提交
242

243 244 245
    /* set parent and toplevel widget */
    child->parent = RT_NULL;
    child->toplevel = RT_NULL;
B
bernard.xiong 已提交
246
}
247
RTM_EXPORT(rtgui_container_remove_child);
B
bernard.xiong 已提交
248 249 250 251

/* destroy all children of container */
void rtgui_container_destroy_children(rtgui_container_t *container)
{
252
    struct rtgui_list_node *node;
B
bernard.xiong 已提交
253

254 255
    if (container == RT_NULL)
        return;
B
bernard.xiong 已提交
256

257 258 259 260
    node = container->children.next;
    while (node != RT_NULL)
    {
        rtgui_widget_t *child = rtgui_list_entry(node, rtgui_widget_t, sibling);
B
bernard.xiong 已提交
261

262 263 264 265
        if (RTGUI_IS_CONTAINER(child))
        {
            /* break parent firstly */
            child->parent = RT_NULL;
B
bernard.xiong 已提交
266

267 268 269
            /* destroy children of child */
            rtgui_container_destroy_children(RTGUI_CONTAINER(child));
        }
B
bernard.xiong 已提交
270

271 272
        /* remove widget from parent's children list */
        rtgui_list_remove(&(container->children), &(child->sibling));
B
bernard.xiong 已提交
273

274 275
        /* set parent and toplevel widget */
        child->parent = RT_NULL;
B
bernard.xiong 已提交
276

277 278
        /* destroy object and remove from parent */
        rtgui_object_destroy(RTGUI_OBJECT(child));
B
bernard.xiong 已提交
279

280 281
        node = container->children.next;
    }
B
bernard.xiong 已提交
282

283
    container->children.next = RT_NULL;
B
bernard.xiong 已提交
284

285 286
    /* update widget clip */
    rtgui_win_update_clip(RTGUI_WIN(RTGUI_WIDGET(container)->toplevel));
B
bernard.xiong 已提交
287
}
288
RTM_EXPORT(rtgui_container_destroy_children);
B
bernard.xiong 已提交
289

290
rtgui_widget_t *rtgui_container_get_first_child(rtgui_container_t *container)
B
bernard.xiong 已提交
291
{
292
    rtgui_widget_t *child = RT_NULL;
B
bernard.xiong 已提交
293

294
    RT_ASSERT(container != RT_NULL);
295

296 297 298 299
    if (container->children.next != RT_NULL)
    {
        child = rtgui_list_entry(container->children.next, rtgui_widget_t, sibling);
    }
B
bernard.xiong 已提交
300

301
    return child;
B
bernard.xiong 已提交
302
}
303
RTM_EXPORT(rtgui_container_get_first_child);
304

305
void rtgui_container_set_box(rtgui_container_t *container, struct rtgui_box *box)
306
{
307
    if (container == RT_NULL || box  == RT_NULL)
308 309
        return;

310 311
    container->layout_box = box;
    box->container = container;
312
}
313
RTM_EXPORT(rtgui_container_set_box);
314

315
void rtgui_container_layout(struct rtgui_container *container)
316
{
317 318
    if (container == RT_NULL || container->layout_box == RT_NULL)
        return;
319

320
    rtgui_box_layout(container->layout_box);
321
}
322
RTM_EXPORT(rtgui_container_layout);
323