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