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/comboboxtext.h>
40 // Necessary for gettext
41 (void) bindtextdomain(PACKAGE, LOCALEDIR);
45 Gtkmm2ext::get_ink_pixel_size (Glib::RefPtr<Pango::Layout> layout,
49 Pango::Rectangle ink_rect = layout->get_ink_extents ();
51 width = (ink_rect.get_width() + PANGO_SCALE / 2) / PANGO_SCALE;
52 height = (ink_rect.get_height() + PANGO_SCALE / 2) / PANGO_SCALE;
56 get_pixel_size (Glib::RefPtr<Pango::Layout> layout,
60 layout->get_pixel_size (width, height);
64 Gtkmm2ext::set_size_request_to_display_given_text (Gtk::Widget &w, const gchar *text,
65 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)
86 const vector<string>* to_use;
87 vector<string>::const_iterator i;
89 for (i = strings.begin(); i != strings.end(); ++i) {
90 if ((*i).find_first_of ("gy") != string::npos) {
91 /* contains a descender */
96 if (i == strings.end()) {
97 /* make a copy of the strings then add one that has a descender */
105 for (vector<string>::const_iterator i = to_use->begin(); i != to_use->end(); ++i) {
106 get_pixel_size (w.create_pango_layout (*i), width, height);
107 width_max = max(width_max,width);
108 height_max = max(height_max, height);
111 w.set_size_request(width_max + hpadding, height_max + vpadding);
115 demultiply_alpha (guint8 src,
118 /* cairo pixel buffer data contains RGB values with the alpha
119 values premultiplied.
121 GdkPixbuf pixel buffer data contains RGB values without the
124 this removes the alpha component from the cairo version and
125 returns the GdkPixbuf version.
127 return alpha ? ((guint (src) << 8) - src) / alpha : 0;
131 convert_bgra_to_rgba (guint8 const* src,
136 guint8 const* src_pixel = src;
137 guint8* dst_pixel = dst;
139 /* cairo pixel data is endian-dependent ARGB with A in the most significant 8 bits,
140 with premultipled alpha values (see preceding function)
142 GdkPixbuf pixel data is non-endian-dependent RGBA with R in the lowest addressable
143 8 bits, and non-premultiplied alpha values.
145 convert from the cairo values to the GdkPixbuf ones.
148 for (int y = 0; y < height; y++) {
149 for (int x = 0; x < width; x++) {
150 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
151 /* Cairo [ B G R A ] is actually [ B G R A ] in memory SOURCE
153 Pixbuf [ R G B A ] is actually [ R G B A ] in memory DEST
155 dst_pixel[0] = demultiply_alpha (src_pixel[2],
156 src_pixel[3]); // R [0] <= [ 2 ]
157 dst_pixel[1] = demultiply_alpha (src_pixel[1],
158 src_pixel[3]); // G [1] <= [ 1 ]
159 dst_pixel[2] = demultiply_alpha (src_pixel[0],
160 src_pixel[3]); // B [2] <= [ 0 ]
161 dst_pixel[3] = src_pixel[3]; // alpha
163 #elif G_BYTE_ORDER == G_BIG_ENDIAN
164 /* Cairo [ B G R A ] is actually [ A R G B ] in memory SOURCE
166 Pixbuf [ R G B A ] is actually [ R G B A ] in memory DEST
168 dst_pixel[0] = demultiply_alpha (src_pixel[1],
169 src_pixel[0]); // R [0] <= [ 1 ]
170 dst_pixel[1] = demultiply_alpha (src_pixel[2],
171 src_pixel[0]); // G [1] <= [ 2 ]
172 dst_pixel[2] = demultiply_alpha (src_pixel[3],
173 src_pixel[0]); // B [2] <= [ 3 ]
174 dst_pixel[3] = src_pixel[0]; // alpha
177 #error ardour does not currently support PDP-endianess
186 Glib::RefPtr<Gdk::Pixbuf>
187 Gtkmm2ext::pixbuf_from_string(const string& name, const Pango::FontDescription& font, int clip_width, int clip_height, Gdk::Color fg)
189 static Glib::RefPtr<Gdk::Pixbuf>* empty_pixbuf = 0;
192 if (empty_pixbuf == 0) {
193 empty_pixbuf = new Glib::RefPtr<Gdk::Pixbuf>;
194 *empty_pixbuf = Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB, true, 8, clip_width, clip_height);
196 return *empty_pixbuf;
199 Glib::RefPtr<Gdk::Pixbuf> buf = Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB, true, 8, clip_width, clip_height);
201 cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, clip_width, clip_height);
202 cairo_t* cr = cairo_create (surface);
203 cairo_text_extents_t te;
205 cairo_set_source_rgba (cr, fg.get_red_p(), fg.get_green_p(), fg.get_blue_p(), 1.0);
206 cairo_select_font_face (cr, font.get_family().c_str(),
207 CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
208 cairo_set_font_size (cr, font.get_size() / Pango::SCALE);
209 cairo_text_extents (cr, name.c_str(), &te);
211 cairo_move_to (cr, 0.5, int (0.5 - te.height / 2 - te.y_bearing + clip_height / 2));
212 cairo_show_text (cr, name.c_str());
214 convert_bgra_to_rgba(cairo_image_surface_get_data (surface), buf->get_pixels(), clip_width, clip_height);
217 cairo_surface_destroy(surface);
223 Gtkmm2ext::set_popdown_strings (Gtk::ComboBoxText& cr, const vector<string>& strings, bool set_size, gint hpadding, gint vpadding)
225 vector<string>::const_iterator i;
230 set_size_request_to_display_given_text (cr, strings, COMBO_FUDGE+10+hpadding, 15+vpadding);
233 for (i = strings.begin(); i != strings.end(); ++i) {
239 Gtkmm2ext::get_paned_handle (Gtk::Paned& paned)
241 return GTK_PANED(paned.gobj())->handle;
245 Gtkmm2ext::set_decoration (Gtk::Window* win, Gdk::WMDecoration decor)
247 win->get_window()->set_decorations (decor);
250 void Gtkmm2ext::set_treeview_header_as_default_label(Gtk::TreeViewColumn* c)
252 gtk_tree_view_column_set_widget( c->gobj(), GTK_WIDGET(0) );
256 Gtkmm2ext::detach_menu (Gtk::Menu& menu)
258 /* its possible for a Gtk::Menu to have no gobj() because it has
259 not yet been instantiated. Catch this and provide a safe
263 if (menu.get_attach_widget()) {
270 Gtkmm2ext::possibly_translate_keyval_to_make_legal_accelerator (uint32_t& keyval)
272 int fakekey = GDK_VoidSymbol;
276 case GDK_ISO_Left_Tab:
281 fakekey = GDK_uparrow;
285 fakekey = GDK_downarrow;
289 fakekey = GDK_rightarrow;
293 fakekey = GDK_leftarrow;
297 fakekey = GDK_3270_Enter;
308 if (fakekey != GDK_VoidSymbol) {
317 Gtkmm2ext::possibly_translate_legal_accelerator_to_real_key (uint32_t keyval)
352 Gtkmm2ext::physical_screen_height (Glib::RefPtr<Gdk::Window> win)
354 GdkScreen* scr = gdk_screen_get_default();
358 gint monitor = gdk_screen_get_monitor_at_window (scr, win->gobj());
359 gdk_screen_get_monitor_geometry (scr, monitor, &r);
362 return gdk_screen_get_height (scr);
367 Gtkmm2ext::physical_screen_width (Glib::RefPtr<Gdk::Window> win)
369 GdkScreen* scr = gdk_screen_get_default();
373 gint monitor = gdk_screen_get_monitor_at_window (scr, win->gobj());
374 gdk_screen_get_monitor_geometry (scr, monitor, &r);
377 return gdk_screen_get_width (scr);
382 Gtkmm2ext::container_clear (Gtk::Container& c)
384 list<Gtk::Widget*> children = c.get_children();
385 for (list<Gtk::Widget*>::iterator child = children.begin(); child != children.end(); ++child) {
392 Gtkmm2ext::rounded_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double w, double h, double r)
394 rounded_rectangle (context->cobj(), x, y, w, h, r);
398 Gtkmm2ext::rounded_rectangle (cairo_t* cr, double x, double y, double w, double h, double r)
400 /* renders small shapes better than most others */
408 cairo_move_to (cr, x+r,y); // Move to A
409 cairo_line_to (cr, x+w-r,y); // Straight line to B
410 cairo_curve_to (cr, x+w,y,x+w,y,x+w,y+r); // Curve to C, Control points are both at Q
411 cairo_line_to (cr, x+w,y+h-r); // Move to D
412 cairo_curve_to (cr, x+w,y+h,x+w,y+h,x+w-r,y+h); // Curve to E
413 cairo_line_to (cr, x+r,y+h); // Line to F
414 cairo_curve_to (cr, x,y+h,x,y+h,x,y+h-r); // Curve to G
415 cairo_line_to (cr, x,y+r); // Line to H
416 cairo_curve_to (cr, x,y,x,y,x+r,y); // Curve to A
422 Gtkmm2ext::rounded_rectangle (Cairo::RefPtr<Cairo::Context> context, double x, double y, double width, double height, double radius)
424 /* doesn't render small shapes well at all, and does not absolutely honor width & height */
426 double x0 = x+radius/2.0;
427 double y0 = y+radius/2.0;
428 double rect_width = width - radius;
429 double rect_height = height - radius;
433 double x1=x0+rect_width;
434 double y1=y0+rect_height;
436 if (rect_width/2<radius) {
437 if (rect_height/2<radius) {
438 context->move_to (x0, (y0 + y1)/2);
439 context->curve_to (x0 ,y0, x0, y0, (x0 + x1)/2, y0);
440 context->curve_to (x1, y0, x1, y0, x1, (y0 + y1)/2);
441 context->curve_to (x1, y1, x1, y1, (x1 + x0)/2, y1);
442 context->curve_to (x0, y1, x0, y1, x0, (y0 + y1)/2);
444 context->move_to (x0, y0 + radius);
445 context->curve_to (x0 ,y0, x0, y0, (x0 + x1)/2, y0);
446 context->curve_to (x1, y0, x1, y0, x1, y0 + radius);
447 context->line_to (x1 , y1 - radius);
448 context->curve_to (x1, y1, x1, y1, (x1 + x0)/2, y1);
449 context->curve_to (x0, y1, x0, y1, x0, y1- radius);
452 if (rect_height/2<radius) {
453 context->move_to (x0, (y0 + y1)/2);
454 context->curve_to (x0 , y0, x0 , y0, x0 + radius, y0);
455 context->line_to (x1 - radius, y0);
456 context->curve_to (x1, y0, x1, y0, x1, (y0 + y1)/2);
457 context->curve_to (x1, y1, x1, y1, x1 - radius, y1);
458 context->line_to (x0 + radius, y1);
459 context->curve_to (x0, y1, x0, y1, x0, (y0 + y1)/2);
461 context->move_to (x0, y0 + radius);
462 context->curve_to (x0 , y0, x0 , y0, x0 + radius, y0);
463 context->line_to (x1 - radius, y0);
464 context->curve_to (x1, y0, x1, y0, x1, y0 + radius);
465 context->line_to (x1 , y1 - radius);
466 context->curve_to (x1, y1, x1, y1, x1 - radius, y1);
467 context->line_to (x0 + radius, y1);
468 context->curve_to (x0, y1, x0, y1, x0, y1- radius);
472 context->close_path ();
478 Glib::RefPtr<Gdk::Window>
479 Gtkmm2ext::window_to_draw_on (Gtk::Widget& w, Gtk::Widget** parent)
481 if (w.get_has_window()) {
482 return w.get_window();
485 (*parent) = w.get_parent();
488 if ((*parent)->get_has_window()) {
489 return (*parent)->get_window ();
491 (*parent) = (*parent)->get_parent ();
494 return Glib::RefPtr<Gdk::Window> ();
499 fit_to_pixels (const string& str, int pixel_width, Pango::FontDescription& font, int& actual_width, bool with_ellipses)
502 Glib::RefPtr<Pango::Layout> layout = foo.create_pango_layout (str);
503 Glib::RefPtr<Pango::LayoutLine> line;
505 layout->set_font_description (font);
506 layout->set_width (pixel_width * PANGO_SCALE);
509 layout->set_ellipsize (PANGO_ELLIPSIZE_END);
511 layout->set_wrap_mode (PANGO_WRAP_CHAR);
513 line = layout->get_line_readonly (0);
515 /* XXX: might need special care to get the ellipsis character, not sure
517 return strdup (layout->get_text () + line->start_index, line->length);