24 #include <pangomm/layout.h>
36 #include "canvas/utils.h"
37 #include "canvas/colors.h"
45 #define BASELINESTRETCH (1.25)
46 #define TRACKHEADERBTNW (3.10)
64 , _char_pixel_width (0)
65 , _char_pixel_height (0)
66 , _char_avg_pixel_width (0)
70 , _corner_radius (2.5)
75 , fill_inactive_color (0)
76 , fill_active_color (0)
77 , text_active_color(0)
78 , text_inactive_color(0)
80 , led_inactive_color(0)
81 , led_custom_color (0)
82 , use_custom_led_color (false)
85 , led_inset_pattern (0)
87 , _act_on_release (true)
89 , _distinct_led_click (false)
92 , _fixed_colors_set (false)
93 , _fallthrough_to_parent (false)
94 , _layout_ellipsize_width (-1)
95 , _ellipsis (
Pango::ELLIPSIZE_NONE)
96 , _update_colors (true)
108 , _corner_radius (2.5)
113 , fill_inactive_color (0)
114 , fill_active_color (0)
115 , text_active_color(0)
116 , text_inactive_color(0)
117 , led_active_color(0)
118 , led_inactive_color(0)
119 , led_custom_color (0)
120 , use_custom_led_color (false)
122 , concave_pattern (0)
123 , led_inset_pattern (0)
125 , _act_on_release (true)
127 , _distinct_led_click (false)
130 , _fixed_colors_set (false)
131 , _fallthrough_to_parent (false)
132 , _layout_ellipsize_width (-1)
133 , _ellipsis (
Pango::ELLIPSIZE_NONE)
134 , _update_colors (true)
135 , _pattern_height (0)
164 _layout->set_font_description (fd);
173 if (!is_realized()) {
223 void (*rounded_function)(cairo_t*, double, double, double, double, double);
244 rounded_function (cr, 0, 0, get_width(), get_height(), corner_radius + 1.5);
245 cairo_set_source_rgba (cr, 0, 0, 0, 1);
251 rounded_function (cr, 1, 1, get_width() - 2, get_height() - 2, corner_radius);
269 cairo_set_line_width (cr, 2.0);
270 rounded_function (cr, 2, 2, get_width() - 4, get_height() - 4, corner_radius-0.5);
290 #define VECTORICONSTROKEFILL(fillalpha) \
291 cairo_set_line_width(cr, 1.5); \
292 cairo_set_source_rgba (cr, 0, 0, 0, 1.0); \
293 cairo_stroke_preserve(cr); \
294 cairo_set_source_rgba (cr, 1, 1, 1, (fillalpha)); \
299 double x = rint((get_width() -
_pixbuf->get_width()) * .5);
300 const double y = rint((get_height() -
_pixbuf->get_height()) * .5);
301 #if 0 // DEBUG style (print on hover)
303 printf(
"%s: p:%dx%d (%dx%d)\n",
306 get_width(), get_height());
314 cairo_rectangle (cr, x, y,
_pixbuf->get_width(),
_pixbuf->get_height());
315 gdk_cairo_set_source_pixbuf (cr,
_pixbuf->gobj(), x, y);
322 const double x = get_width() * .5;
323 const double y = get_height() * .5;
324 const double r = std::min(x, y) * .6;
325 const double slit = .11 * M_PI;
327 cairo_translate(cr, x, y);
329 cairo_arc (cr, 0, 0, r, 0, 2 * M_PI);
331 cairo_set_source_rgba (cr, .95, .1, .1, 1.);
333 cairo_set_source_rgba (cr, .95, .44, .44, 1.);
335 cairo_fill_preserve(cr);
336 cairo_set_source_rgba (cr, .0, .0, .0, .5);
337 cairo_set_line_width(cr, 1);
341 cairo_set_source_rgba (cr, .15, .07, .07, 1.0);
343 cairo_rotate (cr, -.5 * M_PI);
344 cairo_move_to(cr, 0, 0);
345 cairo_arc (cr, 0, 0, r *.85, -slit, slit);
346 cairo_line_to(cr, 0, 0);
347 cairo_close_path(cr);
350 cairo_rotate (cr, 2. * M_PI / 3.);
352 cairo_move_to(cr, 0, 0);
353 cairo_arc (cr, 0, 0, r *.85, -slit, slit);
354 cairo_line_to(cr, 0, 0);
355 cairo_close_path(cr);
358 cairo_rotate (cr, 2. * M_PI / 3.);
359 cairo_move_to(cr, 0, 0);
360 cairo_arc (cr, 0, 0, r *.85, -slit, slit);
361 cairo_line_to(cr, 0, 0);
362 cairo_close_path(cr);
367 cairo_arc (cr, 0, 0, r * .3, 0, 2 * M_PI);
369 cairo_set_source_rgba (cr, .95, .1, .1, 1.);
371 cairo_set_source_rgba (cr, .95, .44, .44, 1.);
373 cairo_set_source_rgba (cr, .0, .0, .0, 1.0);
374 cairo_arc (cr, 0, 0, r *.15, 0, 2 * M_PI);
380 const double x = get_width() * .5;
381 const double y = get_height() * .5;
382 const double r = std::min(x, y) * .55;
383 cairo_arc (cr, x, y, r, 0, 2 * M_PI);
385 cairo_set_source_rgba (cr, .95, .1, .1, 1.);
387 cairo_set_source_rgba (cr, .95, .44, .44, 1.);
388 cairo_fill_preserve(cr);
389 cairo_set_source_rgba (cr, .0, .0, .0, .8);
390 cairo_set_line_width(cr, 1);
394 const double x = get_width() * .5;
395 const double y = get_height() * .5;
396 const double o = .5 + std::min(x, y) * .4;
397 ArdourCanvas::set_source_rgba (cr, text_color);
398 cairo_set_line_width(cr, 1);
399 cairo_move_to(cr, x-o, y-o);
400 cairo_line_to(cr, x+o, y+o);
401 cairo_move_to(cr, x+o, y-o);
402 cairo_line_to(cr, x-o, y+o);
406 const double x0 = get_width() * .2;
407 const double x1 = get_width() * .8;
409 const double y0 = get_height() * .25;
410 const double y1= get_height() * .75;
412 const double ym= get_height() * .5;
415 const double xa0= get_height() * .39;
416 const double xa1= get_height() * .61;
417 const double ya0= get_height() * .35;
418 const double ya1= get_height() * .65;
420 ArdourCanvas::set_source_rgba (cr, text_color);
421 cairo_set_line_width(cr, 1);
424 cairo_move_to(cr, x0, y0);
425 cairo_line_to(cr, x0, y1);
426 cairo_move_to(cr, x1, y0);
427 cairo_line_to(cr, x1, y1);
430 cairo_move_to(cr, x0, ym);
431 cairo_line_to(cr, x1, ym);
434 cairo_move_to(cr, x0, ym);
435 cairo_line_to(cr, xa0, ya0);
436 cairo_move_to(cr, x0, ym);
437 cairo_line_to(cr, xa0, ya1);
440 cairo_move_to(cr, x1, ym);
441 cairo_line_to(cr, xa1, ya0);
442 cairo_move_to(cr, x1, ym);
443 cairo_line_to(cr, xa1, ya1);
447 const double x = get_width() * .5;
448 const double y = get_height() * .5;
449 const double r = std::min(x, y) * .75;
450 ArdourCanvas::set_source_rgba (cr, text_color);
451 cairo_set_line_width(cr, 1);
452 cairo_arc (cr, x, y, r, .57 * M_PI, 2.43 * M_PI);
456 cairo_arc (cr, x, y * 0.5, r * .15, 0, 2 * M_PI);
458 cairo_arc (cr, x * 0.5, y, r * .15, 0, 2 * M_PI);
460 cairo_arc (cr, x * 1.5, y, r * .15, 0, 2 * M_PI);
463 cairo_arc (cr, x * 0.677, y * .677, r * .15, 0, 2 * M_PI);
465 cairo_arc (cr, x * 1.323, y * .677, r * .15, 0, 2 * M_PI);
469 cairo_arc (cr, x, y+r, r * .26, 1.05 * M_PI, 1.95 * M_PI);
473 const int wh = std::min (get_width(), get_height());
475 (get_width() - wh) * .5 + wh * .25,
476 (get_height() - wh) * .5 + wh * .25,
482 const int wh = std::min (get_width(), get_height()) * .5;
483 const double y = get_height() * .5;
484 const double x = get_width() - wh;
486 const float tri = ceil(.577 * wh);
488 cairo_move_to (cr, x + wh * .5, y);
489 cairo_line_to (cr, x - wh * .5, y - tri);
490 cairo_line_to (cr, x - wh * .5, y + tri);
491 cairo_close_path (cr);
496 const int wh = std::min (get_width(), get_height()) * .1;
497 const double xc = get_width() * .5;
498 const double yh = get_height();
504 cairo_arc (cr, xc, yh *.75, wh, 0, 2 * M_PI);
509 int wh = std::min (get_width(), get_height());
510 const double y = get_height() * .5;
511 const double x = get_width() - wh * .5;
513 const float tri = ceil(.577 * wh * 2);
515 const float ln = std::min (get_width(), get_height()) * .07;
519 x - wh - ln, y - tri * 1.7,
527 x + wh - ln, y - tri * 1.7,
534 cairo_move_to (cr, x - wh, y);
535 cairo_line_to (cr, x + wh, y - tri);
536 cairo_line_to (cr, x + wh, y + tri);
538 cairo_move_to (cr, x + wh, y);
539 cairo_line_to (cr, x - wh, y - tri);
540 cairo_line_to (cr, x - wh, y + tri);
543 cairo_close_path (cr);
547 const double x = get_width() * .5;
548 const double y = get_height() * .5;
549 const double r = std::min(x, y);
551 cairo_arc (cr, x, y, r * .62, 0, 2 * M_PI);
552 cairo_arc_negative (cr, x, y, r * .35, 2 * M_PI, 0);
555 #define ARCARROW(rad, ang) \
556 x + (rad) * sin((ang) * 2.0 * M_PI), y + (rad) * cos((ang) * 2.0 * M_PI)
558 cairo_move_to (cr,
ARCARROW(r * .35, .72));
559 cairo_line_to (cr,
ARCARROW(r * .15, .72));
560 cairo_line_to (cr,
ARCARROW(r * .56, .60));
561 cairo_line_to (cr,
ARCARROW(r * .75, .72));
562 cairo_line_to (cr,
ARCARROW(r * .62, .72));
564 cairo_set_source_rgba (cr, 0, 0, 0, 1.0);
565 cairo_stroke_preserve(cr);
566 cairo_close_path (cr);
567 cairo_set_source_rgba (cr, 1, 1, 1, 1.0);
572 const double x = get_width() * .5;
573 const double y = get_height() * .5;
574 const double wh = std::min(x, y);
575 const double h = wh * .85;
576 const double w = wh * .55;
577 const double lw = w * .34;
580 x - w * .7, y + h * .25,
585 cairo_move_to (cr, x - w, y + h);
586 cairo_line_to (cr, x + w, y + h);
587 cairo_line_to (cr, x + w * .35, y - h);
588 cairo_line_to (cr, x - w * .35, y - h);
589 cairo_line_to (cr, x - w, y + h);
591 cairo_move_to (cr, x - w + lw, y + h -lw);
592 cairo_line_to (cr, x - w * .35 + lw, y - h + lw);
593 cairo_line_to (cr, x + w * .35 - lw, y - h + lw);
594 cairo_line_to (cr, x + w - lw, y + h -lw);
595 cairo_line_to (cr, x - w + lw, y + h -lw);
603 const double dx = lw * .2;
604 const double dy = lw * .4;
605 cairo_move_to (cr, x - w * .3 , y + h * .25 + lw * .5);
606 cairo_line_to (cr, x - w + dx , y - h + lw + dy);
607 cairo_line_to (cr, x - w + lw , y - h + lw);
608 cairo_line_to (cr, x - w * .3 + lw, y + h * .25 + lw * .5);
609 cairo_close_path (cr);
614 x - w * .7, y + h * .25,
622 #undef VECTORICONSTROKEFILL
628 #if 0 // DEBUG style (print on hover)
630 bool layout_font =
true;
631 Pango::FontDescription fd =
_layout->get_font_description();
632 if (fd.gobj() == NULL) {
634 fd = get_pango_context()->get_font_description();
636 printf(
"%s: f:%dx%d aw:%.3f bh:%.0f t:%dx%d (%dx%d) %s\"%s\"\n",
641 get_width(), get_height(),
642 layout_font ?
"L:" :
"W:",
643 fd.to_string().c_str());
648 cairo_rectangle (cr, 2, 1, get_width() - 4, get_height() - 2);
652 ArdourCanvas::set_source_rgba (cr, text_color);
653 const double text_ypos = (get_height() -
_text_height) * .5;
657 cairo_move_to (cr, text_margin, text_ypos);
658 pango_cairo_show_layout (cr,
_layout->gobj());
664 cairo_move_to (cr, text_margin, text_ypos);
666 pango_cairo_show_layout (cr,
_layout->gobj());
675 cairo_rotate(cr,
_angle * M_PI / 180.0);
676 cairo_device_to_user(cr, &ww, &wh);
684 if (
_xalign < 0) xa = ceil(.5 + (ww * fabs(
_xalign) + text_margin));
686 cairo_move_to (cr, xa, ya);
687 pango_cairo_update_layout(cr,
_layout->gobj());
688 pango_cairo_show_layout (cr,
_layout->gobj());
697 const float triw2 = ceil(.577 *
_diameter * .5);
699 cairo_set_source_rgba (cr, 1, 1, 1, 0.4);
700 cairo_move_to(cr, get_width() - triw2 - 3. , rint((get_height() + trih) * .5));
701 cairo_rel_line_to(cr, -triw2, -trih);
702 cairo_rel_line_to(cr, 2. * triw2, 0);
703 cairo_close_path(cr);
705 cairo_set_source_rgba (cr, 1, 1, 1, 0.4);
708 cairo_move_to(cr, get_width() - triw2 - 3 , rint((get_height() + trih) * .5));
709 cairo_rel_line_to(cr, .5 - triw2, .5 - trih);
710 cairo_rel_line_to(cr, 2. * triw2 - 1, 0);
711 cairo_close_path(cr);
712 cairo_set_source_rgba (cr, 0, 0, 0, 0.8);
713 cairo_set_line_width(cr, 1);
725 cairo_translate (cr, led_xoff, get_height() * .5);
727 cairo_translate (cr, get_width() - led_xoff, get_height() * .5);
730 cairo_translate (cr, get_width() * .5, get_height() * .5);
735 cairo_arc (cr, 0, 0,
_diameter * .5, 0, 2 * M_PI);
741 cairo_set_source_rgb (cr, 0, 0, 0);
742 cairo_arc (cr, 0, 0,
_diameter * .5 - 1 * ARDOUR_UI::ui_scale, 0, 2 * M_PI);
746 ArdourCanvas::set_source_rgba (cr, led_color);
747 cairo_arc (cr, 0, 0,
_diameter * .5 - 3 * ARDOUR_UI::ui_scale, 0, 2 * M_PI);
755 rounded_function (cr, 0, 0, get_width(), get_height(), corner_radius);
757 ArdourCanvas::set_source_rgb_a (cr, ins_color, 0.6);
765 rounded_function (cr, 1, 1, get_width() - 2, get_height() - 2, corner_radius);
766 cairo_set_source_rgba (cr, 0.905, 0.917, 0.925, 0.2);
773 rounded_function (cr, 1, 1, get_width() - 2, get_height() - 2, corner_radius);
774 cairo_set_line_width(cr, 2);
775 cairo_set_source_rgba (cr, 0.1, 0.1, 0.1, .5);
781 cairo_set_line_width(cr, 1);
782 cairo_set_source_rgba (cr, 1, 0, 0, 0.8);
783 rounded_function (cr, 0.5, 0.5, get_width() - 1, get_height() - 1, corner_radius);
793 rounded_function (cr, 1.5, 1.5, get_width() - 3, get_height() - 3, corner_radius);
794 cairo_set_source_rgba (cr, 0.905, 0.917, 0.925, 0.8);
796 cairo_set_dash (cr, &dashes, 1, 0);
797 cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT);
798 cairo_set_line_width (cr, 1.0);
800 cairo_set_dash (cr, 0, 0, 0);
814 CairoWidget::on_realize ();
825 req->width = req->height = 0;
826 CairoWidget::on_size_request (req);
849 req->height = std::max(req->height,
_pixbuf->get_height() + 4);
854 req->height = std::max (req->height, (
int) lrint (
_diameter) + 4);
865 req->height = std::max(req->height, wh);
879 if (req->width < req->height)
880 req->width = req->height;
881 if (req->height < req->width)
882 req->height = req->width;
886 if ((req->width -
_text_width) & 1) { ++req->width; }
887 if ((req->height -
_text_height) & 1) { ++req->height; }
890 printf(
"REQ: %s: %dx%d\n", get_name().c_str(), req->width, req->height);
905 std::string
name = get_name();
947 unsigned char r, g, b, a;
950 double white_contrast = (max (
double(r), 255.) - min (
double(r), 255.)) +
951 (max (
double(g), 255.) - min (
double(g), 255.)) +
952 (max (
double(b), 255.) - min (
double(b), 255.));
954 double black_contrast = (max (
double(r), 0.) - min (
double(r), 0.)) +
955 (max (
double(g), 0.) - min (
double(g), 0.)) +
956 (max (
double(b), 0.) - min (
double(b), 0.));
965 white_contrast = (max (
double(r), 255.) - min (
double(r), 255.)) +
966 (max (
double(g), 255.) - min (
double(g), 255.)) +
967 (max (
double(b), 255.) - min (
double(b), 255.));
969 black_contrast = (max (
double(r), 0.) - min (
double(r), 0.)) +
970 (max (
double(g), 0.) - min (
double(g), 0.)) +
971 (max (
double(b), 0.) - min (
double(b), 0.));
1000 convex_pattern = cairo_pattern_create_linear (0.0, 0, 0.0, get_height());
1001 cairo_pattern_add_color_stop_rgba (
convex_pattern, 0.0, 0,0,0, 0.0);
1002 cairo_pattern_add_color_stop_rgba (
convex_pattern, 1.0, 0,0,0, 0.35);
1005 concave_pattern = cairo_pattern_create_linear (0.0, 0, 0.0, get_height());
1118 warning <<
_(
"button cannot watch state of non-existing Controllable\n") <<
endmsg;
1129 if (fabs (val) >= 0.5
f) {
1146 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (
_action);
1161 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (
_action);
1164 if (tact->get_active()) {
1186 if (is_realized()) {
1224 if (is_realized()) {
1256 return CairoWidget::on_focus_in_event (ev);
1264 return CairoWidget::on_focus_out_event (ev);
1270 (ev->keyval == GDK_space || ev->keyval == GDK_Return))
1278 return CairoWidget::on_key_release_event (ev);
1290 return CairoWidget::on_enter_notify_event (ev);
1302 return CairoWidget::on_leave_notify_event (ev);
1310 if (is_realized()) {
1319 if (
_action->property_sensitive ()) {
1339 if (is_realized ()) {
1358 if (is_realized ()) {
1368 _layout = Pango::Layout::create (get_pango_context());
1386 std::string x =
_(
"ABCDEFGHIJLKMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
1388 _layout->get_pixel_size (w, h);
1392 Glib::ustring gx(x);
1401 if (
_action->property_visible ()) {
1411 string str =
_action->property_tooltip().get_value();
ArdourCanvas::Color color(const std::string &, bool *failed=0) const
boost::shared_ptr< PBD::Controllable > get_controllable() const
sigc::signal< void > DPIReset
static ARDOUR_UI * instance()
void set_controllable(boost::shared_ptr< PBD::Controllable >)
LIBPBD_API Transmitter warning
std::ostream & endmsg(std::ostream &ostr)
#define UINT_TO_RGBA(u, r, g, b, a)
virtual void set_related_action(Glib::RefPtr< Gtk::Action > a)
uint32_t contrasting_text_color(uint32_t c)
LIBGTKMM2EXT_API void rounded_top_rectangle(Cairo::RefPtr< Cairo::Context > context, double x, double y, double w, double h, double r=10)
virtual double get_value(void) const =0
bool button_press_handler(GdkEventButton *)
void set_tip(Gtk::Widget &w, const gchar *tip)
static UIConfiguration * config()
sigc::signal< void > ColorsChanged
LIBGTKMM2EXT_API void rounded_rectangle(Cairo::RefPtr< Cairo::Context > context, double x, double y, double w, double h, double r=10)
Glib::RefPtr< Gtk::Action > _action
#define RGBA_TO_UINT(r, g, b, a)
LIBGTKMM2EXT_API void rounded_top_left_rectangle(Cairo::RefPtr< Cairo::Context > context, double x, double y, double w, double h, double r=10)
LIBGTKMM2EXT_API void rounded_top_right_rectangle(Cairo::RefPtr< Cairo::Context > context, double x, double y, double w, double h, double r=10)
std::string string_compose(const std::string &fmt, const T1 &o1)