summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/display/nr-svgfonts.cpp35
-rw-r--r--src/display/nr-svgfonts.h1
-rw-r--r--src/sp-font-face.cpp8
-rw-r--r--src/sp-font.cpp3
-rw-r--r--src/sp-glyph-kerning.cpp2
-rw-r--r--src/sp-glyph-kerning.h2
-rw-r--r--src/sp-glyph.cpp13
-rw-r--r--src/sp-glyph.h4
-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
-rw-r--r--src/unicoderange.cpp26
-rw-r--r--src/unicoderange.h3
-rw-r--r--src/xml/Makefile_insert2
-rw-r--r--src/xml/helper-observer.cpp43
-rw-r--r--src/xml/helper-observer.h35
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__