// -*- C++ -*- /* * GChemPaint library * theme.cc * * Copyright (C) 2002-2007 Jean Bréfort * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 * USA */ #include "gchempaint-config.h" #include "document.h" #include "theme.h" #include "settings.h" #include #include #include #include double DefaultBondLength = 140.; double DefaultBondAngle = 120.; double DefaultBondDist = 5.; double DefaultBondWidth = 1.0; double DefaultArrowLength = 200; double DefaultArrowHeadA = 6.0; double DefaultArrowHeadB = 8.0; double DefaultArrowHeadC = 4.0; double DefaultArrowDist = 5.0; double DefaultArrowWidth = 1.0; double DefaultHashWidth = 1.0; double DefaultHashDist = 2.0; double DefaultStereoBondWidth = 5.0; double DefaultZoomFactor = 0.25; double DefaultPadding = 2.0; double DefaultArrowPadding = 16.0; double DefaultStoichiometryPadding = 1.; double DefaultObjectPadding = 16.0; double DefaultSignPadding = 8.0; //double DefaultChargeSignHeight = 12.; double DefaultChargeSignSize = 9.; //double DefaultChargeYAlign = 10.; gchar *DefaultFontFamily = NULL; PangoStyle DefaultFontStyle = PANGO_STYLE_NORMAL; PangoWeight DefaultFontWeight = PANGO_WEIGHT_NORMAL; PangoVariant DefaultFontVariant = PANGO_VARIANT_NORMAL; PangoStretch DefaultFontStretch = PANGO_STRETCH_NORMAL; gint DefaultFontSize = 12 * PANGO_SCALE; gchar *DefaultTextFontFamily = NULL; PangoStyle DefaultTextFontStyle = PANGO_STYLE_NORMAL; PangoWeight DefaultTextFontWeight = PANGO_WEIGHT_NORMAL; PangoVariant DefaultTextFontVariant = PANGO_VARIANT_NORMAL; PangoStretch DefaultTextFontStretch = PANGO_STRETCH_NORMAL; gint DefaultTextFontSize = 12 * PANGO_SCALE; gcpTheme::gcpTheme (char const *name) { m_ZoomFactor = DefaultZoomFactor; m_BondLength = DefaultBondLength; m_BondAngle = DefaultBondAngle; m_BondDist = DefaultBondDist; m_BondWidth = DefaultBondWidth; m_ArrowLength = DefaultArrowLength; m_HashWidth = DefaultHashWidth; m_HashDist = DefaultHashDist; m_StereoBondWidth = DefaultStereoBondWidth; m_Padding = DefaultPadding; m_ArrowHeadA = DefaultArrowHeadA; m_ArrowHeadB = DefaultArrowHeadB; m_ArrowHeadC = DefaultArrowHeadC; m_ArrowDist = DefaultArrowDist; m_ArrowPadding = DefaultArrowPadding; m_ArrowWidth = DefaultArrowWidth; m_StoichiometryPadding = DefaultStoichiometryPadding; m_ObjectPadding = DefaultObjectPadding; m_SignPadding = DefaultSignPadding; m_ChargeSignSize = DefaultChargeSignSize; m_FontFamily = strdup ((DefaultFontFamily)? DefaultFontFamily: "Bitstream Vera Sans"); m_FontStyle = DefaultFontStyle; m_FontWeight = DefaultFontWeight; m_FontVariant = DefaultFontVariant; m_FontStretch = DefaultFontStretch; m_FontSize = DefaultFontSize; m_TextFontFamily = strdup ((DefaultTextFontFamily)? DefaultTextFontFamily: "Bitstream Vera Serif"); m_TextFontStyle = DefaultTextFontStyle; m_TextFontWeight = DefaultTextFontWeight; m_TextFontVariant = DefaultTextFontVariant; m_TextFontStretch = DefaultTextFontStretch; m_TextFontSize = DefaultTextFontSize; if (name) m_Name = name; m_ThemeType = DEFAULT_THEME_TYPE; modified = false; } gcpTheme::~gcpTheme () { if (m_FontFamily) g_free (m_FontFamily); if (m_TextFontFamily) g_free (m_TextFontFamily); } gcpThemeManager ThemeManager; static void on_config_changed (GConfClient *client, guint cnxn_id, GConfEntry *entry, gcpThemeManager *manager) { manager->OnConfigChanged (client, cnxn_id, entry); } // transform functions for gconf key values static double inv (double x) {return 1 / x;} static PangoStyle set_fontstyle (int val) { switch (val) { case 0: return PANGO_STYLE_NORMAL; case 1: return PANGO_STYLE_OBLIQUE; case 2: return PANGO_STYLE_ITALIC; default: return PANGO_STYLE_NORMAL; } } static PangoWeight set_fontweight (int val) { switch (val) { case 2: return PANGO_WEIGHT_ULTRALIGHT; case 3: return PANGO_WEIGHT_LIGHT; case 4: return PANGO_WEIGHT_NORMAL; case 6: return PANGO_WEIGHT_SEMIBOLD; case 7: return PANGO_WEIGHT_BOLD; case 8: return PANGO_WEIGHT_ULTRABOLD; case 9: return PANGO_WEIGHT_HEAVY; default: return PANGO_WEIGHT_NORMAL; } } static PangoVariant set_fontvariant (int val) { switch (val) { case 0: return PANGO_VARIANT_NORMAL; case 1: return PANGO_VARIANT_SMALL_CAPS; default: return PANGO_VARIANT_NORMAL; } } static PangoStretch set_fontstretch (int val) { switch (val) { case 0: return PANGO_STRETCH_ULTRA_CONDENSED; case 1: return PANGO_STRETCH_EXTRA_CONDENSED; case 2: return PANGO_STRETCH_CONDENSED; case 3: return PANGO_STRETCH_SEMI_CONDENSED; case 4: return PANGO_STRETCH_NORMAL; case 5: return PANGO_STRETCH_SEMI_EXPANDED; case 6: return PANGO_STRETCH_EXPANDED; case 7: return PANGO_STRETCH_EXTRA_EXPANDED; case 8: return PANGO_STRETCH_ULTRA_EXPANDED; default: return PANGO_STRETCH_NORMAL; } } static int set_fontsize (double val) {return (int) (val * PANGO_SCALE);} gcpThemeManager::gcpThemeManager () { bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR); #ifdef ENABLE_NLS bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); #endif GError *error = NULL; m_ConfClient = gconf_client_get_default (); gconf_client_add_dir (m_ConfClient, "/apps/gchempaint/settings", GCONF_CLIENT_PRELOAD_ONELEVEL, NULL); GCU_GCONF_GET (ROOTDIR"bond-length", float, DefaultBondLength, 140.) GCU_GCONF_GET (ROOTDIR"bond-angle", float, DefaultBondAngle, 120.) GCU_GCONF_GET (ROOTDIR"bond-dist", float, DefaultBondDist, 5.) GCU_GCONF_GET (ROOTDIR"bond-width", float, DefaultBondWidth, 1.0) GCU_GCONF_GET (ROOTDIR"arrow-length", float, DefaultArrowLength, 200) GCU_GCONF_GET (ROOTDIR"arrow-headA", float, DefaultArrowHeadA, 6.0) GCU_GCONF_GET (ROOTDIR"arrow-headB", float, DefaultArrowHeadB, 8.0) GCU_GCONF_GET (ROOTDIR"arrow-headC", float, DefaultArrowHeadC, 4.0) GCU_GCONF_GET (ROOTDIR"arrow-dist", float, DefaultArrowDist, 5.0) GCU_GCONF_GET (ROOTDIR"arrow-width", float, DefaultArrowWidth, 1.0) GCU_GCONF_GET (ROOTDIR"hash-width", float, DefaultHashWidth, 1.0) GCU_GCONF_GET (ROOTDIR"hash-dist", float, DefaultHashDist, 2.0) GCU_GCONF_GET (ROOTDIR"stereo-width", float, DefaultStereoBondWidth, 5.0) GCU_GCONF_GET_N_TRANSFORM (ROOTDIR"scale", float, DefaultZoomFactor, 4.0, inv) GCU_GCONF_GET (ROOTDIR"padding", float, DefaultPadding, 2.0) GCU_GCONF_GET (ROOTDIR"arrow-padding", float, DefaultArrowPadding, 16.0) GCU_GCONF_GET (ROOTDIR"stoichiometry-padding", float, DefaultStoichiometryPadding, 1.) GCU_GCONF_GET (ROOTDIR"object-padding", float, DefaultObjectPadding, 16.0) GCU_GCONF_GET (ROOTDIR"sign-padding", float, DefaultSignPadding, 8.0) GCU_GCONF_GET (ROOTDIR"charge-sign-size", float, DefaultChargeSignSize, 9.) GCU_GCONF_GET_STRING (ROOTDIR"font-family", DefaultFontFamily, "Bitstream Vera Sans") GCU_GCONF_GET_N_TRANSFORM (ROOTDIR"font-style", int, DefaultFontStyle, 0, set_fontstyle) GCU_GCONF_GET_N_TRANSFORM (ROOTDIR"font-weight", int, DefaultFontWeight, 4, set_fontweight) GCU_GCONF_GET_N_TRANSFORM (ROOTDIR"font-variant", int, DefaultFontVariant, 0, set_fontvariant) GCU_GCONF_GET_N_TRANSFORM (ROOTDIR"font-stretch", int, DefaultFontStretch, 4, set_fontstretch) GCU_GCONF_GET_N_TRANSFORM (ROOTDIR"font-size", float, DefaultFontSize, 12., set_fontsize) GCU_GCONF_GET_STRING (ROOTDIR"text-font-family", DefaultTextFontFamily, "Bitstream Vera Serif") GCU_GCONF_GET_N_TRANSFORM (ROOTDIR"text-font-style", int, DefaultTextFontStyle, 0, set_fontstyle) GCU_GCONF_GET_N_TRANSFORM (ROOTDIR"text-font-weight", int, DefaultTextFontWeight, 4, set_fontweight) GCU_GCONF_GET_N_TRANSFORM (ROOTDIR"text-font-variant", int, DefaultTextFontVariant, 0, set_fontvariant) GCU_GCONF_GET_N_TRANSFORM (ROOTDIR"text-font-stretch", int, DefaultTextFontStretch, 4, set_fontstretch) GCU_GCONF_GET_N_TRANSFORM (ROOTDIR"text-font-size", float, DefaultTextFontSize, 12., set_fontsize) m_NotificationId = gconf_client_notify_add (m_ConfClient, "/apps/gchempaint/settings", (GConfClientNotifyFunc) on_config_changed, this, NULL, NULL); // Build default theme from settings m_Themes["GChemPaint"] = new gcpTheme ("GChemPaint"); m_Names.push_front ("GChemPaint"); // load global themes string path = DATADIR; path += "/gchempaint/themes"; ParseDir (path, GLOBAL_THEME_TYPE); // load local themes char *szhome = getenv ("HOME"); if (szhome) path = szhome; path += "/.gchempaint/themes"; ParseDir (path, LOCAL_THEME_TYPE); gchar *default_theme =NULL; GCU_GCONF_GET_STRING (ROOTDIR"default-theme", default_theme, "GChemPaint"); m_DefaultTheme = m_Themes[default_theme]; g_free (default_theme); if (!m_DefaultTheme) m_DefaultTheme = m_Themes["GChemPaint"]; } gcpThemeManager::~gcpThemeManager () { g_type_init (); gconf_client_notify_remove (m_ConfClient, m_NotificationId); gconf_client_remove_dir (m_ConfClient, "/apps/gchempaint/settings", NULL); g_object_unref (m_ConfClient); // save themes if needed, then delete gcpTheme *theme, *def = NULL; map ::iterator i, iend = m_Themes.end (); for (i = m_Themes.begin (); i != iend; i++) { theme = (*i).second; if (!theme || (def && theme == def)) continue; // this theme has already been deleted if (theme->modified && theme->m_ThemeType == LOCAL_THEME_TYPE) { xmlDocPtr doc = xmlNewDoc((xmlChar*)"1.0"); xmlDocSetRootElement (doc, xmlNewDocNode (doc, NULL, (xmlChar*) "chemistry", NULL)); if (theme->Save (doc)) { char *szhome = getenv ("HOME"); string home, path; if (szhome) home = szhome; path = home + "/.gchempaint/themes"; GDir *dir = g_dir_open (path.c_str (), 0, NULL); if (!dir) { string gcppath; gcppath = home + "/.gchempaint"; dir = g_dir_open (gcppath.c_str (), 0, NULL); if (dir) g_dir_close (dir); else mkdir (gcppath.c_str (), 0x1ed); mkdir (path.c_str (), 0x1ed); } else g_dir_close (dir); path += string ("/") + theme->GetName (); xmlSaveFormatFile (path.c_str (), doc, true); } } else if (theme->m_Name == "Default") def = theme; delete theme; } g_free (DefaultFontFamily); g_free (DefaultTextFontFamily); } gcpTheme *gcpThemeManager::GetTheme (char const *name) { if (!strcmp (_(name), _("Default"))) return m_DefaultTheme; return m_Themes[name]; } gcpTheme *gcpThemeManager::GetTheme (string &name) { if (name == "Default" || name == _("Default") ) return m_DefaultTheme; return m_Themes[name.c_str ()]; } list const &gcpThemeManager::GetThemesNames () { return m_Names; } void gcpThemeManager::OnConfigChanged (GConfClient *client, guint cnxn_id, GConfEntry *entry) { if (client != m_ConfClient) return; // we might want an error message? if (cnxn_id != m_NotificationId) return; // we might want an error message? gcpTheme *Theme = m_Themes["GChemPaint"]; if (!strcmp (gconf_entry_get_key (entry),ROOTDIR"bond-length")) { DefaultBondLength = gconf_value_get_float (gconf_entry_get_value (entry)); Theme->m_BondLength = DefaultBondLength; } else if (!strcmp (gconf_entry_get_key (entry),ROOTDIR"bond-angle")) { DefaultBondAngle = gconf_value_get_float (gconf_entry_get_value (entry)); Theme->m_BondAngle = DefaultBondAngle; } else if (!strcmp (gconf_entry_get_key (entry),ROOTDIR"bond-dist")) { DefaultBondDist = gconf_value_get_float (gconf_entry_get_value (entry)); Theme->m_BondDist = DefaultBondDist; } else if (!strcmp (gconf_entry_get_key (entry),ROOTDIR"bond-width")) { DefaultBondWidth = gconf_value_get_float (gconf_entry_get_value (entry)); Theme->m_BondWidth = DefaultBondWidth; } else if (!strcmp (gconf_entry_get_key (entry),ROOTDIR"arrow-length")) { DefaultArrowLength = gconf_value_get_float (gconf_entry_get_value (entry)); Theme->m_ArrowLength = DefaultArrowLength; } else if (!strcmp (gconf_entry_get_key (entry),ROOTDIR"arrow-headA")) { DefaultArrowHeadA = gconf_value_get_float (gconf_entry_get_value (entry)); Theme->m_ArrowHeadA = DefaultArrowHeadA; } else if (!strcmp (gconf_entry_get_key (entry),ROOTDIR"arrow-headB")) { DefaultArrowHeadB = gconf_value_get_float (gconf_entry_get_value (entry)); Theme->m_ArrowHeadB = DefaultArrowHeadB; } else if (!strcmp (gconf_entry_get_key (entry),ROOTDIR"arrow-headC")) { DefaultArrowHeadC = gconf_value_get_float (gconf_entry_get_value (entry)); Theme->m_ArrowHeadC = DefaultArrowHeadC; } else if (!strcmp (gconf_entry_get_key (entry),ROOTDIR"arrow-dist")) { DefaultArrowDist = gconf_value_get_float (gconf_entry_get_value (entry)); Theme->m_ArrowDist = DefaultArrowDist; } else if (!strcmp (gconf_entry_get_key (entry),ROOTDIR"arrow-width")) { DefaultArrowWidth = gconf_value_get_float (gconf_entry_get_value (entry)); Theme->m_ArrowWidth = DefaultArrowWidth; } else if (!strcmp (gconf_entry_get_key (entry),ROOTDIR"hash-width")) { DefaultHashWidth = gconf_value_get_float (gconf_entry_get_value (entry)); Theme->m_HashWidth = DefaultHashWidth; } else if (!strcmp (gconf_entry_get_key (entry),ROOTDIR"hash-dist")) { DefaultHashDist = gconf_value_get_float (gconf_entry_get_value (entry)); Theme->m_HashDist = DefaultHashDist; } else if (!strcmp (gconf_entry_get_key (entry),ROOTDIR"stereo-width")) { DefaultStereoBondWidth = gconf_value_get_float (gconf_entry_get_value (entry)); Theme->m_StereoBondWidth = DefaultStereoBondWidth; } else if (!strcmp (gconf_entry_get_key (entry),ROOTDIR"scale")) { double scale = gconf_value_get_float (gconf_entry_get_value (entry)); if (scale > 1e-5) { DefaultZoomFactor = 1 / scale; Theme->m_ZoomFactor = DefaultZoomFactor; } } else if (!strcmp (gconf_entry_get_key (entry),ROOTDIR"padding")) { DefaultPadding = gconf_value_get_float (gconf_entry_get_value (entry)); Theme->m_Padding = DefaultPadding; } else if (!strcmp (gconf_entry_get_key (entry),ROOTDIR"stoichiometry-padding")) { DefaultStoichiometryPadding = gconf_value_get_float (gconf_entry_get_value (entry)); Theme->m_StoichiometryPadding = DefaultStoichiometryPadding; } else if (!strcmp (gconf_entry_get_key (entry),ROOTDIR"object-padding")) { DefaultObjectPadding = gconf_value_get_float (gconf_entry_get_value (entry)); Theme->m_ObjectPadding = DefaultObjectPadding; } else if (!strcmp (gconf_entry_get_key (entry),ROOTDIR"charge-sign-padding")) { DefaultSignPadding = gconf_value_get_float (gconf_entry_get_value (entry)); Theme->m_SignPadding = DefaultSignPadding; } else if (!strcmp (gconf_entry_get_key (entry),ROOTDIR"charge-sign-size")) { DefaultChargeSignSize = gconf_value_get_float (gconf_entry_get_value (entry)); Theme->m_ChargeSignSize = DefaultChargeSignSize; } else if (!strcmp (gconf_entry_get_key (entry),ROOTDIR"font-family")) { char const *name = gconf_value_get_string (gconf_entry_get_value (entry)); if (name) { if (DefaultFontFamily != NULL) g_free (DefaultFontFamily); DefaultFontFamily = g_strdup (name); Theme->m_FontFamily = DefaultFontFamily; } } else if (!strcmp (gconf_entry_get_key (entry),ROOTDIR"font-style")) { DefaultFontStyle = set_fontstyle (gconf_value_get_int (gconf_entry_get_value (entry))); Theme->m_FontStyle = DefaultFontStyle; } else if (!strcmp (gconf_entry_get_key (entry),ROOTDIR"font-weight")) { DefaultFontWeight = set_fontweight (gconf_value_get_int (gconf_entry_get_value (entry))); Theme->m_FontWeight = DefaultFontWeight; } else if (!strcmp (gconf_entry_get_key (entry),ROOTDIR"font-variant")) { DefaultFontVariant = set_fontvariant (gconf_value_get_int (gconf_entry_get_value (entry))); Theme->m_FontVariant = DefaultFontVariant; } else if (!strcmp (gconf_entry_get_key (entry),ROOTDIR"font-stretch")) { DefaultFontStretch = set_fontstretch (gconf_value_get_int (gconf_entry_get_value (entry))); Theme->m_FontStretch = DefaultFontStretch; } else if (!strcmp (gconf_entry_get_key (entry),ROOTDIR"font-size")) { DefaultFontSize = set_fontsize (gconf_value_get_float (gconf_entry_get_value (entry))); Theme->m_FontSize = DefaultFontSize; } else if (!strcmp (gconf_entry_get_key (entry),ROOTDIR"text-font-family")) { char const *name = gconf_value_get_string (gconf_entry_get_value (entry)); if (name) { if (DefaultTextFontFamily != NULL) g_free (DefaultTextFontFamily); DefaultTextFontFamily = g_strdup (name); Theme->m_TextFontFamily = DefaultTextFontFamily; } } else if (!strcmp (gconf_entry_get_key (entry),ROOTDIR"text-font-style")) { DefaultTextFontStyle = set_fontstyle (gconf_value_get_int (gconf_entry_get_value (entry))); Theme->m_TextFontStyle = DefaultTextFontStyle; } else if (!strcmp (gconf_entry_get_key (entry),ROOTDIR"text-font-weight")) { DefaultTextFontWeight = set_fontweight (gconf_value_get_int (gconf_entry_get_value (entry))); Theme->m_TextFontWeight = DefaultTextFontWeight; } else if (!strcmp (gconf_entry_get_key (entry),ROOTDIR"text-font-variant")) { DefaultTextFontVariant = set_fontvariant (gconf_value_get_int (gconf_entry_get_value (entry))); Theme->m_TextFontVariant = DefaultTextFontVariant; } else if (!strcmp (gconf_entry_get_key (entry),ROOTDIR"text-font-stretch")) { DefaultTextFontStretch = set_fontstretch (gconf_value_get_int (gconf_entry_get_value (entry))); Theme->m_TextFontStretch = DefaultTextFontStretch; } else if (!strcmp (gconf_entry_get_key (entry),ROOTDIR"text-font-size")) { DefaultTextFontSize = set_fontsize (gconf_value_get_float (gconf_entry_get_value (entry))); Theme->m_TextFontSize = DefaultTextFontSize; } else if (!strcmp (gconf_entry_get_key (entry),ROOTDIR"default-theme")) { char const *name = gconf_value_get_string (gconf_entry_get_value (entry)); gcpTheme *pTheme = m_Themes[name]; if (pTheme) m_DefaultTheme = pTheme; } } gcpTheme *gcpThemeManager::CreateNewTheme (gcpTheme *theme) { gchar *name = g_strdup (_("NewTheme1")); int i = 2; while (m_Themes[name] != NULL) { g_free (name); name = g_strdup_printf (_("NewTheme%d"), i++); } gcpTheme *pTheme = new gcpTheme (name); m_Themes[name] = pTheme; m_Names.push_back (name); g_free (name); if (theme) { pTheme->m_ZoomFactor = theme->m_ZoomFactor; pTheme->m_BondLength = theme->m_BondLength; pTheme->m_BondAngle = theme->m_BondAngle; pTheme->m_BondDist = theme->m_BondDist; pTheme->m_BondWidth = theme->m_BondWidth; pTheme->m_ArrowLength = theme->m_ArrowLength; pTheme->m_HashWidth = theme->m_HashWidth; pTheme->m_HashDist = theme->m_HashDist; pTheme->m_StereoBondWidth = theme->m_StereoBondWidth; pTheme->m_Padding = theme->m_Padding; pTheme->m_ArrowHeadA = theme->m_ArrowHeadA; pTheme->m_ArrowHeadB = theme->m_ArrowHeadB; pTheme->m_ArrowHeadC = theme->m_ArrowHeadC; pTheme->m_ArrowDist = theme->m_ArrowDist; pTheme->m_ArrowPadding = theme->m_ArrowPadding; pTheme->m_ArrowWidth = theme->m_ArrowWidth; pTheme->m_StoichiometryPadding = theme->m_StoichiometryPadding; pTheme->m_ObjectPadding = theme->m_ObjectPadding; pTheme->m_SignPadding = theme->m_SignPadding; pTheme->m_ChargeSignSize = theme->m_ChargeSignSize; g_free (pTheme->m_FontFamily); pTheme->m_FontFamily = strdup (theme->m_FontFamily); pTheme->m_FontStyle = theme->m_FontStyle; pTheme->m_FontWeight = theme->m_FontWeight; pTheme->m_FontVariant = theme->m_FontVariant; pTheme->m_FontStretch = theme->m_FontStretch; pTheme->m_FontSize = theme->m_FontSize; g_free (pTheme->m_TextFontFamily); pTheme->m_TextFontFamily = strdup (theme->m_TextFontFamily); pTheme->m_TextFontStyle = theme->m_TextFontStyle; pTheme->m_TextFontWeight = theme->m_TextFontWeight; pTheme->m_TextFontVariant = theme->m_TextFontVariant; pTheme->m_TextFontStretch = theme->m_TextFontStretch; pTheme->m_TextFontSize = theme->m_TextFontSize; } pTheme->m_ThemeType = LOCAL_THEME_TYPE; pTheme->modified = true; return pTheme; } void gcpThemeManager::ParseDir (string &path, ThemeType type) { char const *name; xmlDocPtr doc; xmlNodePtr node; gcpTheme *theme; string filename; GDir *dir = g_dir_open (path.c_str (), 0, NULL); if (dir) { path += "/"; while ((name = g_dir_read_name (dir))) { if (name[strlen (name) - 1] == '~') continue; // don't read backups filename = path + name; doc = xmlParseFile (filename.c_str ()); node = doc->children; if (!strcmp ((char*)node->name, "chemistry")) { node = node->children; while (node && !strcmp ((char*)node->name, "text")) node = node->next; if (node && !strcmp ((char*)node->name, "theme")) { theme = new gcpTheme (""); theme->Load (node); if (theme->GetName () != name) { theme->m_Name = name; theme->modified = true; } if (theme->m_ThemeType == DEFAULT_THEME_TYPE || theme->m_ThemeType == GLOBAL_THEME_TYPE) name = _(name); if (m_Themes.find (name) != m_Themes.end ()) { delete theme; continue; } theme->m_ThemeType = type; m_Themes[name] = theme; m_Names.push_back (name); } } xmlFree (doc); } g_dir_close (dir); } } void gcpThemeManager::AddFileTheme (gcpTheme *theme, char const *label) { string name = theme->GetName ().c_str (); if (name == "Default") name = "GChemPaint"; if (m_Themes.find (name) != m_Themes.end ()) { name = string ((label)? label: _("Unknown")) + ":" + name; } m_Themes[name] = theme; m_Names.push_back (name); } void gcpThemeManager::RemoveFileTheme (gcpTheme *theme) { char const *name = NULL; map ::iterator i, iend = m_Themes.end (); for (i = m_Themes.begin (); i != iend; i++) if ((*i).second == theme) { name = (*i).first.c_str (); break; } m_Names.remove (name); m_Themes.erase (name); } void gcpThemeManager::ChangeThemeName (gcpTheme *theme, char const *name) { m_Themes.erase (theme->m_Name); m_Names.remove (theme->m_Name); theme->m_Name = name; m_Themes[name] = theme; m_Names.push_back (name); } void gcpThemeManager::SetDefaultTheme (char const *name) { gcpTheme *pTheme = m_Themes[name]; if (pTheme) { m_DefaultTheme = pTheme; } } bool gcpTheme::Save (xmlDocPtr xml) { xmlNodePtr node = xmlNewDocNode (xml, NULL, (xmlChar*) "theme", NULL); char *buf; if (!node) return false; if (m_Name.length () > 0) xmlNewProp (node, (xmlChar*) "name", (xmlChar*) m_Name.c_str ()); buf = g_strdup_printf("%g", m_BondLength); xmlNewProp (node, (xmlChar*) "bond-length", (xmlChar*) buf); g_free (buf); buf = g_strdup_printf("%g", m_BondAngle); xmlNewProp (node, (xmlChar*) "bond-angle", (xmlChar*) buf); g_free (buf); buf = g_strdup_printf("%g", m_BondDist); xmlNewProp (node, (xmlChar*) "bond-dist", (xmlChar*) buf); g_free (buf); buf = g_strdup_printf("%g", m_BondWidth); xmlNewProp (node, (xmlChar*) "bond-width", (xmlChar*) buf); g_free (buf); buf = g_strdup_printf("%g", m_ArrowLength); xmlNewProp (node, (xmlChar*) "arrow-length", (xmlChar*) buf); g_free (buf); buf = g_strdup_printf("%g", m_ArrowHeadA); xmlNewProp (node, (xmlChar*) "arrow-head-a", (xmlChar*) buf); g_free (buf); buf = g_strdup_printf("%g", m_ArrowHeadB); xmlNewProp (node, (xmlChar*) "arrow-head-b", (xmlChar*) buf); g_free (buf); buf = g_strdup_printf("%g", m_ArrowHeadC); xmlNewProp (node, (xmlChar*) "arrow-head-c", (xmlChar*) buf); g_free (buf); buf = g_strdup_printf("%g", m_ArrowDist); xmlNewProp (node, (xmlChar*) "arrow-dist", (xmlChar*) buf); g_free (buf); buf = g_strdup_printf("%g", m_ArrowWidth); xmlNewProp (node, (xmlChar*) "arrow-width", (xmlChar*) buf); g_free (buf); buf = g_strdup_printf("%g", m_ArrowPadding); xmlNewProp (node, (xmlChar*) "arrow-padding", (xmlChar*) buf); g_free (buf); buf = g_strdup_printf("%g", m_HashWidth); xmlNewProp (node, (xmlChar*) "hash-width", (xmlChar*) buf); g_free (buf); buf = g_strdup_printf("%g", m_HashDist); xmlNewProp (node, (xmlChar*) "hash-dist", (xmlChar*) buf); g_free (buf); buf = g_strdup_printf("%g", m_StereoBondWidth); xmlNewProp (node, (xmlChar*) "stereo-bond-width", (xmlChar*) buf); g_free (buf); buf = g_strdup_printf("%g", 1 / m_ZoomFactor); xmlNewProp (node, (xmlChar*) "zoom-factor", (xmlChar*) buf); g_free (buf); buf = g_strdup_printf("%g", m_Padding); xmlNewProp (node, (xmlChar*) "padding", (xmlChar*) buf); g_free (buf); buf = g_strdup_printf("%g", m_StoichiometryPadding); xmlNewProp (node, (xmlChar*) "stoichiometry-padding", (xmlChar*) buf); g_free (buf); buf = g_strdup_printf("%g", m_ObjectPadding); xmlNewProp (node, (xmlChar*) "object-padding", (xmlChar*) buf); g_free (buf); buf = g_strdup_printf("%g", m_SignPadding); xmlNewProp (node, (xmlChar*) "sign-padding", (xmlChar*) buf); g_free (buf); buf = g_strdup_printf("%g", m_ChargeSignSize); xmlNewProp (node, (xmlChar*) "charge-sign-size", (xmlChar*) buf); g_free (buf); xmlNewProp (node, (xmlChar*) "font-family", (xmlChar*) m_FontFamily); buf = NULL; switch (m_FontStyle) { case PANGO_STYLE_NORMAL: buf = (char*) "normal"; break; case PANGO_STYLE_OBLIQUE: buf = (char*) "oblique"; break; case PANGO_STYLE_ITALIC: buf = (char*) "italic"; break; } if (buf) xmlNewProp (node, (xmlChar*) "font-style", (xmlChar*) buf); buf = NULL; switch (m_FontWeight) { case PANGO_WEIGHT_ULTRALIGHT: buf = (char*) "ultra-light"; break; case PANGO_WEIGHT_LIGHT: buf = (char*) "light"; break; case PANGO_WEIGHT_NORMAL: buf = (char*) "normal"; break; case PANGO_WEIGHT_SEMIBOLD: buf = (char*) "semi-bold"; break; case PANGO_WEIGHT_BOLD: buf = (char*) "bold"; break; case PANGO_WEIGHT_ULTRABOLD: buf = (char*) "ultra-bold"; break; case PANGO_WEIGHT_HEAVY: buf = (char*) "heavy"; break; } if (buf) xmlNewProp (node, (xmlChar*) "font-weight", (xmlChar*) buf); xmlNewProp (node, (xmlChar*) "font-variant", (xmlChar*) ((m_FontVariant == PANGO_VARIANT_SMALL_CAPS)? "small-caps": "normal")); buf = NULL; switch (m_FontStretch) { case PANGO_STRETCH_ULTRA_CONDENSED: buf = (char*) "ultra-condensed"; break; case PANGO_STRETCH_EXTRA_CONDENSED: buf = (char*) "extra-condensed"; break; case PANGO_STRETCH_CONDENSED: buf = (char*) "condensed"; break; case PANGO_STRETCH_SEMI_CONDENSED: buf = (char*) "semi-condensed"; break; case PANGO_STRETCH_NORMAL: buf = (char*) "normal"; break; case PANGO_STRETCH_SEMI_EXPANDED: buf = (char*) "semi-expanded"; break; case PANGO_STRETCH_EXPANDED: buf = (char*) "expanded"; break; case PANGO_STRETCH_EXTRA_EXPANDED: buf = (char*) "extra-expanded"; break; case PANGO_STRETCH_ULTRA_EXPANDED: buf = (char*) "ultra-expanded"; break; } if (buf) xmlNewProp (node, (xmlChar*) "font-stretch", (xmlChar*) buf); buf = g_strdup_printf("%d", m_FontSize); xmlNewProp (node, (xmlChar*) "font-size", (xmlChar*) buf); g_free (buf); xmlNewProp (node, (xmlChar*) "text-font-family", (xmlChar*) m_TextFontFamily); buf = NULL; switch (m_TextFontStyle) { case PANGO_STYLE_NORMAL: buf = (char*) "normal"; break; case PANGO_STYLE_OBLIQUE: buf = (char*) "oblique"; break; case PANGO_STYLE_ITALIC: buf = (char*) "italic"; break; } if (buf) xmlNewProp (node, (xmlChar*) "text-font-style", (xmlChar*) buf); buf = NULL; switch (m_TextFontWeight) { case PANGO_WEIGHT_ULTRALIGHT: buf = (char*) "ultra-light"; break; case PANGO_WEIGHT_LIGHT: buf = (char*) "light"; break; case PANGO_WEIGHT_NORMAL: buf = (char*) "normal"; break; case PANGO_WEIGHT_SEMIBOLD: buf = (char*) "semi-bold"; break; case PANGO_WEIGHT_BOLD: buf = (char*) "bold"; break; case PANGO_WEIGHT_ULTRABOLD: buf = (char*) "ultra-bold"; break; case PANGO_WEIGHT_HEAVY: buf = (char*) "heavy"; break; } if (buf) xmlNewProp (node, (xmlChar*) "text-font-weight", (xmlChar*) buf); xmlNewProp (node, (xmlChar*) "text-font-variant", (xmlChar*) ((m_TextFontVariant == PANGO_VARIANT_SMALL_CAPS)? "small-caps": "normal")); buf = NULL; switch (m_TextFontStretch) { case PANGO_STRETCH_ULTRA_CONDENSED: buf = (char*) "ultra-condensed"; break; case PANGO_STRETCH_EXTRA_CONDENSED: buf = (char*) "extra-condensed"; break; case PANGO_STRETCH_CONDENSED: buf = (char*) "condensed"; break; case PANGO_STRETCH_SEMI_CONDENSED: buf = (char*) "semi-condensed"; break; case PANGO_STRETCH_NORMAL: buf = (char*) "normal"; break; case PANGO_STRETCH_SEMI_EXPANDED: buf = (char*) "semi-expanded"; break; case PANGO_STRETCH_EXPANDED: buf = (char*) "expanded"; break; case PANGO_STRETCH_EXTRA_EXPANDED: buf = (char*) "extra-expanded"; break; case PANGO_STRETCH_ULTRA_EXPANDED: buf = (char*) "ultra-expanded"; break; } if (buf) xmlNewProp (node, (xmlChar*) "text-font-stretch", (xmlChar*) buf); buf = g_strdup_printf("%d", m_TextFontSize); xmlNewProp (node, (xmlChar*) "text-font-size", (xmlChar*) buf); g_free (buf); xmlAddChild (xml->children, node); return true; } #define READ_DOUBLE(var,name) \ buf = (char*) xmlGetProp (node, (xmlChar*) name); \ if (buf) { \ var = strtod (buf, NULL); \ xmlFree (buf); \ } #define READ_INT(var,name) \ buf = (char*) xmlGetProp (node, (xmlChar*) name); \ if (buf) { \ var = strtol (buf, NULL, 10); \ xmlFree (buf); \ } bool gcpTheme::Load (xmlNodePtr node) { char *buf = (char*) xmlGetProp (node, (xmlChar*) "name"); if (buf) { m_Name = buf; xmlFree (buf); } READ_DOUBLE (m_BondLength, "bond-length"); READ_DOUBLE (m_BondAngle, "bond-angle"); READ_DOUBLE (m_BondDist, "bond-dist"); READ_DOUBLE (m_BondWidth, "bond-width"); READ_DOUBLE (m_ArrowLength, "arrow-length"); READ_DOUBLE (m_ArrowHeadA, "arrow-head-a"); READ_DOUBLE (m_ArrowHeadB, "arrow-head-b"); READ_DOUBLE (m_ArrowHeadC, "arrow-head-c"); READ_DOUBLE (m_ArrowDist, "arrow-dist"); READ_DOUBLE (m_ArrowWidth, "arrow-width"); READ_DOUBLE (m_ArrowPadding, "arrow-padding"); READ_DOUBLE (m_HashWidth, "hash-width"); READ_DOUBLE (m_HashDist, "hash-dist"); READ_DOUBLE (m_StereoBondWidth, "stereo-bond-width"); READ_DOUBLE (m_ZoomFactor, "zoom-factor"); m_ZoomFactor = 1 / m_ZoomFactor; READ_DOUBLE (m_Padding, "padding"); READ_DOUBLE (m_StoichiometryPadding, "stoichiometry-padding"); READ_DOUBLE (m_ObjectPadding, "object-padding"); READ_DOUBLE (m_SignPadding, "sign-padding"); READ_DOUBLE (m_ChargeSignSize, "charge-sign-size"); buf = (char*) xmlGetProp (node, (xmlChar*) "font-family"); if (buf) { if (m_FontFamily) g_free (m_FontFamily); m_FontFamily = g_strdup (buf); } buf = (char*) xmlGetProp (node, (xmlChar*) "font-style"); if (buf) { if (!strcmp (buf, "normal")) m_FontStyle = PANGO_STYLE_NORMAL; else if (!strcmp (buf, "oblique")) m_FontStyle = PANGO_STYLE_OBLIQUE; else if (!strcmp (buf, "italic")) m_FontStyle = PANGO_STYLE_ITALIC; xmlFree (buf); } buf = (char*) xmlGetProp (node, (xmlChar*) "font-weight"); if (buf) { if (!strcmp (buf, "ultra-light")) m_FontWeight= PANGO_WEIGHT_ULTRALIGHT; else if (!strcmp (buf, "light")) m_FontWeight = PANGO_WEIGHT_LIGHT; else if (!strcmp (buf, "normal")) m_FontWeight = PANGO_WEIGHT_NORMAL; else if (!strcmp (buf, "semi-bold")) m_FontWeight = PANGO_WEIGHT_SEMIBOLD; else if (!strcmp (buf, "bold")) m_FontWeight = PANGO_WEIGHT_BOLD; else if (!strcmp (buf, "ultra-bold")) m_FontWeight = PANGO_WEIGHT_ULTRABOLD; else if (!strcmp (buf, "heavy")) m_FontWeight = PANGO_WEIGHT_HEAVY; xmlFree (buf); } buf = (char*) xmlGetProp (node, (xmlChar*) "font-variant"); if (buf) { if (!strcmp (buf, "normal")) m_FontVariant = PANGO_VARIANT_NORMAL; else if (!strcmp (buf, "small-caps")) m_FontVariant = PANGO_VARIANT_SMALL_CAPS; xmlFree (buf); } buf = (char*) xmlGetProp (node, (xmlChar*) "font-stretch"); if (buf) { if (!strcmp (buf, "ultra-condensed")) m_FontStretch = PANGO_STRETCH_ULTRA_CONDENSED; else if (!strcmp (buf, "extra-condensed")) m_FontStretch = PANGO_STRETCH_EXTRA_CONDENSED; else if (!strcmp (buf, "condensed")) m_FontStretch = PANGO_STRETCH_CONDENSED; else if (!strcmp (buf, "semi-condensed")) m_FontStretch = PANGO_STRETCH_SEMI_CONDENSED; else if (!strcmp (buf, "normal")) m_FontStretch = PANGO_STRETCH_NORMAL; else if (!strcmp (buf, "semi-expanded")) m_FontStretch = PANGO_STRETCH_SEMI_EXPANDED; else if (!strcmp (buf, "expanded")) m_FontStretch = PANGO_STRETCH_EXPANDED; else if (!strcmp (buf, "extra-expanded")) m_FontStretch = PANGO_STRETCH_EXTRA_EXPANDED; else if (!strcmp (buf, "ultra-expanded")) m_FontStretch = PANGO_STRETCH_ULTRA_EXPANDED; xmlFree (buf); } READ_INT (m_FontSize, "font-size"); buf = (char*) xmlGetProp (node, (xmlChar*) "text-font-family"); if (buf) { if (m_TextFontFamily) g_free (m_TextFontFamily); m_TextFontFamily = g_strdup (buf); xmlFree (buf); } buf = (char*) xmlGetProp (node, (xmlChar*) "text-font-style"); if (buf) { if (!strcmp (buf, "normal")) m_TextFontStyle = PANGO_STYLE_NORMAL; else if (!strcmp (buf, "oblique")) m_TextFontStyle = PANGO_STYLE_OBLIQUE; else if (!strcmp (buf, "italic")) m_TextFontStyle = PANGO_STYLE_ITALIC; xmlFree (buf); } buf = (char*) xmlGetProp (node, (xmlChar*) "text-font-weight"); if (buf) { if (!strcmp (buf, "ultra-light")) m_TextFontWeight= PANGO_WEIGHT_ULTRALIGHT; else if (!strcmp (buf, "light")) m_TextFontWeight = PANGO_WEIGHT_LIGHT; else if (!strcmp (buf, "normal")) m_TextFontWeight = PANGO_WEIGHT_NORMAL; else if (!strcmp (buf, "semi-bold")) m_TextFontWeight = PANGO_WEIGHT_SEMIBOLD; else if (!strcmp (buf, "bold")) m_TextFontWeight = PANGO_WEIGHT_BOLD; else if (!strcmp (buf, "ultra-bold")) m_TextFontWeight = PANGO_WEIGHT_ULTRABOLD; else if (!strcmp (buf, "heavy")) m_TextFontWeight = PANGO_WEIGHT_HEAVY; xmlFree (buf); } buf = (char*) xmlGetProp (node, (xmlChar*) "text-font-variant"); if (buf) { if (!strcmp (buf, "normal")) m_TextFontVariant = PANGO_VARIANT_NORMAL; else if (!strcmp (buf, "small-caps")) m_TextFontVariant = PANGO_VARIANT_SMALL_CAPS; xmlFree (buf); } buf = (char*) xmlGetProp (node, (xmlChar*) "text-font-stretch"); if (buf) { if (!strcmp (buf, "ultra-condensed")) m_TextFontStretch = PANGO_STRETCH_ULTRA_CONDENSED; else if (!strcmp (buf, "extra-condensed")) m_TextFontStretch = PANGO_STRETCH_EXTRA_CONDENSED; else if (!strcmp (buf, "condensed")) m_TextFontStretch = PANGO_STRETCH_CONDENSED; else if (!strcmp (buf, "semi-condensed")) m_TextFontStretch = PANGO_STRETCH_SEMI_CONDENSED; else if (!strcmp (buf, "normal")) m_TextFontStretch = PANGO_STRETCH_NORMAL; else if (!strcmp (buf, "semi-expanded")) m_TextFontStretch = PANGO_STRETCH_SEMI_EXPANDED; else if (!strcmp (buf, "expanded")) m_TextFontStretch = PANGO_STRETCH_EXPANDED; else if (!strcmp (buf, "extra-expanded")) m_TextFontStretch = PANGO_STRETCH_EXTRA_EXPANDED; else if (!strcmp (buf, "ultra-expanded")) m_TextFontStretch = PANGO_STRETCH_ULTRA_EXPANDED; xmlFree (buf); } READ_INT (m_TextFontSize, "text-font-size"); m_ThemeType = FILE_THEME_TYPE; return true; } #define TEST_FIELD(field) \ if (field != theme.field) \ return false; #define TEST_FLOAT_FIELD(field) \ if (fabs (1. - field / theme.field) > 1e-7) \ return false; bool gcpTheme::operator== (const gcpTheme &theme) { TEST_FLOAT_FIELD (m_BondLength) TEST_FLOAT_FIELD (m_BondAngle) TEST_FLOAT_FIELD (m_BondDist) TEST_FLOAT_FIELD (m_BondWidth) TEST_FLOAT_FIELD (m_ArrowLength) TEST_FLOAT_FIELD (m_ArrowWidth) TEST_FLOAT_FIELD (m_ArrowDist) TEST_FLOAT_FIELD (m_ArrowHeadA) TEST_FLOAT_FIELD (m_ArrowHeadB) TEST_FLOAT_FIELD (m_ArrowHeadC) TEST_FLOAT_FIELD (m_ArrowPadding) TEST_FLOAT_FIELD (m_HashWidth) TEST_FLOAT_FIELD (m_HashDist) TEST_FLOAT_FIELD (m_StereoBondWidth) TEST_FLOAT_FIELD (m_ZoomFactor) TEST_FLOAT_FIELD (m_Padding) TEST_FLOAT_FIELD (m_StoichiometryPadding) TEST_FLOAT_FIELD (m_ObjectPadding) TEST_FLOAT_FIELD (m_SignPadding) TEST_FLOAT_FIELD (m_ChargeSignSize) if (strcmp (m_FontFamily, theme.m_FontFamily)) return false; TEST_FIELD (m_FontStyle) TEST_FIELD (m_FontWeight) TEST_FIELD (m_FontVariant) TEST_FIELD (m_FontStretch) TEST_FIELD (m_FontSize) if (strcmp (m_TextFontFamily, theme.m_TextFontFamily)) return false; TEST_FIELD (m_TextFontStyle) TEST_FIELD (m_TextFontWeight) TEST_FIELD (m_TextFontVariant) TEST_FIELD (m_TextFontStretch) TEST_FIELD (m_TextFontSize) return true; } void gcpTheme::RemoveClient (Object *client) { set ::iterator iter = m_Clients.find (client); if (iter != m_Clients.end ()) m_Clients.erase (iter); if (m_ThemeType == FILE_THEME_TYPE && m_Clients.size () == 0) { ThemeManager.RemoveFileTheme (this); delete this; } } void gcpTheme::NotifyChanged () { set ::iterator iter, enditer = m_Clients.end (); for (iter = m_Clients.begin (); iter != enditer; iter++) (*iter)->OnSignal (OnThemeChangedSignal, NULL); }