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: 1 окт. 2019 г.
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_SYS_LSPSTYLE_H_
23 #define UI_TK_SYS_LSPSTYLE_H_
24 
25 namespace lsp
26 {
27     namespace tk
28     {
29         /**
30          * Style Listener
31          */
32         class IStyleListener
33         {
34             public:
35                 virtual ~IStyleListener();
36 
37             public:
38                 /**
39                  * Notify about property value change
40                  * @param property property identifier
41                  */
42                 virtual void notify(ui_atom_t property);
43         };
44 
45         /**
46          * Some widget style. Allows nesting
47          */
48         class LSPStyle
49         {
50             protected:
51                 enum flags_t
52                 {
53                     F_DEFAULT           = 1 << 0,
54                     F_NTF_LISTENERS     = 1 << 1,
55                     F_NTF_CHILDREN      = 1 << 2
56                 };
57 
58                 typedef struct property_t
59                 {
60                     ui_atom_t           id;         // Unique identifier of property
61                     ssize_t             type;       // Type of property
62                     size_t              refs;       // Number of references
63                     size_t              changes;    // Number of changes
64                     size_t              flags;      // Flags
65                     LSPStyle           *owner;      // Style that is owning a property
66                     union
67                     {
68                         ssize_t     iValue;
69                         float       fValue;
70                         bool        bValue;
71                         char       *sValue;
72                     } v;
73                 } property_t;
74 
75                 typedef struct listener_t
76                 {
77                     ui_atom_t           nId;        // Property identifier
78                     IStyleListener     *pListener;  // Listener
79                 } listener_t;
80 
81             private:
82                 cvector<LSPStyle>       vParents;
83                 cvector<LSPStyle>       vChildren;
84                 cstorage<property_t>    vProperties;
85                 cstorage<listener_t>    vListeners;
86                 ssize_t                 nLock;
87                 bool                    bDelayed;
88 
89             public:
90                 explicit LSPStyle();
91                 virtual ~LSPStyle();
92 
93                 status_t            init();
94                 void                destroy();
95 
96             protected:
97                 void                undef_property(property_t *property);
98                 void                do_destroy();
99                 void                delayed_notify();
100                 property_t         *get_property_recursive(ui_atom_t id);
101                 property_t         *get_parent_property(ui_atom_t id);
102                 property_t         *get_property(ui_atom_t id);
103                 status_t            set_property(ui_atom_t id, property_t *src);
104                 status_t            sync_property(property_t *p);
105                 property_t         *create_property(ui_atom_t id, const property_t *src);
106                 property_t         *create_property(ui_atom_t id, ui_property_type_t type);
107                 status_t            set_property_default(property_t *dst);
108                 status_t            copy_property(property_t *dst, const property_t *src);
109 
get_property(ui_atom_t id)110                 inline const property_t   *get_property(ui_atom_t id) const { return const_cast<LSPStyle *>(this)->get_property(id); };
get_property_recursive(ui_atom_t id)111                 inline const property_t   *get_property_recursive(ui_atom_t id) const { return const_cast<LSPStyle *>(this)->get_property_recursive(id); };
112 
113                 void                sync();
114                 void                notify_change(property_t *prop);
115                 void                notify_children(property_t *prop);
116                 void                notify_listeners(property_t *prop);
117 
118             public:
119                 /**
120                  * Get number of parent styles
121                  * @return number of parent styles
122                  */
parents()123                 inline size_t       parents() const     { return vParents.size();   }
124 
125                 /**
126                  * Get parent style
127                  * @param idx sequential number of parent style starting with 0
128                  * @return parent style or NULL if does not exist
129                  */
parent(size_t idx)130                 inline LSPStyle    *parent(size_t idx)  { return vParents.get(idx); };
131 
132                 /**
133                  * Set parent style
134                  * @param parent parent style
135                  * @param idx parent index, negative value means last
136                  * @return status of operation
137                  */
138                 status_t            add_parent(LSPStyle *parent, ssize_t idx = -1);
139 
140                 /**
141                  * Remove the parent style
142                  * @param parent parent style to remove
143                  * @return status of operation
144                  */
145                 status_t            remove_parent(LSPStyle *parent);
146 
147                 /**
148                  * Check whether style has a parent
149                  * @param parent parent style
150                  * @param recursive flag that indicates that a recursive search should be performed
151                  * @return true if style has a parent
152                  */
153                 bool                has_parent(LSPStyle *parent, bool recursive = false);
154 
155                 /**
156                  * Get number of child styles
157                  * @return number of child styles
158                  */
children()159                 inline size_t       children() const    { return vChildren.size();   }
160 
161                 /**
162                  * Get child style
163                  * @param idx sequential number of child style starting with 0
164                  * @return child style or NULL if does not exist
165                  */
child(size_t idx)166                 inline LSPStyle    *child(size_t idx)  { return vChildren.get(idx); };
167 
168                 /**
169                  * Add child style
170                  * @param child child style
171                  * @param idx child index, negative value means last
172                  * @return status of operation
173                  */
174                 status_t            add_child(LSPStyle *child, ssize_t idx = -1);
175 
176                 /** Remove child style
177                  *
178                  * @param child child style to remove
179                  * @return status of operation
180                  */
181                 status_t            remove_child(LSPStyle *child);
182 
183                 /**
184                  * Check whether style has a child
185                  * @param child child style
186                  * @param recursive flag that indicates that a recursive search should be performed
187                  * @return true if style has a child
188                  */
189                 bool                has_child(LSPStyle *child, bool recursive = false);
190 
191             public:
192                 /**
193                  * Bind listener to property
194                  * @param id property identifier
195                  * @return status of operation
196                  */
197                 status_t            bind(ui_atom_t id, ui_property_type_t type, IStyleListener *listener);
198 
bind_int(ui_atom_t id,IStyleListener * listener)199                 inline status_t     bind_int(ui_atom_t id, IStyleListener *listener)        { return bind(id, PT_INT, listener); };
bind_float(ui_atom_t id,IStyleListener * listener)200                 inline status_t     bind_float(ui_atom_t id, IStyleListener *listener)      { return bind(id, PT_FLOAT, listener); };
bind_bool(ui_atom_t id,IStyleListener * listener)201                 inline status_t     bind_bool(ui_atom_t id, IStyleListener *listener)       { return bind(id, PT_BOOL, listener); };
bind_string(ui_atom_t id,IStyleListener * listener)202                 inline status_t     bind_string(ui_atom_t id, IStyleListener *listener)     { return bind(id, PT_STRING, listener); };
203 
204                 /**
205                  * Check that listener is already bound to the property
206                  * @param id property identifier
207                  * @param listener listener
208                  * @return true if listener is bound
209                  */
210                 bool                is_bound(ui_atom_t id, IStyleListener *listener) const;
211 
212                 /**
213                  * Unbind listener from a property
214                  * @param id property identifier
215                  * @param listener property listener
216                  * @return status of operation
217                  */
218                 status_t            unbind(ui_atom_t id, IStyleListener *listener);
219 
220             public:
221                 /**
222                  * Return overall number of properties
223                  * @return overall number of properties
224                  */
properties()225                 inline size_t       properties() const  { return vProperties.size(); }
226 
227                 /**
228                  * Return overall number of listeners
229                  * @return overall number of listeners
230                  */
listeners()231                 inline size_t       listeners() const   { return vListeners.size(); }
232 
233             public:
234                 /**
235                  * Start transactional update of properties.
236                  * All listeners and children will be notified
237                  * only after transaction becomes completed
238                  */
239                 void                begin();
240 
241                 /**
242                  * End transactional update of properties.
243                  * All listeners and children will be notified
244                  */
245                 void                end();
246 
247                 status_t            get_int(ui_atom_t id, ssize_t *dst) const;
248                 status_t            get_float(ui_atom_t id, float *dst) const;
249                 status_t            get_bool(ui_atom_t id, bool *dst) const;
250                 status_t            get_string(ui_atom_t id, LSPString *dst) const;
251                 status_t            get_string(ui_atom_t id, const char **dst) const;
252                 bool                exists(ui_atom_t id) const;
253                 bool                is_default(ui_atom_t id) const;
254                 ssize_t             get_type(ui_atom_t id) const;
255 
256                 status_t            set_int(ui_atom_t id, ssize_t value);
257                 status_t            set_float(ui_atom_t id, float value);
258                 status_t            set_bool(ui_atom_t id, bool value);
259                 status_t            set_string(ui_atom_t id, const LSPString *value);
260                 status_t            set_string(ui_atom_t id, const char *value);
261                 status_t            set_default(ui_atom_t id);
262         };
263 
264     } /* namespace tk */
265 } /* namespace lsp */
266 
267 #endif /* UI_TK_SYS_LSPSTYLE_H_ */
268