#include <gtkmm2ext/utils.h>
#include "ardour/rc_configuration.h"
#include "ardour/filesystem_paths.h"
+
#include "canvas/item.h"
+#include "canvas/utils.h"
#include "ardour_ui.h"
#include "debug.h"
using namespace PBD;
using Gtkmm2ext::Keyboard;
-sigc::signal<void> DPIReset;
+namespace ARDOUR_UI_UTILS {
+ sigc::signal<void> DPIReset;
+}
+
+#ifdef PLATFORM_WINDOWS
+#define random() rand()
+#endif
/** Add an element to a menu, settings its sensitivity.
* @param s true to make sensitive, false to make insensitive
*/
void
-add_item_with_sensitivity (Menu_Helpers::MenuList& m, Menu_Helpers::MenuElem e, bool s)
+ARDOUR_UI_UTILS::add_item_with_sensitivity (Menu_Helpers::MenuList& m, Menu_Helpers::MenuElem e, bool s)
{
m.push_back (e);
if (!s) {
gint
-just_hide_it (GdkEventAny */*ev*/, Gtk::Window *win)
+ARDOUR_UI_UTILS::just_hide_it (GdkEventAny */*ev*/, Gtk::Window *win)
{
win->hide ();
return 0;
*/
unsigned char*
-xpm2rgb (const char** xpm, uint32_t& w, uint32_t& h)
+ARDOUR_UI_UTILS::xpm2rgb (const char** xpm, uint32_t& w, uint32_t& h)
{
static long vals[256], val;
uint32_t t, x, y, colors, cpp;
}
unsigned char*
-xpm2rgba (const char** xpm, uint32_t& w, uint32_t& h)
+ARDOUR_UI_UTILS::xpm2rgba (const char** xpm, uint32_t& w, uint32_t& h)
{
static long vals[256], val;
uint32_t t, x, y, colors, cpp;
return (savergb);
}
+/** Returns a Pango::FontDescription given a string describing the font.
+ *
+ * If the returned FontDescription does not specify a family, then
+ * the family is set to "Sans". This mirrors GTK's behaviour in
+ * gtkstyle.c.
+ *
+ * Some environments will force Pango to specify the family
+ * even if it was not specified in the string describing the font.
+ * Such environments should be left unaffected by this function,
+ * since the font family will be left alone.
+ *
+ * There may be other similar font specification enforcement
+ * that we might add here later.
+ */
Pango::FontDescription
-get_font_for_style (string widgetname)
+ARDOUR_UI_UTILS::sanitized_font (std::string const& name)
+{
+ Pango::FontDescription fd (name);
+
+ if (fd.get_family().empty()) {
+ fd.set_family ("Sans");
+ }
+
+ return fd;
+}
+
+Pango::FontDescription
+ARDOUR_UI_UTILS::get_font_for_style (string widgetname)
{
Gtk::Window window (WINDOW_TOPLEVEL);
Gtk::Label foobar;
return Pango::FontDescription (pfd); /* make a copy */
}
-uint32_t
-rgba_from_style (string style, uint32_t r, uint32_t g, uint32_t b, uint32_t a, string attr, int state, bool rgba)
+void
+ARDOUR_UI_UTILS::set_color_from_rgb (Gdk::Color& c, uint32_t rgb)
{
- /* In GTK+2, styles aren't set up correctly if the widget is not
- attached to a toplevel window that has a screen pointer.
+ /* Gdk::Color color ranges are 16 bit, so scale from 8 bit by
+ multiplying by 256.
*/
-
- static Gtk::Window* window = 0;
-
- if (window == 0) {
- window = new Window (WINDOW_TOPLEVEL);
- }
-
- Gtk::Label foo;
-
- window->add (foo);
-
- foo.set_name (style);
- foo.ensure_style ();
-
- GtkRcStyle* rc = foo.get_style()->gobj()->rc_style;
-
- if (rc) {
- if (attr == "fg") {
- r = rc->fg[state].red / 257;
- g = rc->fg[state].green / 257;
- b = rc->fg[state].blue / 257;
-
- /* what a hack ... "a" is for "active" */
- if (state == Gtk::STATE_NORMAL && rgba) {
- a = rc->fg[GTK_STATE_ACTIVE].red / 257;
- }
- } else if (attr == "bg") {
- r = g = b = 0;
- r = rc->bg[state].red / 257;
- g = rc->bg[state].green / 257;
- b = rc->bg[state].blue / 257;
- } else if (attr == "base") {
- r = rc->base[state].red / 257;
- g = rc->base[state].green / 257;
- b = rc->base[state].blue / 257;
- } else if (attr == "text") {
- r = rc->text[state].red / 257;
- g = rc->text[state].green / 257;
- b = rc->text[state].blue / 257;
- }
- } else {
- warning << string_compose (_("missing RGBA style for \"%1\""), style) << endl;
- }
-
- window->remove ();
-
- if (state == Gtk::STATE_NORMAL && rgba) {
- return (uint32_t) RGBA_TO_UINT(r,g,b,a);
- } else {
- return (uint32_t) RGB_TO_UINT(r,g,b);
- }
+ c.set_rgb ((rgb >> 16)*256, ((rgb & 0xff00) >> 8)*256, (rgb & 0xff)*256);
}
-bool
-rgba_p_from_style (string style, float *r, float *g, float *b, string attr, int state)
+void
+ARDOUR_UI_UTILS::set_color_from_rgba (Gdk::Color& c, uint32_t rgba)
{
- static Gtk::Window* window = 0;
- assert (r && g && b);
-
- if (window == 0) {
- window = new Window (WINDOW_TOPLEVEL);
- }
-
- Gtk::EventBox foo;
-
- window->add (foo);
-
- foo.set_name (style);
- foo.ensure_style ();
+ /* Gdk::Color color ranges are 16 bit, so scale from 8 bit by
+ multiplying by 256.
+ */
+ c.set_rgb ((rgba >> 24)*256, ((rgba & 0xff0000) >> 16)*256, ((rgba & 0xff00) >> 8)*256);
+}
- GtkRcStyle* rc = foo.get_style()->gobj()->rc_style;
+uint32_t
+ARDOUR_UI_UTILS::gdk_color_to_rgba (Gdk::Color const& c)
+{
+ /* since alpha value is not available from a Gdk::Color, it is
+ hardcoded as 0xff (aka 255 or 1.0)
+ */
- if (!rc) {
- warning << string_compose (_("missing RGBA style for \"%1\""), style) << endl;
- return false;
- }
- if (attr == "fg") {
- *r = rc->fg[state].red / 65535.0;
- *g = rc->fg[state].green / 65535.0;
- *b = rc->fg[state].blue / 65535.0;
- } else if (attr == "bg") {
- *r = rc->bg[state].red / 65535.0;
- *g = rc->bg[state].green / 65535.0;
- *b = rc->bg[state].blue / 65535.0;
- } else if (attr == "base") {
- *r = rc->base[state].red / 65535.0;
- *g = rc->base[state].green / 65535.0;
- *b = rc->base[state].blue / 65535.0;
- } else if (attr == "text") {
- *r = rc->text[state].red / 65535.0;
- *g = rc->text[state].green / 65535.0;
- *b = rc->text[state].blue / 65535.0;
- } else {
- return false;
- }
+ const uint32_t r = c.get_red_p () * 255.0;
+ const uint32_t g = c.get_green_p () * 255.0;
+ const uint32_t b = c.get_blue_p () * 255.0;
+ const uint32_t a = 0xff;
- window->remove ();
- return true;
+ return RGBA_TO_UINT (r,g,b,a);
}
-void
-set_color (Gdk::Color& c, int rgb)
-{
- c.set_rgb((rgb >> 16)*256, ((rgb & 0xff00) >> 8)*256, (rgb & 0xff)*256);
-}
bool
-relay_key_press (GdkEventKey* ev, Gtk::Window* win)
+ARDOUR_UI_UTILS::relay_key_press (GdkEventKey* ev, Gtk::Window* win)
{
PublicEditor& ed (PublicEditor::instance());
}
bool
-forward_key_press (GdkEventKey* ev)
+ARDOUR_UI_UTILS::forward_key_press (GdkEventKey* ev)
{
- return PublicEditor::instance().on_key_press_event(ev);
+ return PublicEditor::instance().on_key_press_event(ev);
}
bool
-emulate_key_event (Gtk::Widget* w, unsigned int keyval)
+ARDOUR_UI_UTILS::emulate_key_event (Gtk::Widget* w, unsigned int keyval)
{
GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET(w->gobj()));
GdkKeymap *keymap = gdk_keymap_get_for_display (display);
}
bool
-key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev)
+ARDOUR_UI_UTILS::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev)
{
GtkWindow* win = window.gobj();
GtkWidget* focus = gtk_window_get_focus (win);
#endif
- DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Win = %1 focus = %7 Key event: code = %2 state = %3 special handling ? %4 magic widget focus ? %5 allow_activation ? %6\n",
+ DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Win = %1 focus = %7 (%8) Key event: code = %2 state = %3 special handling ? %4 magic widget focus ? %5 allow_activation ? %6\n",
win,
ev->keyval,
ev->state,
special_handling_of_unmodified_accelerators,
Keyboard::some_magic_widget_has_focus(),
allow_activating,
- focus));
+ focus,
+ (focus ? gtk_widget_get_name (focus) : "no focus widget")));
/* This exists to allow us to override the way GTK handles
key events. The normal sequence is:
/* no special handling or there are modifiers in effect: accelerate first */
DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
- DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 string:%4 hardware_keycode:%5 group:%6\n",
- ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group));
+ DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
+ ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
if (allow_activating) {
DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
}
Glib::RefPtr<Gdk::Pixbuf>
-get_xpm (std::string name)
+ARDOUR_UI_UTILS::get_xpm (std::string name)
{
if (!xpm_map[name]) {
- SearchPath spath(ARDOUR::ardour_data_search_path());
+ Searchpath spath(ARDOUR::ardour_data_search_path());
spath.add_subdirectory_to_paths("pixmaps");
std::string data_file_path;
- if(!find_file_in_search_path (spath, name, data_file_path)) {
+ if(!find_file (spath, name, data_file_path)) {
fatal << string_compose (_("cannot find XPM file for %1"), name) << endmsg;
}
return xpm_map[name];
}
+vector<string>
+ARDOUR_UI_UTILS::get_icon_sets ()
+{
+ Searchpath spath(ARDOUR::ardour_data_search_path());
+ spath.add_subdirectory_to_paths ("icons");
+ vector<string> r;
+
+ r.push_back (_("default"));
+
+ for (vector<string>::iterator s = spath.begin(); s != spath.end(); ++s) {
+
+ vector<string> entries;
+
+ get_paths (entries, *s, false, false);
+
+ for (vector<string>::iterator e = entries.begin(); e != entries.end(); ++e) {
+ if (Glib::file_test (*e, Glib::FILE_TEST_IS_DIR)) {
+ r.push_back (Glib::filename_to_utf8 (Glib::path_get_basename(*e)));
+ }
+ }
+ }
+
+ return r;
+}
+
std::string
-get_icon_path (const char* cname)
+ARDOUR_UI_UTILS::get_icon_path (const char* cname, string icon_set, bool is_image)
{
+ std::string data_file_path;
string name = cname;
- name += X_(".png");
- SearchPath spath(ARDOUR::ardour_data_search_path());
+ if (is_image) {
+ name += X_(".png");
+ }
- spath.add_subdirectory_to_paths("icons");
+ Searchpath spath(ARDOUR::ardour_data_search_path());
- std::string data_file_path;
+ if (!icon_set.empty() && icon_set != _("default")) {
- if (!find_file_in_search_path (spath, name, data_file_path)) {
- fatal << string_compose (_("cannot find icon image for %1 using %2"), name, spath.to_string()) << endmsg;
+ /* add "icons/icon_set" but .. not allowed to add both of these at once */
+ spath.add_subdirectory_to_paths ("icons");
+ spath.add_subdirectory_to_paths (icon_set);
+
+ find_file (spath, name, data_file_path);
+ } else {
+ spath.add_subdirectory_to_paths ("icons");
+ find_file (spath, name, data_file_path);
+ }
+
+ if (is_image && data_file_path.empty()) {
+
+ if (!icon_set.empty() && icon_set != _("default")) {
+ warning << string_compose (_("icon \"%1\" not found for icon set \"%2\", fallback to default"), cname, icon_set) << endmsg;
+ }
+
+ Searchpath def (ARDOUR::ardour_data_search_path());
+ def.add_subdirectory_to_paths ("icons");
+
+ if (!find_file (def, name, data_file_path)) {
+ fatal << string_compose (_("cannot find icon image for %1 using %2"), name, spath.to_string()) << endmsg;
+ abort(); /*NOTREACHED*/
+ }
}
return data_file_path;
}
+Glib::RefPtr<Gdk::Pixbuf>
+ARDOUR_UI_UTILS::get_icon (const char* cname, string icon_set)
+{
+ Glib::RefPtr<Gdk::Pixbuf> img;
+ try {
+ img = Gdk::Pixbuf::create_from_file (get_icon_path (cname, icon_set));
+ } catch (const Gdk::PixbufError &e) {
+ cerr << "Caught PixbufError: " << e.what() << endl;
+ } catch (...) {
+ error << string_compose (_("Caught exception while loading icon named %1"), cname) << endmsg;
+ }
+
+ return img;
+}
+
+namespace ARDOUR_UI_UTILS {
Glib::RefPtr<Gdk::Pixbuf>
get_icon (const char* cname)
{
return img;
}
+}
string
-longest (vector<string>& strings)
+ARDOUR_UI_UTILS::longest (vector<string>& strings)
{
if (strings.empty()) {
return string ("");
}
bool
-key_is_legal_for_numeric_entry (guint keyval)
+ARDOUR_UI_UTILS::key_is_legal_for_numeric_entry (guint keyval)
{
/* we assume that this does not change over the life of the process
*/
return false;
}
+
void
-set_pango_fontsize ()
+ARDOUR_UI_UTILS::set_pango_fontsize ()
{
long val = ARDOUR::Config->get_font_scale();
/* FT2 rendering - used by GnomeCanvas, sigh */
+#ifndef PLATFORM_WINDOWS
pango_ft2_font_map_set_resolution ((PangoFT2FontMap*) pango_ft2_font_map_new(), val/1024, val/1024);
+#endif
/* Cairo rendering, in case there is any */
}
void
-reset_dpi ()
+ARDOUR_UI_UTILS::reset_dpi ()
{
long val = ARDOUR::Config->get_font_scale();
set_pango_fontsize ();
}
void
-resize_window_to_proportion_of_monitor (Gtk::Window* window, int max_width, int max_height)
+ARDOUR_UI_UTILS::resize_window_to_proportion_of_monitor (Gtk::Window* window, int max_width, int max_height)
{
Glib::RefPtr<Gdk::Screen> screen = window->get_screen ();
Gdk::Rectangle monitor_rect;
/** Replace _ with __ in a string; for use with menu item text to make underscores displayed correctly */
string
-escape_underscores (string const & s)
+ARDOUR_UI_UTILS::escape_underscores (string const & s)
{
string o;
string::size_type const N = s.length ();
/** Replace < and > with < and > respectively to make < > display correctly in markup strings */
string
-escape_angled_brackets (string const & s)
+ARDOUR_UI_UTILS::escape_angled_brackets (string const & s)
{
string o = s;
boost::replace_all (o, "<", "<");
}
Gdk::Color
-unique_random_color (list<Gdk::Color>& used_colors)
+ARDOUR_UI_UTILS::unique_random_color (list<Gdk::Color>& used_colors)
{
Gdk::Color newcolor;
}
string
-rate_as_string (float r)
+ARDOUR_UI_UTILS::rate_as_string (float r)
{
char buf[32];
if (fmod (r, 1000.0f)) {