summaryrefslogtreecommitdiffstats
path: root/src/ui/dialog
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/dialog')
-rw-r--r--src/ui/dialog/document-properties.cpp36
-rw-r--r--src/ui/dialog/document-properties.h28
-rw-r--r--src/ui/dialog/filter-effects-dialog.cpp46
-rw-r--r--src/ui/dialog/filter-effects-dialog.h6
-rw-r--r--src/ui/dialog/svg-fonts-dialog.cpp530
-rw-r--r--src/ui/dialog/svg-fonts-dialog.h98
6 files changed, 558 insertions, 186 deletions
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
{