2 Copyright (C) 2003 Paul 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.
25 #include <libart_lgpl/art_misc.h>
26 #include <gtkmm/window.h>
27 #include <gtkmm/combo.h>
28 #include <gtkmm/label.h>
29 #include <gtkmm/paned.h>
30 #include <gtk/gtkpaned.h>
32 #include <gtkmm2ext/utils.h>
33 #include <ardour/ardour.h>
35 #include "ardour_ui.h"
39 #include "rgb_macros.h"
40 #include "canvas_impl.h"
49 fit_to_pixels (const ustring& str, int pixel_width, Pango::FontDescription& font, int& actual_width, bool with_ellipses)
52 Glib::RefPtr<Pango::Layout> layout = foo.create_pango_layout ("");
53 ustring::size_type shorter_by = 0;
56 layout->set_font_description (font);
61 ustring::iterator last = ustr.end();
62 --last; /* now points at final entry */
66 while (!ustr.empty()) {
68 layout->set_text (txt);
71 Gtkmm2ext::get_ink_pixel_size (layout, width, height);
73 if (width < pixel_width) {
81 if (with_ellipses && shorter_by > 3) {
93 just_hide_it (GdkEventAny *ev, Gtk::Window *win)
99 /* xpm2rgb copied from nixieclock, which bore the legend:
101 nixieclock - a nixie desktop timepiece
102 Copyright (C) 2000 Greg Ercolano, erco@3dsite.com
104 and was released under the GPL.
108 xpm2rgb (const char** xpm, uint32_t& w, uint32_t& h)
110 static long vals[256], val;
111 uint32_t t, x, y, colors, cpp;
113 unsigned char *savergb, *rgb;
117 if ( sscanf(xpm[0], "%u%u%u%u", &w, &h, &colors, &cpp) != 4 ) {
118 error << string_compose (_("bad XPM header %1"), xpm[0])
123 savergb = rgb = (unsigned char*)art_alloc (h * w * 3);
125 // LOAD XPM COLORMAP LONG ENOUGH TO DO CONVERSION
126 for (t = 0; t < colors; ++t) {
127 sscanf (xpm[t+1], "%c c #%lx", &c, &val);
131 // COLORMAP -> RGB CONVERSION
132 // Get low 3 bytes from vals[]
136 for (y = h-1; y > 0; --y) {
138 for (p = xpm[1+colors+(h-y-1)], x = 0; x < w; x++, rgb += 3) {
139 val = vals[(int)*p++];
140 *(rgb+2) = val & 0xff; val >>= 8; // 2:B
141 *(rgb+1) = val & 0xff; val >>= 8; // 1:G
142 *(rgb+0) = val & 0xff; // 0:R
150 xpm2rgba (const char** xpm, uint32_t& w, uint32_t& h)
152 static long vals[256], val;
153 uint32_t t, x, y, colors, cpp;
155 unsigned char *savergb, *rgb;
160 if ( sscanf(xpm[0], "%u%u%u%u", &w, &h, &colors, &cpp) != 4 ) {
161 error << string_compose (_("bad XPM header %1"), xpm[0])
166 savergb = rgb = (unsigned char*)art_alloc (h * w * 4);
168 // LOAD XPM COLORMAP LONG ENOUGH TO DO CONVERSION
170 if (strstr (xpm[1], "None")) {
171 sscanf (xpm[1], "%c", &transparent);
178 for (; t < colors; ++t) {
179 sscanf (xpm[t+1], "%c c #%lx", &c, &val);
183 // COLORMAP -> RGB CONVERSION
184 // Get low 3 bytes from vals[]
188 for (y = h-1; y > 0; --y) {
192 for (p = xpm[1+colors+(h-y-1)], x = 0; x < w; x++, rgb += 4) {
194 if (transparent && (*p++ == transparent)) {
202 *(rgb+3) = alpha; // 3: alpha
203 *(rgb+2) = val & 0xff; val >>= 8; // 2:B
204 *(rgb+1) = val & 0xff; val >>= 8; // 1:G
205 *(rgb+0) = val & 0xff; // 0:R
212 ArdourCanvas::Points*
213 get_canvas_points (string who, uint32_t npoints)
215 // cerr << who << ": wants " << npoints << " canvas points" << endl;
216 #ifdef TRAP_EXCESSIVE_POINT_REQUESTS
217 if (npoints > (uint32_t) gdk_screen_width() + 4) {
221 return new ArdourCanvas::Points (npoints);
224 Pango::FontDescription
225 get_font_for_style (string widgetname)
227 Gtk::Window window (WINDOW_TOPLEVEL);
229 Glib::RefPtr<Gtk::Style> style;
232 foobar.set_name (widgetname);
233 foobar.ensure_style();
235 style = foobar.get_style ();
236 return style->get_font();
240 rgba_from_style (string style, uint32_t r, uint32_t g, uint32_t b, uint32_t a, string attr, int state, bool rgba)
242 /* In GTK+2, styles aren't set up correctly if the widget is not
243 attached to a toplevel window that has a screen pointer.
246 static Gtk::Window* window = 0;
249 window = new Window (WINDOW_TOPLEVEL);
256 foo.set_name (style);
259 GtkRcStyle* waverc = foo.get_style()->gobj()->rc_style;
263 r = waverc->fg[state].red / 257;
264 g = waverc->fg[state].green / 257;
265 b = waverc->fg[state].blue / 257;
266 /* what a hack ... "a" is for "active" */
267 if (state == Gtk::STATE_NORMAL && rgba) {
268 a = waverc->fg[GTK_STATE_ACTIVE].red / 257;
270 } else if (attr == "bg") {
272 r = waverc->bg[state].red / 257;
273 g = waverc->bg[state].green / 257;
274 b = waverc->bg[state].blue / 257;
275 } else if (attr == "base") {
276 r = waverc->base[state].red / 257;
277 g = waverc->base[state].green / 257;
278 b = waverc->base[state].blue / 257;
279 } else if (attr == "text") {
280 r = waverc->text[state].red / 257;
281 g = waverc->text[state].green / 257;
282 b = waverc->text[state].blue / 257;
285 warning << string_compose (_("missing RGBA style for \"%1\""), style) << endl;
290 if (state == Gtk::STATE_NORMAL && rgba) {
291 return (uint32_t) RGBA_TO_UINT(r,g,b,a);
293 return (uint32_t) RGB_TO_UINT(r,g,b);
298 canvas_item_visible (ArdourCanvas::Item* item)
300 return (item->gobj()->object.flags & GNOME_CANVAS_ITEM_VISIBLE) ? true : false;
304 set_color (Gdk::Color& c, int rgb)
306 c.set_rgb((rgb >> 16)*256, ((rgb & 0xff00) >> 8)*256, (rgb & 0xff)*256);
310 key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev)
312 GtkWindow* win = window.gobj();
313 GtkWidget* focus = gtk_window_get_focus (win);
314 bool special_handling_of_unmodified_accelerators = false;
316 #undef DEBUG_ACCELERATOR_HANDLING
317 #ifdef DEBUG_ACCELERATOR_HANDLING
318 bool debug = (getenv ("ARDOUR_DEBUG_ACCELERATOR_HANDLING") != 0);
322 if (GTK_IS_ENTRY(focus)) {
323 special_handling_of_unmodified_accelerators = true;
327 #ifdef DEBUG_ACCELERATOR_HANDLING
329 cerr << "Key event: code = " << ev->keyval << " state = " << hex << ev->state << dec << " focus is an entry ? "
330 << special_handling_of_unmodified_accelerators
335 /* This exists to allow us to override the way GTK handles
336 key events. The normal sequence is:
338 a) event is delivered to a GtkWindow
339 b) accelerators/mnemonics are activated
340 c) if (b) didn't handle the event, propagate to
341 the focus widget and/or focus chain
343 The problem with this is that if the accelerators include
344 keys without modifiers, such as the space bar or the
345 letter "e", then pressing the key while typing into
346 a text entry widget results in the accelerator being
347 activated, instead of the desired letter appearing
350 There is no good way of fixing this, but this
351 represents a compromise. The idea is that
352 key events involving modifiers (not Shift)
353 get routed into the activation pathway first, then
354 get propagated to the focus widget if necessary.
356 If the key event doesn't involve modifiers,
357 we deliver to the focus widget first, thus allowing
358 it to get "normal text" without interference
361 Of course, this can also be problematic: if there
362 is a widget with focus, then it will swallow
363 all "normal text" accelerators.
367 if (!special_handling_of_unmodified_accelerators) {
369 /* pretend that certain key events that GTK does not allow
370 to be used as accelerators are actually something that
376 switch (ev->keyval) {
378 ret = gtk_accel_groups_activate(G_OBJECT(win), GDK_uparrow, GdkModifierType(ev->state));
382 ret = gtk_accel_groups_activate(G_OBJECT(win), GDK_downarrow, GdkModifierType(ev->state));
386 ret = gtk_accel_groups_activate(G_OBJECT(win), GDK_rightarrow, GdkModifierType(ev->state));
390 ret = gtk_accel_groups_activate(G_OBJECT(win), GDK_leftarrow, GdkModifierType(ev->state));
402 if (!special_handling_of_unmodified_accelerators ||
403 ev->state & (Gdk::MOD1_MASK|
407 Gdk::CONTROL_MASK)) {
409 /* no special handling or modifiers in effect: accelerate first */
411 #ifdef DEBUG_ACCELERATOR_HANDLING
413 cerr << "\tactivate, then propagate\n";
416 if (!gtk_window_activate_key (win, ev)) {
417 return gtk_window_propagate_key_event (win, ev);
419 #ifdef DEBUG_ACCELERATOR_HANDLING
421 cerr << "\tnot handled\n";
428 /* no modifiers, propagate first */
430 #ifdef DEBUG_ACCELERATOR_HANDLING
432 cerr << "\tactivate, then propagate\n";
435 if (!gtk_window_propagate_key_event (win, ev)) {
436 return gtk_window_activate_key (win, ev);
440 #ifdef DEBUG_ACCELERATOR_HANDLING
442 cerr << "\tnot handled\n";
448 Glib::RefPtr<Gdk::Pixbuf>
449 get_xpm (std::string name)
451 if (!xpm_map[name]) {
452 xpm_map[name] = Gdk::Pixbuf::create_from_file (ARDOUR::find_data_file(name, "pixmaps"));
455 return (xpm_map[name]);
458 Glib::RefPtr<Gdk::Pixbuf>
459 get_icon (const char* cname)
464 string path = ARDOUR::find_data_file (name, "icons");
467 fatal << string_compose (_("cannot find icon image for %1"), name) << endmsg;
471 return Gdk::Pixbuf::create_from_file (path);
475 longest (vector<string>& strings)
477 if (strings.empty()) {
481 vector<string>::iterator longest = strings.begin();
482 string::size_type longest_length = (*longest).length();
484 vector<string>::iterator i = longest;
487 while (i != strings.end()) {
489 string::size_type len = (*i).length();
491 if (len > longest_length) {
493 longest_length = len;
503 key_is_legal_for_numeric_entry (guint keyval)
521 case GDK_KP_Subtract: