diff options
| author | Tavmjong Bah <tavmjong@free.fr> | 2018-04-13 09:43:53 +0000 |
|---|---|---|
| committer | Tavmjong Bah <tavmjong@free.fr> | 2018-04-13 09:43:53 +0000 |
| commit | 1ddfdd2c6d5f915da6a7563c2d29021d53ff07ed (patch) | |
| tree | 21241bccd07beb89b054b746685f118021e4cf93 /src | |
| parent | Remove unused variables. (diff) | |
| download | inkscape-1ddfdd2c6d5f915da6a7563c2d29021d53ff07ed.tar.gz inkscape-1ddfdd2c6d5f915da6a7563c2d29021d53ff07ed.zip | |
Replace C FontSelector by C++ FontSelector.
Fix synchonization problems between users of FontLister (FontSelector/Text toolbar).
Hide unused size widget in Glyphs dialog.
Display style names in FontSelector using own style.
Diffstat (limited to 'src')
| -rw-r--r-- | src/libnrtype/font-lister.cpp | 157 | ||||
| -rw-r--r-- | src/libnrtype/font-lister.h | 43 | ||||
| -rw-r--r-- | src/ui/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/ui/dialog/glyphs.cpp | 55 | ||||
| -rw-r--r-- | src/ui/dialog/glyphs.h | 12 | ||||
| -rw-r--r-- | src/ui/dialog/text-edit.cpp | 79 | ||||
| -rw-r--r-- | src/ui/dialog/text-edit.h | 12 | ||||
| -rw-r--r-- | src/ui/widget/font-selector.cpp | 385 | ||||
| -rw-r--r-- | src/ui/widget/font-selector.h | 165 | ||||
| -rw-r--r-- | src/widgets/font-selector.cpp | 509 | ||||
| -rw-r--r-- | src/widgets/font-selector.h | 68 |
11 files changed, 805 insertions, 682 deletions
diff --git a/src/libnrtype/font-lister.cpp b/src/libnrtype/font-lister.cpp index 7c26f0b92..20ab3786d 100644 --- a/src/libnrtype/font-lister.cpp +++ b/src/libnrtype/font-lister.cpp @@ -2,8 +2,9 @@ #include <config.h> #endif -#include <gtkmm/liststore.h> -#include <gtkmm/treemodel.h> +#include <glibmm/regex.h> + +#include <gtkmm/cellrenderertext.h> #include <libnrtype/font-instance.h> @@ -15,12 +16,13 @@ #include "document.h" #include "inkscape.h" #include "preferences.h" + #include "object/sp-object.h" #include "object/sp-root.h" #include "object/sp-namedview.h" + #include "xml/repr.h" -#include <glibmm/regex.h> //#define DEBUG_FONT @@ -46,6 +48,10 @@ static const char* sp_font_family_get_name(PangoFontFamily* family) namespace Inkscape { FontLister::FontLister() + : current_family_row (0) + , current_family ("sans-serif") + , current_style ("Normal") + , block (false) { font_list_store = Gtk::ListStore::create(FontList); font_list_store->freeze_notify(); @@ -82,10 +88,6 @@ FontLister::FontLister() } } - current_family_row = 0; - current_family = "sans-serif"; - current_style = "Normal"; - font_list_store->thaw_notify(); style_list_store = Gtk::ListStore::create(FontStyleList); @@ -126,9 +128,10 @@ FontLister *FontLister::get_instance() return instance; } -void FontLister::ensureRowStyles(GtkTreeModel* model, GtkTreeIter const* iterator) +// To do: remove model (not needed for C++ version). +// Ensures the style list for a particular family has been created. +void FontLister::ensureRowStyles(Glib::RefPtr<Gtk::TreeModel> model, Gtk::TreeModel::iterator const iter) { - Gtk::TreeIter iter(model, iterator); Gtk::TreeModel::Row row = *iter; if (!row[FontList.styles]) { if (row[FontList.pango_family]) { @@ -178,6 +181,12 @@ void FontLister::insert_font_family(Glib::ustring new_family) (*treeModelIter)[FontList.styles] = styles; (*treeModelIter)[FontList.onSystem] = false; (*treeModelIter)[FontList.pango_family] = NULL; + + current_family = new_family; + current_family_row = 0; + current_style = "Normal"; + + emit_update(); } void FontLister::update_font_list(SPDocument *document) @@ -304,6 +313,7 @@ void FontLister::update_font_list(SPDocument *document) // std::cout << " Out: row: " << current_family_row << " " << current_family << std::endl; font_list_store->thaw_notify(); + emit_update(); } void FontLister::update_font_data_recursive(SPObject& r, std::map<Glib::ustring, std::set<Glib::ustring>> &font_data) @@ -335,6 +345,16 @@ void FontLister::update_font_data_recursive(SPObject& r, std::map<Glib::ustring, } } +void FontLister::emit_update() +{ + if (block) return; + + block = true; + update_signal.emit (get_fontspec()); + block = false; +} + + Glib::ustring FontLister::canonize_fontspec(Glib::ustring fontspec) { @@ -468,6 +488,9 @@ std::pair<Glib::ustring, Glib::ustring> FontLister::selection_update() std::cout << "FontLister::selection_update: exit" << std::endl; std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << std::endl; #endif + + emit_update(); + return std::make_pair(current_family, current_style); } @@ -486,10 +509,13 @@ void FontLister::set_fontspec(Glib::ustring new_fontspec, bool /*check*/) set_font_family(new_family, false); set_font_style(new_style); + + emit_update(); } // TODO: use to determine font-selector best style +// TODO: create new function new_font_family(Gtk::TreeModel::iterator iter) std::pair<Glib::ustring, Glib::ustring> FontLister::new_font_family(Glib::ustring new_family, bool /*check_style*/) { #ifdef DEBUG_FONT @@ -577,6 +603,9 @@ std::pair<Glib::ustring, Glib::ustring> FontLister::set_font_family(Glib::ustrin std::cout << "FontLister::set_font_family: end" << std::endl; std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << std::endl; #endif + + emit_update(); + return ui; } @@ -626,6 +655,8 @@ void FontLister::set_font_style(Glib::ustring new_style) std::cout << "FontLister::set_font_style: end" << std::endl; std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << std::endl; #endif + + emit_update(); } @@ -799,7 +830,6 @@ Glib::ustring FontLister::fontspec_from_style(SPStyle *style) Gtk::TreeModel::Row FontLister::get_row_for_font(Glib::ustring family) { - Gtk::TreePath path; Gtk::TreeModel::iterator iter = font_list_store->get_iter("0"); while (iter != font_list_store->children().end()) { @@ -823,7 +853,6 @@ Gtk::TreePath FontLister::get_path_for_font(Glib::ustring family) Gtk::TreeModel::Row FontLister::get_row_for_style(Glib::ustring style) { - Gtk::TreePath path; Gtk::TreeModel::iterator iter = style_list_store->get_iter("0"); while (iter != style_list_store->children().end()) { @@ -980,14 +1009,97 @@ const Glib::RefPtr<Gtk::ListStore> FontLister::get_style_list() const // Helper functions // Separator function (if true, a separator will be drawn) -gboolean font_lister_separator_func(GtkTreeModel *model, GtkTreeIter *iter, gpointer /*data*/) +bool font_lister_separator_func(const Glib::RefPtr<Gtk::TreeModel>& model, + const Gtk::TreeModel::iterator& iter) { + + // Of what use is 'model', can we avoid using font_lister? + Inkscape::FontLister* font_lister = Inkscape::FontLister::get_instance(); + Gtk::TreeModel::Row row = *iter; + Glib::ustring entry = row[font_lister->FontList.family]; + return entry == "#"; +} + +// Needed until Text toolbar updated +gboolean font_lister_separator_func2(GtkTreeModel *model, GtkTreeIter *iter, gpointer /*data*/) { gchar *text = 0; gtk_tree_model_get(model, iter, 0, &text, -1); // Column 0: FontList.family return (text && strcmp(text, "#") == 0); } -void font_lister_cell_data_func(GtkCellLayout * /*cell_layout*/, +// Draw system fonts in dark blue, missing fonts with red strikeout. +// Used by both FontSelector and Text toolbar. +void font_lister_cell_data_func (Gtk::CellRenderer *renderer, Gtk::TreeIter const &iter) +{ + Inkscape::FontLister* font_lister = Inkscape::FontLister::get_instance(); + Gtk::TreeModel::Row row = *iter; + + Glib::ustring family = row[font_lister->FontList.family]; + bool onSystem = row[font_lister->FontList.onSystem]; + + Glib::ustring family_escaped = Glib::strescape( family ); + Glib::ustring markup; + + if (!onSystem) { + markup = "<span foreground='darkblue'>"; + + // See if font-family is on system (separately for each family in font stack). + std::vector<Glib::ustring> tokens = Glib::Regex::split_simple("\\s*,\\s*", family); + + for (auto token: tokens) { + bool found = false; + Gtk::TreeModel::Children children = font_lister->get_font_list()->children(); + for (auto iter2: children) { + Gtk::TreeModel::Row row2 = *iter2; + Glib::ustring family2 = row2[font_lister->FontList.family]; + bool onSystem2 = row2[font_lister->FontList.onSystem]; + if (onSystem2 && familyNamesAreEqual(token, family)) { + found = true; + break; + } + } + + if (found) { + markup += Glib::strescape (token); + markup += ", "; + } else { + markup += "<span strikethrough=\"true\" strikethrough_color=\"red\">"; + markup += Glib::strescape (token); + markup += "</span>"; + markup += ", "; + } + } + + // Remove extra comma and space from end. + if (markup.size() >= 2) { + markup.resize(markup.size() - 2); + } + markup += "</span>"; + + } else { + markup = family_escaped; + } + + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + int show_sample = prefs->getInt("/tools/text/show_sample_in_list", 1); + if (show_sample) { + + Glib::ustring sample = prefs->getString("/tools/text/font_sample"); + + markup += " <span foreground='gray' font_family='"; + markup += family_escaped; + markup += "'>"; + markup += sample; + markup += "</span>"; + } + + // std::cout << "Markup: " << markup << std::endl; + + renderer->set_property("markup", markup); +} + +// Needed until Text toolbar updated +void font_lister_cell_data_func2(GtkCellLayout * /*cell_layout*/, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, @@ -1063,6 +1175,25 @@ void font_lister_cell_data_func(GtkCellLayout * /*cell_layout*/, g_free(family_escaped); } +// Draw Face name with face style. +void font_lister_style_cell_data_func (Gtk::CellRenderer *renderer, Gtk::TreeIter const &iter) +{ + Inkscape::FontLister* font_lister = Inkscape::FontLister::get_instance(); + Gtk::TreeModel::Row row = *iter; + + Glib::ustring family = font_lister->get_font_family(); + Glib::ustring style = row[font_lister->FontStyleList.cssStyle]; + + Glib::ustring style_escaped = Glib::strescape( style ); + Glib::ustring font_desc = family + ", " + style; + Glib::ustring markup; + + markup = "<span font='" + font_desc + "'>" + style_escaped + "</span>"; + std::cout << " markup: " << markup << std::endl; + + renderer->set_property("markup", markup); +} + /* Local Variables: mode:c++ diff --git a/src/libnrtype/font-lister.h b/src/libnrtype/font-lister.h index e5acdc107..7125cc0f4 100644 --- a/src/libnrtype/font-lister.h +++ b/src/libnrtype/font-lister.h @@ -19,16 +19,22 @@ #include <map> #include <set> +#include <glibmm/ustring.h> +#include <glibmm/stringutils.h> // For strescape() + #include <gtkmm/liststore.h> #include <gtkmm/treemodelcolumn.h> #include <gtkmm/treepath.h> -#include <glibmm/ustring.h> class SPObject; class SPDocument; class SPCSSAttr; class SPStyle; +namespace Gtk { +class CellRenderer; +} + namespace Inkscape { /** @@ -53,6 +59,10 @@ namespace Inkscape { * * This class is used by the UI interface (text-toolbar, font-select, etc.). * + * This class is a singleton (one instance per Inkscape session). Since fonts + * used in a document are added to the list, there really should be one + * instance per document. + * * "Font" includes family and style. It should not be used when one * means font-family. */ @@ -258,9 +268,21 @@ public: Glib::ustring get_best_style_match(Glib::ustring family, Glib::ustring style); /** - * Makes sure style ListStore is filled. + * Ensures the style list for a particular family has been created. + */ + void ensureRowStyles(Glib::RefPtr<Gtk::TreeModel> model, Gtk::TreeModel::iterator const iter); + + /** + * Let users of FontLister know to update GUI. + * This is to allow synchronization of changes across multiple widgets. + * Handlers should block signals. + * Input is fontspec to set. */ - void ensureRowStyles(GtkTreeModel* model, GtkTreeIter const* iter); + sigc::connection connectUpdate(sigc::slot<void, Glib::ustring> slot) { + return update_signal.connect(slot); + } + + bool blocked() { return block; } private: FontLister(); @@ -282,21 +304,32 @@ private: * If a font-family is not on system, this list of styles is used. */ GList *default_styles; + + bool block; + void emit_update(); + sigc::signal<void, Glib::ustring> update_signal; }; } // namespace Inkscape // Helper functions -gboolean font_lister_separator_func(GtkTreeModel *model, +bool font_lister_separator_func (const Glib::RefPtr<Gtk::TreeModel>& model, + const Gtk::TreeModel::iterator& iter); + +gboolean font_lister_separator_func2(GtkTreeModel *model, GtkTreeIter *iter, gpointer /*data*/); -void font_lister_cell_data_func(GtkCellLayout * /*cell_layout*/, +void font_lister_cell_data_func (Gtk::CellRenderer *renderer, Gtk::TreeIter const &iter); + +void font_lister_cell_data_func2(GtkCellLayout * /*cell_layout*/, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer /*data*/); +void font_lister_style_cell_data_func (Gtk::CellRenderer *renderer, Gtk::TreeIter const &iter); + #endif /* diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index 1de3d1354..029c00126 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -137,6 +137,7 @@ set(ui_SRC widget/entry.cpp widget/filter-effect-chooser.cpp widget/font-button.cpp + widget/font-selector.cpp widget/font-variants.cpp widget/frame.cpp widget/highlight-picker.cpp @@ -331,6 +332,7 @@ set(ui_SRC widget/entry.h widget/filter-effect-chooser.h widget/font-button.h + widget/font-selector.h widget/font-variants.h widget/frame.h widget/highlight-picker.h diff --git a/src/ui/dialog/glyphs.cpp b/src/ui/dialog/glyphs.cpp index eb13700ec..07973b4c0 100644 --- a/src/ui/dialog/glyphs.cpp +++ b/src/ui/dialog/glyphs.cpp @@ -26,11 +26,12 @@ #include "verbs.h" #include "libnrtype/font-instance.h" +#include "libnrtype/font-lister.h" #include "object/sp-flowtext.h" #include "object/sp-text.h" -#include "widgets/font-selector.h" +#include "ui/widget/font-selector.h" namespace Inkscape { namespace UI { @@ -323,13 +324,6 @@ GlyphColumns *GlyphsPanel::getColumns() GlyphsPanel::GlyphsPanel() : Inkscape::UI::Widget::Panel("/dialogs/glyphs", SP_VERB_DIALOG_GLYPHS), store(Gtk::ListStore::create(*getColumns())), - iconView(0), - entry(0), - label(0), - insertBtn(0), - scriptCombo(0), - fsel(0), - targetDesktop(0), deskTrack(), instanceConns(), desktopConns() @@ -340,16 +334,19 @@ GlyphsPanel::GlyphsPanel() : // ------------------------------- - GtkWidget *fontsel = sp_font_selector_new(); - fsel = SP_FONT_SELECTOR(fontsel); - sp_font_selector_set_fontspec( fsel, sp_font_selector_get_fontspec(fsel), 12.0 ); - - gtk_widget_set_size_request (fontsel, 0, 150); - g_signal_connect( G_OBJECT(fontsel), "font_set", G_CALLBACK(fontChangeCB), this ); + { + fontSelector = new Inkscape::UI::Widget::FontSelector (false); + fontSelector->set_fontsize_visible (false); + fontSelector->set_size (12.0); + fontSelector->set_name ("Glyphs"); - table->attach(*Gtk::manage(Glib::wrap(fontsel)), 0, row, 3, 1); - row++; + sigc::connection conn = + fontSelector->connectChanged(sigc::hide(sigc::mem_fun(*this, &GlyphsPanel::rebuild))); + instanceConns.push_back(conn); + table->attach(*Gtk::manage(fontSelector), 0, row, 3, 1); + row++; + } // ------------------------------- @@ -597,13 +594,6 @@ void GlyphsPanel::glyphSelectionChanged() calcCanInsert(); } -void GlyphsPanel::fontChangeCB(SPFontSelector * /*fontsel*/, Glib::ustring /*fontspec*/, GlyphsPanel *self) -{ - if (self) { - self->rebuild(); - } -} - void GlyphsPanel::selectionModifiedCB(guint flags) { bool style = ((flags & ( SP_OBJECT_CHILD_MODIFIED_FLAG | @@ -636,24 +626,28 @@ void GlyphsPanel::calcCanInsert() } } -void GlyphsPanel::readSelection( bool updateStyle, bool /*updateContent*/ ) +void GlyphsPanel::readSelection( bool updateStyle, bool updateContent ) { calcCanInsert(); - if (targetDesktop && updateStyle) { - //SPStyle query(SP_ACTIVE_DOCUMENT); + if (updateStyle) { + Inkscape::FontLister* fontlister = Inkscape::FontLister::get_instance(); + + // Update family/style based on selection. + fontlister->selection_update(); - //int result_family = sp_desktop_query_style(targetDesktop, &query, QUERY_STYLE_PROPERTY_FONTFAMILY); - //int result_style = sp_desktop_query_style(targetDesktop, &query, QUERY_STYLE_PROPERTY_FONTSTYLE); - //int result_numbers = sp_desktop_query_style(targetDesktop, &query, QUERY_STYLE_PROPERTY_FONTNUMBERS); + // Get fontspec for selection. + Glib::ustring fontspec = fontlister->get_fontspec(); + // Update GUI. + fontSelector->set_fontspec (fontspec); } } void GlyphsPanel::rebuild() { - Glib::ustring fontspec = fsel ? sp_font_selector_get_fontspec(fsel) : ""; + Glib::ustring fontspec = fontSelector->get_fontspec(); font_instance* font = 0; if( !fontspec.empty() ) { @@ -661,7 +655,6 @@ void GlyphsPanel::rebuild() } if (font) { - //double sp_font_selector_get_size (SPFontSelector *fsel); GUnicodeScript script = G_UNICODE_SCRIPT_INVALID_CODE; Glib::ustring scriptName = scriptCombo->get_active_text(); diff --git a/src/ui/dialog/glyphs.h b/src/ui/dialog/glyphs.h index 66db421e9..818d38811 100644 --- a/src/ui/dialog/glyphs.h +++ b/src/ui/dialog/glyphs.h @@ -20,13 +20,13 @@ class Label; class ListStore; } -struct SPFontSelector; -class font_instance; - - namespace Inkscape { namespace UI { +namespace Widget { +class FontSelector; +} + namespace Dialog { class GlyphColumns; @@ -52,8 +52,6 @@ private: static GlyphColumns *getColumns(); - static void fontChangeCB(SPFontSelector *fontsel, Glib::ustring fontspec, GlyphsPanel *self); - void rebuild(); void glyphActivated(Gtk::TreeModel::Path const & path); @@ -72,7 +70,7 @@ private: Gtk::Button *insertBtn; Gtk::ComboBoxText *scriptCombo; Gtk::ComboBoxText *rangeCombo; - SPFontSelector *fsel; + Inkscape::UI::Widget::FontSelector *fontSelector; SPDesktop *targetDesktop; DesktopTracker deskTrack; diff --git a/src/ui/dialog/text-edit.cpp b/src/ui/dialog/text-edit.cpp index f770f1d23..2c122da49 100644 --- a/src/ui/dialog/text-edit.cpp +++ b/src/ui/dialog/text-edit.cpp @@ -52,11 +52,10 @@ extern "C" { #include "ui/icon-names.h" #include "ui/interface.h" +#include "ui/widget/font-selector.h" #include "util/units.h" -#include "widgets/font-selector.h" - namespace Inkscape { namespace UI { @@ -87,19 +86,15 @@ TextEdit::TextEdit() /* Font tab -------------------------------- */ /* Font selector */ - GtkWidget *fontsel = sp_font_selector_new (); - gtk_widget_set_size_request (fontsel, 0, 150); - fsel = SP_FONT_SELECTOR(fontsel); - fontsel_hbox.pack_start(*Gtk::manage(Glib::wrap(fontsel)), true, true); - fontsel_hbox.set_name("Font Selector HBox"); + // Do nothing. /* Font preview */ - preview_label.set_ellipsize(Pango::ELLIPSIZE_END); - preview_label.set_justify(Gtk::JUSTIFY_CENTER); - preview_label.set_line_wrap(FALSE); + preview_label.set_ellipsize (Pango::ELLIPSIZE_END); + preview_label.set_justify (Gtk::JUSTIFY_CENTER); + preview_label.set_line_wrap (false); - font_vbox.pack_start(fontsel_hbox, true, true); - font_vbox.pack_start(preview_label, true, true, VB_MARGIN); + font_vbox.pack_start(font_selector, true, true); + font_vbox.pack_start(preview_label, false, false, 5); /* Text tab -------------------------------- */ scroller.set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC ); @@ -133,8 +128,8 @@ TextEdit::TextEdit() notebook.append_page(font_vbox, font_label); notebook.append_page(text_vbox, text_label); notebook.append_page(vari_vbox, vari_label); - - /* Buttons (under notebook) ------------------ */ + + /* Buttons (below notebook) ------------------ */ setasdefault_button.set_use_underline(true); apply_button.set_can_default(); button_row.pack_start(setasdefault_button, false, false, 0); @@ -148,16 +143,18 @@ TextEdit::TextEdit() contents->pack_start(button_row, false, false, VB_MARGIN); /* Signal handlers */ - g_signal_connect ( G_OBJECT (fontsel), "font_set", G_CALLBACK (onFontChange), this ); g_signal_connect ( G_OBJECT (text_buffer), "changed", G_CALLBACK (onTextChange), this ); setasdefault_button.signal_clicked().connect(sigc::mem_fun(*this, &TextEdit::onSetDefault)); apply_button.signal_clicked().connect(sigc::mem_fun(*this, &TextEdit::onApply)); close_button.signal_clicked().connect(sigc::bind(_signal_response.make_slot(), GTK_RESPONSE_CLOSE)); + fontChangedConn = font_selector.connectChanged (sigc::mem_fun(*this, &TextEdit::onFontChange)); fontVariantChangedConn = vari_vbox.connectChanged(sigc::bind(sigc::ptr_fun(&onFontVariantChange), this)); desktopChangeConn = deskTrack.connectDesktopChanged( sigc::mem_fun(*this, &TextEdit::setTargetDesktop) ); deskTrack.connect(GTK_WIDGET(gobj())); + font_selector.set_name ("TextEdit"); + show_all_children(); } @@ -168,6 +165,7 @@ TextEdit::~TextEdit() selectChangedConn.disconnect(); desktopChangeConn.disconnect(); deskTrack.disconnect(); + fontChangedConn.disconnect(); fontVariantChangedConn.disconnect(); } @@ -239,34 +237,29 @@ void TextEdit::onReadSelection ( gboolean dostyle, gboolean /*docontent*/ ) // Query style from desktop into it. This returns a result flag and fills query with the // style of subselection, if any, or selection - //int result_fontspec = sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION); - int result_family = sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_FONTFAMILY); - int result_style = sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_FONTSTYLE); int result_numbers = sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_FONTNUMBERS); - // If querying returned nothing, read the style from the text tool prefs (default style for new texts) - // (Ok to not get a font specification - must just rely on the family and style in that case) - if (result_family == QUERY_STYLE_NOTHING || - result_style == QUERY_STYLE_NOTHING || - result_numbers == QUERY_STYLE_NOTHING) { + // If querying returned nothing, read the style from the text tool prefs (default style for new texts). + if (result_numbers == QUERY_STYLE_NOTHING) { query.readFromPrefs("/tools/text"); } - // FIXME: process result_family/style == QUERY_STYLE_MULTIPLE_DIFFERENT by showing "Many" in the lists + Inkscape::FontLister* font_lister = Inkscape::FontLister::get_instance(); - Inkscape::FontLister* fontlister = Inkscape::FontLister::get_instance(); + // Update family/style based on selection. + font_lister->selection_update(); - // This is normally done for us by text-toolbar but only when we are in text editing context - fontlister->update_font_list(this->desktop->getDocument()); - fontlister->selection_update(); - - Glib::ustring fontspec = fontlister->get_fontspec(); + // Get fontspec for selection. + Glib::ustring fontspec = font_lister->get_fontspec(); + font_selector.set_fontspec (fontspec); + // Update Size. Inkscape::Preferences *prefs = Inkscape::Preferences::get(); int unit = prefs->getInt("/options/font/unitType", SP_CSS_UNIT_PT); double size = sp_style_css_size_px_to_units(query.font_size.computed, unit); - sp_font_selector_set_fontspec(fsel, fontspec, size ); + font_selector.set_size (size); + // Update Preview setPreviewText (fontspec, phrase); // Update font variant widget @@ -293,15 +286,16 @@ void TextEdit::setPreviewText (Glib::ustring font_spec, Glib::ustring phrase) Inkscape::Preferences *prefs = Inkscape::Preferences::get(); int unit = prefs->getInt("/options/font/unitType", SP_CSS_UNIT_PT); - double pt_size = Inkscape::Util::Quantity::convert(sp_style_css_size_units_to_px(sp_font_selector_get_size(fsel), unit), "px", "pt"); + double pt_size = + Inkscape::Util::Quantity::convert( + sp_style_css_size_units_to_px(font_selector.get_fontsize(), unit), "px", "pt"); pt_size = std::min(pt_size, 100.0); // Pango font size is in 1024ths of a point Glib::ustring size = std::to_string( int(pt_size * PANGO_SCALE) ); Glib::ustring markup = "<span font=\'" + font_spec_escaped + - "\' size=\'" + size + "\'>" + phrase_escaped + "</span>"; - - preview_label.set_markup(markup.c_str()); + "\' size=\'" + size + "\'>" + phrase + "</span>"; + preview_label.set_markup (markup); } @@ -361,7 +355,7 @@ SPCSSAttr *TextEdit::fillTextStyle () { SPCSSAttr *css = sp_repr_css_attr_new (); - Glib::ustring fontspec = sp_font_selector_get_fontspec (fsel); + Glib::ustring fontspec = font_selector.get_fontspec(); if( !fontspec.empty() ) { @@ -373,9 +367,10 @@ SPCSSAttr *TextEdit::fillTextStyle () Inkscape::Preferences *prefs = Inkscape::Preferences::get(); int unit = prefs->getInt("/options/font/unitType", SP_CSS_UNIT_PT); if (prefs->getBool("/options/font/textOutputPx", true)) { - os << sp_style_css_size_units_to_px(sp_font_selector_get_size (fsel), unit) << sp_style_get_css_unit_string(SP_CSS_UNIT_PX); + os << sp_style_css_size_units_to_px(font_selector.get_fontsize(), unit) + << sp_style_get_css_unit_string(SP_CSS_UNIT_PX); } else { - os << sp_font_selector_get_size (fsel) << sp_style_get_css_unit_string(unit); + os << font_selector.get_fontsize() << sp_style_get_css_unit_string(unit); } sp_repr_css_set_property (css, "font-size", os.str().c_str()); } @@ -433,7 +428,7 @@ void TextEdit::onApply() } // Update FontLister - Glib::ustring fontspec = sp_font_selector_get_fontspec (fsel); + Glib::ustring fontspec = font_selector.get_fontspec(); if( !fontspec.empty() ) { Inkscape::FontLister *fontlister = Inkscape::FontLister::get_instance(); fontlister->set_fontspec( fontspec, false ); @@ -461,7 +456,7 @@ void TextEdit::onChange() gtk_text_buffer_get_bounds (text_buffer, &start, &end); gchar *str = gtk_text_buffer_get_text(text_buffer, &start, &end, TRUE); - Glib::ustring fontspec = sp_font_selector_get_fontspec(fsel); + Glib::ustring fontspec = font_selector.get_fontspec(); const gchar *phrase = str && *str ? str : samplephrase.c_str(); setPreviewText(fontspec, phrase); g_free (str); @@ -477,9 +472,9 @@ void TextEdit::onTextChange (GtkTextBuffer *text_buffer, TextEdit *self) self->onChange(); } -void TextEdit::onFontChange(SPFontSelector * /*fontsel*/, gchar* fontspec, TextEdit *self) +void TextEdit::onFontChange(Glib::ustring fontspec) { - self->onChange(); + onChange(); } void TextEdit::onFontVariantChange(TextEdit *self) diff --git a/src/ui/dialog/text-edit.h b/src/ui/dialog/text-edit.h index f28bc4eaf..e891c8e42 100644 --- a/src/ui/dialog/text-edit.h +++ b/src/ui/dialog/text-edit.h @@ -30,6 +30,8 @@ #include "ui/widget/panel.h" #include "ui/widget/frame.h" #include "ui/dialog/desktop-tracker.h" + +#include "ui/widget/font-selector.h" #include "ui/widget/font-variants.h" class SPItem; @@ -101,19 +103,15 @@ protected: * * onFontChange updates the dialog UI. The subfunction setPreviewText updates the preview label. * - * @param fontsel pointer to SPFontSelector (currently not used). * @param fontspec for the text to be previewed. - * @param self pointer to the current instance of the dialog. */ - static void onFontChange (SPFontSelector *fontsel, gchar* fontspec, TextEdit *self); + void onFontChange (Glib::ustring fontspec); /** * Callback invoked when the user modifies the font variant through the dialog. * * onFontChange updates the dialog UI. The subfunction setPreviewText updates the preview label. * - * @param fontsel pointer to FontVariant (currently not used). - * @param fontspec for the text to be previewed. * @param self pointer to the current instance of the dialog. */ static void onFontVariantChange (TextEdit *self); @@ -166,8 +164,7 @@ private: Gtk::VBox font_vbox; Gtk::Label font_label; - Gtk::Box fontsel_hbox; - SPFontSelector *fsel; + Inkscape::UI::Widget::FontSelector font_selector; Gtk::Label preview_label; // Share with variants tab? // Tab 2: Text ---------------------- // @@ -195,6 +192,7 @@ private: sigc::connection selectChangedConn; sigc::connection subselChangedConn; sigc::connection selectModifiedConn; + sigc::connection fontChangedConn; sigc::connection fontVariantChangedConn; // Other diff --git a/src/ui/widget/font-selector.cpp b/src/ui/widget/font-selector.cpp new file mode 100644 index 000000000..3e535aee4 --- /dev/null +++ b/src/ui/widget/font-selector.cpp @@ -0,0 +1,385 @@ +/* + * Author: + * Tavmjong Bah <tavmjong@free.fr> + * + * Copyright (C) 2018 Tavmong Bah + * + * Released under GNU GPL. Read the file 'COPYING' for more information. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <glibmm/i18n.h> + +#include "font-selector.h" + +#include "libnrtype/font-lister.h" +#include "libnrtype/font-instance.h" + +// For updating from selection +#include "inkscape.h" +#include "desktop.h" +#include "object/sp-text.h" + +namespace Inkscape { +namespace UI { +namespace Widget { + +FontSelector::FontSelector (bool with_size) + : Gtk::Grid () + , family_frame (_("Font family")) + , style_frame (C_("Font selector", "Style")) + , size_label (_("Font size")) + , size_combobox (true) // With entry + , signal_block (false) + , font_size (18) +{ + + Inkscape::FontLister* font_lister = Inkscape::FontLister::get_instance(); + + // Font family + family_treecolumn.pack_start (family_cell, false); + family_treecolumn.set_fixed_width (200); + family_treecolumn.add_attribute (family_cell, "text", 0); + family_treecolumn.set_cell_data_func (family_cell, &font_lister_cell_data_func); + + family_treeview.set_row_separator_func (&font_lister_separator_func); + family_treeview.set_model (font_lister->get_font_list()); + family_treeview.set_name ("FontSelector: Family"); + family_treeview.set_headers_visible (false); + family_treeview.append_column (family_treecolumn); + + family_scroll.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); + family_scroll.add (family_treeview); + + family_frame.set_hexpand (true); + family_frame.set_vexpand (true); + family_frame.add (family_scroll); + + // Style + style_treecolumn.pack_start (style_cell, false); + style_treecolumn.add_attribute (style_cell, "text", 0); + //style_treecolumn.set_cell_data_func (style_cell, &font_lister_style_cell_data_func); + style_treecolumn.set_cell_data_func (style_cell, sigc::mem_fun(*this, &FontSelector::style_cell_data_func)); + + style_treeview.set_model (font_lister->get_style_list()); + style_treeview.set_name ("FontSelector: Style"); + style_treeview.append_column ("CSS", font_lister->FontStyleList.cssStyle); + //style_treeview.append_column ("Face",font_lister->FontStyleList.displayStyle); + style_treeview.append_column (style_treecolumn); + + style_scroll.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); + style_scroll.add (style_treeview); + + style_frame.set_vexpand (true); + style_frame.add (style_scroll); + + // Size + size_combobox.set_name ("FontSelector: Size"); + set_sizes(); + size_combobox.set_active_text( "18" ); + + // Grid + set_name ("FontSelector: Grid"); + attach (family_frame, 0, 0, 1, 2); + attach (style_frame, 1, 0, 2, 1); + if (with_size) { // Glyph panel does not use size. + attach (size_label, 1, 1, 1, 1); + attach (size_combobox, 2, 1, 1, 1); + } + + // Add signals + family_treeview.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &FontSelector::on_family_changed)); + style_treeview.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &FontSelector::on_style_changed)); + size_combobox.signal_changed().connect(sigc::mem_fun(*this, &FontSelector::on_size_changed)); + + show_all_children(); + + // Initialize font family lists. (May already be done.) Should be done on document change. + font_lister->update_font_list(SP_ACTIVE_DESKTOP->getDocument()); + + font_lister->connectUpdate(sigc::mem_fun(*this, &FontSelector::set_fontspec)); +} + +void +FontSelector::set_sizes () +{ + size_combobox.remove_all(); + + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + int unit = prefs->getInt("/options/font/unitType", SP_CSS_UNIT_PT); + + int sizes[] = { + 4, 6, 8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22, 24, 28, + 32, 36, 40, 48, 56, 64, 72, 144 + }; + + // Array must be same length as SPCSSUnit in style-internal.h + // PX PT PC MM CM IN EM EX % + double ratios[] = {1, 1, 1, 10, 4, 40, 100, 16, 8, 0.16}; + + for (unsigned int i = 0; i < G_N_ELEMENTS(sizes); ++i) + { + double size = sizes[i]/ratios[unit]; + size_combobox.append( Glib::ustring::format(size) ); + } +} + +void +FontSelector::set_fontsize_tooltip() +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + int unit = prefs->getInt("/options/font/unitType", SP_CSS_UNIT_PT); + Glib::ustring tooltip = Glib::ustring::format(_("Font size"), " (", sp_style_get_css_unit_string(unit), ")"); + size_combobox.set_tooltip_text (tooltip); +} + +// Update GUI. TODO: Rename function +void +FontSelector::set_fontspec (const Glib::ustring& fontspec) +{ + signal_block = true; + + if (!fontspec.empty()) { + Inkscape::FontLister *font_lister = Inkscape::FontLister::get_instance(); + std::pair<Glib::ustring, Glib::ustring> ui = font_lister->ui_from_fontspec( fontspec ); + Glib::ustring family = ui.first; + Glib::ustring style = ui.second; + Gtk::TreePath path; + + // Set font family + try { + path = font_lister->get_row_for_font (family); + } catch (...) { + g_warning( "Couldn't find row for font-family: %s", family.c_str() ); + path.clear(); + path.push_back(0); + } + family_treeview.set_cursor (path); + family_treeview.scroll_to_row (path); + + // Get font-lister style list for selected family + Gtk::TreeModel::Row row = font_lister->get_row_for_font (family); + GList *styles; + row.get_value(1, styles); + + // Copy font-lister style list to private list store, searching for match. + Gtk::TreeModel::iterator match; + FontLister::FontStyleListClass FontStyleList; + Glib::RefPtr<Gtk::ListStore> local_style_list_store = Gtk::ListStore::create(FontStyleList); + for ( ; styles; styles = styles->next ) { + Gtk::TreeModel::iterator treeModelIter = local_style_list_store->append(); + (*treeModelIter)[FontStyleList.cssStyle] = ((StyleNames *)styles->data)->CssName; + (*treeModelIter)[FontStyleList.displayStyle] = ((StyleNames *)styles->data)->DisplayName; + if (style == ((StyleNames*)styles->data)->CssName) { + match = treeModelIter; + } + } + + // Attach store to tree view and select row. + style_treeview.set_model (local_style_list_store); + if (match) { + style_treeview.get_selection()->select (match); + } + } + + signal_block = false; +} + +void +FontSelector::set_size (double size) +{ + signal_block = true; + + // Set font size + std::stringstream ss; + ss << size; + size_combobox.get_entry()->set_text( ss.str() ); + font_size = size; // Store value + set_fontsize_tooltip(); + + signal_block = false; +} + + +Glib::ustring +FontSelector::get_fontspec() { + + // Build new fontspec from GUI settings + Glib::ustring family = "Sans"; // Default...family list may not have been constructed. + Gtk::TreeModel::iterator iter = family_treeview.get_selection()->get_selected(); + if (iter) { + (*iter).get_value(0, family); + } + + Glib::ustring style = "Normal"; + iter = style_treeview.get_selection()->get_selected(); + if (iter) { + (*iter).get_value(0, style); + } + + if (family.empty()) { + std::cerr << "FontSelector::get_fontspec: empty family!" << std::endl; + } + + if (style.empty()) { + std::cerr << "FontSelector::get_fontspec: empty style!" << std::endl; + } + + Glib::ustring fontspec = family + ", " + style; + + return fontspec; +} + +void +FontSelector::style_cell_data_func (Gtk::CellRenderer *renderer, Gtk::TreeIter const &iter) +{ + Glib::ustring family = "Sans"; // Default...family list may not have been constructed. + Gtk::TreeModel::iterator iter_family = family_treeview.get_selection()->get_selected(); + if (iter_family) { + (*iter_family).get_value(0, family); + } + + Glib::ustring style = "Normal"; + (*iter).get_value(0, style); + + Glib::ustring style_escaped = Glib::strescape( style ); + Glib::ustring font_desc = family + ", " + style; + Glib::ustring markup; + + markup = "<span font='" + font_desc + "'>" + style_escaped + "</span>"; + + // std::cout << " markup: " << markup << " (" << name << ")" << std::endl; + + renderer->set_property("markup", markup); +} + + +// Callbacks + +// Need to update style list +void +FontSelector::on_family_changed() { + + if (signal_block) return; + signal_block = true; + + Glib::RefPtr<Gtk::TreeModel> model; + Gtk::TreeModel::iterator iter = family_treeview.get_selection()->get_selected(model); + + if (!iter) { + // This can happen just after the family list is recreated. + signal_block = false; + return; + } + + Inkscape::FontLister *fontlister = Inkscape::FontLister::get_instance(); + fontlister->ensureRowStyles(model, iter); + + Gtk::TreeModel::Row row = *iter; + + // Get family name + Glib::ustring family; + row.get_value(0, family); + + // Get style list (TO DO: Get rid of GList) + GList *styles; + row.get_value(1, styles); + + // Find best style match for selected family with current style (e.g. of selected text). + Glib::ustring style = fontlister->get_font_style(); + Glib::ustring best = fontlister->get_best_style_match (family, style); + + // Create are own store of styles for selected font-family (the font-family selected + // in the dialog may not be the same as stored in the font-lister class until the + // "Apply" button is triggered). + Gtk::TreeModel::iterator it_best; + FontLister::FontStyleListClass FontStyleList; + Glib::RefPtr<Gtk::ListStore> local_style_list_store = Gtk::ListStore::create(FontStyleList); + + // Build list and find best match. + for ( ; styles; styles = styles->next ) { + Gtk::TreeModel::iterator treeModelIter = local_style_list_store->append(); + (*treeModelIter)[FontStyleList.cssStyle] = ((StyleNames *)styles->data)->CssName; + (*treeModelIter)[FontStyleList.displayStyle] = ((StyleNames *)styles->data)->DisplayName; + if (best == ((StyleNames*)styles->data)->CssName) { + it_best = treeModelIter; + } + } + + // Attach store to tree view and select row. + style_treeview.set_model (local_style_list_store); + if (it_best) { + style_treeview.get_selection()->select (it_best); + } + + signal_block = false; + + // Let world know + changed_emit(); +} + +void +FontSelector::on_style_changed() { + + if (signal_block) return; + + // Let world know + changed_emit(); +} + +void +FontSelector::on_size_changed() { + + if (signal_block) return; + + double size; + Glib::ustring input = size_combobox.get_active_text(); + try { + size = std::stod (input); + } + catch (std::invalid_argument) { + std::cerr << "FontSelector::on_size_changed: Invalid input: " << input << std::endl; + size = -1; + } + + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + // Arbitrary: Text and Font preview freezes with huge font sizes. + int max_size = prefs->getInt("/dialogs/textandfont/maxFontSize", 10000); + + if (size <= 0) { + return; + } + if (size > max_size) + size = max_size; + + if (fabs(font_size - size) > 0.001) { + font_size = size; + // Let world know + changed_emit(); + } +} + +void +FontSelector::changed_emit() { + signal_block = true; + changed_signal.emit (get_fontspec()); + signal_block = false; +} + +} // namespace Widget +} // namespace UI +} // namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8 : diff --git a/src/ui/widget/font-selector.h b/src/ui/widget/font-selector.h new file mode 100644 index 000000000..2fd4eee72 --- /dev/null +++ b/src/ui/widget/font-selector.h @@ -0,0 +1,165 @@ +/* + * Author: + * Tavmjong Bah <tavmjong@free.fr> + * + * Copyright (C) 2018 Tavmong Bah + * + * Released under GNU GPL. Read the file 'COPYING' for more information. + * + * + * The routines here create and manage a font selector widget with three parts, + * one each for font-family, font-style, and font-size. + * + * It is used by the TextEdit and Glyphs panel dialogs. The FontLister class is used + * to access the list of font-families and their associated styles for fonts either + * on the system or in the document. The FontLister class is also used by the Text + * toolbar. Fonts are kept track of by their "fontspecs" which are the same as the + * strings that Pango generates. + * + * The main functions are: + * Create the font-seletor widget. + * Update the lists when a new text selection is made. + * Update the Style list when a new font-family is selected, highlighting the + * best match to the original font style (as not all fonts have the same style options). + * Emit a signal when any change is made so that the Text Preview can be updated. + * Provide the currently selected values. + */ + +#ifndef INKSCAPE_UI_WIDGET_FONT_SELECTOR_H +#define INKSCAPE_UI_WIDGET_FONT_SELECTOR_H + +#include <gtkmm/grid.h> +#include <gtkmm/frame.h> +#include <gtkmm/scrolledwindow.h> +#include <gtkmm/treeview.h> +#include <gtkmm/label.h> +#include <gtkmm/comboboxtext.h> + +// class SPDesktop; +// class SPObject; +class SPStyle; +class SPCSSAttr; + +namespace Inkscape { +namespace UI { +namespace Widget { + +/** + * A container of widgets for selecting font faces. + * + * It is used by the TextEdit and Glyphs panel dialogs. The FontSelector class utilizes the + * FontLister class to obtain a list of font-families and their associated styles for fonts either + * on the system or in the document. The FontLister class is also used by the Text toolbar. Fonts + * are kept track of by their "fontspecs" which are the same as the strings that Pango generates. + * + * The main functions are: + * Create the font-selector widget. + * Update the child widgets when a new text selection is made. + * Update the Style list when a new font-family is selected, highlighting the + * best match to the original font style (as not all fonts have the same style options). + * Emit a signal when any change is made to a child widget. + */ +class FontSelector : public Gtk::Grid +{ + +public: + + /** + * Constructor + */ + FontSelector (bool with_size = true); + +protected: + + // Font family + Gtk::Frame family_frame; + Gtk::ScrolledWindow family_scroll; + Gtk::TreeView family_treeview; + Gtk::TreeViewColumn family_treecolumn; + Gtk::CellRendererText family_cell; + + // Font style + Gtk::Frame style_frame; + Gtk::ScrolledWindow style_scroll; + Gtk::TreeView style_treeview; + Gtk::TreeViewColumn style_treecolumn; + Gtk::CellRendererText style_cell; + + // Font size + Gtk::Label size_label; + Gtk::ComboBoxText size_combobox; + +private: + + // Set sizes in font size combobox. + void set_sizes(); + void set_fontsize_tooltip(); + + // Use font style when listing style names. + void style_cell_data_func (Gtk::CellRenderer *renderer, Gtk::TreeIter const &iter); + + // Signal handlers + void on_family_changed(); + void on_style_changed(); + void on_size_changed(); + + // Signals + sigc::signal<void, Glib::ustring> changed_signal; + void changed_emit(); + bool signal_block; + + // Variables + double font_size; + +public: + + /** + * Update GUI based on fontspec + */ + void set_fontspec (const Glib::ustring& fontspec); + void set_size (double size); + + /** + * Get fontspec based on current settings. (Does not handle size, yet.) + */ + Glib::ustring get_fontspec(); + + /** + * Get font size. Could be merged with fontspec. + */ + double get_fontsize() { return font_size; }; + + /** + * Shoe/hide size widgets + */ + void set_fontsize_visible( bool visible = true ) { + size_label.set_visible (visible); + size_combobox.set_visible (visible); + } + + /** + * Let others know that user has changed GUI settings. + * (Used to enable 'Apply' and 'Default' buttons.) + */ + sigc::connection connectChanged(sigc::slot<void, Glib::ustring> slot) { + return changed_signal.connect(slot); + } +}; + + +} // namespace Widget +} // namespace UI +} // namespace Inkscape + +#endif // INKSCAPE_UI_WIDGET_FONT_SETTINGS_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8 : diff --git a/src/widgets/font-selector.cpp b/src/widgets/font-selector.cpp deleted file mode 100644 index 532622bb0..000000000 --- a/src/widgets/font-selector.cpp +++ /dev/null @@ -1,509 +0,0 @@ -/** - * Font selection widgets - * - * Authors: - * Chris Lahey <clahey@ximian.com> - * Lauris Kaplinski <lauris@kaplinski.com> - * bulia byak <buliabyak@users.sf.net> - * Johan Engelen <j.b.c.engelen@ewi.utwente.nl> - * Tavmjong Bah <tavmjong@free.fr> - * - * Copyright (C) 1999-2001 Ximian, Inc. - * Copyright (C) 2002 Lauris Kaplinski - * Copyright (C) -2013 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <libnrtype/font-lister.h> -#include <libnrtype/font-instance.h> - -#include <glibmm/i18n.h> - -#include "desktop.h" -#include "widgets/font-selector.h" - -/* SPFontSelector */ - -struct SPFontSelector -{ - GtkBox hbox; - - bool block_emit; - - GtkWidget *family; - GtkWidget *style; - GtkWidget *size; - - GtkWidget *family_treeview; - GtkWidget *style_treeview; - - gfloat fontsize; - bool fontsize_dirty; - Glib::ustring *fontspec; -}; - - -struct SPFontSelectorClass -{ - GtkBoxClass parent_class; - - void (* font_set) (SPFontSelector *fsel, gchar *fontspec); -}; - -enum { - FONT_SET, - LAST_SIGNAL -}; - -static void sp_font_selector_dispose (GObject *object); - -static void sp_font_selector_family_select_row (GtkTreeSelection *selection, - SPFontSelector *fsel); - -static void sp_font_selector_style_select_row (GtkTreeSelection *selection, - SPFontSelector *fsel); - -static void sp_font_selector_size_changed (GtkComboBox *combobox, - SPFontSelector *fsel); - -static void sp_font_selector_emit_set (SPFontSelector *fsel); -static void sp_font_selector_set_sizes( SPFontSelector *fsel ); - -static guint fs_signals[LAST_SIGNAL] = { 0 }; - -G_DEFINE_TYPE(SPFontSelector, sp_font_selector, GTK_TYPE_BOX); - -static void sp_font_selector_class_init(SPFontSelectorClass *c) -{ - GObjectClass *object_class = G_OBJECT_CLASS(c); - - fs_signals[FONT_SET] = g_signal_new ("font_set", - G_TYPE_FROM_CLASS(object_class), - (GSignalFlags)G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET(SPFontSelectorClass, font_set), - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, - 1, G_TYPE_POINTER); - - object_class->dispose = sp_font_selector_dispose; -} - -static void sp_font_selector_set_size_tooltip(SPFontSelector *fsel) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - int unit = prefs->getInt("/options/font/unitType", SP_CSS_UNIT_PT); - Glib::ustring tooltip = Glib::ustring::format(_("Font size"), " (", sp_style_get_css_unit_string(unit), ")"); - gtk_widget_set_tooltip_text (fsel->size, _(tooltip.c_str())); -} - - -/* - * Create a widget with children for selecting font-family, font-style, and font-size. - */ -static void sp_font_selector_init(SPFontSelector *fsel) -{ - //gtk_box_set_homogeneous(GTK_BOX(fsel), TRUE); - //gtk_box_set_spacing(GTK_BOX(fsel), 4); - - /* Family frame */ - GtkWidget *f = gtk_frame_new(_("Font family")); - gtk_widget_show (f); - gtk_box_pack_start (GTK_BOX(fsel), f, TRUE, TRUE, 0); - - GtkWidget *sw = gtk_scrolled_window_new(NULL, NULL); - gtk_widget_show(sw); - gtk_container_set_border_width(GTK_CONTAINER (sw), 4); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN); - gtk_container_add(GTK_CONTAINER(f), sw); - - fsel->family_treeview = gtk_tree_view_new (); - gtk_tree_view_set_row_separator_func( GTK_TREE_VIEW(fsel->family_treeview), - GtkTreeViewRowSeparatorFunc ((gpointer)font_lister_separator_func), - NULL, NULL ); - gtk_widget_show_all(GTK_WIDGET (fsel->family_treeview)); - GtkTreeViewColumn *column = gtk_tree_view_column_new (); - GtkCellRenderer *cell = gtk_cell_renderer_text_new (); - gtk_tree_view_column_pack_start (column, cell, FALSE); - gtk_tree_view_column_set_fixed_width (column, 200); - gtk_tree_view_column_set_attributes (column, cell, "text", 0, NULL); - gtk_tree_view_column_set_cell_data_func (column, cell, - GtkTreeCellDataFunc (font_lister_cell_data_func), - NULL, NULL ); - gtk_tree_view_append_column (GTK_TREE_VIEW(fsel->family_treeview), column); - gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(fsel->family_treeview), FALSE); - - /* Muck with style, see text-toolbar.cpp */ - gtk_widget_set_name( GTK_WIDGET(fsel->family_treeview), "font_selector_family" ); - - auto css_provider = gtk_css_provider_new(); - auto screen = gdk_screen_get_default(); - gtk_style_context_add_provider_for_screen(screen, - GTK_STYLE_PROVIDER(css_provider), - GTK_STYLE_PROVIDER_PRIORITY_USER); - - Inkscape::FontLister* fontlister = Inkscape::FontLister::get_instance(); - Glib::RefPtr<Gtk::ListStore> store = fontlister->get_font_list(); - gtk_tree_view_set_model (GTK_TREE_VIEW(fsel->family_treeview), GTK_TREE_MODEL (Glib::unwrap (store))); - //gtk_tree_view_set_tooltip_column(GTK_TREE_VIEW(fsel->family_treeview),2); - gtk_container_add(GTK_CONTAINER(sw), fsel->family_treeview); - gtk_widget_show_all (sw); - - GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(fsel->family_treeview)); - g_signal_connect (G_OBJECT(selection), "changed", G_CALLBACK (sp_font_selector_family_select_row), fsel); - g_object_set_data (G_OBJECT(fsel), "family-treeview", fsel->family_treeview); - - - /* Style frame */ - f = gtk_frame_new(C_("Font selector", "Style")); - gtk_widget_show(f); - gtk_box_pack_start(GTK_BOX (fsel), f, FALSE, TRUE, 0); - - auto vb = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4); - gtk_box_set_homogeneous(GTK_BOX(vb), FALSE); - gtk_widget_show(vb); - gtk_container_set_border_width(GTK_CONTAINER (vb), 4); - gtk_container_add(GTK_CONTAINER(f), vb); - - sw = gtk_scrolled_window_new(NULL, NULL); - gtk_widget_show(sw); - gtk_container_set_border_width(GTK_CONTAINER (sw), 4); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN); - gtk_box_pack_start(GTK_BOX (vb), sw, TRUE, TRUE, 0); - - fsel->style_treeview = gtk_tree_view_new (); - - // CSS Style name - cell = gtk_cell_renderer_text_new (); - column = gtk_tree_view_column_new_with_attributes ("CSS", cell, "text", 0, NULL ); - //gtk_tree_view_column_pack_start (column, cell, FALSE); - gtk_tree_view_column_set_resizable (column, TRUE); - gtk_tree_view_append_column (GTK_TREE_VIEW(fsel->style_treeview), column); - - // Display Style name - cell = gtk_cell_renderer_text_new (); - column = gtk_tree_view_column_new_with_attributes (_("Face"), cell, "text", 1, NULL ); - //gtk_tree_view_column_pack_start (column, cell, FALSE); - gtk_tree_view_append_column (GTK_TREE_VIEW(fsel->style_treeview), column); - - //gtk_tree_view_set_tooltip_column(GTK_TREE_VIEW(fsel->style_treeview), 1); - gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(fsel->style_treeview), TRUE); - gtk_container_add(GTK_CONTAINER(sw), fsel->style_treeview); - gtk_widget_show_all (sw); - - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(fsel->style_treeview)); - g_signal_connect (G_OBJECT(selection), "changed", G_CALLBACK (sp_font_selector_style_select_row), fsel); - - auto hb = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4); - gtk_box_set_homogeneous(GTK_BOX(hb), FALSE); - gtk_widget_show(hb); - gtk_box_pack_start(GTK_BOX(vb), hb, FALSE, FALSE, 0); - - // Font-size - fsel->size = gtk_combo_box_text_new_with_entry (); - - sp_font_selector_set_size_tooltip(fsel); - gtk_widget_set_size_request(fsel->size, 90, -1); - g_signal_connect (G_OBJECT(fsel->size), "changed", G_CALLBACK (sp_font_selector_size_changed), fsel); - gtk_box_pack_end (GTK_BOX(hb), fsel->size, FALSE, FALSE, 0); - - GtkWidget *l = gtk_label_new(_("Font size:")); - gtk_widget_show_all (l); - gtk_box_pack_end(GTK_BOX (hb), l, TRUE, TRUE, 0); - - sp_font_selector_set_sizes(fsel); - - gtk_widget_show_all (fsel->size); - - // Set default size... next two lines must match - gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(fsel->size))), "18.0"); - fsel->fontsize = 18.0; - fsel->fontsize_dirty = false; - - fsel->fontspec = new Glib::ustring; -} - -static void sp_font_selector_dispose(GObject *object) -{ - SPFontSelector *fsel = SP_FONT_SELECTOR (object); - - if (fsel->fontspec) { - delete fsel->fontspec; - } - - if (G_OBJECT_CLASS(sp_font_selector_parent_class)->dispose) { - G_OBJECT_CLASS(sp_font_selector_parent_class)->dispose(object); - } -} - -// Callback when family changed, updates style list for new family. -static void sp_font_selector_family_select_row(GtkTreeSelection *selection, - SPFontSelector *fsel) -{ - - // We need our own copy of the style list store since the font-family - // may not be the same in the font-selector as stored in the font-lister - // TODO: use font-lister class for this by modifying new_font_family to accept an optional style list - // TODO: add store to SPFontSelector struct and reuse. - - // Start by getting iterator to selected font - GtkTreeModel *model; - GtkTreeIter iter; - if (!gtk_tree_selection_get_selected (selection, &model, &iter)) return; - - Inkscape::FontLister *fontlister = Inkscape::FontLister::get_instance(); - fontlister->ensureRowStyles(model, &iter); - - // Next get family name with its style list - gchar *family; - GList *list=NULL; - gtk_tree_model_get (model, &iter, 0, &family, 1, &list, -1); - - // Find best style match for selected family with current style (e.g. of selected text). - Glib::ustring style = fontlister->get_font_style(); - Glib::ustring best = fontlister->get_best_style_match (family, style); - - // Create our own store of styles for selected font-family and find index of best style match - int path_index = 0; - int index = 0; - GtkListStore *store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING); // Where is this deleted? - for ( ; list ; list = list->next ) - { - gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, - 0, ((StyleNames*)list->data)->CssName.c_str(), - 1, ((StyleNames*)list->data)->DisplayName.c_str(), - -1); - if( best.compare( ((StyleNames*)list->data)->CssName ) == 0 ) { - path_index = index; - } - ++index; - } - - // Attach store to tree view. Can trigger style changed signal (but not FONT_SET): - gtk_tree_view_set_model (GTK_TREE_VIEW (fsel->style_treeview), GTK_TREE_MODEL (store)); - //gtk_tree_view_set_tooltip_column(GTK_TREE_VIEW(fsel->style_treeview),1); - - // Get path to best style - GtkTreePath *path = gtk_tree_path_new (); - gtk_tree_path_append_index (path, path_index); - - // Highlight best style. Triggers style changed signal: - gtk_tree_selection_select_path (gtk_tree_view_get_selection (GTK_TREE_VIEW (fsel->style_treeview)), path); - gtk_tree_path_free (path); -} - -// Callback when row changed -static void sp_font_selector_style_select_row (GtkTreeSelection * /*selection*/, - SPFontSelector *fsel) -{ - if (!fsel->block_emit) - { - sp_font_selector_emit_set (fsel); - } -} - - -/* - * Set the default list of font sizes, scaled to the users preferred unit - * TODO: This routine occurs both here and in text-toolbar. Move to font-lister? - */ -static void sp_font_selector_set_sizes( SPFontSelector *fsel ) -{ - GtkListStore *store = GTK_LIST_STORE(gtk_combo_box_get_model (GTK_COMBO_BOX(fsel->size))); - gtk_list_store_clear(store); - - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - int unit = prefs->getInt("/options/font/unitType", SP_CSS_UNIT_PT); - - int sizes[] = { - 4, 6, 8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22, 24, 28, - 32, 36, 40, 48, 56, 64, 72, 144 - }; - - // Array must be same length as SPCSSUnit in style.h - float ratios[] = {1, 1, 1, 10, 4, 40, 100, 16, 8, 0.16}; - - for (unsigned int n = 0; n < G_N_ELEMENTS(sizes); ++n) - { - double size = sizes[n] / ratios[unit]; - - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT(fsel->size), Glib::ustring::format(size).c_str()); - } - -} - -// Callback when size changed -static void sp_font_selector_size_changed( GtkComboBox */*cbox*/, SPFontSelector *fsel ) -{ - char *text = NULL; - text = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (fsel->size)); - gfloat old_size = fsel->fontsize; - - gchar *endptr; - gdouble value = -1; - if (text) { - value = g_strtod (text, &endptr); - if (endptr == text) // conversion failed, non-numeric input - value = -1; - free (text); - } - - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - int max_size = prefs->getInt("/dialogs/textandfont/maxFontSize", 10000); // somewhat arbitrary, but text&font preview freezes with too huge fontsizes - - if (value <= 0) { - return; // could not parse value - } - if (value > max_size) - value = max_size; - - fsel->fontsize = value; - if ( fabs(fsel->fontsize-old_size) > 0.001) - { - fsel->fontsize_dirty = true; - } - - sp_font_selector_emit_set (fsel); -} - - -// Called from sp_font_selector_style_select_row -// Called from sp_font_selector_size_changed -// Called indirectly for sp_font_selector_family_select_row (since style changes). -// Emits FONT_SET signal (handled by TextEdit::onFontChange, GlyphsPanel::fontChangeCB). -static void sp_font_selector_emit_set (SPFontSelector *fsel) -{ - - GtkTreeSelection *selection_family; - GtkTreeSelection *selection_style; - GtkTreeModel *model_family; - GtkTreeModel *model_style; - GtkTreeIter iter_family; - GtkTreeIter iter_style; - char *family=NULL, *style=NULL; - - //We need to check this here since most GtkTreeModel operations are not atomic - //See GtkListStore documentation, Chapter "Atomic Operations" --mderezynski - - model_family = gtk_tree_view_get_model (GTK_TREE_VIEW (fsel->family_treeview)); - if (!model_family) return; - model_style = gtk_tree_view_get_model (GTK_TREE_VIEW (fsel->style_treeview)); - if (!model_style ) return; - - selection_family = gtk_tree_view_get_selection (GTK_TREE_VIEW (fsel->family_treeview)); - selection_style = gtk_tree_view_get_selection (GTK_TREE_VIEW (fsel->style_treeview )); - - if (!gtk_tree_selection_get_selected (selection_family, NULL, &iter_family)) return; - if (!gtk_tree_selection_get_selected (selection_style, NULL, &iter_style )) return; - - gtk_tree_model_get (model_family, &iter_family, 0, &family, -1); - gtk_tree_model_get (model_style, &iter_style, 0, &style, -1); - - if ((!family) || (!style)) return; - - Glib::ustring fontspec = family; - fontspec += ", "; - fontspec += style; - - *(fsel->fontspec) = fontspec; - - g_signal_emit(fsel, fs_signals[FONT_SET], 0, fontspec.c_str()); -} - -GtkWidget *sp_font_selector_new() -{ - SPFontSelector *fsel = SP_FONT_SELECTOR(g_object_new(SP_TYPE_FONT_SELECTOR, NULL)); - - return GTK_WIDGET(fsel); -} - - -/* - * Sets the values displayed in the font-selector from a fontspec. - * It is only called from TextEdit with a new selection and from GlyphsPanel - */ -void sp_font_selector_set_fontspec (SPFontSelector *fsel, Glib::ustring fontspec, double size) -{ - if (!fontspec.empty()) - { - - Inkscape::FontLister *font_lister = Inkscape::FontLister::get_instance(); - std::pair<Glib::ustring, Glib::ustring> ui = font_lister->ui_from_fontspec( fontspec ); - Glib::ustring family = ui.first; - Glib::ustring style = ui.second; - Gtk::TreePath path; - try { - path = font_lister->get_row_for_font (family); - } catch (...) { - g_warning( "Couldn't find row for font-family: %s", family.c_str() ); - return; - } - - // High light selected family and scroll so it is in view. - fsel->block_emit = true; - gtk_tree_selection_select_path (gtk_tree_view_get_selection (GTK_TREE_VIEW (fsel->family_treeview)), path.gobj()); - gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (fsel->family_treeview), path.gobj(), NULL, TRUE, 0.5, 0.5); - fsel->block_emit = false; // TODO: Should this be moved to the end? - - - // We don't need to get best style since this is only called on a new - // selection where we already know the "best" style. - // Glib::ustring bestStyle = font_lister->get_best_style_match (family, style); - // std::cout << "Best: " << bestStyle << std::endl; - - // The "trial" style list and the regular list are the same in this case. - Gtk::TreePath path_c; - try { - path_c = font_lister->get_row_for_style( style ); - } catch (...) { - g_warning( "Couldn't find row for style: %s (%s)", style.c_str(), family.c_str() ); - return; - } - - gtk_tree_selection_select_path (gtk_tree_view_get_selection (GTK_TREE_VIEW (fsel->style_treeview)), path_c.gobj()); - gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (fsel->style_treeview), path_c.gobj(), NULL, TRUE, 0.5, 0.5); - - if (size != fsel->fontsize) - { - gchar s[8]; - g_snprintf (s, 8, "%.5g", size); // UI, so printf is ok - gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(fsel->size))), s); - fsel->fontsize = size; - sp_font_selector_set_size_tooltip(fsel); - sp_font_selector_set_sizes(fsel); - } - } - -} - -Glib::ustring sp_font_selector_get_fontspec(SPFontSelector *fsel) -{ - return *(fsel->fontspec); -} - -/* - * Return the font size in pixels - */ -double sp_font_selector_get_size(SPFontSelector *fsel) -{ - return fsel->fontsize; -} - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8 : diff --git a/src/widgets/font-selector.h b/src/widgets/font-selector.h deleted file mode 100644 index ff5472d2d..000000000 --- a/src/widgets/font-selector.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef SP_FONT_SELECTOR_H -#define SP_FONT_SELECTOR_H - -/* - * Font selection widgets - * - * Authors: - * Chris Lahey <clahey@ximian.com> - * Lauris Kaplinski <lauris@kaplinski.com> - * Tavmjong Bah <tavmjong@free.fr> - * - * Copyright (C) 1999-2001 Ximian, Inc. - * Copyright (C) 2002 Lauris Kaplinski - * Copyright (C) 1999-2013 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include <glib.h> - -struct SPFontSelector; - -#define SP_TYPE_FONT_SELECTOR (sp_font_selector_get_type ()) -#define SP_FONT_SELECTOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SP_TYPE_FONT_SELECTOR, SPFontSelector)) -#define SP_IS_FONT_SELECTOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SP_TYPE_FONT_SELECTOR)) - -/* - * The routines here create and manage a font selector widget with three parts, - * one each for font-family, font-style, and font-size. - * - * It is used by the TextEdit and Glyphs panel dialogs. The FontLister class is used - * to access the list of font-families and their associated styles for fonts either - * on the system or in the document. The FontLister class is also used by the Text - * toolbar. Fonts are kept track of by their "fontspecs" which are the same as the - * strings that Pango generates. - * - * The main functions are: - * Create the font-seletor widget. - * Update the lists when a new text selection is made. - * Update the Style list when a new font-family is selected, highlighting the - * best match to the original font style (as not all fonts have the same style options). - * Emit a signal when any change is made so that the Text Preview can be updated. - * Provide the currently selected values. - */ - -/* SPFontSelector */ - -GType sp_font_selector_get_type (void); - -GtkWidget *sp_font_selector_new (void); - -void sp_font_selector_set_fontspec (SPFontSelector *fsel, Glib::ustring fontspec, double size); -Glib::ustring sp_font_selector_get_fontspec (SPFontSelector *fsel); - -double sp_font_selector_get_size (SPFontSelector *fsel); - -#endif // !SP_FONT_SELECTOR_H - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8 : |
