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 descener */
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
, 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 /* renders small shapes better than most others */
402 context
->move_to(x
+r
,y
); // Move to A
403 context
->line_to(x
+w
-r
,y
); // Straight line to B
404 context
->curve_to(x
+w
,y
,x
+w
,y
,x
+w
,y
+r
); // Curve to C, Control points are both at Q
405 context
->line_to(x
+w
,y
+h
-r
); // Move to D
406 context
->curve_to(x
+w
,y
+h
,x
+w
,y
+h
,x
+w
-r
,y
+h
); // Curve to E
407 context
->line_to(x
+r
,y
+h
); // Line to F
408 context
->curve_to(x
,y
+h
,x
,y
+h
,x
,y
+h
-r
); // Curve to G
409 context
->line_to(x
,y
+r
); // Line to H
410 context
->curve_to(x
,y
,x
,y
,x
+r
,y
); // Curve to A
416 Gtkmm2ext::rounded_rectangle (Cairo::RefPtr
<Cairo::Context
> context
, double x
, double y
, double width
, double height
, double radius
)
418 /* doesn't render small shapes well at all, and does not absolutely honor width & height */
420 double x0
= x
+radius
/2.0;
421 double y0
= y
+radius
/2.0;
422 double rect_width
= width
- radius
;
423 double rect_height
= height
- radius
;
427 double x1
=x0
+rect_width
;
428 double y1
=y0
+rect_height
;
430 if (rect_width
/2<radius
) {
431 if (rect_height
/2<radius
) {
432 context
->move_to (x0
, (y0
+ y1
)/2);
433 context
->curve_to (x0
,y0
, x0
, y0
, (x0
+ x1
)/2, y0
);
434 context
->curve_to (x1
, y0
, x1
, y0
, x1
, (y0
+ y1
)/2);
435 context
->curve_to (x1
, y1
, x1
, y1
, (x1
+ x0
)/2, y1
);
436 context
->curve_to (x0
, y1
, x0
, y1
, x0
, (y0
+ y1
)/2);
438 context
->move_to (x0
, y0
+ radius
);
439 context
->curve_to (x0
,y0
, x0
, y0
, (x0
+ x1
)/2, y0
);
440 context
->curve_to (x1
, y0
, x1
, y0
, x1
, y0
+ radius
);
441 context
->line_to (x1
, y1
- radius
);
442 context
->curve_to (x1
, y1
, x1
, y1
, (x1
+ x0
)/2, y1
);
443 context
->curve_to (x0
, y1
, x0
, y1
, x0
, y1
- radius
);
446 if (rect_height
/2<radius
) {
447 context
->move_to (x0
, (y0
+ y1
)/2);
448 context
->curve_to (x0
, y0
, x0
, y0
, x0
+ radius
, y0
);
449 context
->line_to (x1
- radius
, y0
);
450 context
->curve_to (x1
, y0
, x1
, y0
, x1
, (y0
+ y1
)/2);
451 context
->curve_to (x1
, y1
, x1
, y1
, x1
- radius
, y1
);
452 context
->line_to (x0
+ radius
, y1
);
453 context
->curve_to (x0
, y1
, x0
, y1
, x0
, (y0
+ y1
)/2);
455 context
->move_to (x0
, y0
+ radius
);
456 context
->curve_to (x0
, y0
, x0
, y0
, x0
+ radius
, y0
);
457 context
->line_to (x1
- radius
, y0
);
458 context
->curve_to (x1
, y0
, x1
, y0
, x1
, y0
+ radius
);
459 context
->line_to (x1
, y1
- radius
);
460 context
->curve_to (x1
, y1
, x1
, y1
, x1
- radius
, y1
);
461 context
->line_to (x0
+ radius
, y1
);
462 context
->curve_to (x0
, y1
, x0
, y1
, x0
, y1
- radius
);
466 context
->close_path ();