1 /*
2  * Copyright (C) 2020 Linux Studio Plugins Project <https://lsp-plug.in/>
3  *           (C) 2020 Vladimir Sadovnikov <sadko4u@gmail.com>
4  *
5  * This file is part of lsp-plugins
6  * Created on: 15 июн. 2017 г.
7  *
8  * lsp-plugins is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * any later version.
12  *
13  * lsp-plugins is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with lsp-plugins. If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 #include <ui/tk/tk.h>
23 
24 namespace lsp
25 {
26     namespace tk
27     {
28         const w_class_t LSPWidget::metadata = { "LSPWidget", NULL };
29 
LSPWidget(LSPDisplay * dpy)30         LSPWidget::LSPWidget(LSPDisplay *dpy):
31             sPadding(this),
32             sBgColor(this),
33             sBrightness(this)
34         {
35             pUID            = NULL;
36             pDisplay        = dpy;
37             pSurface        = NULL;
38             pParent         = NULL;
39             enCursor        = MP_DEFAULT;
40             sSize.nLeft     = 0;
41             sSize.nTop      = 0;
42             sSize.nWidth    = 0;
43             sSize.nHeight   = 0;
44             nFlags          = REDRAW_SURFACE | F_VISIBLE | F_HFILL | F_VFILL;
45             pClass          = &metadata;
46         }
47 
~LSPWidget()48         LSPWidget::~LSPWidget()
49         {
50             do_destroy();
51         }
52 
instance_of(const w_class_t * wclass) const53         bool LSPWidget::instance_of(const w_class_t *wclass) const
54         {
55             const w_class_t *wc = pClass;
56             while (wc != NULL)
57             {
58                 if (wc == wclass)
59                     return true;
60                 wc = wc->parent;
61             }
62 
63             return false;
64         }
65 
init()66         status_t LSPWidget::init()
67         {
68             // Initialize style
69             status_t res = sStyle.init();
70             if (res == STATUS_OK)
71                 res = sStyle.add_parent(pDisplay->theme()->root());
72             if (res == STATUS_OK)
73                 res = sBgColor.bind("bg_color");
74             if (res == STATUS_OK)
75                 res = sBrightness.bind("brightness");
76 
77             // Declare slots
78             ui_handler_id_t id = 0;
79 
80             id = sSlots.add(LSPSLOT_FOCUS_IN, slot_focus_in, self());
81             if (id >= 0) id = sSlots.add(LSPSLOT_FOCUS_OUT, slot_focus_out, self());
82             if (id >= 0) id = sSlots.add(LSPSLOT_KEY_DOWN, slot_key_down, self());
83             if (id >= 0) id = sSlots.add(LSPSLOT_KEY_UP, slot_key_up, self());
84             if (id >= 0) id = sSlots.add(LSPSLOT_MOUSE_DOWN, slot_mouse_down, self());
85             if (id >= 0) id = sSlots.add(LSPSLOT_MOUSE_UP, slot_mouse_up, self());
86             if (id >= 0) id = sSlots.add(LSPSLOT_MOUSE_MOVE, slot_mouse_move, self());
87             if (id >= 0) id = sSlots.add(LSPSLOT_MOUSE_SCROLL, slot_mouse_scroll, self());
88             if (id >= 0) id = sSlots.add(LSPSLOT_MOUSE_DBL_CLICK, slot_mouse_dbl_click, self());
89             if (id >= 0) id = sSlots.add(LSPSLOT_MOUSE_TRI_CLICK, slot_mouse_tri_click, self());
90             if (id >= 0) id = sSlots.add(LSPSLOT_MOUSE_IN, slot_mouse_in, self());
91             if (id >= 0) id = sSlots.add(LSPSLOT_MOUSE_OUT, slot_mouse_out, self());
92             if (id >= 0) id = sSlots.add(LSPSLOT_HIDE, slot_hide, self());
93             if (id >= 0) id = sSlots.add(LSPSLOT_SHOW, slot_show, self());
94             if (id >= 0) id = sSlots.add(LSPSLOT_DESTROY, slot_destroy, self());
95             if (id >= 0) id = sSlots.add(LSPSLOT_RESIZE, slot_resize, self());
96             if (id >= 0) id = sSlots.add(LSPSLOT_RESIZE_PARENT, slot_resize_parent, self());
97             if (id >= 0) id = sSlots.add(LSPSLOT_DRAG_REQUEST, slot_drag_request, self());
98 
99             return (id >= 0) ? STATUS_OK : -id;
100         }
101 
do_destroy()102         void LSPWidget::do_destroy()
103         {
104             // Set parent widget to NULL
105             set_parent(NULL);
106 
107             // Destroy surface
108             if (pSurface != NULL)
109             {
110                 pSurface->destroy();
111                 delete pSurface;
112                 pSurface = NULL;
113             }
114 
115             // Execute slots and unbind all to prevent duplicate on_destroy calls
116             sSlots.execute(LSPSLOT_DESTROY, this);
117             sSlots.destroy();
118 
119             // Destroy widget identifier
120             if (pUID != NULL)
121                 ::free(pUID);
122             pUID = NULL;
123         }
124 
unlink_widget(LSPWidget * w)125         void LSPWidget::unlink_widget(LSPWidget *w)
126         {
127             if (w == NULL)
128                 return;
129             if (w->pParent == this)
130                 w->pParent  = NULL;
131         }
132 
init_color(color_t value,LSPColor * color)133         void LSPWidget::init_color(color_t value, LSPColor *color)
134         {
135             Color c;
136             if (pDisplay != NULL)
137             {
138                 LSPTheme *theme = pDisplay->theme();
139 
140                 if (theme != NULL)
141                     theme->get_color(value, c);
142             }
143             color->copy(&c);
144         }
145 
slot_mouse_move(LSPWidget * sender,void * ptr,void * data)146         status_t LSPWidget::slot_mouse_move(LSPWidget *sender, void *ptr, void *data)
147         {
148             if ((ptr == NULL) || (data == NULL))
149                 return STATUS_BAD_ARGUMENTS;
150 
151             LSPWidget *_this  = static_cast<LSPWidget *>(ptr);
152             ws_event_t *ev  = static_cast<ws_event_t *>(data);
153             return _this->on_mouse_move(ev);
154         }
155 
slot_mouse_down(LSPWidget * sender,void * ptr,void * data)156         status_t LSPWidget::slot_mouse_down(LSPWidget *sender, void *ptr, void *data)
157         {
158             if ((ptr == NULL) || (data == NULL))
159                 return STATUS_BAD_ARGUMENTS;
160 
161             LSPWidget *_this  = static_cast<LSPWidget *>(ptr);
162             ws_event_t *ev  = static_cast<ws_event_t *>(data);
163             return _this->on_mouse_down(ev);
164         }
165 
slot_mouse_up(LSPWidget * sender,void * ptr,void * data)166         status_t LSPWidget::slot_mouse_up(LSPWidget *sender, void *ptr, void *data)
167         {
168             if ((ptr == NULL) || (data == NULL))
169                 return STATUS_BAD_ARGUMENTS;
170 
171             LSPWidget *_this  = static_cast<LSPWidget *>(ptr);
172             ws_event_t *ev  = static_cast<ws_event_t *>(data);
173             return _this->on_mouse_up(ev);
174         }
175 
slot_mouse_dbl_click(LSPWidget * sender,void * ptr,void * data)176         status_t LSPWidget::slot_mouse_dbl_click(LSPWidget *sender, void *ptr, void *data)
177         {
178             if ((ptr == NULL) || (data == NULL))
179                 return STATUS_BAD_ARGUMENTS;
180 
181             LSPWidget *_this  = static_cast<LSPWidget *>(ptr);
182             ws_event_t *ev  = static_cast<ws_event_t *>(data);
183             return _this->on_mouse_dbl_click(ev);
184         }
185 
slot_mouse_tri_click(LSPWidget * sender,void * ptr,void * data)186         status_t LSPWidget::slot_mouse_tri_click(LSPWidget *sender, void *ptr, void *data)
187         {
188             if ((ptr == NULL) || (data == NULL))
189                 return STATUS_BAD_ARGUMENTS;
190 
191             LSPWidget *_this  = static_cast<LSPWidget *>(ptr);
192             ws_event_t *ev  = static_cast<ws_event_t *>(data);
193             return _this->on_mouse_tri_click(ev);
194         }
195 
slot_mouse_scroll(LSPWidget * sender,void * ptr,void * data)196         status_t LSPWidget::slot_mouse_scroll(LSPWidget *sender, void *ptr, void *data)
197         {
198             if ((ptr == NULL) || (data == NULL))
199                 return STATUS_BAD_ARGUMENTS;
200 
201             LSPWidget *_this  = static_cast<LSPWidget *>(ptr);
202             ws_event_t *ev  = static_cast<ws_event_t *>(data);
203             return _this->on_mouse_scroll(ev);
204         }
205 
slot_mouse_in(LSPWidget * sender,void * ptr,void * data)206         status_t LSPWidget::slot_mouse_in(LSPWidget *sender, void *ptr, void *data)
207         {
208             if ((ptr == NULL) || (data == NULL))
209                 return STATUS_BAD_ARGUMENTS;
210 
211             LSPWidget *_this  = static_cast<LSPWidget *>(ptr);
212             ws_event_t *ev  = static_cast<ws_event_t *>(data);
213             return _this->on_mouse_in(ev);
214         }
215 
slot_mouse_out(LSPWidget * sender,void * ptr,void * data)216         status_t LSPWidget::slot_mouse_out(LSPWidget *sender, void *ptr, void *data)
217         {
218             if ((ptr == NULL) || (data == NULL))
219                 return STATUS_BAD_ARGUMENTS;
220 
221             LSPWidget *_this  = static_cast<LSPWidget *>(ptr);
222             ws_event_t *ev  = static_cast<ws_event_t *>(data);
223             return _this->on_mouse_out(ev);
224         }
225 
slot_key_down(LSPWidget * sender,void * ptr,void * data)226         status_t LSPWidget::slot_key_down(LSPWidget *sender, void *ptr, void *data)
227         {
228             if ((ptr == NULL) || (data == NULL))
229                 return STATUS_BAD_ARGUMENTS;
230 
231             LSPWidget *_this  = static_cast<LSPWidget *>(ptr);
232             ws_event_t *ev  = static_cast<ws_event_t *>(data);
233             return _this->on_key_down(ev);
234         }
235 
slot_key_up(LSPWidget * sender,void * ptr,void * data)236         status_t LSPWidget::slot_key_up(LSPWidget *sender, void *ptr, void *data)
237         {
238             if ((ptr == NULL) || (data == NULL))
239                 return STATUS_BAD_ARGUMENTS;
240 
241             LSPWidget *_this  = static_cast<LSPWidget *>(ptr);
242             ws_event_t *ev  = static_cast<ws_event_t *>(data);
243             return _this->on_key_up(ev);
244         }
245 
slot_hide(LSPWidget * sender,void * ptr,void * data)246         status_t LSPWidget::slot_hide(LSPWidget *sender, void *ptr, void *data)
247         {
248             if (ptr == NULL)
249                 return STATUS_BAD_ARGUMENTS;
250 
251             LSPWidget *_this  = static_cast<LSPWidget *>(ptr);
252             return _this->on_hide();
253         }
254 
slot_show(LSPWidget * sender,void * ptr,void * data)255         status_t LSPWidget::slot_show(LSPWidget *sender, void *ptr, void *data)
256         {
257             if (ptr == NULL)
258                 return STATUS_BAD_ARGUMENTS;
259 
260             LSPWidget *_this  = static_cast<LSPWidget *>(ptr);
261             return _this->on_show();
262         }
263 
slot_destroy(LSPWidget * sender,void * ptr,void * data)264         status_t LSPWidget::slot_destroy(LSPWidget *sender, void *ptr, void *data)
265         {
266             if (ptr == NULL)
267                 return STATUS_BAD_ARGUMENTS;
268 
269             LSPWidget *_this  = static_cast<LSPWidget *>(ptr);
270             return _this->on_destroy();
271         }
272 
slot_resize(LSPWidget * sender,void * ptr,void * data)273         status_t LSPWidget::slot_resize(LSPWidget *sender, void *ptr, void *data)
274         {
275             if ((ptr == NULL) || (data == NULL))
276                 return STATUS_BAD_ARGUMENTS;
277 
278             LSPWidget *_this  = static_cast<LSPWidget *>(ptr);
279             realize_t *ev   = static_cast<realize_t *>(data);
280             return _this->on_resize(ev);
281         }
282 
slot_resize_parent(LSPWidget * sender,void * ptr,void * data)283         status_t LSPWidget::slot_resize_parent(LSPWidget *sender, void *ptr, void *data)
284         {
285             if ((ptr == NULL) || (data == NULL))
286                 return STATUS_BAD_ARGUMENTS;
287 
288             LSPWidget *_this  = static_cast<LSPWidget *>(ptr);
289             realize_t *ev   = static_cast<realize_t *>(data);
290             return _this->on_resize_parent(ev);
291         }
292 
slot_focus_in(LSPWidget * sender,void * ptr,void * data)293         status_t LSPWidget::slot_focus_in(LSPWidget *sender, void *ptr, void *data)
294         {
295             if ((ptr == NULL) || (data == NULL))
296                 return STATUS_BAD_ARGUMENTS;
297 
298             LSPWidget *_this  = static_cast<LSPWidget *>(ptr);
299             ws_event_t *ev  = static_cast<ws_event_t *>(data);
300             return _this->on_focus_in(ev);
301         }
302 
slot_focus_out(LSPWidget * sender,void * ptr,void * data)303         status_t LSPWidget::slot_focus_out(LSPWidget *sender, void *ptr, void *data)
304         {
305             if ((ptr == NULL) || (data == NULL))
306                 return STATUS_BAD_ARGUMENTS;
307 
308             LSPWidget *_this  = static_cast<LSPWidget *>(ptr);
309             ws_event_t *ev  = static_cast<ws_event_t *>(data);
310             return _this->on_focus_out(ev);
311         }
312 
slot_drag_request(LSPWidget * sender,void * ptr,void * data)313         status_t LSPWidget::slot_drag_request(LSPWidget *sender, void *ptr, void *data)
314         {
315             if ((ptr == NULL) || (data == NULL))
316                 return STATUS_BAD_ARGUMENTS;
317 
318             LSPWidget *_this  = static_cast<LSPWidget *>(ptr);
319             ws_event_t *ev  = static_cast<ws_event_t *>(data);
320             const char * const *ctype = _this->pDisplay->get_drag_mime_types();
321 
322             return _this->on_drag_request(ev, ctype);
323         }
324 
relative_left() const325         ssize_t LSPWidget::relative_left() const
326         {
327             return sSize.nLeft - ((pParent != NULL) ? pParent->left() : 0);
328         }
329 
relative_right() const330         ssize_t LSPWidget::relative_right() const
331         {
332             return sSize.nLeft - ((pParent != NULL) ? pParent->left() : 0) + sSize.nWidth;
333         }
334 
relative_top() const335         ssize_t LSPWidget::relative_top() const
336         {
337             return sSize.nTop - ((pParent != NULL) ? pParent->top() : 0);
338         }
339 
relative_bottom() const340         ssize_t LSPWidget::relative_bottom() const
341         {
342             return sSize.nTop - ((pParent != NULL) ? pParent->top() : 0) + sSize.nHeight;
343         }
344 
inside(ssize_t x,ssize_t y)345         bool LSPWidget::inside(ssize_t x, ssize_t y)
346         {
347             if (!(nFlags & F_VISIBLE))
348                 return false;
349             else if (x < sSize.nLeft)
350                 return false;
351             else if (x >= (sSize.nLeft + sSize.nWidth))
352                 return false;
353             else if (y < sSize.nTop)
354                 return false;
355             else if (y >= (sSize.nTop + sSize.nHeight))
356                 return false;
357 
358             return true;
359         }
360 
active_cursor() const361         mouse_pointer_t LSPWidget::active_cursor() const
362         {
363             return enCursor;
364         }
365 
hide()366         bool LSPWidget::hide()
367         {
368             if (!(nFlags & F_VISIBLE))
369                 return false;
370             nFlags &= ~F_VISIBLE;
371 //            lsp_trace("class = %s, this=%p", get_class()->name, this);
372 
373             // Drop surface to not to eat memory
374             if (pSurface != NULL)
375             {
376                 pSurface->destroy();
377                 delete pSurface;
378                 pSurface = NULL;
379             }
380 
381             // Execute slot
382             sSlots.execute(LSPSLOT_HIDE, this);
383 
384             // Query draw for parent widget
385             if (pParent != NULL)
386                 pParent->query_resize();
387 
388             return true;
389         }
390 
show()391         bool LSPWidget::show()
392         {
393             if (nFlags & F_VISIBLE)
394                 return false;
395 //            lsp_trace("class = %s, this=%p", get_class()->name, this);
396 
397             nFlags |= F_VISIBLE;
398             if (pParent != NULL)
399                 pParent->query_resize();
400             query_draw(REDRAW_CHILD | REDRAW_SURFACE);
401             sSlots.execute(LSPSLOT_SHOW, this);
402 
403             return true;
404         }
405 
set_parent(LSPComplexWidget * parent)406         void LSPWidget::set_parent(LSPComplexWidget *parent)
407         {
408             if (pParent == parent)
409                 return;
410 
411             if (pParent != NULL)
412             {
413                 LSPWindow *wnd = widget_cast<LSPWindow>(toplevel());
414                 if (wnd != NULL)
415                     wnd->unfocus_child(this);
416                 sStyle.remove_parent(pParent->style()); // Unlink style
417 
418                 LSPWidgetContainer *wc = widget_cast<LSPWidgetContainer>(pParent);
419                 if (wc != NULL)
420                     wc->remove(this);
421             }
422 
423             pParent = parent;
424             if (parent != NULL) // Inherit the style of parent widget
425                 sStyle.add_parent(parent->style());
426         }
427 
toplevel()428         LSPWidget *LSPWidget::toplevel()
429         {
430             LSPWidget *p = this;
431             while (p->pParent != NULL)
432                 p = p->pParent;
433 
434             return p;
435         }
436 
query_draw(size_t flags)437         void LSPWidget::query_draw(size_t flags)
438         {
439             if (!(nFlags & F_VISIBLE))
440                 return;
441             nFlags     |= (flags & (REDRAW_CHILD | REDRAW_SURFACE));
442             if (pParent != NULL)
443                 pParent->query_draw(REDRAW_CHILD);
444         }
445 
commit_redraw()446         void LSPWidget::commit_redraw()
447         {
448             nFlags &= ~(REDRAW_SURFACE | REDRAW_CHILD);
449         }
450 
queue_destroy()451         status_t LSPWidget::queue_destroy()
452         {
453             if (pDisplay == NULL)
454                 return STATUS_BAD_STATE;
455             return pDisplay->queue_destroy(this);
456         }
457 
query_resize()458         void LSPWidget::query_resize()
459         {
460             LSPWidget *w = toplevel();
461             if ((w != NULL) && (w != this))
462                 w->query_resize();
463         }
464 
set_expand(bool value)465         void LSPWidget::set_expand(bool value)
466         {
467             size_t flags = nFlags;
468             if (value)
469                 nFlags  |= F_EXPAND;
470             else
471                 nFlags  &= ~F_EXPAND;
472 
473             if (flags != nFlags)
474                 query_resize();
475         }
476 
set_fill(bool value)477         void LSPWidget::set_fill(bool value)
478         {
479             size_t flags = nFlags;
480             if (value)
481                 nFlags  |= F_HFILL | F_VFILL;
482             else
483                 nFlags  &= ~(F_HFILL | F_VFILL);
484 
485             if (flags != nFlags)
486                 query_resize();
487         }
488 
set_hfill(bool value)489         void LSPWidget::set_hfill(bool value)
490         {
491             size_t flags = nFlags;
492             if (value)
493                 nFlags  |= F_HFILL;
494             else
495                 nFlags  &= ~F_HFILL;
496 
497             if (flags != nFlags)
498                 query_resize();
499         }
500 
set_vfill(bool value)501         void LSPWidget::set_vfill(bool value)
502         {
503             size_t flags = nFlags;
504             if (value)
505                 nFlags  |= F_VFILL;
506             else
507                 nFlags  &= ~F_VFILL;
508 
509             if (flags != nFlags)
510                 query_resize();
511         }
512 
set_visible(bool visible)513         void LSPWidget::set_visible(bool visible)
514         {
515             if (visible)
516                 show();
517             else
518                 hide();
519         }
520 
521         /** Set mouse pointer
522          *
523          * @param mp mouse pointer
524          * @return mouse pointer
525          */
set_cursor(mouse_pointer_t mp)526         status_t LSPWidget::set_cursor(mouse_pointer_t mp)
527         {
528             enCursor       = mp;
529             return STATUS_OK;
530         }
531 
render(ISurface * s,bool force)532         void LSPWidget::render(ISurface *s, bool force)
533         {
534             // Get surface of widget
535             ISurface *src  = get_surface(s);
536             if (src == NULL)
537                 return;
538 
539             // Render to the main surface
540             s->draw(src, sSize.nLeft, sSize.nTop);
541         }
542 
set_unique_id(const char * uid)543         status_t LSPWidget::set_unique_id(const char *uid)
544         {
545             char *rep = NULL;
546             if (uid != NULL)
547             {
548                 if ((rep = strdup(uid)) == NULL)
549                     return STATUS_NO_MEM;
550             }
551 
552             if (pUID != NULL)
553                 free(pUID);
554             pUID = rep;
555             return STATUS_OK;
556         }
557 
get_surface(ISurface * s)558         ISurface *LSPWidget::get_surface(ISurface *s)
559         {
560             return get_surface(s, sSize.nWidth, sSize.nHeight);
561         }
562 
get_surface(ISurface * s,ssize_t width,ssize_t height)563         ISurface *LSPWidget::get_surface(ISurface *s, ssize_t width, ssize_t height)
564         {
565             // Check surface
566             if (pSurface != NULL)
567             {
568                 if ((width != ssize_t(pSurface->width())) || (height != ssize_t(pSurface->height())))
569                 {
570                     pSurface->destroy();
571                     delete pSurface;
572                     pSurface    = NULL;
573                 }
574             }
575 
576             // Create new surface if needed
577             if (pSurface == NULL)
578             {
579                 if (s == NULL)
580                     return NULL;
581 
582                 // Do not return surface if size is negative
583                 if ((width <= 0) || (height <= 0))
584                     return NULL;
585 
586                 pSurface        = s->create(width, height);
587                 if (pSurface == NULL)
588                     return NULL;
589                 nFlags         |= REDRAW_SURFACE;
590             }
591 
592             // Redraw surface if required
593             if (nFlags & REDRAW_SURFACE)
594             {
595                 draw(pSurface);
596                 nFlags         &= ~REDRAW_SURFACE;
597             }
598 
599             return pSurface;
600         }
601 
draw(ISurface * s)602         void LSPWidget::draw(ISurface *s)
603         {
604         }
605 
realize(const realize_t * r)606         void LSPWidget::realize(const realize_t *r)
607         {
608             // Do not report size request on size change
609             if ((sSize.nLeft == r->nLeft) &&
610                 (sSize.nTop  == r->nTop) &&
611                 (sSize.nWidth == r->nWidth) &&
612                 (sSize.nHeight == r->nHeight))
613                 return;
614 
615             // Execute slot and update size
616             realize_t xr = *r;
617             sSlots.execute(LSPSLOT_RESIZE, this, &xr);
618             sSize       = *r;
619         }
620 
size_request(size_request_t * r)621         void LSPWidget::size_request(size_request_t *r)
622         {
623             r->nMinWidth    = -1;
624             r->nMinHeight   = -1;
625             r->nMaxWidth    = -1;
626             r->nMaxHeight   = -1;
627         }
628 
has_focus() const629         bool LSPWidget::has_focus() const
630         {
631             if (!(nFlags & F_VISIBLE))
632                 return false;
633 
634             LSPWidget *_this = const_cast<LSPWidget *>(this);
635             LSPWindow *wnd = widget_cast<LSPWindow>(_this->toplevel());
636             return (wnd != NULL) ? (wnd->focused_child() == this) : false;
637         }
638 
set_focus(bool focus)639         status_t LSPWidget::set_focus(bool focus)
640         {
641             if (!(nFlags & F_VISIBLE))
642                 return STATUS_OK;
643 
644             LSPWindow *wnd = widget_cast<LSPWindow>(toplevel());
645             if (wnd == NULL)
646                 return STATUS_BAD_HIERARCHY;
647             return (focus) ? wnd->focus_child(this) : wnd->unfocus_child(this);
648         }
649 
toggle_focus()650         status_t LSPWidget::toggle_focus()
651         {
652             if (!(nFlags & F_VISIBLE))
653                 return STATUS_OK;
654 
655             LSPWindow *wnd = widget_cast<LSPWindow>(toplevel());
656             return (wnd != NULL) ? wnd->toggle_child_focus(this) : STATUS_BAD_HIERARCHY;
657         }
658 
mark_pointed()659         status_t LSPWidget::mark_pointed()
660         {
661             LSPWindow *wnd = widget_cast<LSPWindow>(toplevel());
662             if (wnd == NULL)
663                 return STATUS_SUCCESS;
664             return wnd->point_child(this);
665         }
666 
handle_event(const ws_event_t * e)667         status_t LSPWidget::handle_event(const ws_event_t *e)
668         {
669             #define FWD_EVENT(ev, slot_id) \
670                 case ev: \
671                 { \
672                     ws_event_t tmp = *e; \
673                     sSlots.execute(slot_id, this, &tmp); \
674                     break; \
675                 }
676 
677             switch (e->nType)
678             {
679                 FWD_EVENT(UIE_KEY_DOWN, LSPSLOT_KEY_DOWN )
680                 FWD_EVENT(UIE_KEY_UP, LSPSLOT_KEY_UP )
681                 FWD_EVENT(UIE_MOUSE_DOWN, LSPSLOT_MOUSE_DOWN )
682                 FWD_EVENT(UIE_MOUSE_UP, LSPSLOT_MOUSE_UP )
683                 FWD_EVENT(UIE_MOUSE_IN, LSPSLOT_MOUSE_IN )
684                 FWD_EVENT(UIE_MOUSE_OUT, LSPSLOT_MOUSE_OUT )
685                 FWD_EVENT(UIE_MOUSE_MOVE, LSPSLOT_MOUSE_MOVE )
686                 FWD_EVENT(UIE_MOUSE_SCROLL, LSPSLOT_MOUSE_SCROLL )
687                 FWD_EVENT(UIE_MOUSE_DBL_CLICK, LSPSLOT_MOUSE_DBL_CLICK )
688                 FWD_EVENT(UIE_MOUSE_TRI_CLICK, LSPSLOT_MOUSE_TRI_CLICK )
689                 FWD_EVENT(UIE_FOCUS_IN, LSPSLOT_FOCUS_IN )
690                 FWD_EVENT(UIE_FOCUS_OUT, LSPSLOT_FOCUS_OUT )
691                 FWD_EVENT(UIE_DRAG_REQUEST, LSPSLOT_DRAG_REQUEST )
692 
693                 default:
694                     break;
695             }
696             #undef FWD_EVENT
697 
698             return STATUS_OK;
699         }
700 
destroy()701         void LSPWidget::destroy()
702         {
703             do_destroy();
704         }
705 
on_key_down(const ws_event_t * e)706         status_t LSPWidget::on_key_down(const ws_event_t *e)
707         {
708             return STATUS_OK;
709         }
710 
on_key_up(const ws_event_t * e)711         status_t LSPWidget::on_key_up(const ws_event_t *e)
712         {
713             return STATUS_OK;
714         }
715 
on_mouse_down(const ws_event_t * e)716         status_t LSPWidget::on_mouse_down(const ws_event_t *e)
717         {
718             return STATUS_OK;
719         }
720 
on_mouse_up(const ws_event_t * e)721         status_t LSPWidget::on_mouse_up(const ws_event_t *e)
722         {
723             return STATUS_OK;
724         }
725 
on_mouse_move(const ws_event_t * e)726         status_t LSPWidget::on_mouse_move(const ws_event_t *e)
727         {
728             return STATUS_OK;
729         }
730 
on_mouse_in(const ws_event_t * e)731         status_t LSPWidget::on_mouse_in(const ws_event_t *e)
732         {
733             // Always mark widget pointed
734             return mark_pointed();
735         }
736 
on_mouse_out(const ws_event_t * e)737         status_t LSPWidget::on_mouse_out(const ws_event_t *e)
738         {
739             return STATUS_OK;
740         }
741 
on_mouse_scroll(const ws_event_t * e)742         status_t LSPWidget::on_mouse_scroll(const ws_event_t *e)
743         {
744             return STATUS_OK;
745         }
746 
on_mouse_dbl_click(const ws_event_t * e)747         status_t LSPWidget::on_mouse_dbl_click(const ws_event_t *e)
748         {
749             return STATUS_OK;
750         }
751 
on_mouse_tri_click(const ws_event_t * e)752         status_t LSPWidget::on_mouse_tri_click(const ws_event_t *e)
753         {
754             return STATUS_OK;
755         }
756 
on_resize(const realize_t * r)757         status_t LSPWidget::on_resize(const realize_t *r)
758         {
759             return STATUS_OK;
760         }
761 
on_resize_parent(const realize_t * r)762         status_t LSPWidget::on_resize_parent(const realize_t *r)
763         {
764             return STATUS_OK;
765         }
766 
on_hide()767         status_t LSPWidget::on_hide()
768         {
769             return STATUS_OK;
770         }
771 
on_show()772         status_t LSPWidget::on_show()
773         {
774             return STATUS_OK;
775         }
776 
on_destroy()777         status_t LSPWidget::on_destroy()
778         {
779             return STATUS_OK;
780         }
781 
on_focus_in(const ws_event_t * e)782         status_t LSPWidget::on_focus_in(const ws_event_t *e)
783         {
784             return STATUS_OK;
785         }
786 
on_focus_out(const ws_event_t * e)787         status_t LSPWidget::on_focus_out(const ws_event_t *e)
788         {
789             return STATUS_OK;
790         }
791 
on_drag_request(const ws_event_t * e,const char * const * ctype)792         status_t LSPWidget::on_drag_request(const ws_event_t *e, const char * const *ctype)
793         {
794             return STATUS_OK;
795         }
796     }
797 
798 } /* namespace lsp */
799