2 Copyright (C) 1999 Paul Barton-Davis
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.
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.
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.
23 #include <gtk/gtkpaned.h>
26 #include <gtkmm2ext/utils.h>
27 #include <gtkmm/widget.h>
28 #include <gtkmm/button.h>
29 #include <gtkmm/window.h>
30 #include <gtkmm/paned.h>
31 #include <gtkmm/label.h>
32 #include <gtkmm/comboboxtext.h>
41 // Necessary for gettext
42 (void) bindtextdomain(PACKAGE, LOCALEDIR);
46 Gtkmm2ext::get_ink_pixel_size (Glib::RefPtr<Pango::Layout> layout,
50 Pango::Rectangle ink_rect = layout->get_ink_extents ();
52 width = (ink_rect.get_width() + PANGO_SCALE / 2) / PANGO_SCALE;
53 height = (ink_rect.get_height() + PANGO_SCALE / 2) / PANGO_SCALE;
57 get_pixel_size (Glib::RefPtr<Pango::Layout> layout,
61 layout->get_pixel_size (width, height);
65 Gtkmm2ext::set_size_request_to_display_given_text (Gtk::Widget &w, const gchar *text,
66 gint hpadding, gint vpadding)
71 get_pixel_size (w.create_pango_layout (text), width, height);
72 w.set_size_request(width + hpadding, height + vpadding);
76 Gtkmm2ext::set_size_request_to_display_given_text (Gtk::Widget &w,
77 const std::vector<std::string>& strings,
78 gint hpadding, gint vpadding)
85 const vector<string>* to_use;
86 vector<string>::const_iterator i;
88 for (i = strings.begin(); i != strings.end(); ++i) {
89 if ((*i).find_first_of ("gy") != string::npos) {
90 /* contains a descender */
95 if (i == strings.end()) {
96 /* make a copy of the strings then add one that has a descender */
104 for (vector<string>::const_iterator i = to_use->begin(); i != to_use->end(); ++i) {
105 get_pixel_size (w.create_pango_layout (*i), width, height);
106 width_max = max(width_max,width);
107 height_max = max(height_max, height);
110 w.set_size_request(width_max + hpadding, height_max + vpadding);
114 demultiply_alpha (guint8 src,
117 /* cairo pixel buffer data contains RGB values with the alpha
118 values premultiplied.
120 GdkPixbuf pixel buffer data contains RGB values without the
123 this removes the alpha component from the cairo version and
124 returns the GdkPixbuf version.
126 return alpha ? ((guint (src) << 8) - src) / alpha : 0;
130 convert_bgra_to_rgba (guint8 const* src,
135 guint8 const* src_pixel = src;
136 guint8* dst_pixel = dst;
138 /* cairo pixel data is endian-dependent ARGB with A in the most significant 8 bits,
139 with premultipled alpha values (see preceding function)
141 GdkPixbuf pixel data is non-endian-dependent RGBA with R in the lowest addressable
142 8 bits, and non-premultiplied alpha values.
144 convert from the cairo values to the GdkPixbuf ones.
147 for (int y = 0; y < height; y++) {
148 for (int x = 0; x < width; x++) {
149 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
150 /* Cairo [ B G R A ] is actually [ B G R A ] in memory SOURCE
152 Pixbuf [ R G B A ] is actually [ R G B A ] in memory DEST
154 dst_pixel[0] = demultiply_alpha (src_pixel[2],
155 src_pixel[3]); // R [0] <= [ 2 ]
156 dst_pixel[1] = demultiply_alpha (src_pixel[1],
157 src_pixel[3]); // G [1] <= [ 1 ]
158 dst_pixel[2] = demultiply_alpha (src_pixel[0],
159 src_pixel[3]); // B [2] <= [ 0 ]
160 dst_pixel[3] = src_pixel[3]; // alpha
162 #elif G_BYTE_ORDER == G_BIG_ENDIAN
163 /* Cairo [ B G R A ] is actually [ A R G B ] in memory SOURCE
165 Pixbuf [ R G B A ] is actually [ R G B A ] in memory DEST
167 dst_pixel[0] = demultiply_alpha (src_pixel[1],
168 src_pixel[0]); // R [0] <= [ 1 ]
169 dst_pixel[1] = demultiply_alpha (src_pixel[2],
170 src_pixel[0]); // G [1] <= [ 2 ]
171 dst_pixel[2] = demultiply_alpha (src_pixel[3],
172 src_pixel[0]); // B [2] <= [ 3 ]
173 dst_pixel[3] = src_pixel[0]; // alpha
176 #error ardour does not currently support PDP-endianess
185 Glib::RefPtr<Gdk::Pixbuf>
186 Gtkmm2ext::pixbuf_from_string(const string& name, const Pango::FontDescription& font, int clip_width, int clip_height, Gdk::Color fg)
188 static Glib::RefPtr<Gdk::Pixbuf>* empty_pixbuf = 0;
191 if (empty_pixbuf == 0) {
192 empty_pixbuf = new Glib::RefPtr<Gdk::Pixbuf>;
193 *empty_pixbuf = Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB, true, 8, clip_width, clip_height);
195 return *empty_pixbuf;
198 Glib::RefPtr<Gdk::Pixbuf> buf = Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB, true, 8, clip_width, clip_height);
200 cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, clip_width, clip_height);
201 cairo_t* cr = cairo_create (surface);
202 cairo_text_extents_t te;
204 cairo_set_source_rgba (cr, fg.get_red_p(), fg.get_green_p(), fg.get_blue_p(), 1.0);
205 cairo_select_font_face (cr, font.get_family().c_str(),
206 CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
207 cairo_set_font_size (cr, font.get_size() / Pango::SCALE);
208 cairo_text_extents (cr, name.c_str(), &te);
210 cairo_move_to (cr, 0.5, int (0.5 - te.height / 2 - te.y_bearing + clip_height / 2));
211 cairo_show_text (cr, name.c_str());
213 convert_bgra_to_rgba(cairo_image_surface_get_data (surface), buf->get_pixels(), clip_width, clip_height);
216 cairo_surface_destroy(surface);
222 Gtkmm2ext::set_popdown_strings (Gtk::ComboBoxText& cr, const vector<string>& strings)
224 vector<string>::const_iterator i;
228 for (i = strings.begin(); i != strings.end(); ++i) {
234 Gtkmm2ext::get_paned_handle (Gtk::Paned& paned)
236 return GTK_PANED(paned.gobj())->handle;
240 Gtkmm2ext::set_decoration (Gtk::Window* win, Gdk::WMDecoration decor)
242 win->get_window()->set_decorations (decor);
245 void Gtkmm2ext::set_treeview_header_as_default_label(Gtk::TreeViewColumn* c)
247 gtk_tree_view_column_set_widget( c->gobj(), GTK_WIDGET(0) );
251 Gtkmm2ext::detach_menu (Gtk::Menu& menu)
253 /* its possible for a Gtk::Menu to have no gobj() because it has
254 not yet been instantiated. Catch this and provide a safe
258 if (menu.get_attach_widget()) {
265 Gtkmm2ext::possibly_translate_keyval_to_make_legal_accelerator (uint32_t& keyval)
267 int fakekey = GDK_VoidSymbol;
271 case GDK_ISO_Left_Tab:
276 fakekey = GDK_uparrow;
280 fakekey = GDK_downarrow;
284 fakekey = GDK_rightarrow;
288 fakekey = GDK_leftarrow;
292 fakekey = GDK_3270_Enter;
303 if (fakekey != GDK_VoidSymbol) {
312 Gtkmm2ext::possibly_translate_legal_accelerator_to_real_key (uint32_t keyval)
347 Gtkmm2ext::physical_screen_height (Glib::RefPtr<Gdk::Window> win)
349 GdkScreen* scr = gdk_screen_get_default();
353 gint monitor = gdk_screen_get_monitor_at_window (scr, win->gobj());
354 gdk_screen_get_monitor_geometry (scr, monitor, &r);
357 return gdk_screen_get_height (scr);
362 Gtkmm2ext::physical_screen_width (Glib::RefPtr<Gdk::Window> win)
364 GdkScreen* scr = gdk_screen_get_default();
368 gint monitor = gdk_screen_get_monitor_at_window (scr, win->gobj());
369 gdk_screen_get_monitor_geometry (scr, monitor, &r);
372 return gdk_screen_get_width (scr);
377 Gtkmm2ext::container_clear (Gtk::Container& c)
379 list<Gtk::Widget*> children = c.get_children();
380 for (list<Gtk::Widget*>::iterator child = children.begin(); child != children.end(); ++child) {
386 Gtkmm2ext::rounded_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double w, double h, double r)
388 rounded_rectangle (context->cobj(), x, y, w, h, r);
391 Gtkmm2ext::rounded_top_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double w, double h, double r)
393 rounded_top_rectangle (context->cobj(), x, y, w, h, r);
396 Gtkmm2ext::rounded_top_left_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double w, double h, double r)
398 rounded_top_left_rectangle (context->cobj(), x, y, w, h, r);
401 Gtkmm2ext::rounded_top_right_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double w, double h, double r)
403 rounded_top_right_rectangle (context->cobj(), x, y, w, h, r);
406 Gtkmm2ext::rounded_top_half_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double w, double h, double r)
408 rounded_top_half_rectangle (context->cobj(), x, y, w, h, r);
411 Gtkmm2ext::rounded_bottom_half_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double w, double h, double r)
413 rounded_bottom_half_rectangle (context->cobj(), x, y, w, h, r);
417 Gtkmm2ext::rounded_rectangle (cairo_t* cr, double x, double y, double w, double h, double r)
425 cairo_move_to (cr, x+r,y); // Move to A
426 cairo_line_to (cr, x+w-r,y); // Straight line to B
427 cairo_curve_to (cr, x+w,y,x+w,y,x+w,y+r); // Curve to C, Control points are both at Q
428 cairo_line_to (cr, x+w,y+h-r); // Move to D
429 cairo_curve_to (cr, x+w,y+h,x+w,y+h,x+w-r,y+h); // Curve to E
430 cairo_line_to (cr, x+r,y+h); // Line to F
431 cairo_curve_to (cr, x,y+h,x,y+h,x,y+h-r); // Curve to G
432 cairo_line_to (cr, x,y+r); // Line to H
433 cairo_curve_to (cr, x,y,x,y,x+r,y); // Curve to A
437 Gtkmm2ext::rounded_top_half_rectangle (cairo_t* cr, double x, double y, double w, double h, double r)
445 cairo_move_to (cr, x+r,y); // Move to A
446 cairo_line_to (cr, x+w-r,y); // Straight line to B
447 cairo_curve_to (cr, x+w,y,x+w,y,x+w,y+r); // Curve to C, Control points are both at Q
448 cairo_line_to (cr, x+w,y+h); // Move to E
449 cairo_line_to (cr, x,y+h); // Line to F
450 cairo_line_to (cr, x,y+r); // Line to H
451 cairo_curve_to (cr, x,y,x,y,x+r,y); // Curve to A
455 Gtkmm2ext::rounded_bottom_half_rectangle (cairo_t* cr, double x, double y, double w, double h, double r)
463 cairo_move_to (cr, x,y); // Move to A
464 cairo_line_to (cr, x+w,y); // Straight line to B
465 cairo_line_to (cr, x+w,y+h-r); // Move to D
466 cairo_curve_to (cr, x+w,y+h,x+w,y+h,x+w-r,y+h); // Curve to E
467 cairo_line_to (cr, x+r,y+h); // Line to F
468 cairo_curve_to (cr, x,y+h,x,y+h,x,y+h-r); // Curve to G
469 cairo_line_to (cr, x,y); // Line to A
474 Gtkmm2ext::rounded_top_rectangle (cairo_t* cr, double x, double y, double w, double h, double r)
482 cairo_move_to (cr, x+r,y); // Move to A
483 cairo_line_to (cr, x+w-r,y); // Straight line to B
484 cairo_curve_to (cr, x+w,y,x+w,y,x+w,y+r); // Curve to C, Control points are both at Q
485 cairo_line_to (cr, x+w,y+h); // Move to E
486 cairo_line_to (cr, x,y+h); // Line to F
487 cairo_line_to (cr, x,y+r); // Line to H
488 cairo_curve_to (cr, x,y,x,y,x+r,y); // Curve to A
492 Gtkmm2ext::rounded_top_left_rectangle (cairo_t* cr, double x, double y, double w, double h, double r)
500 cairo_move_to (cr, x+r,y); // Move to A
501 cairo_line_to (cr, x+w,y); // Straight line to B
502 cairo_line_to (cr, x+w,y+h); // Move to E
503 cairo_line_to (cr, x,y+h); // Line to F
504 cairo_line_to (cr, x,y+r); // Line to H
505 cairo_curve_to (cr, x,y,x,y,x+r,y); // Curve to A
509 Gtkmm2ext::rounded_top_right_rectangle (cairo_t* cr, double x, double y, double w, double h, double r)
517 cairo_move_to (cr, x,y); // Move to A
518 cairo_line_to (cr, x+w-r,y); // Straight line to B
519 cairo_curve_to (cr, x+w,y,x+w,y,x+w,y+r); // Curve to C, Control points are both at Q
520 cairo_line_to (cr, x+w,y+h); // Move to E
521 cairo_line_to (cr, x,y+h); // Line to F
522 cairo_line_to (cr, x,y); // Line to A
525 Glib::RefPtr<Gdk::Window>
526 Gtkmm2ext::window_to_draw_on (Gtk::Widget& w, Gtk::Widget** parent)
528 if (w.get_has_window()) {
529 return w.get_window();
532 (*parent) = w.get_parent();
535 if ((*parent)->get_has_window()) {
536 return (*parent)->get_window ();
538 (*parent) = (*parent)->get_parent ();
541 return Glib::RefPtr<Gdk::Window> ();
545 Gtkmm2ext::pixel_width (const string& str, Pango::FontDescription& font)
548 Glib::RefPtr<Pango::Layout> layout = foo.create_pango_layout ("");
550 layout->set_font_description (font);
551 layout->set_text (str);
554 Gtkmm2ext::get_ink_pixel_size (layout, width, height);
560 Gtkmm2ext::fit_to_pixels (const string& str, int pixel_width, Pango::FontDescription& font, int& actual_width, bool with_ellipses)
562 /* DECEMBER 2011: THIS PROTOTYPE OF fit_to_pixels() IS NOT USED
563 ANYWHERE AND HAS NOT BEEN TESTED.
566 Glib::RefPtr<Pango::Layout> layout = foo.create_pango_layout (str);
567 Glib::RefPtr<const Pango::LayoutLine> line;
569 layout->set_font_description (font);
570 layout->set_width (pixel_width * PANGO_SCALE);
573 layout->set_ellipsize (Pango::ELLIPSIZE_END);
575 layout->set_wrap (Pango::WRAP_CHAR);
578 line = layout->get_line (0);
580 /* XXX: might need special care to get the ellipsis character, not sure
584 string s = string (layout->get_text ().substr(line->get_start_index(), line->get_length()));
586 cerr << "fit to pixels of " << str << " returns " << s << endl;
592 /** Try to fit a string into a given horizontal space by ellipsizing it.
593 * @param cr Cairo context in which the text will be plotted.
595 * @param avail Available horizontal space.
596 * @return (Text, possibly ellipsized) and (horizontal size of text)
599 std::pair<std::string, double>
600 Gtkmm2ext::fit_to_pixels (cairo_t* cr, std::string name, double avail)
602 /* XXX hopefully there exists a more efficient way of doing this */
604 bool abbreviated = false;
608 cairo_text_extents_t ext;
609 cairo_text_extents (cr, name.c_str(), &ext);
611 if (ext.width < avail || name.length() <= 4) {
617 name = name.substr (0, name.length() - 4) + "...";
619 name = name.substr (0, name.length() - 3) + "...";
624 return std::make_pair (name, width);
628 Gtkmm2ext::left_aligned_label (string const & t)
630 Gtk::Label* l = new Gtk::Label (t);
631 l->set_alignment (0, 0.5);