replace unicode dash with (monospace) minus.
[ardour.git] / gtk2_ardour / ardour_button.cc
1 /*
2     Copyright (C) 2010 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 <cmath>
22 #include <algorithm>
23
24 #include <pangomm/layout.h>
25
26 #include "pbd/compose.h"
27 #include "pbd/error.h"
28
29 #include "gtkmm2ext/utils.h"
30 #include "gtkmm2ext/rgb_macros.h"
31 #include "gtkmm2ext/gui_thread.h"
32
33 #include "ardour/rc_configuration.h" // for widget prelight preference
34
35 #include "ardour_button.h"
36 #include "ardour_ui.h"
37 #include "global_signals.h"
38
39 #include "i18n.h"
40
41 #define REFLECTION_HEIGHT 2
42
43 using namespace Gdk;
44 using namespace Gtk;
45 using namespace Glib;
46 using namespace PBD;
47 using std::max;
48 using std::min;
49 using namespace std;
50
51 ArdourButton::Element ArdourButton::default_elements = ArdourButton::Element (ArdourButton::Edge|ArdourButton::Body|ArdourButton::Text);
52 ArdourButton::Element ArdourButton::led_default_elements = ArdourButton::Element (ArdourButton::default_elements|ArdourButton::Indicator);
53 ArdourButton::Element ArdourButton::just_led_default_elements = ArdourButton::Element (ArdourButton::Edge|ArdourButton::Body|ArdourButton::Indicator);
54 bool ArdourButton::_flat_buttons = false;
55
56 ArdourButton::ArdourButton (Element e)
57         : _elements (e)
58         , _tweaks (Tweaks (0))
59         , _text_width (0)
60         , _text_height (0)
61         , _diameter (11.0)
62         , _corner_radius (4.0)
63         , _corner_mask (0xf)
64         , border_color (0)
65         , fill_color_active (0)
66         , fill_color_inactive (0)
67         , fill_pattern (0)
68         , fill_pattern_active (0)
69         , shine_pattern (0)
70         , led_inset_pattern (0)
71         , reflection_pattern (0)
72         , _led_rect (0)
73         , _act_on_release (true)
74         , _led_left (false)
75         , _fixed_diameter (true)
76         , _distinct_led_click (false)
77         , _hovering (false)
78 {
79         ColorsChanged.connect (sigc::mem_fun (*this, &ArdourButton::color_handler));
80 }
81
82 ArdourButton::ArdourButton (const std::string& str, Element e)
83         : _elements (e)
84         , _tweaks (Tweaks (0))
85         , _text_width (0)
86         , _text_height (0)
87         , _diameter (11.0)
88         , _corner_radius (4.0)
89         , _corner_mask (0xf)
90         , border_color (0)
91         , fill_color_active (0)
92         , fill_color_inactive (0)
93         , fill_pattern (0)
94         , fill_pattern_active (0)
95         , shine_pattern (0)
96         , led_inset_pattern (0)
97         , reflection_pattern (0)
98         , _led_rect (0)
99         , _act_on_release (true)
100         , _led_left (false)
101         , _fixed_diameter (true)
102         , _distinct_led_click (false)
103         , _hovering (false)
104 {
105         set_text (str);
106 }
107
108 ArdourButton::~ArdourButton()
109 {
110         delete _led_rect;
111
112         if (shine_pattern) {
113                 cairo_pattern_destroy (shine_pattern);
114         }
115
116         if (fill_pattern) {
117                 cairo_pattern_destroy (fill_pattern);
118         }
119         
120         if (fill_pattern_active) {
121                 cairo_pattern_destroy (fill_pattern_active);
122         }
123         
124         if (led_inset_pattern) {
125                 cairo_pattern_destroy (led_inset_pattern);
126         }
127         
128         if (reflection_pattern) {
129                 cairo_pattern_destroy (reflection_pattern);
130         }
131
132 }
133
134 void
135 ArdourButton::set_text (const std::string& str)
136 {
137         _text = str;
138
139         if (!_layout && !_text.empty()) {
140                 _layout = Pango::Layout::create (get_pango_context());
141         } 
142
143         if (_layout) {
144                 _layout->set_text (str);
145         }
146
147         queue_resize ();
148 }
149
150 void
151 ArdourButton::set_markup (const std::string& str)
152 {
153         _text = str;
154
155         if (!_layout) {
156                 _layout = Pango::Layout::create (get_pango_context());
157         } 
158
159         _layout->set_text (str);
160         queue_resize ();
161 }
162
163 void
164 ArdourButton::render (cairo_t* cr)
165 {
166         void (*rounded_function)(cairo_t*, double, double, double, double, double);
167
168         switch (_corner_mask) {
169         case 0x1: /* upper left only */
170                 rounded_function = Gtkmm2ext::rounded_top_left_rectangle;
171                 break;
172         case 0x2: /* upper right only */
173                 rounded_function = Gtkmm2ext::rounded_top_right_rectangle;
174                 break;
175         case 0x3: /* upper only */
176                 rounded_function = Gtkmm2ext::rounded_top_rectangle;
177                 break;
178                 /* should really have functions for lower right, lower left,
179                    lower only, but for now, we don't
180                 */
181         default:
182                 rounded_function = Gtkmm2ext::rounded_rectangle;
183         }
184
185         if (!_fixed_diameter) {
186                 _diameter = std::min (get_width(), get_height());
187         }
188
189         float r,g,b,a;
190
191         if ((_elements & Body)==Body) {
192                 if (_elements & Edge) {
193
194                         cairo_set_source_rgba (cr, 0, 0, 0, 1);
195                         rounded_function(cr, 0, 0, get_width(), get_height(), _corner_radius);
196                         cairo_fill (cr);
197
198                         rounded_function (cr, 1, 1, get_width()-2, get_height()-2, _corner_radius - 1.5);
199                 } else {
200                         rounded_function (cr, 0, 0, get_width(), get_height(), _corner_radius);
201                 }
202
203                 if (active_state() == Gtkmm2ext::ImplicitActive) {
204                         
205                         if (!(_tweaks & ImplicitUsesSolidColor)) {
206                                 cairo_set_source (cr, fill_pattern);
207                         } else {
208                                 cairo_set_source (cr, fill_pattern_active);
209                         }
210                         cairo_fill (cr);
211                         
212                         if (!(_tweaks & ImplicitUsesSolidColor)) {
213                                 //border
214                                 UINT_TO_RGBA (fill_color_active, &r, &g, &b, &a);
215                                 cairo_set_line_width (cr, 1.0);
216                                 rounded_function (cr, 2, 2, get_width()-4, get_height()-4, _corner_radius - 1.5);
217                                 cairo_set_source_rgba (cr, r/255.0, g/255.0, b/255.0, a/255.0);
218                                 cairo_stroke (cr);
219                         }
220                                 
221                 } else if (active_state() == Gtkmm2ext::ExplicitActive || ((_elements & Indicator)==Indicator) ) {
222
223                         //background color
224                         cairo_set_source (cr, fill_pattern_active);
225                         cairo_fill (cr);
226
227                 } else {
228
229                         //background color
230                         cairo_set_source (cr, fill_pattern);
231                         cairo_fill (cr);
232
233                 }
234         }
235
236         if ( ((_elements & FlatFace)==FlatFace) && (active_state() != Gtkmm2ext::ExplicitActive) ) {
237
238                 if ( !_flat_buttons ) {
239                         float rheight = get_height()*0.5-REFLECTION_HEIGHT;
240                         Gtkmm2ext::rounded_rectangle (cr, 2, 3, get_width()-4, rheight, _corner_radius-1);
241                         cairo_set_source (cr, shine_pattern);
242                         cairo_fill (cr);
243                 }
244
245                 if (active_state() == Gtkmm2ext::ExplicitActive) {
246
247                         UINT_TO_RGBA (fill_color_active, &r, &g, &b, &a);
248                         cairo_set_line_width (cr, 2.0);
249                         rounded_function (cr, 2, 2, get_width()-4, get_height()-4, _corner_radius - 2.0);
250                         cairo_set_source_rgba (cr, r/255.0, g/255.0, b/255.0, a/255.0);
251                         cairo_fill (cr);
252
253                 } else {
254
255                         UINT_TO_RGBA (fill_color_inactive, &r, &g, &b, &a);
256                         cairo_set_line_width (cr, 2.0);
257                         rounded_function (cr, 2, 2, get_width()-4, get_height()-4, _corner_radius - 2.0);
258                         cairo_set_source_rgba (cr, r/255.0, g/255.0, b/255.0, a/255.0);
259                         cairo_fill (cr);
260
261                 }
262         }
263
264         if (_pixbuf) {
265
266                 double x,y;
267                 x = (get_width() - _pixbuf->get_width())/2.0;
268                 y = (get_height() - _pixbuf->get_height())/2.0;
269
270                 cairo_rectangle (cr, x, y, _pixbuf->get_width(), _pixbuf->get_height());
271                 gdk_cairo_set_source_pixbuf (cr, _pixbuf->gobj(), x, y);
272                 cairo_fill (cr);
273         }
274
275         /* text, if any */
276
277         int text_margin;
278
279         if (get_width() < 75) {
280                 text_margin = 5;
281         } else {
282                 text_margin = 10;
283         }
284
285         if ( ((_elements & Text)==Text) && !_text.empty()) {
286
287                 cairo_new_path (cr);    
288
289                 if (_elements & Indicator) {
290                         if (_led_left) {
291                                 cairo_move_to (cr, text_margin + _diameter + 4, get_height()/2.0 - _text_height/2.0);
292                         } else {
293                                 cairo_move_to (cr, text_margin, get_height()/2.0 - _text_height/2.0);
294                         }
295                 } else {
296                         /* center text */
297                         cairo_move_to (cr, (get_width() - _text_width)/2.0, get_height()/2.0 - _text_height/2.0);
298                 }
299
300                 cairo_set_source_rgba (cr, text_r, text_g, text_b, text_a);
301                 pango_cairo_show_layout (cr, _layout->gobj());
302         } 
303
304         if (((_elements & Indicator)==Indicator)) {
305
306                 /* move to the center of the indicator/led */
307
308                 cairo_save (cr);
309
310                 if (_elements & Text) {
311                         if (_led_left) {
312                                 cairo_translate (cr, text_margin + (_diameter/2.0), get_height()/2.0);
313                         } else {
314                                 cairo_translate (cr, get_width() - ((_diameter/2.0) + 4.0), get_height()/2.0);
315                         }
316                 } else {
317                         cairo_translate (cr, get_width()/2.0, get_height()/2.0);
318                 }
319                 
320                 //inset
321                 cairo_arc (cr, 0, 0, _diameter/2, 0, 2 * M_PI);
322                 cairo_set_source (cr, led_inset_pattern);
323                 cairo_fill (cr);
324                 
325                 //black ring
326                 cairo_set_source_rgb (cr, 0, 0, 0);
327                 cairo_arc (cr, 0, 0, _diameter/2-2, 0, 2 * M_PI);
328                 cairo_fill(cr);
329                 
330                 //led color
331                 cairo_set_source_rgba (cr, led_r, led_g, led_b, led_a);
332                 cairo_arc (cr, 0, 0, _diameter/2-3, 0, 2 * M_PI);
333                 cairo_fill(cr);
334                 
335                 cairo_restore (cr);
336         }
337
338
339         /* a partially transparent gray layer to indicate insensitivity */
340
341         if ((visual_state() & Gtkmm2ext::Insensitive)) {
342                 rounded_function (cr, 0, 0, get_width(), get_height(), _corner_radius);
343                 cairo_set_source_rgba (cr, 0.505, 0.517, 0.525, 0.5);
344                 cairo_fill (cr);
345         }
346
347         //reflection
348         bool show_reflection = (active_state() == Gtkmm2ext::ExplicitActive);
349         show_reflection &= !_flat_buttons;
350         show_reflection &= !((_elements & Indicator)==Indicator);
351         if ( show_reflection ) {
352                 float rheight = get_height()*0.5-REFLECTION_HEIGHT;
353                 Gtkmm2ext::rounded_rectangle (cr, 2, get_height()*0.5-1, get_width()-4, rheight, _corner_radius-1);
354                 cairo_set_source (cr, shine_pattern);
355                 cairo_fill (cr);
356         }
357
358         /* if requested, show hovering */
359         
360         if (ARDOUR::Config->get_widget_prelight()) {
361                 if (_hovering) {
362                         rounded_function (cr, 0, 0, get_width(), get_height(), _corner_radius);
363                         cairo_set_source_rgba (cr, 0.905, 0.917, 0.925, 0.2);
364                         cairo_fill (cr);
365                 }
366         }
367 }
368
369 void
370 ArdourButton::set_diameter (float d)
371 {
372         _diameter = (d*2) + 5.0;
373
374         if (_diameter != 0.0) {
375                 _fixed_diameter = true;
376         }
377
378         set_colors ();
379 }
380
381 void
382 ArdourButton::set_corner_radius (float r)
383 {
384         _corner_radius = r;
385         set_dirty ();
386 }
387
388 void
389 ArdourButton::on_size_request (Gtk::Requisition* req)
390 {
391         int xpad = 0;
392         int ypad = 6;
393
394         CairoWidget::on_size_request (req);
395
396         if ((_elements & Text) && !_text.empty()) {
397                 _layout->get_pixel_size (_text_width, _text_height);
398                 if (_text_width + _diameter < 75) {
399                         xpad = 7;
400                 } else {
401                         xpad = 20;
402                 }
403         } else {
404                 _text_width = 0;
405                 _text_height = 0;
406         }
407
408         if (_pixbuf) {
409                 xpad = 6;
410         }
411
412         if ((_elements & Indicator) && _fixed_diameter) {
413                 if (_pixbuf) {
414                         req->width = _pixbuf->get_width() + lrint (_diameter) + xpad;
415                         req->height = max (_pixbuf->get_height(), (int) lrint (_diameter)) + ypad;
416                 } else {
417                         req->width = _text_width + lrint (_diameter) + xpad;
418                         req->height = max (_text_height, (int) lrint (_diameter)) + ypad;
419                 }
420         } else {
421                 if (_pixbuf) {
422                         req->width = _pixbuf->get_width() + xpad;
423                         req->height = _pixbuf->get_height() + ypad;
424                 }  else {
425                         req->width = _text_width + xpad;
426                         req->height = _text_height + ypad;
427                 }
428         }
429 }
430
431 void
432 ArdourButton::set_colors ()
433 {
434         uint32_t start_color;
435         uint32_t end_color;
436         uint32_t r, g, b, a;
437         uint32_t text_color;
438         uint32_t led_color;
439
440         if (active_state() == Gtkmm2ext::ImplicitActive && (_tweaks & ImplicitUsesSolidColor)) {
441                 fill_color_active = ARDOUR_UI::config()->color_by_name (string_compose ("%1: led active", get_name()));
442         } else {
443                 fill_color_active = ARDOUR_UI::config()->color_by_name (string_compose ("%1: fill end active", get_name()));
444         }
445         fill_color_inactive = ARDOUR_UI::config()->color_by_name (string_compose ("%1: fill end", get_name()));
446         border_color = ARDOUR_UI::config()->color_by_name ( "button border" );
447
448         if (shine_pattern) {
449                 cairo_pattern_destroy (shine_pattern);
450                 shine_pattern = 0;
451         }
452
453         if (fill_pattern) {
454                 cairo_pattern_destroy (fill_pattern);
455                 fill_pattern = 0;
456         }
457
458         if (fill_pattern_active) {
459                 cairo_pattern_destroy (fill_pattern_active);
460                 fill_pattern_active = 0;
461         }
462
463         if (_elements & Body) {
464
465                 start_color = ARDOUR_UI::config()->color_by_name (string_compose ("%1: fill start active", get_name()));
466                 
467                 if (_flat_buttons) {
468                         end_color = start_color;
469                 } else {
470                         end_color = fill_color_active;
471                 }
472                 UINT_TO_RGBA (start_color, &r, &g, &b, &a);
473
474                 active_r = r/255.0;
475                 active_g = g/255.0;
476                 active_b = b/255.0;
477                 active_a = a/255.0;
478
479                 shine_pattern = cairo_pattern_create_linear (0.0, 0.0, 0.0, get_height());
480                 cairo_pattern_add_color_stop_rgba (shine_pattern, 0, 1,1,1,0.0);
481                 cairo_pattern_add_color_stop_rgba (shine_pattern, 0.5, 1,1,1,0.1);
482                 cairo_pattern_add_color_stop_rgba (shine_pattern, 0.7, 1,1,1,0.2);
483                 cairo_pattern_add_color_stop_rgba (shine_pattern, 1, 1,1,1,0.1);
484
485                 fill_pattern = cairo_pattern_create_linear (0.0, 0.0, 0.0, get_height()-3);
486                 if (_flat_buttons) {
487                         end_color = start_color = ARDOUR_UI::config()->color_by_name (string_compose ("%1: fill end", get_name()));
488                 } else {
489                         start_color = ARDOUR_UI::config()->color_by_name (string_compose ("%1: fill start", get_name()));
490                         end_color = fill_color_inactive;
491                 }
492                 UINT_TO_RGBA (start_color, &r, &g, &b, &a);
493                 cairo_pattern_add_color_stop_rgba (fill_pattern, 0, r/255.0,g/255.0,b/255.0, a/255.0);
494                 UINT_TO_RGBA (end_color, &r, &g, &b, &a);
495                 cairo_pattern_add_color_stop_rgba (fill_pattern, 1, r/255.0,g/255.0,b/255.0, a/255.0);
496
497                 fill_pattern_active = cairo_pattern_create_linear (0.0, 0.0, 0.0, get_height()-3);
498                 if (_flat_buttons) {
499                         if (active_state() == Gtkmm2ext::ImplicitActive && (_tweaks & ImplicitUsesSolidColor)) {
500                                 end_color = start_color = ARDOUR_UI::config()->color_by_name (string_compose ("%1: led active", get_name()));
501                         } else {
502                                 end_color = start_color = ARDOUR_UI::config()->color_by_name (string_compose ("%1: fill end active", get_name()));
503                         }
504                 } else {
505                         if (active_state() == Gtkmm2ext::ImplicitActive && (_tweaks & ImplicitUsesSolidColor)) {
506                                 start_color = ARDOUR_UI::config()->color_by_name (string_compose ("%1: led", get_name()));
507                                 end_color = ARDOUR_UI::config()->color_by_name (string_compose ("%1: led active", get_name()));
508                         } else {
509                                 start_color = ARDOUR_UI::config()->color_by_name (string_compose ("%1: fill start active", get_name()));
510                                 end_color = ARDOUR_UI::config()->color_by_name (string_compose ("%1: fill end active", get_name()));
511                         }
512                 }
513                 UINT_TO_RGBA (start_color, &r, &g, &b, &a);
514                 cairo_pattern_add_color_stop_rgba (fill_pattern_active, 0, r/255.0,g/255.0,b/255.0, a/255.0);
515                 UINT_TO_RGBA (end_color, &r, &g, &b, &a);
516                 cairo_pattern_add_color_stop_rgba (fill_pattern_active, 1, r/255.0,g/255.0,b/255.0, a/255.0);
517         }
518
519         if (led_inset_pattern) {
520                 cairo_pattern_destroy (led_inset_pattern);
521         }
522         
523         if (reflection_pattern) {
524                 cairo_pattern_destroy (reflection_pattern);
525         }
526
527         if (_elements & Indicator) {
528                 led_inset_pattern = cairo_pattern_create_linear (0.0, 0.0, 0.0, _diameter);
529                 cairo_pattern_add_color_stop_rgba (led_inset_pattern, 0, 0,0,0, 0.4);
530                 cairo_pattern_add_color_stop_rgba (led_inset_pattern, 1, 1,1,1, 0.7);
531
532                 reflection_pattern = cairo_pattern_create_linear (0.0, 0.0, 0.0, _diameter/2-3);
533                 cairo_pattern_add_color_stop_rgba (reflection_pattern, 0, 1,1,1, active_state() ? 0.4 : 0.2);
534                 cairo_pattern_add_color_stop_rgba (reflection_pattern, 1, 1,1,1, 0.0);
535         }
536         
537         /* text and LED colors */
538
539         if (active_state() == Gtkmm2ext::ExplicitActive || ((_tweaks & ImplicitUsesSolidColor) && active_state() == Gtkmm2ext::ImplicitActive)) {
540                 text_color = ARDOUR_UI::config()->color_by_name (string_compose ("%1: text active", get_name()));
541                 led_color = ARDOUR_UI::config()->color_by_name (string_compose ("%1: led active", get_name()));
542         } else {
543                 text_color = ARDOUR_UI::config()->color_by_name (string_compose ("%1: text", get_name()));
544                 led_color = ARDOUR_UI::config()->color_by_name (string_compose ("%1: led", get_name()));
545         }
546
547         UINT_TO_RGBA (text_color, &r, &g, &b, &a);
548         text_r = r/255.0;
549         text_g = g/255.0;
550         text_b = b/255.0;
551         text_a = a/255.0;
552         UINT_TO_RGBA (led_color, &r, &g, &b, &a);
553         led_r = r/255.0;
554         led_g = g/255.0;
555         led_b = b/255.0;
556         led_a = a/255.0;
557
558         set_dirty ();
559 }
560
561 void
562 ArdourButton::set_led_left (bool yn)
563 {
564         _led_left = yn;
565 }
566
567 bool
568 ArdourButton::on_button_press_event (GdkEventButton *ev)
569 {
570         if ((_elements & Indicator) && _led_rect && _distinct_led_click) {
571                 if (ev->x >= _led_rect->x && ev->x < _led_rect->x + _led_rect->width && 
572                     ev->y >= _led_rect->y && ev->y < _led_rect->y + _led_rect->height) {
573                         return true;
574                 }
575         }
576
577         if (_tweaks & ShowClick) {
578                 set_active_state (Gtkmm2ext::ExplicitActive);
579         }
580
581         if (binding_proxy.button_press_handler (ev)) {
582                 return true;
583         }
584
585         if (!_act_on_release) {
586                 if (_action) {
587                         _action->activate ();
588                         return true;
589                 }
590         }
591
592         return false;
593 }
594
595 bool
596 ArdourButton::on_button_release_event (GdkEventButton *ev)
597 {
598         if ((_elements & Indicator) && _led_rect && _distinct_led_click) {
599                 if (ev->x >= _led_rect->x && ev->x < _led_rect->x + _led_rect->width && 
600                     ev->y >= _led_rect->y && ev->y < _led_rect->y + _led_rect->height) {
601                         signal_led_clicked(); /* EMIT SIGNAL */
602                         return true;
603                 }
604         }
605
606         if (_tweaks & ShowClick) {
607                 unset_active_state ();
608         }
609
610         signal_clicked ();
611
612         if (_act_on_release) {
613                 if (_action) {
614                         _action->activate ();
615                         return true;
616                 }
617         }
618
619
620         return false;
621 }
622
623 void
624 ArdourButton::set_distinct_led_click (bool yn)
625 {
626         _distinct_led_click = yn;
627         setup_led_rect ();
628 }
629
630 void
631 ArdourButton::color_handler ()
632 {
633         set_colors ();
634         set_dirty ();
635 }
636
637 void
638 ArdourButton::on_size_allocate (Allocation& alloc)
639 {
640         CairoWidget::on_size_allocate (alloc);
641         setup_led_rect ();
642         set_colors ();
643 }
644
645 void
646 ArdourButton::set_controllable (boost::shared_ptr<Controllable> c)
647 {
648         watch_connection.disconnect ();
649         binding_proxy.set_controllable (c);
650 }
651
652 void
653 ArdourButton::watch ()
654 {
655         boost::shared_ptr<Controllable> c (binding_proxy.get_controllable ());
656
657         if (!c) {
658                 warning << _("button cannot watch state of non-existing Controllable\n") << endmsg;
659                 return;
660         }
661
662         c->Changed.connect (watch_connection, invalidator(*this), boost::bind (&ArdourButton::controllable_changed, this), gui_context());
663 }
664
665 void
666 ArdourButton::controllable_changed ()
667 {
668         float val = binding_proxy.get_controllable()->get_value();
669
670         if (fabs (val) >= 0.5f) {
671                 set_active_state (Gtkmm2ext::ExplicitActive);
672         } else {
673                 unset_active_state ();
674         }
675 }
676
677 void
678 ArdourButton::set_related_action (RefPtr<Action> act)
679 {
680         Gtkmm2ext::Activatable::set_related_action (act);
681
682         if (_action) {
683
684                 action_tooltip_changed ();
685
686                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (_action);
687                 if (tact) {
688                         action_toggled ();
689                         tact->signal_toggled().connect (sigc::mem_fun (*this, &ArdourButton::action_toggled));
690                 } 
691
692                 _action->connect_property_changed ("sensitive", sigc::mem_fun (*this, &ArdourButton::action_sensitivity_changed));
693                 _action->connect_property_changed ("visible", sigc::mem_fun (*this, &ArdourButton::action_visibility_changed));
694                 _action->connect_property_changed ("tooltip", sigc::mem_fun (*this, &ArdourButton::action_tooltip_changed));
695         }
696 }
697
698 void
699 ArdourButton::action_toggled ()
700 {
701         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (_action);
702
703         if (tact) {
704                 if (tact->get_active()) {
705                         set_active_state (Gtkmm2ext::ExplicitActive);
706                 } else {
707                         unset_active_state ();
708                 }
709         }
710 }       
711
712 void
713 ArdourButton::on_style_changed (const RefPtr<Gtk::Style>&)
714 {
715         set_colors ();
716 }
717
718 void
719 ArdourButton::setup_led_rect ()
720 {
721         int text_margin;
722
723         if (get_width() < 75) {
724                 text_margin = 3;
725         } else {
726                 text_margin = 10;
727         }
728
729         if (_elements & Indicator) {
730                 _led_rect = new cairo_rectangle_t;
731                 
732                 if (_elements & Text) {
733                         if (_led_left) {
734                                 _led_rect->x = text_margin;
735                         } else {
736                                 _led_rect->x = get_width() - text_margin - _diameter/2.0;
737                         }
738                 } else {
739                         /* centered */
740                         _led_rect->x = get_width()/2.0 - _diameter/2.0;
741                 }
742
743                 _led_rect->y = get_height()/2.0 - _diameter/2.0;
744                 _led_rect->width = _diameter;
745                 _led_rect->height = _diameter;
746
747         } else {
748                 delete _led_rect;
749                 _led_rect = 0;
750         }
751 }
752
753 void
754 ArdourButton::set_image (const RefPtr<Gdk::Pixbuf>& img)
755 {
756         _pixbuf = img;
757         queue_draw ();
758 }
759
760 void
761 ArdourButton::set_active_state (Gtkmm2ext::ActiveState s)
762 {
763         bool changed = (_active_state != s);
764         CairoWidget::set_active_state (s);
765         if (changed) {
766                 set_colors ();
767         }
768 }
769         
770 void
771 ArdourButton::set_visual_state (Gtkmm2ext::VisualState s)
772 {
773         bool changed = (_visual_state != s);
774         CairoWidget::set_visual_state (s);
775         if (changed) {
776                 set_colors ();
777         }
778 }
779         
780 bool
781 ArdourButton::on_enter_notify_event (GdkEventCrossing* ev)
782 {
783         _hovering = true;
784
785         if (ARDOUR::Config->get_widget_prelight()) {
786                 queue_draw ();
787         }
788
789         return CairoWidget::on_enter_notify_event (ev);
790 }
791
792 bool
793 ArdourButton::on_leave_notify_event (GdkEventCrossing* ev)
794 {
795         _hovering = false;
796
797         if (ARDOUR::Config->get_widget_prelight()) {
798                 queue_draw ();
799         }
800
801         return CairoWidget::on_leave_notify_event (ev);
802 }
803
804 void
805 ArdourButton::set_tweaks (Tweaks t)
806 {
807         if (_tweaks != t) {
808                 _tweaks = t;
809                 queue_draw ();
810         }
811 }
812
813 void
814 ArdourButton::action_sensitivity_changed ()
815 {
816         if (_action->property_sensitive ()) {
817                 set_visual_state (Gtkmm2ext::VisualState (visual_state() & ~Gtkmm2ext::Insensitive));
818         } else {
819                 set_visual_state (Gtkmm2ext::VisualState (visual_state() | Gtkmm2ext::Insensitive));
820         }
821         
822 }
823
824
825 void
826 ArdourButton::action_visibility_changed ()
827 {
828         if (_action->property_visible ()) {
829                 show ();
830         } else {
831                 hide ();
832         }
833 }
834
835 void
836 ArdourButton::action_tooltip_changed ()
837 {
838         string str = _action->property_tooltip().get_value();
839         ARDOUR_UI::instance()->set_tip (*this, str);
840 }
841
842 void
843 ArdourButton::set_rounded_corner_mask (int mask)
844 {
845         _corner_mask = mask;
846         queue_draw ();
847 }
848
849 void
850 ArdourButton::set_elements (Element e)
851 {
852         _elements = e;
853         set_colors ();
854 }
855
856 void
857 ArdourButton::add_elements (Element e)
858 {
859         _elements = (ArdourButton::Element) (_elements | e);
860         set_colors ();
861 }
862
863 void
864 ArdourButton::set_flat_buttons (bool yn)
865 {
866         _flat_buttons = yn;
867 }