diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/display/nr-svgfonts.cpp | 35 | ||||
| -rw-r--r-- | src/display/nr-svgfonts.h | 1 | ||||
| -rw-r--r-- | src/sp-font-face.cpp | 8 | ||||
| -rw-r--r-- | src/sp-font.cpp | 3 | ||||
| -rw-r--r-- | src/sp-glyph-kerning.cpp | 2 | ||||
| -rw-r--r-- | src/sp-glyph-kerning.h | 2 | ||||
| -rw-r--r-- | src/sp-glyph.cpp | 13 | ||||
| -rw-r--r-- | src/sp-glyph.h | 4 | ||||
| -rw-r--r-- | src/ui/dialog/document-properties.cpp | 36 | ||||
| -rw-r--r-- | src/ui/dialog/document-properties.h | 28 | ||||
| -rw-r--r-- | src/ui/dialog/filter-effects-dialog.cpp | 46 | ||||
| -rw-r--r-- | src/ui/dialog/filter-effects-dialog.h | 6 | ||||
| -rw-r--r-- | src/ui/dialog/svg-fonts-dialog.cpp | 530 | ||||
| -rw-r--r-- | src/ui/dialog/svg-fonts-dialog.h | 98 | ||||
| -rw-r--r-- | src/unicoderange.cpp | 26 | ||||
| -rw-r--r-- | src/unicoderange.h | 3 | ||||
| -rw-r--r-- | src/xml/Makefile_insert | 2 | ||||
| -rw-r--r-- | src/xml/helper-observer.cpp | 43 | ||||
| -rw-r--r-- | src/xml/helper-observer.h | 35 |
19 files changed, 710 insertions, 211 deletions
diff --git a/src/display/nr-svgfonts.cpp b/src/display/nr-svgfonts.cpp index 723929ea7..633f4cddd 100644 --- a/src/display/nr-svgfonts.cpp +++ b/src/display/nr-svgfonts.cpp @@ -91,7 +91,7 @@ SvgFont::scaled_font_init (cairo_scaled_font_t *scaled_font, return CAIRO_STATUS_SUCCESS; } -unsigned int size_of_substring(gchar* substring, gchar* str){ +unsigned int size_of_substring(const char* substring, gchar* str){ const gchar* original_substring = substring; while((g_utf8_get_char(substring)==g_utf8_get_char(str)) && g_utf8_get_char(substring) != 0 && g_utf8_get_char(str) != 0){ @@ -129,7 +129,7 @@ SvgFont::scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font, while(g_utf8_get_char(_utf8) != 0){ missing = true; for (i=0; i < (unsigned long) this->glyphs.size(); i++){ - if ( (len = size_of_substring(this->glyphs[i]->unicode, _utf8)) ){ + if ( (len = size_of_substring(this->glyphs[i]->unicode.c_str(), _utf8)) ){ //TODO: store this cluster _utf8+=len; count++; @@ -144,7 +144,6 @@ SvgFont::scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font, } } -//g_warning("count is %d", count); //We use that info to allocate memory for the glyphs *glyphs = (cairo_glyph_t*) malloc(count*sizeof(cairo_glyph_t)); @@ -159,7 +158,7 @@ SvgFont::scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font, while(g_utf8_get_char(_utf8) != 0){ len = 0; for (i=0; i < (unsigned long) this->glyphs.size(); i++){ - if ( (len = size_of_substring(this->glyphs[i]->unicode, _utf8)) ){ + if ( (len = size_of_substring(this->glyphs[i]->unicode.c_str(), _utf8)) ){ //check whether is there a glyph declared on the SVG document // that matches with the text string in its current position for(SPObject* node = this->font->children;previous_unicode && node;node=node->next){ @@ -168,7 +167,7 @@ SvgFont::scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font, if ( (((SPHkern*)node)->u1->contains(previous_unicode[0]) || ((SPHkern*)node)->g1->contains(previous_glyph_name)) && (((SPHkern*)node)->u2->contains(this->glyphs[i]->unicode[0]) - || ((SPHkern*)node)->g2->contains(this->glyphs[i]->glyph_name)) + || ((SPHkern*)node)->g2->contains(this->glyphs[i]->glyph_name.c_str())) )//TODO: verify what happens when using unicode strings. x -= (((SPHkern*)node)->k / this->font->horiz_adv_x); } @@ -176,13 +175,13 @@ SvgFont::scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font, if ( (((SPVkern*)node)->u1->contains(previous_unicode[0]) || ((SPVkern*)node)->g1->contains(previous_glyph_name)) && (((SPVkern*)node)->u2->contains(this->glyphs[i]->unicode[0]) - || ((SPVkern*)node)->g2->contains(this->glyphs[i]->glyph_name)) + || ((SPVkern*)node)->g2->contains(this->glyphs[i]->glyph_name.c_str())) )//TODO: idem y -= (((SPVkern*)node)->k / this->font->vert_adv_y); } } - previous_unicode = this->glyphs[i]->unicode;//used for kerning checking - previous_glyph_name = this->glyphs[i]->glyph_name;//used for kerning checking + previous_unicode = (char*) this->glyphs[i]->unicode.c_str();//used for kerning checking + previous_glyph_name = (char*) this->glyphs[i]->glyph_name.c_str();//used for kerning checking (*glyphs)[count].index = i; (*glyphs)[count].x = x; (*glyphs)[count++].y = y; @@ -227,10 +226,8 @@ SvgFont::scaled_font_render_glyph (cairo_scaled_font_t *scaled_font, if (glyph == this->glyphs.size()){ if (!this->missingglyph) return CAIRO_STATUS_SUCCESS; node = (SPObject*) this->missingglyph; - g_warning("RENDER MISSING-GLYPH"); } else { node = (SPObject*) this->glyphs[glyph]; - g_warning("RENDER %s", this->glyphs[glyph]->unicode); } //glyphs can be described by arbitrary SVG declared in the childnodes of a glyph node @@ -248,9 +245,16 @@ SvgFont::scaled_font_render_glyph (cairo_scaled_font_t *scaled_font, if (!pathv.empty()){ //This glyph has a path description on its d attribute, so we render it: cairo_new_path(cr); + //adjust scale of the glyph Geom::Scale s(1.0/((SPFont*) node->parent)->horiz_adv_x); + //This matrix flips the glyph vertically + Geom::Matrix m(Geom::Coord(1),Geom::Coord(0),Geom::Coord(0),Geom::Coord(-1),Geom::Coord(0),Geom::Coord(0)); + //then we offset it + pathv += Geom::Point(Geom::Coord(0),Geom::Coord(-((SPFont*) node->parent)->horiz_adv_x)); + Geom::Rect area( Geom::Point(0,0), Geom::Point(1,1) ); //I need help here! (reaction: note that the 'area' parameter is an *optional* rect, so you can pass an empty Geom::OptRect() ) - feed_pathvector_to_cairo (cr, pathv, s, area, false, 0); + + feed_pathvector_to_cairo (cr, pathv, s*m, area, false, 0); cairo_fill(cr); } @@ -263,11 +267,9 @@ SvgFont::get_font_face(){ if (!this->userfont) { for(SPObject* node = this->font->children;node;node=node->next){ if (SP_IS_GLYPH(node)){ - g_warning("glyphs.push_back((SPGlyph*)node); (node->unicode='%s')", ((SPGlyph*)node)->unicode); this->glyphs.push_back((SPGlyph*)node); } if (SP_IS_MISSING_GLYPH(node)){ - g_warning("missingglyph=(SPMissingGlyph*)node;"); this->missingglyph=(SPMissingGlyph*)node; } } @@ -275,4 +277,11 @@ SvgFont::get_font_face(){ } return this->userfont->face; } + +void SvgFont::refresh(){ + this->glyphs.clear(); + delete this->userfont; + this->userfont = NULL; +} + #endif //#ifdef ENABLE_SVG_FONTS diff --git a/src/display/nr-svgfonts.h b/src/display/nr-svgfonts.h index a41627f86..ebf5ad08b 100644 --- a/src/display/nr-svgfonts.h +++ b/src/display/nr-svgfonts.h @@ -32,6 +32,7 @@ cairo_font_face_t* face; class SvgFont{ public: SvgFont(SPFont* spfont); +void refresh(); cairo_font_face_t* get_font_face(); cairo_status_t scaled_font_init (cairo_scaled_font_t *scaled_font, cairo_font_extents_t *metrics); cairo_status_t scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font, const char *utf8, int utf8_len, cairo_glyph_t **glyphs, int *num_glyphs, cairo_text_cluster_t **clusters, int *num_clusters, cairo_text_cluster_flags_t *flags); diff --git a/src/sp-font-face.cpp b/src/sp-font-face.cpp index c4197406b..811d9a14f 100644 --- a/src/sp-font-face.cpp +++ b/src/sp-font-face.cpp @@ -26,6 +26,7 @@ #include "document.h" #include "helper-fns.h" +//TODO: apparently unused. Maybe should be removed. class ObjectContainer { @@ -360,8 +361,8 @@ static void sp_fontface_init(SPFontFace *face) std::vector<FontFaceStretchType> stretch; stretch.push_back(SP_FONTFACE_STRETCH_NORMAL); face->font_stretch = stretch; -/* face->font_family = NULL; + /* //face->font_style = ; //face->font_variant = ; //face->font_weight = ; @@ -492,6 +493,11 @@ static void sp_fontface_set(SPObject *object, unsigned int key, const gchar *val std::vector<FontFaceStretchType> stretch; switch (key) { + case SP_PROP_FONT_FAMILY: + if (face->font_family) g_free(face->font_family); + face->font_family = g_strdup(value); + object->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; case SP_PROP_FONT_STYLE: style = sp_read_fontFaceStyleType(value); if (face->font_style.size() != style.size()){ diff --git a/src/sp-font.cpp b/src/sp-font.cpp index f586e6c62..f2d37f3bf 100644 --- a/src/sp-font.cpp +++ b/src/sp-font.cpp @@ -144,7 +144,8 @@ sp_font_remove_child(SPObject *object, Inkscape::XML::Node *child) static void sp_font_release(SPObject *object) { - //SPFont *font = SP_FONT(object); + SPFont *font = SP_FONT(object); + sp_document_remove_resource(SP_OBJECT_DOCUMENT(object), "font", object); if (((SPObjectClass *) parent_class)->release) { ((SPObjectClass *) parent_class)->release(object); diff --git a/src/sp-glyph-kerning.cpp b/src/sp-glyph-kerning.cpp index bd5340b6b..6d08f212c 100644 --- a/src/sp-glyph-kerning.cpp +++ b/src/sp-glyph-kerning.cpp @@ -135,7 +135,7 @@ GlyphNames::~GlyphNames(){ if (this->names) g_free(this->names); } -bool GlyphNames::contains(gchar* name){ +bool GlyphNames::contains(const char* name){ if (!(this->names) || !name) return false; std::istringstream is(this->names); std::string str; diff --git a/src/sp-glyph-kerning.h b/src/sp-glyph-kerning.h index 8da752e49..ec0866c2c 100644 --- a/src/sp-glyph-kerning.h +++ b/src/sp-glyph-kerning.h @@ -36,7 +36,7 @@ class GlyphNames{ public: GlyphNames(const gchar* value); ~GlyphNames(); -bool contains(gchar* name); +bool contains(const char* name); private: gchar* names; }; diff --git a/src/sp-glyph.cpp b/src/sp-glyph.cpp index fb7cea15d..8af78a0aa 100644 --- a/src/sp-glyph.cpp +++ b/src/sp-glyph.cpp @@ -72,8 +72,9 @@ static void sp_glyph_class_init(SPGlyphClass *gc) static void sp_glyph_init(SPGlyph *glyph) { //TODO: correct these values: - glyph->unicode = NULL; - glyph->glyph_name = NULL; + + new (&glyph->unicode) Glib::ustring(); + new (&glyph->glyph_name) Glib::ustring(); glyph->d = NULL; glyph->orientation = GLYPH_ORIENTATION_BOTH; glyph->arabic_form = GLYPH_ARABIC_FORM_INITIAL; @@ -151,13 +152,13 @@ static void sp_glyph_set(SPObject *object, unsigned int key, const gchar *value) switch (key) { case SP_ATTR_UNICODE: - if (glyph->unicode) g_free(glyph->unicode); - glyph->unicode = g_strdup(value); + glyph->unicode.clear(); + if (value) glyph->unicode.append(value); object->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_GLYPH_NAME: - if (glyph->glyph_name) g_free(glyph->glyph_name); - glyph->glyph_name = g_strdup(value); + glyph->glyph_name.clear(); + if (value) glyph->glyph_name.append(value); object->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_D: diff --git a/src/sp-glyph.h b/src/sp-glyph.h index b7a7c316f..8c35a3a83 100644 --- a/src/sp-glyph.h +++ b/src/sp-glyph.h @@ -39,8 +39,8 @@ enum glyphOrientation { }; struct SPGlyph : public SPObject { - char* unicode; - char* glyph_name; + Glib::ustring unicode; + Glib::ustring glyph_name; char* d; glyphOrientation orientation; glyphArabicForm arabic_form; diff --git a/src/ui/dialog/document-properties.cpp b/src/ui/dialog/document-properties.cpp index 713acc23e..277652596 100644 --- a/src/ui/dialog/document-properties.cpp +++ b/src/ui/dialog/document-properties.cpp @@ -388,42 +388,6 @@ DocumentProperties::build_snap_dtls() attach_all(_page_snap_dtls.table(), array, G_N_ELEMENTS(array)); } -// Very simple observer that just emits a signal if anything happens to a node -DocumentProperties::SignalObserver::SignalObserver() - : _oldsel(0) -{} - -// Add this observer to the SPObject and remove it from any previous object -void -DocumentProperties::SignalObserver::set(SPObject* o) -{ - if(_oldsel && _oldsel->repr) - _oldsel->repr->removeObserver(*this); - if(o && o->repr) - o->repr->addObserver(*this); - _oldsel = o; -} - -void DocumentProperties::SignalObserver::notifyChildAdded(XML::Node&, XML::Node&, XML::Node*) -{ signal_changed()(); } - -void DocumentProperties::SignalObserver::notifyChildRemoved(XML::Node&, XML::Node&, XML::Node*) -{ signal_changed()(); } - -void DocumentProperties::SignalObserver::notifyChildOrderChanged(XML::Node&, XML::Node&, XML::Node*, XML::Node*) -{ signal_changed()(); } - -void DocumentProperties::SignalObserver::notifyContentChanged(XML::Node&, Util::ptr_shared<char>, Util::ptr_shared<char>) -{} - -void DocumentProperties::SignalObserver::notifyAttributeChanged(XML::Node&, GQuark, Util::ptr_shared<char>, Util::ptr_shared<char>) -{ signal_changed()(); } - -sigc::signal<void>& DocumentProperties::SignalObserver::signal_changed() -{ - return _signal_changed; -} - #if ENABLE_LCMS static void lcms_profile_get_name (cmsHPROFILE profile, const gchar **name) diff --git a/src/ui/dialog/document-properties.h b/src/ui/dialog/document-properties.h index 36a6c739b..f4d5724be 100644 --- a/src/ui/dialog/document-properties.h +++ b/src/ui/dialog/document-properties.h @@ -15,7 +15,7 @@ #define INKSCAPE_UI_DIALOG_DOCUMENT_PREFERENCES_H #include <list> -#include <sigc++/sigc++.h> +#include <sigc++/sigc++.h>// #include <gtkmm/notebook.h> #include <glibmm/i18n.h> @@ -26,14 +26,11 @@ #include "ui/widget/tolerance-slider.h" #include "ui/widget/panel.h" -#include "xml/node-observer.h" +#include "xml/helper-observer.h" using namespace Inkscape::UI::Widget; namespace Inkscape { - namespace XML { - class Node; - } namespace UI { namespace Dialog { @@ -71,26 +68,7 @@ protected: void _handleActivateDesktop(Inkscape::Application *application, SPDesktop *desktop); void _handleDeactivateDesktop(Inkscape::Application *application, SPDesktop *desktop); - // Very simple observer that just emits a signal if anything happens to a node - class SignalObserver : public XML::NodeObserver - { - public: - SignalObserver(); - - // Add this observer to the SPObject and remove it from any previous object - void set(SPObject* o); - void notifyChildAdded(XML::Node&, XML::Node&, XML::Node*); - void notifyChildRemoved(XML::Node&, XML::Node&, XML::Node*); - void notifyChildOrderChanged(XML::Node&, XML::Node&, XML::Node*, XML::Node*); - void notifyContentChanged(XML::Node&, Util::ptr_shared<char>, Util::ptr_shared<char>); - void notifyAttributeChanged(XML::Node&, GQuark, Util::ptr_shared<char>, Util::ptr_shared<char>); - sigc::signal<void>& signal_changed(); - private: - sigc::signal<void> _signal_changed; - SPObject* _oldsel; - }; - - SignalObserver _emb_profiles_observer; + Inkscape::XML::SignalObserver _emb_profiles_observer; Gtk::Tooltips _tt; Gtk::Notebook _notebook; diff --git a/src/ui/dialog/filter-effects-dialog.cpp b/src/ui/dialog/filter-effects-dialog.cpp index 08df7fd05..7f92f5f01 100644 --- a/src/ui/dialog/filter-effects-dialog.cpp +++ b/src/ui/dialog/filter-effects-dialog.cpp @@ -91,48 +91,6 @@ int input_count(const SPFilterPrimitive* prim) return 1; } -// Very simple observer that just emits a signal if anything happens to a node -class FilterEffectsDialog::SignalObserver : public XML::NodeObserver -{ -public: - SignalObserver() - : _oldsel(0) - {} - - // Add this observer to the SPObject and remove it from any previous object - void set(SPObject* o) - { - if(_oldsel && _oldsel->repr) - _oldsel->repr->removeObserver(*this); - if(o && o->repr) - o->repr->addObserver(*this); - _oldsel = o; - } - - void notifyChildAdded(XML::Node&, XML::Node&, XML::Node*) - { signal_changed()(); } - - void notifyChildRemoved(XML::Node&, XML::Node&, XML::Node*) - { signal_changed()(); } - - void notifyChildOrderChanged(XML::Node&, XML::Node&, XML::Node*, XML::Node*) - { signal_changed()(); } - - void notifyContentChanged(XML::Node&, Util::ptr_shared<char>, Util::ptr_shared<char>) - {} - - void notifyAttributeChanged(XML::Node&, GQuark, Util::ptr_shared<char>, Util::ptr_shared<char>) - { signal_changed()(); } - - sigc::signal<void>& signal_changed() - { - return _signal_changed; - } -private: - sigc::signal<void> _signal_changed; - SPObject* _oldsel; -}; - class CheckButtonAttr : public Gtk::CheckButton, public AttrWidget { public: @@ -1119,7 +1077,7 @@ Glib::RefPtr<Gtk::Menu> create_popup_menu(Gtk::Widget& parent, sigc::slot<void> /*** FilterModifier ***/ FilterEffectsDialog::FilterModifier::FilterModifier(FilterEffectsDialog& d) - : _dialog(d), _add(Gtk::Stock::NEW), _observer(new SignalObserver) + : _dialog(d), _add(Gtk::Stock::NEW), _observer(new Inkscape::XML::SignalObserver) { Gtk::ScrolledWindow* sw = Gtk::manage(new Gtk::ScrolledWindow); pack_start(*sw); @@ -1443,7 +1401,7 @@ void FilterEffectsDialog::CellRendererConnection::get_size_vfunc( FilterEffectsDialog::PrimitiveList::PrimitiveList(FilterEffectsDialog& d) : _dialog(d), _in_drag(0), - _observer(new SignalObserver) + _observer(new Inkscape::XML::SignalObserver) { d.signal_expose_event().connect(sigc::mem_fun(*this, &PrimitiveList::on_expose_signal)); diff --git a/src/ui/dialog/filter-effects-dialog.h b/src/ui/dialog/filter-effects-dialog.h index ccffb2a67..99b411441 100644 --- a/src/ui/dialog/filter-effects-dialog.h +++ b/src/ui/dialog/filter-effects-dialog.h @@ -33,6 +33,7 @@ #include "sp-filter.h" #include "ui/widget/combo-enums.h" #include "ui/widget/spin-slider.h" +#include "xml/helper-observer.h" using namespace Inkscape::UI::Widget; @@ -55,7 +56,6 @@ public: protected: virtual void show_all_vfunc(); private: - class SignalObserver; class FilterModifier : public Gtk::VBox { @@ -119,7 +119,7 @@ private: Gtk::Button _add; Glib::RefPtr<Gtk::Menu> _menu; sigc::signal<void> _signal_filter_changed; - std::auto_ptr<SignalObserver> _observer; + std::auto_ptr<Inkscape::XML::SignalObserver> _observer; }; class PrimitiveColumns : public Gtk::TreeModel::ColumnRecord @@ -203,7 +203,7 @@ private: sigc::signal<void> _signal_primitive_changed; sigc::connection _scroll_connection; int _autoscroll; - std::auto_ptr<SignalObserver> _observer; + std::auto_ptr<Inkscape::XML::SignalObserver> _observer; }; void init_settings_widgets(); diff --git a/src/ui/dialog/svg-fonts-dialog.cpp b/src/ui/dialog/svg-fonts-dialog.cpp index 4034cb10d..6ef8fa729 100644 --- a/src/ui/dialog/svg-fonts-dialog.cpp +++ b/src/ui/dialog/svg-fonts-dialog.cpp @@ -14,13 +14,16 @@ #ifdef ENABLE_SVG_FONTS +#include "document-private.h" #include <gtkmm/notebook.h> -#include "svg-fonts-dialog.h" #include <glibmm/i18n.h> +#include "selection.h" #include <string.h> -#include "document-private.h" +#include "svg-fonts-dialog.h" #include "xml/node.h" #include "xml/repr.h" +#include "svg/svg.h" +#include <2geom/pathvector.h> SvgFontDrawingArea::SvgFontDrawingArea(){ this->text = ""; @@ -33,6 +36,7 @@ void SvgFontDrawingArea::set_svgfont(SvgFont* svgfont){ void SvgFontDrawingArea::set_text(Glib::ustring text){ this->text = text; + redraw(); } void SvgFontDrawingArea::set_size(int x, int y){ @@ -84,8 +88,12 @@ SvgFontsDialog::AttrEntry::AttrEntry(SvgFontsDialog* d, gchar* lbl, const SPAttr entry.signal_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::AttrEntry::on_attr_changed)); } +void SvgFontsDialog::AttrEntry::set_text(char* t){ + if (!t) return; + entry.set_text(t); +} + void SvgFontsDialog::AttrEntry::on_attr_changed(){ - g_warning("attr entry changed: %s", this->entry.get_text().c_str()); SPObject* o = NULL; for(SPObject* node = this->dialog->get_selected_spfont()->children; node; node=node->next){ @@ -137,46 +145,81 @@ GlyphComboBox::GlyphComboBox(){ } void GlyphComboBox::update(SPFont* spfont){ - if (spfont) { - this->clear(); - for(SPObject* node = spfont->children; node; node=node->next){ - if (SP_IS_GLYPH(node)){ - this->append_text(((SPGlyph*)node)->unicode); - } + if (!spfont) return +//TODO: figure out why do we need to append_text("") before clearing items properly... + + this->append_text(""); //Gtk is refusing to clear the combobox when I comment out this line + this->clear_items(); + + for(SPObject* node = spfont->children; node; node=node->next){ + if (SP_IS_GLYPH(node)){ + this->append_text(((SPGlyph*)node)->unicode); } } } -void SvgFontsDialog::on_kerning_changed(){ - if (this->kerning_pair){ - this->kerning_pair->k = kerning_spin.get_value(); - kerning_preview.redraw(); - _font_da.redraw(); +void SvgFontsDialog::on_kerning_value_changed(){ + if (!this->kerning_pair) return; + SPDocument* document = sp_desktop_document(this->getDesktop()); + + //TODO: I am unsure whether this is the correct way of calling sp_document_maybe_done + Glib::ustring undokey = "svgfonts:hkern:k:"; + undokey += this->kerning_pair->u1->attribute_string(); + undokey += ":"; + undokey += this->kerning_pair->u2->attribute_string(); + + //slider values increase from right to left so that they match the kerning pair preview + this->kerning_pair->repr->setAttribute("k", Glib::Ascii::dtostr(get_selected_spfont()->horiz_adv_x - kerning_slider.get_value()).c_str()); + sp_document_maybe_done(document, undokey.c_str(), SP_VERB_DIALOG_SVG_FONTS, _("Adjust kerning value")); + + //populate_kerning_pairs_box(); + kerning_preview.redraw(); + _font_da.redraw(); +} + +void SvgFontsDialog::glyphs_list_button_release(GdkEventButton* event) +{ + if((event->type == GDK_BUTTON_RELEASE) && (event->button == 3)) { + _GlyphsContextMenu.popup(event->button, event->time); } } -void SvgFontsDialog::on_glyphs_changed(){ - std::string str1(first_glyph.get_active_text()); - std::string str2(second_glyph.get_active_text()); - kerning_preview.set_text((gchar*) (str1+str2).c_str()); - kerning_preview.redraw(); +void SvgFontsDialog::create_glyphs_popup_menu(Gtk::Widget& parent, sigc::slot<void> rem) +{ + Gtk::MenuItem* mi = Gtk::manage(new Gtk::ImageMenuItem(Gtk::Stock::REMOVE)); + _GlyphsContextMenu.append(*mi); + mi->signal_activate().connect(rem); + mi->show(); + _GlyphsContextMenu.accelerate(parent); +} - //look for this kerning pair on the currently selected font - this->kerning_pair = NULL; - for(SPObject* node = this->get_selected_spfont()->children; node; node=node->next){ - if (SP_IS_HKERN(node) && ((SPGlyphKerning*)node)->u1->contains((gchar) first_glyph.get_active_text().c_str()[0]) - && ((SPGlyphKerning*)node)->u2->contains((gchar) second_glyph.get_active_text().c_str()[0]) ){ - this->kerning_pair = (SPGlyphKerning*)node; - continue; - } +void SvgFontsDialog::fonts_list_button_release(GdkEventButton* event) +{ + if((event->type == GDK_BUTTON_RELEASE) && (event->button == 3)) { + _FontsContextMenu.popup(event->button, event->time); } +} + +void SvgFontsDialog::create_fonts_popup_menu(Gtk::Widget& parent, sigc::slot<void> rem) +{ + Gtk::MenuItem* mi = Gtk::manage(new Gtk::ImageMenuItem(Gtk::Stock::REMOVE)); + _FontsContextMenu.append(*mi); + mi->signal_activate().connect(rem); + mi->show(); + _FontsContextMenu.accelerate(parent); +} -//TODO: - //if not found, - //create new kern node - if (this->kerning_pair) - kerning_spin.set_value(this->kerning_pair->k); +void SvgFontsDialog::update_sensitiveness(){ + if (get_selected_spfont()){ + global_vbox.set_sensitive(true); + glyphs_vbox.set_sensitive(true); + kerning_vbox.set_sensitive(true); + } else { + global_vbox.set_sensitive(false); + glyphs_vbox.set_sensitive(false); + kerning_vbox.set_sensitive(false); + } } /* Add all fonts in the document to the combobox. */ @@ -196,16 +239,48 @@ void SvgFontsDialog::update_fonts() const gchar* id = SP_OBJECT_ID(f); row[_columns.label] = lbl ? lbl : (id ? id : "font"); } + + update_sensitiveness(); } void SvgFontsDialog::on_preview_text_changed(){ _font_da.set_text((gchar*) _preview_entry.get_text().c_str()); _font_da.set_text(_preview_entry.get_text()); - _font_da.redraw(); +} + +void SvgFontsDialog::on_kerning_pair_selection_changed(){ + SPGlyphKerning* kern = get_selected_kerning_pair(); + if (!kern) { + kerning_preview.set_text(""); + return; + } + Glib::ustring str; + str += kern->u1->sample_glyph(); + str += kern->u2->sample_glyph(); + + kerning_preview.set_text(str); + this->kerning_pair = kern; + + //slider values increase from right to left so that they match the kerning pair preview + kerning_slider.set_value(get_selected_spfont()->horiz_adv_x - kern->k); +} + +void SvgFontsDialog::update_global_settings_tab(){ + SPFont* font = get_selected_spfont(); + if (!font) return; + + SPObject* obj; + for (obj=font->children; obj; obj=obj->next){ + if (SP_IS_FONTFACE(obj)){ + _familyname_entry->set_text(((SPFontFace*) obj)->font_family); + } + } } void SvgFontsDialog::on_font_selection_changed(){ SPFont* spfont = this->get_selected_spfont(); + if (!spfont) return; + SvgFont* svgfont = this->get_selected_svgfont(); first_glyph.update(spfont); second_glyph.update(spfont); @@ -213,13 +288,17 @@ void SvgFontsDialog::on_font_selection_changed(){ _font_da.set_svgfont(svgfont); _font_da.redraw(); - int steps = 50; double set_width = spfont->horiz_adv_x; setwidth_spin.set_value(set_width); - kerning_spin.set_range(0,set_width); - kerning_spin.set_increments(int(set_width/steps),2*int(set_width/steps)); - kerning_spin.set_value(0); + kerning_slider.set_range(0, set_width); + kerning_slider.set_draw_value(false); + kerning_slider.set_value(0); + + update_global_settings_tab(); + populate_glyphs_box(); + populate_kerning_pairs_box(); + update_sensitiveness(); } void SvgFontsDialog::on_setwidth_changed(){ @@ -230,9 +309,17 @@ void SvgFontsDialog::on_setwidth_changed(){ } } +SPGlyphKerning* SvgFontsDialog::get_selected_kerning_pair() +{ + Gtk::TreeModel::iterator i = _KerningPairsList.get_selection()->get_selected(); + if(i) + return (*i)[_KerningPairsListColumns.spnode]; + return NULL; +} + SvgFont* SvgFontsDialog::get_selected_svgfont() { - Gtk::TreeModel::iterator i = _font_list.get_selection()->get_selected(); + Gtk::TreeModel::iterator i = _FontsList.get_selection()->get_selected(); if(i) return (*i)[_columns.svgfont]; return NULL; @@ -240,19 +327,24 @@ SvgFont* SvgFontsDialog::get_selected_svgfont() SPFont* SvgFontsDialog::get_selected_spfont() { - Gtk::TreeModel::iterator i = _font_list.get_selection()->get_selected(); + Gtk::TreeModel::iterator i = _FontsList.get_selection()->get_selected(); if(i) return (*i)[_columns.spfont]; return NULL; } -Gtk::VBox* SvgFontsDialog::global_settings_tab(){ - Gtk::VBox* global_vbox = Gtk::manage(new Gtk::VBox()); +SPGlyph* SvgFontsDialog::get_selected_glyph() +{ + Gtk::TreeModel::iterator i = _GlyphsList.get_selection()->get_selected(); + if(i) + return (*i)[_GlyphsListColumns.glyph_node]; + return NULL; +} - AttrEntry* familyname; - familyname = new AttrEntry(this, (gchar*) _("Family Name:"), SP_PROP_FONT_FAMILY); +Gtk::VBox* SvgFontsDialog::global_settings_tab(){ + _familyname_entry = new AttrEntry(this, (gchar*) _("Family Name:"), SP_PROP_FONT_FAMILY); - global_vbox->add(*familyname); + global_vbox.pack_start(*_familyname_entry, false, false); /* global_vbox->add(*AttrCombo((gchar*) _("Style:"), SP_PROP_FONT_STYLE)); global_vbox->add(*AttrCombo((gchar*) _("Variant:"), SP_PROP_FONT_VARIANT)); global_vbox->add(*AttrCombo((gchar*) _("Weight:"), SP_PROP_FONT_WEIGHT)); @@ -267,46 +359,301 @@ Gtk::VBox* SvgFontsDialog::global_settings_tab(){ setwidth_spin.set_increments(10, 100); global_vbox->add(*setwidth_hbox); */ - return global_vbox; + return &global_vbox; +} + +void +SvgFontsDialog::populate_glyphs_box() +{ + if (!_GlyphsListStore) return; + _GlyphsListStore->clear(); + + SPFont* spfont = this->get_selected_spfont(); + _glyphs_observer.set(spfont); + + for(SPObject* node = spfont->children; node; node=node->next){ + if (SP_IS_GLYPH(node)){ + Gtk::TreeModel::Row row = *(_GlyphsListStore->append()); + row[_GlyphsListColumns.glyph_node] = (SPGlyph*) node; + row[_GlyphsListColumns.glyph_name] = ((SPGlyph*) node)->glyph_name; + row[_GlyphsListColumns.unicode] = ((SPGlyph*) node)->unicode; + } + } +} + +void +SvgFontsDialog::populate_kerning_pairs_box() +{ + if (!_KerningPairsListStore) return; + _KerningPairsListStore->clear(); + + SPFont* spfont = this->get_selected_spfont(); + + for(SPObject* node = spfont->children; node; node=node->next){ + if (SP_IS_HKERN(node)){ + Gtk::TreeModel::Row row = *(_KerningPairsListStore->append()); + row[_KerningPairsListColumns.first_glyph] = ((SPGlyphKerning*) node)->u1->attribute_string().c_str(); + row[_KerningPairsListColumns.second_glyph] = ((SPGlyphKerning*) node)->u2->attribute_string().c_str(); + row[_KerningPairsListColumns.kerning_value] = ((SPGlyphKerning*) node)->k; + row[_KerningPairsListColumns.spnode] = (SPGlyphKerning*) node; + } + } +} + +SPGlyph *new_glyph(SPDocument* document, SPFont *font, const int count) +{ + g_return_val_if_fail(font != NULL, NULL); + Inkscape::XML::Document *xml_doc = sp_document_repr_doc(document); + + // create a new glyph + Inkscape::XML::Node *repr; + repr = xml_doc->createElement("svg:glyph"); + + std::ostringstream os; + os << _("glyph") << " " << count; + repr->setAttribute("glyph-name", os.str().c_str()); + + // Append the new glyph node to the current font + SP_OBJECT_REPR(font)->appendChild(repr); + Inkscape::GC::release(repr); + + // get corresponding object + SPGlyph *g = SP_GLYPH( document->getObjectByRepr(repr) ); + + g_assert(g != NULL); + g_assert(SP_IS_GLYPH(g)); + + return g; +} + +void SvgFontsDialog::update_glyphs(){ + SPFont* font = get_selected_spfont(); + if (!font) return; + populate_glyphs_box(); + populate_kerning_pairs_box(); + first_glyph.update(font); + second_glyph.update(font); + get_selected_svgfont()->refresh(); + _font_da.redraw(); +} + +void SvgFontsDialog::add_glyph(){ + const int count = _GlyphsListStore->children().size(); + SPDocument* doc = sp_desktop_document(this->getDesktop()); + /* SPGlyph* glyph =*/ new_glyph(doc, get_selected_spfont(), count+1); + + sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Add glyph")); + + update_glyphs(); +} + +void SvgFontsDialog::set_glyph_description_from_selected_path(){ + SPDocument* doc = sp_desktop_document(this->getDesktop()); + Inkscape::Selection* sel = sp_desktop_selection(this->getDesktop()); + if (sel->isEmpty()) return; + Inkscape::XML::Node* node = (Inkscape::XML::Node*) g_slist_nth_data((GSList *)sel->reprList(), 0); + if (!node || !node->matchAttributeName("d")) return; + + Geom::PathVector pathv = sp_svg_read_pathv(node->attribute("d")); + //This matrix flips the glyph vertically + Geom::Matrix m(Geom::Coord(1),Geom::Coord(0),Geom::Coord(0),Geom::Coord(-1),Geom::Coord(0),Geom::Coord(0)); + pathv*=m; + //then we offset it + pathv+=Geom::Point(Geom::Coord(0),Geom::Coord(get_selected_spfont()->horiz_adv_x)); + + get_selected_glyph()->repr->setAttribute("d", (char*) sp_svg_write_path (pathv)); + sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Set glyph curves")); + + update_glyphs(); +} + +void SvgFontsDialog::missing_glyph_description_from_selected_path(){ + SPDocument* doc = sp_desktop_document(this->getDesktop()); + Inkscape::Selection* sel = sp_desktop_selection(this->getDesktop()); + if (sel->isEmpty()) return; + Inkscape::XML::Node* node = (Inkscape::XML::Node*) g_slist_nth_data((GSList *)sel->reprList(), 0); + if (!node || !node->matchAttributeName("d")) return; + + SPObject* obj; + for (obj = get_selected_spfont()->children; obj; obj=obj->next){ + if (SP_IS_MISSING_GLYPH(obj)){ + obj->repr->setAttribute("d", (char*) node->attribute("d")); + sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Set glyph curves")); + } + } + + update_glyphs(); +} + +void SvgFontsDialog::glyph_name_edit(const Glib::ustring&, const Glib::ustring& str){ + Gtk::TreeModel::iterator i = _GlyphsList.get_selection()->get_selected(); + if (!i) return; + + SPGlyph* glyph = (*i)[_GlyphsListColumns.glyph_node]; + glyph->repr->setAttribute("glyph-name", str.c_str()); + + SPDocument* doc = sp_desktop_document(this->getDesktop()); + sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Edit glyph name")); + + update_glyphs(); +} + +void SvgFontsDialog::glyph_unicode_edit(const Glib::ustring&, const Glib::ustring& str){ + Gtk::TreeModel::iterator i = _GlyphsList.get_selection()->get_selected(); + if (!i) return; + + SPGlyph* glyph = (*i)[_GlyphsListColumns.glyph_node]; + glyph->repr->setAttribute("unicode", str.c_str()); + + SPDocument* doc = sp_desktop_document(this->getDesktop()); + sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Set glyph unicode")); + + update_glyphs(); +} + +void SvgFontsDialog::remove_selected_font(){ + SPFont* font = get_selected_spfont(); + + sp_repr_unparent(font->repr); + SPDocument* doc = sp_desktop_document(this->getDesktop()); + sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Remove font")); + + update_fonts(); +} + +void SvgFontsDialog::remove_selected_glyph(){ + if(!_GlyphsList.get_selection()) return; + + Gtk::TreeModel::iterator i = _GlyphsList.get_selection()->get_selected(); + if(!i) return; + + SPGlyph* glyph = (*i)[_GlyphsListColumns.glyph_node]; + sp_repr_unparent(glyph->repr); + + SPDocument* doc = sp_desktop_document(this->getDesktop()); + sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Remove glyph")); + + update_glyphs(); } Gtk::VBox* SvgFontsDialog::glyphs_tab(){ - Gtk::VBox* glyphs_vbox = Gtk::manage(new Gtk::VBox()); - glyphs_vbox->add(*new SvgFontsDialog::AttrEntry(this, (gchar*) _("Glyph Name:"), SP_ATTR_GLYPH_NAME)); - glyphs_vbox->add(*new SvgFontsDialog::AttrEntry(this, (gchar*) _("Unicode:"), SP_ATTR_UNICODE)); - //glyphs_vbox->add(*AttrSpin((gchar*) "Horizontal Advance"), SP_ATTR_HORIZ_ADV_X); - //glyphs_vbox->add(*AttrCombo((gchar*) "Missing Glyph"), SP_ATTR_); ? - return glyphs_vbox; + _GlyphsList.signal_button_release_event().connect_notify(sigc::mem_fun(*this, &SvgFontsDialog::glyphs_list_button_release)); + create_glyphs_popup_menu(_GlyphsList, sigc::mem_fun(*this, &SvgFontsDialog::remove_selected_glyph)); + + Gtk::HBox* missing_glyph_hbox = Gtk::manage(new Gtk::HBox()); + Gtk::Label* missing_glyph_label = Gtk::manage(new Gtk::Label(_("Missing Glyph:"))); + missing_glyph_hbox->pack_start(*missing_glyph_label, false,false); + missing_glyph_hbox->pack_start(missing_glyph_button, false,false); + missing_glyph_button.set_label(_("From selection...")); + missing_glyph_button.signal_clicked().connect(sigc::mem_fun(*this, &SvgFontsDialog::missing_glyph_description_from_selected_path)); + glyphs_vbox.pack_start(*missing_glyph_hbox, false,false); + + glyphs_vbox.add(_GlyphsListScroller); + _GlyphsListScroller.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_ALWAYS); + _GlyphsListScroller.set_size_request(-1, 290);//It seems that is does not work. Why? I want a box with larger height + _GlyphsListScroller.add(_GlyphsList); + _GlyphsListStore = Gtk::ListStore::create(_GlyphsListColumns); + _GlyphsList.set_model(_GlyphsListStore); + _GlyphsList.append_column_editable(_("Glyph Name"), _GlyphsListColumns.glyph_name); + _GlyphsList.append_column_editable(_("Unicode"), _GlyphsListColumns.unicode); + + Gtk::HBox* hb = Gtk::manage(new Gtk::HBox()); + add_glyph_button.set_label(_("Add Glyph")); + add_glyph_button.signal_clicked().connect(sigc::mem_fun(*this, &SvgFontsDialog::add_glyph)); + + hb->pack_start(add_glyph_button, false,false); + hb->pack_start(glyph_from_path_button, false,false); + + glyphs_vbox.pack_start(*hb, false, false); + glyph_from_path_button.set_label(_("Get curves from selection...")); + glyph_from_path_button.signal_clicked().connect(sigc::mem_fun(*this, &SvgFontsDialog::set_glyph_description_from_selected_path)); + + dynamic_cast<Gtk::CellRendererText*>( _GlyphsList.get_column_cell_renderer(0))->signal_edited().connect( + sigc::mem_fun(*this, &SvgFontsDialog::glyph_name_edit)); + + dynamic_cast<Gtk::CellRendererText*>( _GlyphsList.get_column_cell_renderer(1))->signal_edited().connect( + sigc::mem_fun(*this, &SvgFontsDialog::glyph_unicode_edit)); + + _glyphs_observer.signal_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::update_glyphs)); + + return &glyphs_vbox; } -Gtk::VBox* SvgFontsDialog::kerning_tab(){ +void SvgFontsDialog::add_kerning_pair(){ + if (first_glyph.get_active_text() == "" || + second_glyph.get_active_text() == "") return; + + //look for this kerning pair on the currently selected font + this->kerning_pair = NULL; + for(SPObject* node = this->get_selected_spfont()->children; node; node=node->next){ + //TODO: It is not really correct to get only the first byte of each string. + //TODO: We should also support vertical kerning + if (SP_IS_HKERN(node) && ((SPGlyphKerning*)node)->u1->contains((gchar) first_glyph.get_active_text().c_str()[0]) + && ((SPGlyphKerning*)node)->u2->contains((gchar) second_glyph.get_active_text().c_str()[0]) ){ + this->kerning_pair = (SPGlyphKerning*)node; + continue; + } + } + + if (this->kerning_pair) return; //We already have this kerning pair + + SPDocument* document = sp_desktop_document(this->getDesktop()); + Inkscape::XML::Document *xml_doc = sp_document_repr_doc(document); -//kerning setup: - Gtk::VBox* kernvbox = Gtk::manage(new Gtk::VBox()); + // create a new hkern node + Inkscape::XML::Node *repr; + repr = xml_doc->createElement("svg:hkern"); + repr->setAttribute("u1", first_glyph.get_active_text().c_str()); + repr->setAttribute("u2", second_glyph.get_active_text().c_str()); + repr->setAttribute("k", "0"); + + // Append the new hkern node to the current font + SP_OBJECT_REPR(get_selected_spfont())->appendChild(repr); + Inkscape::GC::release(repr); + + // get corresponding object + this->kerning_pair = SP_HKERN( document->getObjectByRepr(repr) ); + + sp_document_done(document, SP_VERB_DIALOG_SVG_FONTS, _("Add kerning pair")); +} + +Gtk::VBox* SvgFontsDialog::kerning_tab(){ //Kerning Setup: - kernvbox->add(*Gtk::manage(new Gtk::Label(_("Kerning Setup:")))); + kerning_vbox.add(*Gtk::manage(new Gtk::Label(_("Kerning Setup:")))); Gtk::HBox* kerning_selector = Gtk::manage(new Gtk::HBox()); kerning_selector->add(*Gtk::manage(new Gtk::Label(_("1st Glyph:")))); kerning_selector->add(first_glyph); kerning_selector->add(*Gtk::manage(new Gtk::Label(_("2nd Glyph:")))); kerning_selector->add(second_glyph); - first_glyph.signal_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::on_glyphs_changed)); - second_glyph.signal_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::on_glyphs_changed)); - kerning_spin.signal_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::on_kerning_changed)); + kerning_selector->add(add_kernpair_button); + add_kernpair_button.set_label(_("Add pair")); + add_kernpair_button.signal_clicked().connect(sigc::mem_fun(*this, &SvgFontsDialog::add_kerning_pair)); + _KerningPairsList.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::on_kerning_pair_selection_changed)); + kerning_slider.signal_value_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::on_kerning_value_changed)); + + kerning_vbox.pack_start(*kerning_selector, false,false); - kernvbox->add(*kerning_selector); - kernvbox->add((Gtk::Widget&) kerning_preview); + kerning_vbox.add(_KerningPairsListScroller); + _KerningPairsListScroller.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_ALWAYS); + _KerningPairsListScroller.add(_KerningPairsList); + _KerningPairsListStore = Gtk::ListStore::create(_KerningPairsListColumns); + _KerningPairsList.set_model(_KerningPairsListStore); + _KerningPairsList.append_column(_("First Unicode range"), _KerningPairsListColumns.first_glyph); + _KerningPairsList.append_column(_("Second Unicode range"), _KerningPairsListColumns.second_glyph); +// _KerningPairsList.append_column_numeric_editable(_("Kerning Value"), _KerningPairsListColumns.kerning_value, "%f"); + + kerning_vbox.add((Gtk::Widget&) kerning_preview); Gtk::HBox* kerning_amount_hbox = Gtk::manage(new Gtk::HBox()); - kernvbox->add(*kerning_amount_hbox); + kerning_vbox.pack_start(*kerning_amount_hbox, false,false); kerning_amount_hbox->add(*Gtk::manage(new Gtk::Label(_("Kerning value:")))); - kerning_amount_hbox->add(kerning_spin); + kerning_amount_hbox->add(kerning_slider); kerning_preview.set_size(300 + 20, 150 + 20); _font_da.set_size(150 + 20, 50 + 20); - return kernvbox; + return &kerning_vbox; } SPFont *new_font(SPDocument *document) @@ -320,33 +667,66 @@ SPFont *new_font(SPDocument *document) // create a new font Inkscape::XML::Node *repr; repr = xml_doc->createElement("svg:font"); + + //By default, set the horizontal advance to 1024 units + repr->setAttribute("horiz-adv-x", "1024"); // Append the new font node to defs SP_OBJECT_REPR(defs)->appendChild(repr); - Inkscape::GC::release(repr); + + //create a missing glyph + Inkscape::XML::Node *fontface; + fontface = xml_doc->createElement("svg:font-face"); + fontface->setAttribute("units-per-em", "1024"); + repr->appendChild(fontface); + + //create a missing glyph + Inkscape::XML::Node *mg; + mg = xml_doc->createElement("svg:missing-glyph"); + mg->setAttribute("d", "M0,0h1020v1024h-1020z"); + repr->appendChild(mg); // get corresponding object SPFont *f = SP_FONT( document->getObjectByRepr(repr) ); g_assert(f != NULL); g_assert(SP_IS_FONT(f)); - + Inkscape::GC::release(mg); + Inkscape::GC::release(repr); return f; } +void set_font_family(SPFont* font, char* str){ + if (!font) return; + SPObject* obj; + for (obj=font->children; obj; obj=obj->next){ + if (SP_IS_FONTFACE(obj)){ + obj->repr->setAttribute("font-family", str); + } + } + + sp_document_done(font->document, SP_VERB_DIALOG_SVG_FONTS, _("Set font family")); +} void SvgFontsDialog::add_font(){ SPDocument* doc = sp_desktop_document(this->getDesktop()); SPFont* font = new_font(doc); const int count = _model->children().size(); - std::ostringstream os; - os << "font" << count; + std::ostringstream os, os2; + os << _("font") << " " << count; font->setLabel(os.str().c_str()); + os2 << "SVGFont " << count; + SPObject* obj; + for (obj=font->children; obj; obj=obj->next){ + if (SP_IS_FONTFACE(obj)){ + obj->repr->setAttribute("font-family", os2.str().c_str()); + } + } + update_fonts(); // select_font(font); -// on_font_selection_changed(); sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Add font")); } @@ -359,7 +739,7 @@ SvgFontsDialog::SvgFontsDialog() Gtk::HBox* hbox = Gtk::manage(new Gtk::HBox()); Gtk::VBox* vbox = Gtk::manage(new Gtk::VBox()); - vbox->pack_start(_font_list); + vbox->pack_start(_FontsList); vbox->pack_start(_add, false, false); hbox->add(*vbox); hbox->add(_font_settings); @@ -367,9 +747,9 @@ SvgFontsDialog::SvgFontsDialog() //List of SVGFonts declared in a document: _model = Gtk::ListStore::create(_columns); - _font_list.set_model(_model); - _font_list.append_column_editable(_("_Font"), _columns.label); - _font_list.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::on_font_selection_changed)); + _FontsList.set_model(_model); + _FontsList.append_column_editable(_("_Font"), _columns.label); + _FontsList.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::on_font_selection_changed)); this->update_fonts(); @@ -393,6 +773,12 @@ SvgFontsDialog::SvgFontsDialog() preview_entry_hbox->add(*Gtk::manage(new Gtk::Label(_("Preview Text:")))); preview_entry_hbox->add(_preview_entry); + _FontsList.signal_button_release_event().connect_notify(sigc::mem_fun(*this, &SvgFontsDialog::fonts_list_button_release)); + create_fonts_popup_menu(_FontsList, sigc::mem_fun(*this, &SvgFontsDialog::remove_selected_font)); + + _defs_observer.set(SP_DOCUMENT_DEFS(sp_desktop_document(this->getDesktop()))); + _defs_observer.signal_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::update_fonts)); + _getContents()->show_all(); } diff --git a/src/ui/dialog/svg-fonts-dialog.h b/src/ui/dialog/svg-fonts-dialog.h index 9eab3b2f8..d1d6b440d 100644 --- a/src/ui/dialog/svg-fonts-dialog.h +++ b/src/ui/dialog/svg-fonts-dialog.h @@ -27,7 +27,7 @@ #include "display/nr-svgfonts.h" #include "attributes.h" - +#include "xml/helper-observer.h" class SvgFontDrawingArea : Gtk::DrawingArea{ public: @@ -66,17 +66,24 @@ public: void update_fonts(); SvgFont* get_selected_svgfont(); SPFont* get_selected_spfont(); + SPGlyph* get_selected_glyph(); + SPGlyphKerning* get_selected_kerning_pair(); + + //TODO: these methods should be private, right?! void on_font_selection_changed(); + void on_kerning_pair_selection_changed(); void on_preview_text_changed(); - void on_glyphs_changed(); - void on_kerning_changed(); + void on_kerning_pair_changed(); + void on_kerning_value_changed(); void on_setwidth_changed(); void add_font(); + //TODO: AttrEntry is currently unused. Should we remove it? class AttrEntry : public Gtk::HBox { public: AttrEntry(SvgFontsDialog* d, gchar* lbl, const SPAttributeEnum attr); + void set_text(char*); private: SvgFontsDialog* dialog; void on_attr_changed(); @@ -85,11 +92,41 @@ public: }; private: + void update_glyphs(); + void update_sensitiveness(); + void update_global_settings_tab(); + void populate_glyphs_box(); + void populate_kerning_pairs_box(); + void set_glyph_description_from_selected_path(); + void missing_glyph_description_from_selected_path(); + void add_glyph(); + void glyph_unicode_edit(const Glib::ustring&, const Glib::ustring&); + void glyph_name_edit(const Glib::ustring&, const Glib::ustring&); + void remove_selected_glyph(); + void remove_selected_font(); + + void add_kerning_pair(); + + void create_glyphs_popup_menu(Gtk::Widget& parent, sigc::slot<void> rem); + void glyphs_list_button_release(GdkEventButton* event); + + void create_fonts_popup_menu(Gtk::Widget& parent, sigc::slot<void> rem); + void fonts_list_button_release(GdkEventButton* event); + + Inkscape::XML::SignalObserver _defs_observer; //in order to update fonts + Inkscape::XML::SignalObserver _glyphs_observer; + Gtk::HBox* AttrCombo(gchar* lbl, const SPAttributeEnum attr); // Gtk::HBox* AttrSpin(gchar* lbl, const SPAttributeEnum attr); Gtk::VBox* global_settings_tab(); + AttrEntry* _familyname_entry; + Gtk::VBox* kerning_tab(); Gtk::VBox* glyphs_tab(); + Gtk::Button _add; + Gtk::Button add_glyph_button; + Gtk::Button glyph_from_path_button; + Gtk::Button missing_glyph_button; class Columns : public Gtk::TreeModel::ColumnRecord { @@ -107,14 +144,63 @@ private: }; Glib::RefPtr<Gtk::ListStore> _model; Columns _columns; - Gtk::Button _add; - Gtk::TreeView _font_list; + Gtk::TreeView _FontsList; + + class GlyphsColumns : public Gtk::TreeModel::ColumnRecord + { + public: + GlyphsColumns() + { + add(glyph_node); + add(glyph_name); + add(unicode); + } + + Gtk::TreeModelColumn<SPGlyph*> glyph_node; + Gtk::TreeModelColumn<Glib::ustring> glyph_name; + Gtk::TreeModelColumn<Glib::ustring> unicode; + }; + GlyphsColumns _GlyphsListColumns; + Glib::RefPtr<Gtk::ListStore> _GlyphsListStore; + Gtk::TreeView _GlyphsList; + Gtk::ScrolledWindow _GlyphsListScroller; + + class KerningPairColumns : public Gtk::TreeModel::ColumnRecord + { + public: + KerningPairColumns() + { + add(first_glyph); + add(second_glyph); + add(kerning_value); + add(spnode); + } + + Gtk::TreeModelColumn<Glib::ustring> first_glyph; + Gtk::TreeModelColumn<Glib::ustring> second_glyph; + Gtk::TreeModelColumn<double> kerning_value; + Gtk::TreeModelColumn<SPGlyphKerning*> spnode; + }; + KerningPairColumns _KerningPairsListColumns; + Glib::RefPtr<Gtk::ListStore> _KerningPairsListStore; + Gtk::TreeView _KerningPairsList; + Gtk::ScrolledWindow _KerningPairsListScroller; + Gtk::Button add_kernpair_button; + Gtk::VBox _font_settings; + Gtk::VBox global_vbox; + Gtk::VBox glyphs_vbox; + Gtk::VBox kerning_vbox; Gtk::Entry _preview_entry; + + Gtk::Menu _FontsContextMenu; + Gtk::Menu _GlyphsContextMenu; + SvgFontDrawingArea _font_da, kerning_preview; GlyphComboBox first_glyph, second_glyph; SPGlyphKerning* kerning_pair; - Gtk::SpinButton kerning_spin, setwidth_spin; + Gtk::SpinButton setwidth_spin; + Gtk::HScale kerning_slider; class EntryWidget : public Gtk::HBox { diff --git a/src/unicoderange.cpp b/src/unicoderange.cpp index a4dcc8a0b..72df25b5c 100644 --- a/src/unicoderange.cpp +++ b/src/unicoderange.cpp @@ -98,3 +98,29 @@ bool UnicodeRange::contains(gchar unicode){ } return false; } + +Glib::ustring UnicodeRange::attribute_string(){ + Glib::ustring result; + unsigned int i; + for(i=0; i<this->unichars.size(); i++){ + result += this->unichars[i]; + if (i!=this->unichars.size()-1) result += ","; + } + + for(i=0; i<this->range.size(); i++){ + result += "U+" + Glib::ustring(this->range[i].start) + "-" + Glib::ustring(this->range[i].end); + if (i!=this->range.size()-1) result += ","; + } + + return result; +} + +gunichar UnicodeRange::sample_glyph(){ + //This could be better + if (unichars.size()) + return unichars[0]; + if (range.size()) + return hex2int(range[0].start); + return (gunichar) ' '; +} + diff --git a/src/unicoderange.h b/src/unicoderange.h index 656f53c50..b0c7f34a9 100644 --- a/src/unicoderange.h +++ b/src/unicoderange.h @@ -1,5 +1,6 @@ #include <glib-object.h> #include<vector> +#include <glibmm.h> struct Urange{ gchar* start; @@ -11,6 +12,8 @@ public: UnicodeRange(const gchar* val); int add_range(gchar* val); bool contains(gchar unicode); +Glib::ustring attribute_string(); +gunichar sample_glyph(); private: std::vector<Urange> range; diff --git a/src/xml/Makefile_insert b/src/xml/Makefile_insert index 9ca81b231..3321031c9 100644 --- a/src/xml/Makefile_insert +++ b/src/xml/Makefile_insert @@ -18,6 +18,8 @@ xml_libspxml_a_SOURCES = \ xml/comment-node.h \ xml/composite-node-observer.cpp xml/composite-node-observer.h \ xml/element-node.h \ + xml/helper-observer.cpp \ + xml/helper-observer.h \ xml/node-observer.h \ xml/quote.cpp \ xml/quote.h \ diff --git a/src/xml/helper-observer.cpp b/src/xml/helper-observer.cpp new file mode 100644 index 000000000..620a88d8c --- /dev/null +++ b/src/xml/helper-observer.cpp @@ -0,0 +1,43 @@ +#include "helper-observer.h" + +namespace Inkscape { +namespace XML { + +// Very simple observer that just emits a signal if anything happens to a node +SignalObserver::SignalObserver() + : _oldsel(0) +{} + +// Add this observer to the SPObject and remove it from any previous object +void SignalObserver::set(SPObject* o) +{ + if(_oldsel && _oldsel->repr) + _oldsel->repr->removeObserver(*this); + if(o && o->repr) + o->repr->addObserver(*this); + _oldsel = o; +} + +void SignalObserver::notifyChildAdded(XML::Node&, XML::Node&, XML::Node*) +{ signal_changed()(); } + +void SignalObserver::notifyChildRemoved(XML::Node&, XML::Node&, XML::Node*) +{ signal_changed()(); } + +void SignalObserver::notifyChildOrderChanged(XML::Node&, XML::Node&, XML::Node*, XML::Node*) +{ signal_changed()(); } + +void SignalObserver::notifyContentChanged(XML::Node&, Util::ptr_shared<char>, Util::ptr_shared<char>) +{} + +void SignalObserver::notifyAttributeChanged(XML::Node&, GQuark, Util::ptr_shared<char>, Util::ptr_shared<char>) +{ signal_changed()(); } + +sigc::signal<void>& SignalObserver::signal_changed() +{ + return _signal_changed; +} + +} //namespace XML +} //namespace Inkscape + diff --git a/src/xml/helper-observer.h b/src/xml/helper-observer.h new file mode 100644 index 000000000..d028d390b --- /dev/null +++ b/src/xml/helper-observer.h @@ -0,0 +1,35 @@ +#ifndef __XML_HELPER_OBSERVER__ +#define __XML_HELPER_OBSERVER__ + +#include "node-observer.h" +#include "node.h" +#include "../sp-object.h" +//#include "../sp-object-repr.h" +#include <sigc++/sigc++.h> + +namespace Inkscape { + namespace XML { + class Node; + + // Very simple observer that just emits a signal if anything happens to a node + class SignalObserver : public NodeObserver + { + public: + SignalObserver(); + + // Add this observer to the SPObject and remove it from any previous object + void set(SPObject* o); + void notifyChildAdded(Node&, Node&, Node*); + void notifyChildRemoved(Node&, Node&, Node*); + void notifyChildOrderChanged(Node&, Node&, Node*, Node*); + void notifyContentChanged(Node&, Util::ptr_shared<char>, Util::ptr_shared<char>); + void notifyAttributeChanged(Node&, GQuark, Util::ptr_shared<char>, Util::ptr_shared<char>); + sigc::signal<void>& signal_changed(); + private: + sigc::signal<void> _signal_changed; + SPObject* _oldsel; + }; + } +} + +#endif //#ifndef __XML_HELPER_OBSERVER__ |
