ardour
button_joiner.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2012 Paul Davis
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or
7  (at your option) any later version.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program; if not, write to the Free Software
16  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 
18 */
19 
20 #include <iostream>
21 #include <algorithm>
22 
23 
24 #include <gtkmm/toggleaction.h>
25 
26 #include "pbd/compose.h"
27 #include "gtkmm2ext/utils.h"
28 #include "gtkmm2ext/rgb_macros.h"
29 
30 #include "ardour_ui.h"
31 #include "button_joiner.h"
32 
33 using namespace Gtk;
34 
35 ButtonJoiner::ButtonJoiner (const std::string& str, Gtk::Widget& lw, Gtk::Widget& rw, bool central_joiner)
36  : left (lw)
37  , right (rw)
38  , name (str)
39  , active_fill_pattern (0)
40  , inactive_fill_pattern (0)
41  , central_link (central_joiner)
42 {
43  packer.set_homogeneous (true);
44 
45  if (central_link) {
46  packer.set_spacing (20);
47  }
48 
49  packer.pack_start (left);
50  packer.pack_start (right);
51  packer.show ();
52 
53  /* this alignment is how we position the box that holds the two widgets
54  within our allocation, and how we request more space around them.
55  */
56 
57  align.add (packer);
58 
59  if (!central_link) {
60  align.set (0.5, 1.0);
61  align.set_padding (9, 0, 9, 9);
62  } else {
63  align.set (0.5, 0.5);
64  align.set_padding (1, 1, 1, 1);
65  }
66 
67  align.show ();
68 
69  add (align);
70 
71  add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|
72  Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
73 
74  uint32_t border_color;
75  uint32_t r, g, b, a;
76 
77  border_color = ARDOUR_UI::config()->color (string_compose ("%1: border end", name));
78  UINT_TO_RGBA (border_color, &r, &g, &b, &a);
79 
80  border_r = r/255.0;
81  border_g = g/255.0;
82  border_b = b/255.0;
83 
84  /* child cairo widgets need the color of the inner edge as their
85  * "background"
86  */
87 
88  Gdk::Color col;
89  col.set_rgb_p (border_r, border_g, border_b);
91 }
92 
94 {
95  if (active_fill_pattern) {
96  cairo_pattern_destroy (active_fill_pattern);
97  cairo_pattern_destroy (inactive_fill_pattern);
98  }
99 }
100 
101 void
102 ButtonJoiner::render (cairo_t* cr, cairo_rectangle_t*)
103 {
104  double h = get_height();
105 
106  if (!get_active()) {
107  cairo_set_source (cr, inactive_fill_pattern);
108  } else {
109  cairo_set_source (cr, active_fill_pattern);
110  }
111 
112  if (!central_link) {
113  /* outer rect */
114 
115  Gtkmm2ext::rounded_top_rectangle (cr, 0, 0, get_width(), h, 8);
116  cairo_fill_preserve (cr);
117 
118  /* outer edge */
119 
120  cairo_set_line_width (cr, 1.5);
121  cairo_set_source_rgb (cr, border_r, border_g, border_b);
122  cairo_stroke (cr);
123 
124  /* inner "edge" */
125 
126  Gtkmm2ext::rounded_top_rectangle (cr, 8, 8, get_width() - 16, h - 8, 6);
127  cairo_stroke (cr);
128  } else {
129  if (get_active()) {
130  Gtkmm2ext::rounded_top_rectangle (cr, 0, 0, (get_width() - 20.0)/2.0 , h, 8);
131  cairo_fill_preserve (cr);
132 
133  Gtkmm2ext::rounded_top_rectangle (cr, (get_width() - 20.)/2.0 + 20.0, 0.0,
134  (get_width() - 20.0)/2.0 , h, 8);
135  cairo_fill_preserve (cr);
136 
137  cairo_move_to (cr, get_width()/2.0 - 10.0, h/2.0);
138  cairo_set_line_width (cr, 1.5);
139  cairo_rel_line_to (cr, 20.0, 0.0);
140  cairo_set_source (cr, active_fill_pattern);
141  cairo_stroke (cr);
142  } else {
143  cairo_arc (cr, get_width()/2.0, h/2.0, 6.0, 0, M_PI*2.0);
144  cairo_set_line_width (cr, 1.5);
145  cairo_fill_preserve (cr);
146  cairo_set_source_rgb (cr, border_r, border_g, border_b);
147  cairo_stroke (cr);
148  }
149  }
150 }
151 
152 void
154 {
156  set_colors ();
157 }
158 
159 bool
161 {
162  if (_action) {
163  _action->activate ();
164  }
165 
166  return true;
167 }
168 
169 void
170 ButtonJoiner::on_size_request (Gtk::Requisition* r)
171 {
172  CairoWidget::on_size_request (r);
173 }
174 
175 void
176 ButtonJoiner::set_related_action (Glib::RefPtr<Action> act)
177 {
179 
180  if (_action) {
181 
183 
184  Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (_action);
185  if (tact) {
186  action_toggled ();
187  tact->signal_toggled().connect (sigc::mem_fun (*this, &ButtonJoiner::action_toggled));
188  }
189 
190  _action->connect_property_changed ("sensitive", sigc::mem_fun (*this, &ButtonJoiner::action_sensitivity_changed));
191  _action->connect_property_changed ("visible", sigc::mem_fun (*this, &ButtonJoiner::action_visibility_changed));
192  _action->connect_property_changed ("tooltip", sigc::mem_fun (*this, &ButtonJoiner::action_tooltip_changed));
193  }
194 }
195 
196 void
198 {
199  if (_action->property_sensitive ()) {
200  set_visual_state (Gtkmm2ext::VisualState (visual_state() & ~Gtkmm2ext::Insensitive));
201  } else {
202  set_visual_state (Gtkmm2ext::VisualState (visual_state() | Gtkmm2ext::Insensitive));
203  }
204 
205 }
206 
207 void
209 {
210  if (_action->property_visible ()) {
211  show ();
212  } else {
213  hide ();
214  }
215 }
216 
217 void
219 {
220  std::string str = _action->property_tooltip().get_value();
221  ARDOUR_UI::instance()->set_tip (*this, str);
222 }
223 
224 void
226 {
227  Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (_action);
228 
229  if (tact) {
230  set_active (tact->get_active());
231  }
232 }
233 
234 void
235 ButtonJoiner::set_active_state (Gtkmm2ext::ActiveState s)
236 {
237  bool changed = (_active_state != s);
239  if (changed) {
240  set_colors ();
241  }
242 }
243 
244 void
246 {
247  uint32_t start_color;
248  uint32_t end_color;
249  uint32_t r, g, b, a;
250 
251  if (active_fill_pattern) {
252  cairo_pattern_destroy (active_fill_pattern);
253  cairo_pattern_destroy (inactive_fill_pattern);
254  }
255 
256  active_fill_pattern = cairo_pattern_create_linear (0.0, 0.0, 0.0, get_height());
257  inactive_fill_pattern = cairo_pattern_create_linear (0.0, 0.0, 0.0, get_height());
258 
259  start_color = ARDOUR_UI::config()->color (string_compose ("%1: fill start", name));
260  end_color = ARDOUR_UI::config()->color (string_compose ("%1: fill end", name));
261  UINT_TO_RGBA (start_color, &r, &g, &b, &a);
262  cairo_pattern_add_color_stop_rgba (inactive_fill_pattern, 0, r/255.0,g/255.0,b/255.0, a/255.0);
263  UINT_TO_RGBA (end_color, &r, &g, &b, &a);
264  cairo_pattern_add_color_stop_rgba (inactive_fill_pattern, 1, r/255.0,g/255.0,b/255.0, a/255.0);
265 
266  start_color = ARDOUR_UI::config()->color (string_compose ("%1: fill start active", name));
267  end_color = ARDOUR_UI::config()->color (string_compose ("%1: fill end active", name));
268  UINT_TO_RGBA (start_color, &r, &g, &b, &a);
269  cairo_pattern_add_color_stop_rgba (active_fill_pattern, 0, r/255.0,g/255.0,b/255.0, a/255.0);
270  UINT_TO_RGBA (end_color, &r, &g, &b, &a);
271  cairo_pattern_add_color_stop_rgba (active_fill_pattern, 1, r/255.0,g/255.0,b/255.0, a/255.0);
272 
273  queue_draw ();
274 }
275 
void render(cairo_t *, cairo_rectangle_t *)
cairo_pattern_t * active_fill_pattern
Definition: button_joiner.h:55
ArdourCanvas::Color color(const std::string &, bool *failed=0) const
Definition: ui_config.cc:567
bool on_button_release_event(GdkEventButton *)
void on_size_request(Gtk::Requisition *)
Gtk::Alignment align
Definition: button_joiner.h:53
Gtk::HBox packer
Definition: button_joiner.h:52
void action_visibility_changed()
double border_r
Definition: button_joiner.h:58
Definition: ardour_ui.h:130
Gtk::Widget & right
Definition: button_joiner.h:51
static ARDOUR_UI * instance()
Definition: ardour_ui.h:187
void on_size_allocate(Gtk::Allocation &)
virtual void set_active_state(Gtkmm2ext::ActiveState)
void set_related_action(Glib::RefPtr< Gtk::Action >)
void action_tooltip_changed()
#define UINT_TO_RGBA(u, r, g, b, a)
Definition: fastmeter.cc:35
virtual void set_related_action(Glib::RefPtr< Gtk::Action > a)
Definition: activatable.h:39
ButtonJoiner(const std::string &, Gtk::Widget &, Gtk::Widget &, bool central_link=false)
void set_active_state(Gtkmm2ext::ActiveState)
Gtkmm2ext::VisualState visual_state() const
Definition: cairo_widget.h:41
LIBGTKMM2EXT_API void rounded_top_rectangle(Cairo::RefPtr< Cairo::Context > context, double x, double y, double w, double h, double r=10)
Definition: utils.cc:525
double border_g
Definition: button_joiner.h:59
void set_tip(Gtk::Widget &w, const gchar *tip)
std::string name
Definition: button_joiner.h:54
Insensitive
Definition: widget_state.h:23
cairo_pattern_t * inactive_fill_pattern
Definition: button_joiner.h:56
const char * name
bool get_active()
Definition: cairo_widget.h:57
void set_active(bool)
static UIConfiguration * config()
Definition: ardour_ui.h:188
virtual void set_visual_state(Gtkmm2ext::VisualState)
Glib::RefPtr< Gtk::Action > _action
Definition: activatable.h:48
void action_toggled()
double border_b
Definition: button_joiner.h:60
Gtk::Widget & left
Definition: button_joiner.h:50
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208
Gtkmm2ext::ActiveState _active_state
Definition: cairo_widget.h:111
void action_sensitivity_changed()
void on_size_allocate(Gtk::Allocation &)
static void provide_background_for_cairo_widget(Gtk::Widget &w, const Gdk::Color &bg)