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 #ifndef UI_TK_LSPWIDGET_H_
23 #define UI_TK_LSPWIDGET_H_
24 
25 namespace lsp
26 {
27     namespace tk
28     {
29         class LSPComplexWidget;
30 
31         /** Basic widget class for any widget in the toolkit
32          *
33          */
34         class LSPWidget: public ws::IEventHandler
35         {
36             public:
37                 static const w_class_t    metadata;
38 
39             protected:
40                 enum flags_t
41                 {
42                     REDRAW_SURFACE  = 1 << 0,       // Need to redraw surface
43                     REDRAW_CHILD    = 1 << 1,       // Need to redraw child only
44                     F_VISIBLE       = 1 << 2,       // Widget is visible
45                     F_REALIZED      = 1 << 3,       // Widget is realized
46                     F_EXPAND        = 1 << 4,       // Area for the widget should be expanded
47                     F_HFILL         = 1 << 5,       // Widget should desirable fill all the provided area horizontally
48                     F_VFILL         = 1 << 6,       // Widget should desirable fill all the provided area vertically
49                 };
50 
51             protected:
52                 char               *pUID;           // Unique widget identifier
53 
54                 LSPDisplay         *pDisplay;
55                 ISurface           *pSurface;
56 
57                 LSPComplexWidget   *pParent;
58                 const w_class_t    *pClass;
59 
60                 realize_t           sSize;          // Geometry
61                 size_t              nFlags;         // Flags
62                 mouse_pointer_t     enCursor;
63 
64                 LSPSlotSet          sSlots;         // Slots
65                 LSPPadding          sPadding;
66 
67                 LSPColor            sBgColor;       // Widget color
68                 LSPFloat            sBrightness;    // Brightness
69                 LSPStyle            sStyle;         // Style
70 
71             //---------------------------------------------------------------------------------
72             // Slot handlers
73             protected:
74                 static status_t slot_mouse_move(LSPWidget *sender, void *ptr, void *data);
75                 static status_t slot_mouse_down(LSPWidget *sender, void *ptr, void *data);
76                 static status_t slot_mouse_up(LSPWidget *sender, void *ptr, void *data);
77                 static status_t slot_mouse_dbl_click(LSPWidget *sender, void *ptr, void *data);
78                 static status_t slot_mouse_tri_click(LSPWidget *sender, void *ptr, void *data);
79                 static status_t slot_mouse_scroll(LSPWidget *sender, void *ptr, void *data);
80                 static status_t slot_mouse_in(LSPWidget *sender, void *ptr, void *data);
81                 static status_t slot_mouse_out(LSPWidget *sender, void *ptr, void *data);
82                 static status_t slot_key_down(LSPWidget *sender, void *ptr, void *data);
83                 static status_t slot_key_up(LSPWidget *sender, void *ptr, void *data);
84                 static status_t slot_hide(LSPWidget *sender, void *ptr, void *data);
85                 static status_t slot_show(LSPWidget *sender, void *ptr, void *data);
86                 static status_t slot_destroy(LSPWidget *sender, void *ptr, void *data);
87                 static status_t slot_resize(LSPWidget *sender, void *ptr, void *data);
88                 static status_t slot_resize_parent(LSPWidget *sender, void *ptr, void *data);
89                 static status_t slot_focus_in(LSPWidget *sender, void *ptr, void *data);
90                 static status_t slot_focus_out(LSPWidget *sender, void *ptr, void *data);
91                 static status_t slot_drag_request(LSPWidget *sender, void *ptr, void *data);
92 
93             //---------------------------------------------------------------------------------
94             // Interface for nested classes
95             protected:
96                 void            do_destroy();
97 
98                 void            unlink_widget(LSPWidget *widget);
99 
100                 void            init_color(color_t value, LSPColor *color);
101 
102             //---------------------------------------------------------------------------------
103             // Construction and destruction
104             public:
105                 explicit LSPWidget(LSPDisplay *dpy);
106                 virtual ~LSPWidget();
107 
108                 /** Initialize wiget
109                  *
110                  */
111                 virtual status_t init();
112 
113                 /** Destroy widget
114                  *
115                  */
116                 virtual void destroy();
117 
118             //---------------------------------------------------------------------------------
119             // Metadata, casting and type information
120             public:
121                 /** Get widget class
122                  *
123                  * @return actual widget class metadata
124                  */
get_class()125                 inline const w_class_t *get_class() const { return pClass; }
126 
127                 /** Check wheter the widget is instance of some class
128                  *
129                  * @param wclass widget class
130                  * @return true if widget is instance of some class
131                  */
132                 bool instance_of(const w_class_t *wclass) const;
133 
instance_of(const w_class_t & wclass)134                 inline bool instance_of(const w_class_t &wclass) const { return instance_of(&wclass); }
135 
136                 /** Another way to check if widget is instance of some class
137                  *
138                  * @return true if widget is instance of some class
139                  */
140                 template <class LSPTarget>
instance_of()141                     inline bool instance_of() const { return instance_of(&LSPTarget::metadata); };
142 
143                 /** Cast widget to another type
144                  *
145                  * @return pointer to widget or NULL if cast failed
146                  */
147                 template <class LSPTarget>
cast()148                     inline LSPTarget *cast() { return instance_of(&LSPTarget::metadata) ? static_cast<LSPTarget *>(this) : NULL; }
149 
150                 /** Cast widget to another type
151                  *
152                  * @return pointer to widget or NULL if cast failed
153                  */
154                 template <class LSPTarget>
cast()155                     inline const LSPTarget *cast() const { return instance_of(&LSPTarget::metadata) ? static_cast<const LSPTarget *>(this) : NULL; }
156 
157                 /** Get pointer to self as pointer to LSPWidget class
158                  *
159                  * @return pointer to self
160                  */
self()161                 inline LSPWidget *self()              { return this;  }
162 
163             //---------------------------------------------------------------------------------
164             // Properties
165             public:
166                 /** Get display
167                  *
168                  * @return display
169                  */
display()170                 inline LSPDisplay *display()        { return pDisplay; };
171 
172                 /** Get horizontal coordinate of the left top corner
173                  *
174                  * @return coordinate of the left corner
175                  */
left()176                 inline ssize_t left() const         { return sSize.nLeft;       };
177 
178                 /** Get horizontal coordinate of the right bottom corner
179                  *
180                  * @return value
181                  */
right()182                 inline ssize_t right() const        { return sSize.nLeft + sSize.nWidth;    };
183 
184                 /** Get vertical coordinate of the left top corner
185                  *
186                  * @return value
187                  */
top()188                 inline ssize_t top() const          { return sSize.nTop;        };
189 
190                 /** Get vertical coordinate of the right bottom corner
191                  *
192                  * @return value
193                  */
bottom()194                 inline ssize_t bottom() const       { return sSize.nTop + sSize.nHeight;     };
195 
196                 /** Get width of the widget
197                  *
198                  * @return width of the widget
199                  */
width()200                 inline ssize_t width() const        { return sSize.nWidth;      };
201 
202                 /** Get height of the widget
203                  *
204                  * @return height of the widget
205                  */
height()206                 inline ssize_t height() const       { return sSize.nHeight;     };
207 
208                 /** Get widget dimensions
209                  *
210                  * @param r real widget dimensions
211                  */
get_dimensions(realize_t * r)212                 inline void get_dimensions(realize_t *r) { *r = sSize; }
213 
214                 /** Check if there is redraw request pending
215                  *
216                  * @return true if there is redraw request pending
217                  */
redraw_pending()218                 inline bool redraw_pending() const  { return nFlags & (REDRAW_SURFACE | REDRAW_CHILD); };
219 
220                 /** Check that widget is visible
221                  *
222                  * @return true if widget is visible
223                  */
visible()224                 inline bool visible() const         { return nFlags & F_VISIBLE; };
225 
226                 /** Check that widget is hidden
227                  *
228                  * @return true if widget is visible
229                  */
hidden()230                 inline bool hidden() const          { return !(nFlags & F_VISIBLE); };
invisible()231                 inline bool invisible() const       { return !(nFlags & F_VISIBLE); };
232 
233                 /** Get expanding flag: true if container should desirable expand area provided for the widget
234                  *
235                  * @return expanding flag
236                  */
expand()237                 inline bool expand() const          { return nFlags & F_EXPAND; }
238 
239                 /** Get fill flag: true if container should desirable fill all provided area with widget
240                  *
241                  * @return fill flag
242                  */
fill()243                 inline bool fill() const            { return (nFlags & (F_HFILL | F_VFILL)) == (F_HFILL | F_VFILL); }
244 
245                 /** Get horizontal fill flag: true if container should horizontally fill all provided area with widget
246                  *
247                  * @return horizontal fill flag
248                  */
hfill()249                 inline bool hfill() const           { return nFlags & F_HFILL; }
250 
251                 /** Get vertical fill flag: true if container should vertically fill all provided area with widget
252                  *
253                  * @return vertical fill flag
254                  */
vfill()255                 inline bool vfill() const           { return nFlags & F_VFILL; }
256 
257                 /** Check that widget has focus
258                  *
259                  * @return widget focus
260                  */
261                 virtual bool has_focus() const;
262 
263                 /** Check that widget has focus
264                  *
265                  * @return widget focus
266                  */
focused()267                 inline bool focused() const         { return has_focus(); };
268 
269                 /** Check that widget is visible
270                  *
271                  * @return true if widget is visible
272                  */
is_visible()273                 inline bool is_visible() const      { return nFlags & F_VISIBLE; };
274 
275                 /** Check that widget is realized
276                  *
277                  * @return true if widget is realized
278                  */
is_realized()279                 inline bool is_realized() const     { return nFlags & F_REALIZED; };
280 
281                 /** Get horizontal coordinate of the left top corner relative to the parent widget
282                  *
283                  * @return the value
284                  */
285                 ssize_t relative_left() const;
286 
287                 /** Get horizontal coordinate of the right bottom corner relative to the parent widget
288                  *
289                  * @return the value
290                  */
291                 ssize_t relative_right() const;
292 
293                 /** Get vertical coordinate of the left top corner relative to the parent widget
294                  *
295                  * @return the value
296                  */
297                 ssize_t relative_top() const;
298 
299                 /** Get vertical coordinate of the right bottom corner relative to the parent widget
300                  *
301                  * @return the value
302                  */
303                 ssize_t relative_bottom() const;
304 
305                 /**
306                  * Get unique widget identifier for DOM search
307                  * @return unique widget identifier for DOM search
308                  */
unique_id()309                 inline const char *unique_id() const {  return pUID;    }
310 
311                 /** Check that specified window coordinate lies within widget's bounds
312                  * Always returns false for invisible widgets
313                  *
314                  * @param x x coordinate
315                  * @param y y coordinate
316                  * @return true on success
317                  */
318                 virtual bool inside(ssize_t x, ssize_t y);
319 
320                 /** Get parent widget
321                  *
322                  * @return parent widget
323                  */
parent()324                 inline LSPComplexWidget *parent()           { return pParent; }
325 
326                 /** Get slots
327                  *
328                  * @return slots
329                  */
slots()330                 inline LSPSlotSet *slots()                  { return &sSlots; }
331 
332                 /** Get slot
333                  *
334                  * @param id slot identifier
335                  * @return pointer to slot or NULL
336                  */
slot(ui_slot_t id)337                 inline LSPSlot *slot(ui_slot_t id)          { return sSlots.slot(id); }
338 
339                 /** Get mouse pointer
340                  *
341                  * @return mouse pointer
342                  */
cursor()343                 inline mouse_pointer_t cursor() const       { return enCursor; }
344 
345                 /** Get active curstor
346                  *
347                  * @return active cursor
348                  */
349                 virtual mouse_pointer_t active_cursor() const;
350 
351                 /** Get widget padding
352                  *
353                  * @return widget padding
354                  */
padding()355                 inline LSPPadding  *padding()               { return &sPadding; };
356 
357                 /**
358                  * Get background color of the widget
359                  * @return background color of the widget
360                  */
bg_color()361                 inline LSPColor    *bg_color()              { return &sBgColor;     }
362 
363                 /**
364                  * Return widget's style
365                  * @return widget's style
366                  */
style()367                 inline LSPStyle    *style()                 { return &sStyle; }
368 
369                 /**
370                  * Get brightness
371                  * @return brightness
372                  */
brightness()373                 inline float        brightness() const      { return sBrightness.get(); }
374 
375             //---------------------------------------------------------------------------------
376             // Manipulation
377             public:
378                 /**
379                  * Set unique widget identifier for DOM search
380                  * @param uid unique widget identifier for DOM search
381                  * @return status of operation
382                  */
383                 status_t            set_unique_id(const char *uid);
384 
385                 /** Query widget for redraw
386                  *
387                  * @param flags redraw flags
388                  */
389                 virtual void        query_draw(size_t flags = REDRAW_SURFACE);
390 
391                 /**
392                  * Put the widget to the destroy queue of the main loop
393                  * @return status of operation
394                  */
395                 virtual status_t    queue_destroy();
396 
397                 /** Query widget for resize
398                  *
399                  */
400                 virtual void        query_resize();
401 
402                 /** Set expanding flag
403                  *
404                  * @param value expanding flag value
405                  */
406                 virtual void        set_expand(bool value = true);
407 
408                 /** Set fill flag
409                  *
410                  * @param value filling flag value
411                  */
412                 virtual void        set_fill(bool value = true);
413 
414                 /** Set horizontal fill flag
415                  *
416                  * @param value horizontal filling flag value
417                  */
418                 virtual void        set_hfill(bool value = true);
419 
420                 /** Set vertical fill flag
421                  *
422                  * @param value vertical filling flag value
423                  */
424                 virtual void        set_vfill(bool value = true);
425 
426                 /**
427                  * Set brightness of the widget
428                  * @param brightness brightness
429                  * @return previous value
430                  */
set_brightness(float brightness)431                 inline float        set_brightness(float brightness) { return sBrightness.set(brightness); }
432 
433                 /** Set mouse pointer
434                  *
435                  * @param mp mouse pointer
436                  * @return mouse pointer
437                  */
438                 virtual status_t    set_cursor(mouse_pointer_t mp);
439 
440                 /** Get widget surface
441                  *
442                  * @param s base surface
443                  * @return widget surface or NULL
444                  */
445                 ISurface           *get_surface(ISurface *s);
446 
447                 /** Get widget surface
448                  *
449                  * @param s base surface
450                  * @param width requested width
451                  * @param height requested height
452                  * @return widget surface or NULL
453                  */
454                 ISurface           *get_surface(ISurface *s, ssize_t width, ssize_t height);
455 
456                 /** Render widget to the external surface
457                  *
458                  * @param surface surface to perform rendering
459                  * @param force force child rendering
460                  */
461                 virtual void        render(ISurface *s, bool force);
462 
463                 /** Draw widget on the internal surface
464                  *
465                  * @param surface surface to perform drawing
466                  */
467                 virtual void        draw(ISurface *s);
468 
469                 /** Realize widget
470                  *
471                  * @param r widget realization parameters
472                  */
473                 virtual void        realize(const realize_t *r);
474 
475                 /** Request for size
476                  *
477                  * @param r minimum and maximum dimensions of the widget
478                  */
479                 virtual void        size_request(size_request_t *r);
480 
481                 /** Hide widget
482                  *
483                  */
484                 virtual bool        hide();
485 
486                 /** Show widget
487                  *
488                  */
489                 virtual bool        show();
490 
491                 /** Set widget visibility
492                  *
493                  * @param visible widget visibility
494                  */
495                 virtual void        set_visible(bool visible=true);
496 
497                 /** Set focus on widget
498                  *
499                  * @param focus focusing parameter
500                  * @return status of operation
501                  */
502                 virtual status_t    set_focus(bool focus = true);
503 
504                 /** Kill focus on widget
505                  *
506                  * @return status of operation
507                  */
kill_focus()508                 inline status_t     kill_focus() { return set_focus(false); };
509 
510                 /** Kill focus on widget
511                  *
512                  * @return status of operation
513                  */
take_focus()514                 inline status_t     take_focus() { return set_focus(true); };
515 
516                 /** Mark this widget to be currently pointed by mouse
517                  *
518                  * @return status of operation
519                  */
520                 status_t            mark_pointed();
521 
522                 /** Invert focus
523                  *
524                  * @return status of operation
525                  */
526                 virtual status_t    toggle_focus();
527 
528                 /** Set widget invisibility
529                  *
530                  * @param invisible widget invisibility
531                  */
532                 inline void         set_invisible(bool invisible=true) { set_visible(!invisible); }
533 
534                 /** Handle UI event from the display
535                  *
536                  * @param e UI event
537                  * @return status of operation
538                  */
539                 virtual status_t    handle_event(const ws_event_t *e);
540 
541                 /** Set parent widget of this widget
542                  *
543                  * @param parent parent widget
544                  */
545                 void                set_parent(LSPComplexWidget *parent);
546 
547                 /** Commit widet redraw
548                  *
549                  */
550                 virtual void        commit_redraw();
551 
552                 /** Get most top-level widget
553                  *
554                  * @return most top-level widget
555                  */
556                 LSPWidget          *toplevel();
557 
558             //---------------------------------------------------------------------------------
559             // Event handling
560             public:
561                 /** Widget has taken focus
562                  *
563                  * @param e event
564                  * @return status of operation
565                  */
566                 virtual status_t on_focus_in(const ws_event_t *e);
567 
568                 /** Widget has lost focus
569                  *
570                  * @param e event
571                  * @return status of operation
572                  */
573                 virtual status_t on_focus_out(const ws_event_t *e);
574 
575                 /** Handle key press event
576                  * @param e event
577                  * @return status of operation
578                  */
579                 virtual status_t on_key_down(const ws_event_t *e);
580 
581                 /** Handle key release event
582                  * @param e event
583                  * @return status of operation
584                  */
585                 virtual status_t on_key_up(const ws_event_t *e);
586 
587                 /** Handle mouse button press event
588                  * @param e event
589                  * @return status of operation
590                  */
591                 virtual status_t on_mouse_down(const ws_event_t *e);
592 
593                 /** Handle mouse button release event
594                  * @param e event
595                  * @return status of operation
596                  */
597                 virtual status_t on_mouse_up(const ws_event_t *e);
598 
599                 /** Handle mouse motion event
600                  * @param e event
601                  * @return status of operation
602                  */
603                 virtual status_t on_mouse_move(const ws_event_t *e);
604 
605                 /** Handle mouse cursor moved into the zone of widget
606                  *
607                  * @param e mouse event that triggered MouseIn
608                  * @return status of operation
609                  */
610                 virtual status_t on_mouse_in(const ws_event_t *e);
611 
612                 /** Handle mouse cursor moved outside the zone of widget
613                  *
614                  * @param e mouse event that triggered MouseIn
615                  * @return status of operation
616                  */
617                 virtual status_t on_mouse_out(const ws_event_t *e);
618 
619                 /** Handle mouse scroll event
620                  *
621                  * @param e event
622                  * @return status of operation
623                  */
624                 virtual status_t on_mouse_scroll(const ws_event_t *e);
625 
626                 /** Handle mouse double click event
627                  *
628                  * @param e event
629                  * @return status of operation
630                  */
631                 virtual status_t on_mouse_dbl_click(const ws_event_t *e);
632 
633                 /** Handle mouse triple click
634                  *
635                  * @param e event
636                  * @return status of operation
637                  */
638                 virtual status_t on_mouse_tri_click(const ws_event_t *e);
639 
640                 /** Geometry has changed: size or position
641                  *
642                  * @param e event
643                  * @return status of operation
644                  */
645                 virtual status_t on_resize(const realize_t *r);
646 
647                 /** Geometry of parent widget has changed: size or position
648                  *
649                  * @param e event
650                  * @return status of operation
651                  */
652                 virtual status_t on_resize_parent(const realize_t *r);
653 
654                 /** The widget becomes hidden
655                  *
656                  * @return status of operation
657                  */
658                 virtual status_t on_hide();
659 
660                 /** The widget becomes visible
661                  *
662                  * @return status of operation
663                  */
664                 virtual status_t on_show();
665 
666                 /** The widget becomes destroyed
667                  *
668                  * @return status of operation
669                  */
670                 virtual status_t on_destroy();
671 
672                 /**
673                  * Process the drag request event
674                  * @param e drag request event
675                  * @param ctype NULL-terminated list of provided content types
676                  * @return status of operation
677                  */
678                 virtual status_t on_drag_request(const ws_event_t *e, const char * const *ctype);
679         };
680 
681         template <class LSPTarget>
widget_cast(LSPWidget * src)682             inline LSPTarget *widget_cast(LSPWidget *src)
683             {
684                 return ((src != NULL) && (src->instance_of(&LSPTarget::metadata))) ? static_cast<LSPTarget *>(src) : NULL;
685             }
686 
687         template <class LSPTarget>
widget_cast(const LSPWidget * src)688             inline const LSPTarget *widget_cast(const LSPWidget *src)
689             {
690                 return ((src != NULL) && (src->instance_of(&LSPTarget::metadata))) ? static_cast<const LSPTarget *>(src) : NULL;
691             }
692 
693         template <class LSPTarget>
widget_ptrcast(void * src)694             inline LSPTarget *widget_ptrcast(void *src)
695             {
696                 LSPWidget *w = (src != NULL) ? static_cast<LSPWidget *>(src) : NULL;
697                 return ((w != NULL) && (w->instance_of(&LSPTarget::metadata))) ? static_cast<LSPTarget *>(w) : NULL;
698             }
699 
700         template <class LSPTarget>
widget_ptrcast(const void * src)701             inline const LSPTarget *widget_ptrcast(const void *src)
702             {
703                 const LSPWidget *w = (src != NULL) ? static_cast<const LSPWidget *>(src) : NULL;
704                 return ((w != NULL) && (w->instance_of(&LSPTarget::metadata))) ? static_cast<const LSPTarget *>(w) : NULL;
705             }
706     }
707 
708 } /* namespace lsp */
709 
710 #endif /* UI_TK_LSPWIDGET_H_ */
711