1 /* B.Jumblr
2  * Pattern-controlled audio stream / sample re-sequencer LV2 plugin
3  *
4  * Copyright (C) 2018 - 2020 by Sven Jähnichen
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3, or (at your option)
9  * any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  */
20 
21 #ifndef SYMBOLWIDGET_HPP_
22 #define SYMBOLWIDGET_HPP_
23 
24 #include "BWidgets/Widget.hpp"
25 #include "BWidgets/Label.hpp"
26 #include "BWidgets/Focusable.hpp"
27 #include <cmath>
28 
29 enum SWSymbol
30 {
31         NOSYMBOL        = -1,
32         ADDSYMBOL       = 0,
33         CLOSESYMBOL     = 1,
34         RIGHTSYMBOL     = 2,
35         LEFTSYMBOL      = 3,
36         PLAYSYMBOL      = 4,
37         MIDISYMBOL      = 5
38 };
39 
40 const std::string symboltxt[7] = {"", "Insert", "Delete", "Move forward", "Move backward", "Play", "MIDI"};
41 
42 class SymbolWidget : public BWidgets::Widget, public BWidgets::Focusable
43 {
44 protected:
45         BColors::ColorSet fgColors_;
46         SWSymbol symbol_;
47         BWidgets::Label focusLabel_;
48 
49 public:
SymbolWidget()50         SymbolWidget () : SymbolWidget (0.0, 0.0, 0.0, 0.0, "symbol", NOSYMBOL) {}
SymbolWidget(const double x,const double y,const double width,const double height,const std::string & name,SWSymbol symbol)51         SymbolWidget (const double x, const double y, const double width, const double height, const std::string& name, SWSymbol symbol) :
52                 Widget (x, y, width, height, name),
53                 Focusable (std::chrono::milliseconds (BWIDGETS_DEFAULT_FOCUS_IN_MS),
54 			   std::chrono::milliseconds (BWIDGETS_DEFAULT_FOCUS_OUT_MS)),
55                 fgColors_ (BColors::whites),
56                 symbol_ (symbol),
57                 focusLabel_ (0, 0, 80, 20, name_ + BWIDGETS_DEFAULT_FOCUS_NAME, symboltxt[symbol + 1])
58         {
59                 focusLabel_.setStacking (BWidgets::STACKING_OVERSIZE);
60    		focusLabel_.resize ();
61    		focusLabel_.hide ();
62    		add (focusLabel_);
63         }
64 
SymbolWidget(const SymbolWidget & that)65         SymbolWidget (const SymbolWidget& that) :
66 		Widget (that), Focusable (that),
67                 fgColors_ (that.fgColors_),
68                 symbol_ (that.symbol_),
69 		focusLabel_ (that.focusLabel_)
70 	{
71 		focusLabel_.hide();
72 		add (focusLabel_);
73 	}
74 
operator =(const SymbolWidget & that)75 	SymbolWidget& operator= (const SymbolWidget& that)
76 	{
77 		release (&focusLabel_);
78 		focusLabel_ = that.focusLabel_;
79 		focusLabel_.hide();
80 
81                 fgColors_ = that.fgColors_;
82                 symbol_ = that.symbol_;
83 
84 		Widget::operator= (that);
85 		Focusable::operator= (that);
86 
87 		add (focusLabel_);
88 
89 		return *this;
90 
91 	}
92 
clone() const93 	virtual BWidgets::Widget* clone () const override {return new SymbolWidget (*this);}
94 
applyTheme(BStyles::Theme & theme,const std::string & name)95 	virtual void applyTheme (BStyles::Theme& theme, const std::string& name) override
96         {
97                 Widget::applyTheme (theme, name);
98                 focusLabel_.applyTheme (theme, name + BWIDGETS_DEFAULT_FOCUS_NAME);
99 		focusLabel_.resize();
100 
101         	void* colorsPtr = theme.getStyle(name, BWIDGETS_KEYWORD_FGCOLORS);
102         	if (colorsPtr)
103                 {
104                         fgColors_ = *((BColors::ColorSet*) colorsPtr);
105                         update ();
106                 }
107         }
108 
applyTheme(BStyles::Theme & theme)109         virtual void applyTheme (BStyles::Theme& theme) override {applyTheme (theme, name_);}
110 
onFocusIn(BEvents::FocusEvent * event)111         virtual void onFocusIn (BEvents::FocusEvent* event) override
112 	{
113 		if (event && event->getWidget())
114 		{
115 			BUtilities::Point pos = event->getPosition();
116 			focusLabel_.moveTo (pos.x - 0.5 * focusLabel_.getWidth(), pos.y - focusLabel_.getHeight());
117 			focusLabel_.show();
118 		}
119 		Widget::onFocusIn (event);
120 	}
121 
onFocusOut(BEvents::FocusEvent * event)122 	virtual void onFocusOut (BEvents::FocusEvent* event) override
123 	{
124 		if (event && event->getWidget()) focusLabel_.hide();
125 		Widget::onFocusOut (event);
126 	}
127 
128 protected:
draw(const BUtilities::RectArea & area)129 	virtual void draw (const BUtilities::RectArea& area) override
130 	{
131                 if ((!widgetSurface_) || (cairo_surface_status (widgetSurface_) != CAIRO_STATUS_SUCCESS)) return;
132 
133 		Widget::draw (area);
134 
135 		cairo_t* cr = cairo_create (widgetSurface_);
136 
137 		if (cairo_status (cr) == CAIRO_STATUS_SUCCESS)
138 		{
139 			// Limit cairo-drawing area
140 			cairo_rectangle (cr, area.getX(), area.getY(), area.getWidth(), area.getHeight());
141 			cairo_clip (cr);
142 
143                         double x0 = getXOffset ();
144 			double y0 = getYOffset ();
145 			double w = getEffectiveWidth ();
146 			double h = getEffectiveHeight ();
147                         double ext = (w < h ? w : h);
148 
149                         switch (symbol_)
150                         {
151                                 case ADDSYMBOL:         cairo_move_to (cr, x0 + w / 2 - ext / 2, y0 + h / 2);
152                                                         cairo_line_to (cr, x0 + w / 2 + ext / 2, y0 + h / 2);
153                                                         cairo_move_to (cr, x0 + w / 2, y0 + h / 2 - ext / 2);
154                                                         cairo_line_to (cr, x0 + w / 2, y0 + h / 2 + ext / 2);
155                                                         cairo_set_line_width (cr, 2.0);
156                                                         cairo_set_source_rgba (cr, CAIRO_RGBA (*fgColors_.getColor (getState ())));
157                                                         cairo_stroke (cr);
158                                                         break;
159 
160                                 case CLOSESYMBOL:       cairo_move_to (cr, x0 + w / 2 - ext / 2, y0 + h / 2);
161                                                         cairo_line_to (cr, x0 + w / 2 + ext / 2, y0 + h / 2);
162                                                         cairo_set_line_width (cr, 2.0);
163                                                         cairo_set_source_rgba (cr, CAIRO_RGBA (*fgColors_.getColor (getState ())));
164                                                         cairo_stroke (cr);
165                                                         break;
166 
167                                 case LEFTSYMBOL:        cairo_move_to (cr, x0 + w / 2 + 0.25 * ext, y0 + h / 2 - ext / 2);
168                                                         cairo_line_to (cr, x0 + w / 2 - 0.25 * ext, y0 + h / 2);
169                                                         cairo_line_to (cr, x0 + w / 2 + 0.25 * ext, y0 + h / 2 + ext / 2);
170                                                         cairo_set_line_width (cr, 2.0);
171                                                         cairo_set_source_rgba (cr, CAIRO_RGBA (*fgColors_.getColor (getState ())));
172                                                         cairo_stroke (cr);
173                                                         break;
174 
175                                 case RIGHTSYMBOL:       cairo_move_to (cr, x0 + w / 2 - 0.25 * ext, y0 + h / 2 - ext / 2);
176                                                         cairo_line_to (cr, x0 + w / 2 + 0.25 * ext, y0 + h / 2);
177                                                         cairo_line_to (cr, x0 + w / 2 - 0.25 * ext, y0 + h / 2 + ext / 2);
178                                                         cairo_set_line_width (cr, 2.0);
179                                                         cairo_set_source_rgba (cr, CAIRO_RGBA (*fgColors_.getColor (getState ())));
180                                                         cairo_stroke (cr);
181                                                         break;
182 
183                                 case PLAYSYMBOL:        cairo_move_to (cr, x0 + 0.25 * w, y0);
184                                                         cairo_line_to (cr, x0 + 0.75 * w, y0 + 0.5 * h);
185                                                         cairo_line_to (cr, x0 + 0.25 * w, y0 + h);
186                                                         cairo_close_path (cr);
187                                                         cairo_set_line_width (cr, 0.0);
188                                                         if (getState() == BColors::NORMAL)
189                                                         {
190                                                                 cairo_set_line_width (cr, 1.0);
191                                                                 cairo_set_source_rgba (cr, CAIRO_RGBA (*fgColors_.getColor (BColors::ACTIVE)));
192                                                                 cairo_stroke (cr);
193                                                         }
194                                                         else
195                                                         {
196                                                                 cairo_set_source_rgba (cr, CAIRO_RGBA (*fgColors_.getColor (getState ())));
197                                                                 cairo_fill (cr);
198                                                         }
199                                                         break;
200 
201                                 case MIDISYMBOL:        cairo_set_line_width (cr, 1.0);
202                                                         cairo_set_source_rgba (cr, CAIRO_RGBA (*fgColors_.getColor (getState ())));
203                                                         for (int i = 0; i < 3; ++i) cairo_rectangle (cr, x0 + 0.5 * w - 0.375 * ext + i * 0.25 * ext, y0 + 0.5 * h - 0.45 * ext, 0.25 * ext, 0.9 * ext);
204                                                         cairo_stroke (cr);
205                                                         cairo_set_line_width (cr, 0.0);
206                                                         for (int i = 0; i < 2; ++i)
207                                                         {
208                                                                 cairo_rectangle (cr, x0 + 0.5 * w - 0.2 * ext + i * 0.25 * ext, y0 + 0.5 * h - 0.45 * ext, 0.15 * ext, 0.6 * ext);
209                                                                 cairo_fill (cr);
210                                                         }
211 
212                                 default:                break;
213                         }
214 
215                         cairo_destroy (cr);
216 		}
217 	}
218 
219 };
220 
221 #endif /* SYMBOLWIDGET_HPP_ */
222