Code

Now users can design a font within inkscape, save it and then open the
[inkscape.git] / src / ui / dialog / svg-fonts-dialog.cpp
1 /** @file
2  * @brief SVG Fonts dialog - implementation
3  */
4 /* Authors:
5  *   Felipe C. da S. Sanches <felipe.sanches@gmail.com>
6  *
7  * Copyright (C) 2008 Authors
8  * Released under GNU GPLv2 (or later).  Read the file 'COPYING' for more information.
9  */
11 #ifdef HAVE_CONFIG_H
12 # include <config.h>
13 #endif
15 #ifdef ENABLE_SVG_FONTS
17 #include "document-private.h"
18 #include <gtkmm/notebook.h>
19 #include <glibmm/i18n.h>
20 #include "selection.h"
21 #include <string.h>
22 #include "svg-fonts-dialog.h"
23 #include "xml/node.h"
24 #include "xml/repr.h"
25 #include "svg/svg.h"
26 #include <2geom/pathvector.h>
28 SvgFontDrawingArea::SvgFontDrawingArea(){
29         this->text = "";
30         this->svgfont = NULL;
31 }
33 void SvgFontDrawingArea::set_svgfont(SvgFont* svgfont){
34         this->svgfont = svgfont;
35 }
37 void SvgFontDrawingArea::set_text(Glib::ustring text){
38         this->text = text;
39         redraw();
40 }
42 void SvgFontDrawingArea::set_size(int x, int y){
43     this->x = x;
44     this->y = y;
45     ((Gtk::Widget*) this)->set_size_request(x, y);
46 }
48 void SvgFontDrawingArea::redraw(){
49         ((Gtk::Widget*) this)->queue_draw();
50 }
52 bool SvgFontDrawingArea::on_expose_event (GdkEventExpose *event){
53   if (this->svgfont){
54     Glib::RefPtr<Gdk::Window> window = get_window();
55     Cairo::RefPtr<Cairo::Context> cr = window->create_cairo_context();
56     cr->set_font_face( Cairo::RefPtr<Cairo::FontFace>(new Cairo::FontFace(this->svgfont->get_font_face(), false /* does not have reference */)) );
57     cr->set_font_size (this->y-20);
58     cr->move_to (10, 10);
59     cr->show_text (this->text.c_str());
60   }
61   return TRUE;
62 }
64 namespace Inkscape {
65 namespace UI {
66 namespace Dialog {
68 /*
69 Gtk::HBox* SvgFontsDialog::AttrEntry(gchar* lbl, const SPAttributeEnum attr){
70     Gtk::HBox* hbox = Gtk::manage(new Gtk::HBox());
71     hbox->add(* Gtk::manage(new Gtk::Label(lbl)) );
72     Gtk::Entry* entry = Gtk::manage(new Gtk::Entry());
73     hbox->add(* entry );
74     hbox->show_all();
76     entry->signal_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::on_attr_changed));
77     return hbox;
78 }
79 */
81 SvgFontsDialog::AttrEntry::AttrEntry(SvgFontsDialog* d, gchar* lbl, const SPAttributeEnum attr){
82     this->dialog = d;
83     this->attr = attr;
84     this->add(* Gtk::manage(new Gtk::Label(lbl)) );
85     this->add(entry);
86     this->show_all();
88     entry.signal_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::AttrEntry::on_attr_changed));
89 }
91 void SvgFontsDialog::AttrEntry::set_text(char* t){
92         if (!t) return;
93         entry.set_text(t);
94 }
96 void SvgFontsDialog::AttrEntry::on_attr_changed(){
98         SPObject* o = NULL;
99         for(SPObject* node = this->dialog->get_selected_spfont()->children; node; node=node->next){
100             switch(this->attr){
101                 case SP_PROP_FONT_FAMILY:
102                         if (SP_IS_FONTFACE(node)){
103                                 o = node;
104                                 continue;
105                         }
106                         break;
107                 default:
108                         o = NULL;
109             }
110         }
112         const gchar* name = (const gchar*)sp_attribute_name(this->attr);
113         if(name && o) {
114             SP_OBJECT_REPR(o)->setAttribute((const gchar*) name, this->entry.get_text().c_str());
115             o->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
117             Glib::ustring undokey = "svgfonts:";
118             undokey += name;
119             sp_document_maybe_done(o->document, undokey.c_str(), SP_VERB_DIALOG_SVG_FONTS,
120                                    _("Set SVG Font attribute"));
121         }
125 Gtk::HBox* SvgFontsDialog::AttrCombo(gchar* lbl, const SPAttributeEnum attr){
126     Gtk::HBox* hbox = Gtk::manage(new Gtk::HBox());
127     hbox->add(* Gtk::manage(new Gtk::Label(lbl)) );
128     hbox->add(* Gtk::manage(new Gtk::ComboBox()) );
129     hbox->show_all();
130     return hbox;
133 /*
134 Gtk::HBox* SvgFontsDialog::AttrSpin(gchar* lbl){
135     Gtk::HBox* hbox = Gtk::manage(new Gtk::HBox());
136     hbox->add(* Gtk::manage(new Gtk::Label(lbl)) );
137     hbox->add(* Gtk::manage(new Gtk::SpinBox()) );
138     hbox->show_all();
139     return hbox;
140 }*/
142 /*** SvgFontsDialog ***/
144 GlyphComboBox::GlyphComboBox(){
147 void GlyphComboBox::update(SPFont* spfont){
148     if (!spfont) return 
149 //TODO: figure out why do we need to append_text("") before clearing items properly...
151         this->append_text(""); //Gtk is refusing to clear the combobox when I comment out this line
152     this->clear_items();
154     for(SPObject* node = spfont->children; node; node=node->next){
155         if (SP_IS_GLYPH(node)){
156             this->append_text(((SPGlyph*)node)->unicode);
157         }
158     }
161 void SvgFontsDialog::on_kerning_value_changed(){
162         if (!this->kerning_pair) return;
163         SPDocument* document = sp_desktop_document(this->getDesktop());
165         //TODO: I am unsure whether this is the correct way of calling sp_document_maybe_done
166     Glib::ustring undokey = "svgfonts:hkern:k:";
167     undokey += this->kerning_pair->u1->attribute_string();
168     undokey += ":";
169     undokey += this->kerning_pair->u2->attribute_string();
171         //slider values increase from right to left so that they match the kerning pair preview
172     this->kerning_pair->repr->setAttribute("k", Glib::Ascii::dtostr(get_selected_spfont()->horiz_adv_x - kerning_slider.get_value()).c_str());
173     sp_document_maybe_done(document, undokey.c_str(), SP_VERB_DIALOG_SVG_FONTS, _("Adjust kerning value"));
175         //populate_kerning_pairs_box();
176     kerning_preview.redraw();
177     _font_da.redraw();
180 void SvgFontsDialog::glyphs_list_button_release(GdkEventButton* event)
182     if((event->type == GDK_BUTTON_RELEASE) && (event->button == 3)) {
183         _GlyphsContextMenu.popup(event->button, event->time);
184     }
187 void SvgFontsDialog::create_glyphs_popup_menu(Gtk::Widget& parent, sigc::slot<void> rem)
189     Gtk::MenuItem* mi = Gtk::manage(new Gtk::ImageMenuItem(Gtk::Stock::REMOVE));
190     _GlyphsContextMenu.append(*mi);
191     mi->signal_activate().connect(rem);
192     mi->show();
193     _GlyphsContextMenu.accelerate(parent);
197 void SvgFontsDialog::fonts_list_button_release(GdkEventButton* event)
199     if((event->type == GDK_BUTTON_RELEASE) && (event->button == 3)) {
200         _FontsContextMenu.popup(event->button, event->time);
201     }
204 void SvgFontsDialog::create_fonts_popup_menu(Gtk::Widget& parent, sigc::slot<void> rem)
206     Gtk::MenuItem* mi = Gtk::manage(new Gtk::ImageMenuItem(Gtk::Stock::REMOVE));
207     _FontsContextMenu.append(*mi);
208     mi->signal_activate().connect(rem);
209     mi->show();
210     _FontsContextMenu.accelerate(parent);
213 void SvgFontsDialog::update_sensitiveness(){
214     if (get_selected_spfont()){
215         global_vbox.set_sensitive(true);
216         glyphs_vbox.set_sensitive(true);
217         kerning_vbox.set_sensitive(true);
218     } else {
219         global_vbox.set_sensitive(false);
220         glyphs_vbox.set_sensitive(false);
221         kerning_vbox.set_sensitive(false);
222         }
225 /* Add all fonts in the document to the combobox. */
226 void SvgFontsDialog::update_fonts()
228     SPDesktop* desktop = this->getDesktop();
229     SPDocument* document = sp_desktop_document(desktop);
230     const GSList* fonts = sp_document_get_resource_list(document, "font");
232     _model->clear();
233     for(const GSList *l = fonts; l; l = l->next) {
234         Gtk::TreeModel::Row row = *_model->append();
235         SPFont* f = (SPFont*)l->data;
236         row[_columns.spfont] = f;
237         row[_columns.svgfont] = new SvgFont(f);
238         const gchar* lbl = f->label();
239         const gchar* id = SP_OBJECT_ID(f);
240         row[_columns.label] = lbl ? lbl : (id ? id : "font");
241     }
243         update_sensitiveness();
246 void SvgFontsDialog::on_preview_text_changed(){
247     _font_da.set_text((gchar*) _preview_entry.get_text().c_str());
248     _font_da.set_text(_preview_entry.get_text());
251 void SvgFontsDialog::on_kerning_pair_selection_changed(){
252         SPGlyphKerning* kern = get_selected_kerning_pair();
253         if (!kern) {
254                 kerning_preview.set_text("");
255                 return;
256         }
257         Glib::ustring str;
258         str += kern->u1->sample_glyph();
259         str += kern->u2->sample_glyph();
261         kerning_preview.set_text(str);
262         this->kerning_pair = kern;
264         //slider values increase from right to left so that they match the kerning pair preview
265         kerning_slider.set_value(get_selected_spfont()->horiz_adv_x - kern->k);
268 void SvgFontsDialog::update_global_settings_tab(){
269         SPFont* font = get_selected_spfont();
270         if (!font) return;
272         SPObject* obj;
273         for (obj=font->children; obj; obj=obj->next){
274                 if (SP_IS_FONTFACE(obj)){
275                         _familyname_entry->set_text(((SPFontFace*) obj)->font_family);
276                 }
277         }
280 void SvgFontsDialog::on_font_selection_changed(){
281     SPFont* spfont = this->get_selected_spfont();
282     if (!spfont) return;
284     SvgFont* svgfont = this->get_selected_svgfont();
285     first_glyph.update(spfont);
286     second_glyph.update(spfont);
287     kerning_preview.set_svgfont(svgfont);
288     _font_da.set_svgfont(svgfont);
289     _font_da.redraw();
291     double set_width = spfont->horiz_adv_x;
292     setwidth_spin.set_value(set_width);
294     kerning_slider.set_range(0, set_width);
295     kerning_slider.set_draw_value(false);
296     kerning_slider.set_value(0);
298         update_global_settings_tab();
299         populate_glyphs_box();
300         populate_kerning_pairs_box();
301         update_sensitiveness();
304 void SvgFontsDialog::on_setwidth_changed(){
305     SPFont* spfont = this->get_selected_spfont();
306     if (spfont){
307         spfont->horiz_adv_x = setwidth_spin.get_value();
308         //TODO: tell cairo that the glyphs cache has to be invalidated
309     }
312 SPGlyphKerning* SvgFontsDialog::get_selected_kerning_pair()
314     Gtk::TreeModel::iterator i = _KerningPairsList.get_selection()->get_selected();
315     if(i)
316         return (*i)[_KerningPairsListColumns.spnode];
317     return NULL;
320 SvgFont* SvgFontsDialog::get_selected_svgfont()
322     Gtk::TreeModel::iterator i = _FontsList.get_selection()->get_selected();
323     if(i)
324         return (*i)[_columns.svgfont];
325     return NULL;
328 SPFont* SvgFontsDialog::get_selected_spfont()
330     Gtk::TreeModel::iterator i = _FontsList.get_selection()->get_selected();
331     if(i)
332         return (*i)[_columns.spfont];
333     return NULL;
336 SPGlyph* SvgFontsDialog::get_selected_glyph()
338     Gtk::TreeModel::iterator i = _GlyphsList.get_selection()->get_selected();
339     if(i)
340         return (*i)[_GlyphsListColumns.glyph_node];
341     return NULL;
344 Gtk::VBox* SvgFontsDialog::global_settings_tab(){
345     _familyname_entry = new AttrEntry(this, (gchar*) _("Family Name:"), SP_PROP_FONT_FAMILY);
347     global_vbox.pack_start(*_familyname_entry, false, false);
348 /*    global_vbox->add(*AttrCombo((gchar*) _("Style:"), SP_PROP_FONT_STYLE));
349     global_vbox->add(*AttrCombo((gchar*) _("Variant:"), SP_PROP_FONT_VARIANT));
350     global_vbox->add(*AttrCombo((gchar*) _("Weight:"), SP_PROP_FONT_WEIGHT));
351 */
352 //Set Width (horiz_adv_x):
353 /*    Gtk::HBox* setwidth_hbox = Gtk::manage(new Gtk::HBox());
354     setwidth_hbox->add(*Gtk::manage(new Gtk::Label(_("Set width:"))));
355     setwidth_hbox->add(setwidth_spin);
357     setwidth_spin.signal_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::on_setwidth_changed));
358     setwidth_spin.set_range(0, 4096);
359     setwidth_spin.set_increments(10, 100);
360     global_vbox->add(*setwidth_hbox);
361 */
362     return &global_vbox;
365 void
366 SvgFontsDialog::populate_glyphs_box()
368         if (!_GlyphsListStore) return;
369     _GlyphsListStore->clear();
371         SPFont* spfont = this->get_selected_spfont();
372         _glyphs_observer.set(spfont);
374     for(SPObject* node = spfont->children; node; node=node->next){
375                 if (SP_IS_GLYPH(node)){
376                     Gtk::TreeModel::Row row = *(_GlyphsListStore->append());
377                     row[_GlyphsListColumns.glyph_node] = (SPGlyph*) node;
378                     row[_GlyphsListColumns.glyph_name] = ((SPGlyph*) node)->glyph_name;
379                     row[_GlyphsListColumns.unicode] = ((SPGlyph*) node)->unicode;
380                 }
381     }
384 void
385 SvgFontsDialog::populate_kerning_pairs_box()
387         if (!_KerningPairsListStore) return;
388     _KerningPairsListStore->clear();
390         SPFont* spfont = this->get_selected_spfont();
392     for(SPObject* node = spfont->children; node; node=node->next){
393                 if (SP_IS_HKERN(node)){
394                     Gtk::TreeModel::Row row = *(_KerningPairsListStore->append());
395                     row[_KerningPairsListColumns.first_glyph] = ((SPGlyphKerning*) node)->u1->attribute_string().c_str();
396                     row[_KerningPairsListColumns.second_glyph] = ((SPGlyphKerning*) node)->u2->attribute_string().c_str();
397                     row[_KerningPairsListColumns.kerning_value] = ((SPGlyphKerning*) node)->k;
398                     row[_KerningPairsListColumns.spnode] = (SPGlyphKerning*) node;
399                 }
400     }
403 SPGlyph *new_glyph(SPDocument* document, SPFont *font, const int count)
405     g_return_val_if_fail(font != NULL, NULL);
406     Inkscape::XML::Document *xml_doc = sp_document_repr_doc(document);
408     // create a new glyph
409     Inkscape::XML::Node *repr;
410     repr = xml_doc->createElement("svg:glyph");
412     std::ostringstream os;
413     os << _("glyph") << " " << count;
414     repr->setAttribute("glyph-name", os.str().c_str());
416     // Append the new glyph node to the current font
417     SP_OBJECT_REPR(font)->appendChild(repr);
418     Inkscape::GC::release(repr);
420     // get corresponding object
421     SPGlyph *g = SP_GLYPH( document->getObjectByRepr(repr) );
422     
423     g_assert(g != NULL);
424     g_assert(SP_IS_GLYPH(g));
426     return g;
429 void SvgFontsDialog::update_glyphs(){
430         SPFont* font = get_selected_spfont();
431         if (!font) return;
432     populate_glyphs_box();
433     populate_kerning_pairs_box();
434     first_glyph.update(font);
435     second_glyph.update(font);
436         get_selected_svgfont()->refresh();
437     _font_da.redraw();
440 void SvgFontsDialog::add_glyph(){
441     const int count = _GlyphsListStore->children().size();
442     SPDocument* doc = sp_desktop_document(this->getDesktop());
443     /* SPGlyph* glyph =*/ new_glyph(doc, get_selected_spfont(), count+1);
445     sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Add glyph"));
447         update_glyphs();
450 void SvgFontsDialog::set_glyph_description_from_selected_path(){
451     SPDocument* doc = sp_desktop_document(this->getDesktop());
452     Inkscape::Selection* sel = sp_desktop_selection(this->getDesktop());
453     if (sel->isEmpty()) return;
454     Inkscape::XML::Node* node = (Inkscape::XML::Node*) g_slist_nth_data((GSList *)sel->reprList(), 0);
455     if (!node || !node->matchAttributeName("d")) return;
457         Geom::PathVector pathv = sp_svg_read_pathv(node->attribute("d"));
458         //This matrix flips the glyph vertically
459     Geom::Matrix m(Geom::Coord(1),Geom::Coord(0),Geom::Coord(0),Geom::Coord(-1),Geom::Coord(0),Geom::Coord(0));
460         pathv*=m;
461         //then we offset it
462         pathv+=Geom::Point(Geom::Coord(0),Geom::Coord(get_selected_spfont()->horiz_adv_x));
464         get_selected_glyph()->repr->setAttribute("d", (char*) sp_svg_write_path (pathv));
465         sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Set glyph curves"));
467         update_glyphs();
470 void SvgFontsDialog::missing_glyph_description_from_selected_path(){
471     SPDocument* doc = sp_desktop_document(this->getDesktop());
472     Inkscape::Selection* sel = sp_desktop_selection(this->getDesktop());
473     if (sel->isEmpty()) return;
474     Inkscape::XML::Node* node = (Inkscape::XML::Node*) g_slist_nth_data((GSList *)sel->reprList(), 0);
475     if (!node || !node->matchAttributeName("d")) return;
477         SPObject* obj;
478         for (obj = get_selected_spfont()->children; obj; obj=obj->next){
479                 if (SP_IS_MISSING_GLYPH(obj)){
480                         obj->repr->setAttribute("d", (char*) node->attribute("d"));
481                         sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Set glyph curves"));
482                 }
483         }
485         update_glyphs();
488 void SvgFontsDialog::glyph_name_edit(const Glib::ustring&, const Glib::ustring& str){
489         Gtk::TreeModel::iterator i = _GlyphsList.get_selection()->get_selected();
490         if (!i) return;
492         SPGlyph* glyph = (*i)[_GlyphsListColumns.glyph_node];
493         glyph->repr->setAttribute("glyph-name", str.c_str());
495     SPDocument* doc = sp_desktop_document(this->getDesktop());
496         sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Edit glyph name"));
498         update_glyphs();
501 void SvgFontsDialog::glyph_unicode_edit(const Glib::ustring&, const Glib::ustring& str){
502         Gtk::TreeModel::iterator i = _GlyphsList.get_selection()->get_selected();
503         if (!i) return;
505         SPGlyph* glyph = (*i)[_GlyphsListColumns.glyph_node];
506         glyph->repr->setAttribute("unicode", str.c_str());
508     SPDocument* doc = sp_desktop_document(this->getDesktop());
509         sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Set glyph unicode"));
511         update_glyphs();
514 void SvgFontsDialog::remove_selected_font(){
515         SPFont* font = get_selected_spfont();
517     sp_repr_unparent(font->repr);
518     SPDocument* doc = sp_desktop_document(this->getDesktop());
519     sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Remove font"));
521     update_fonts();
524 void SvgFontsDialog::remove_selected_glyph(){
525     if(!_GlyphsList.get_selection()) return;
527     Gtk::TreeModel::iterator i = _GlyphsList.get_selection()->get_selected();
528     if(!i) return;
530         SPGlyph* glyph = (*i)[_GlyphsListColumns.glyph_node];
531     sp_repr_unparent(glyph->repr);
533     SPDocument* doc = sp_desktop_document(this->getDesktop());
534     sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Remove glyph"));
536     update_glyphs();
539 Gtk::VBox* SvgFontsDialog::glyphs_tab(){
540     _GlyphsList.signal_button_release_event().connect_notify(sigc::mem_fun(*this, &SvgFontsDialog::glyphs_list_button_release));
541     create_glyphs_popup_menu(_GlyphsList, sigc::mem_fun(*this, &SvgFontsDialog::remove_selected_glyph));
543     Gtk::HBox* missing_glyph_hbox = Gtk::manage(new Gtk::HBox());
544     Gtk::Label* missing_glyph_label = Gtk::manage(new Gtk::Label(_("Missing Glyph:")));
545         missing_glyph_hbox->pack_start(*missing_glyph_label, false,false);
546         missing_glyph_hbox->pack_start(missing_glyph_button, false,false);
547         missing_glyph_button.set_label(_("From selection..."));
548     missing_glyph_button.signal_clicked().connect(sigc::mem_fun(*this, &SvgFontsDialog::missing_glyph_description_from_selected_path));
549         glyphs_vbox.pack_start(*missing_glyph_hbox, false,false);
551         glyphs_vbox.add(_GlyphsListScroller);
552         _GlyphsListScroller.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_ALWAYS);
553     _GlyphsListScroller.set_size_request(-1, 290);//It seems that is does not work. Why? I want a box with larger height
554         _GlyphsListScroller.add(_GlyphsList);
555     _GlyphsListStore = Gtk::ListStore::create(_GlyphsListColumns);
556     _GlyphsList.set_model(_GlyphsListStore);
557     _GlyphsList.append_column_editable(_("Glyph Name"), _GlyphsListColumns.glyph_name);
558     _GlyphsList.append_column_editable(_("Unicode"), _GlyphsListColumns.unicode);
560     Gtk::HBox* hb = Gtk::manage(new Gtk::HBox());
561         add_glyph_button.set_label(_("Add Glyph"));
562         add_glyph_button.signal_clicked().connect(sigc::mem_fun(*this, &SvgFontsDialog::add_glyph));
564         hb->pack_start(add_glyph_button, false,false);
565         hb->pack_start(glyph_from_path_button, false,false);
567         glyphs_vbox.pack_start(*hb, false, false);
568         glyph_from_path_button.set_label(_("Get curves from selection..."));
569     glyph_from_path_button.signal_clicked().connect(sigc::mem_fun(*this, &SvgFontsDialog::set_glyph_description_from_selected_path));
571         dynamic_cast<Gtk::CellRendererText*>( _GlyphsList.get_column_cell_renderer(0))->signal_edited().connect(
572                         sigc::mem_fun(*this, &SvgFontsDialog::glyph_name_edit));
574         dynamic_cast<Gtk::CellRendererText*>( _GlyphsList.get_column_cell_renderer(1))->signal_edited().connect(
575                         sigc::mem_fun(*this, &SvgFontsDialog::glyph_unicode_edit));
577         _glyphs_observer.signal_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::update_glyphs));
579     return &glyphs_vbox;
582 void SvgFontsDialog::add_kerning_pair(){
583         if (first_glyph.get_active_text() == "" ||
584                 second_glyph.get_active_text() == "") return;
586     //look for this kerning pair on the currently selected font
587     this->kerning_pair = NULL;
588     for(SPObject* node = this->get_selected_spfont()->children; node; node=node->next){
589                 //TODO: It is not really correct to get only the first byte of each string.
590                 //TODO: We should also support vertical kerning
591         if (SP_IS_HKERN(node) && ((SPGlyphKerning*)node)->u1->contains((gchar) first_glyph.get_active_text().c_str()[0])
592                                   && ((SPGlyphKerning*)node)->u2->contains((gchar) second_glyph.get_active_text().c_str()[0]) ){
593             this->kerning_pair = (SPGlyphKerning*)node;
594             continue;
595         }
596     }
598     if (this->kerning_pair) return; //We already have this kerning pair
600         SPDocument* document = sp_desktop_document(this->getDesktop());
601         Inkscape::XML::Document *xml_doc = sp_document_repr_doc(document);
603     // create a new hkern node
604         Inkscape::XML::Node *repr;
605     repr = xml_doc->createElement("svg:hkern");
607         repr->setAttribute("u1", first_glyph.get_active_text().c_str());
608         repr->setAttribute("u2", second_glyph.get_active_text().c_str());
609         repr->setAttribute("k", "0");
611     // Append the new hkern node to the current font
612         SP_OBJECT_REPR(get_selected_spfont())->appendChild(repr);
613         Inkscape::GC::release(repr);
615         // get corresponding object
616     this->kerning_pair = SP_HKERN( document->getObjectByRepr(repr) );
618     sp_document_done(document, SP_VERB_DIALOG_SVG_FONTS, _("Add kerning pair"));
621 Gtk::VBox* SvgFontsDialog::kerning_tab(){
622 //Kerning Setup:
623     kerning_vbox.add(*Gtk::manage(new Gtk::Label(_("Kerning Setup:"))));
624     Gtk::HBox* kerning_selector = Gtk::manage(new Gtk::HBox());
625     kerning_selector->add(*Gtk::manage(new Gtk::Label(_("1st Glyph:"))));
626     kerning_selector->add(first_glyph);
627     kerning_selector->add(*Gtk::manage(new Gtk::Label(_("2nd Glyph:"))));
628     kerning_selector->add(second_glyph);
629     kerning_selector->add(add_kernpair_button);
630         add_kernpair_button.set_label(_("Add pair"));
631         add_kernpair_button.signal_clicked().connect(sigc::mem_fun(*this, &SvgFontsDialog::add_kerning_pair));
632     _KerningPairsList.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::on_kerning_pair_selection_changed));
633     kerning_slider.signal_value_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::on_kerning_value_changed));
635     kerning_vbox.pack_start(*kerning_selector, false,false);
637         kerning_vbox.add(_KerningPairsListScroller);
638         _KerningPairsListScroller.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_ALWAYS);
639         _KerningPairsListScroller.add(_KerningPairsList);
640     _KerningPairsListStore = Gtk::ListStore::create(_KerningPairsListColumns);
641     _KerningPairsList.set_model(_KerningPairsListStore);
642     _KerningPairsList.append_column(_("First Unicode range"), _KerningPairsListColumns.first_glyph);
643     _KerningPairsList.append_column(_("Second Unicode range"), _KerningPairsListColumns.second_glyph);
644 //    _KerningPairsList.append_column_numeric_editable(_("Kerning Value"), _KerningPairsListColumns.kerning_value, "%f");
646     kerning_vbox.add((Gtk::Widget&) kerning_preview);
648     Gtk::HBox* kerning_amount_hbox = Gtk::manage(new Gtk::HBox());
649     kerning_vbox.pack_start(*kerning_amount_hbox, false,false);
650     kerning_amount_hbox->add(*Gtk::manage(new Gtk::Label(_("Kerning value:"))));
651     kerning_amount_hbox->add(kerning_slider);
653     kerning_preview.set_size(300 + 20, 150 + 20);
654     _font_da.set_size(150 + 20, 50 + 20);
656     return &kerning_vbox;
659 SPFont *new_font(SPDocument *document)
661     g_return_val_if_fail(document != NULL, NULL);
663     SPDefs *defs = (SPDefs *) SP_DOCUMENT_DEFS(document);
665     Inkscape::XML::Document *xml_doc = sp_document_repr_doc(document);
667     // create a new font
668     Inkscape::XML::Node *repr;
669     repr = xml_doc->createElement("svg:font");
670         
671         //By default, set the horizontal advance to 1024 units  
672         repr->setAttribute("horiz-adv-x", "1024");
674     // Append the new font node to defs
675     SP_OBJECT_REPR(defs)->appendChild(repr);
677         //create a missing glyph
678     Inkscape::XML::Node *fontface;
679     fontface = xml_doc->createElement("svg:font-face");
680         fontface->setAttribute("units-per-em", "1024");
681     repr->appendChild(fontface);
683         //create a missing glyph
684     Inkscape::XML::Node *mg;
685     mg = xml_doc->createElement("svg:missing-glyph");
686         mg->setAttribute("d", "M0,0h1020v1024h-1020z");
687     repr->appendChild(mg);
689     // get corresponding object
690     SPFont *f = SP_FONT( document->getObjectByRepr(repr) );
691     
692     g_assert(f != NULL);
693     g_assert(SP_IS_FONT(f));
694     Inkscape::GC::release(mg);
695     Inkscape::GC::release(repr);
696     return f;
699 void set_font_family(SPFont* font, char* str){
700         if (!font) return;
701         SPObject* obj;
702         for (obj=font->children; obj; obj=obj->next){
703                 if (SP_IS_FONTFACE(obj)){
704                         obj->repr->setAttribute("font-family", str);
705                 }
706         }
708     sp_document_done(font->document, SP_VERB_DIALOG_SVG_FONTS, _("Set font family"));
711 void SvgFontsDialog::add_font(){
712     SPDocument* doc = sp_desktop_document(this->getDesktop());
713     SPFont* font = new_font(doc);
715     const int count = _model->children().size();
716     std::ostringstream os, os2;
717     os << _("font") << " " << count;
718     font->setLabel(os.str().c_str());
720     os2 << "SVGFont " << count;
721         SPObject* obj;
722         for (obj=font->children; obj; obj=obj->next){
723                 if (SP_IS_FONTFACE(obj)){
724                         obj->repr->setAttribute("font-family", os2.str().c_str());
725                 }
726         }
728     update_fonts();
729 //    select_font(font);
731     sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Add font"));
734 SvgFontsDialog::SvgFontsDialog()
735  : UI::Widget::Panel("", "/dialogs/svgfonts", SP_VERB_DIALOG_SVG_FONTS), _add(Gtk::Stock::NEW)
737     _add.signal_clicked().connect(sigc::mem_fun(*this, &SvgFontsDialog::add_font));
739     Gtk::HBox* hbox = Gtk::manage(new Gtk::HBox());
740     Gtk::VBox* vbox = Gtk::manage(new Gtk::VBox());
742     vbox->pack_start(_FontsList);
743     vbox->pack_start(_add, false, false);
744     hbox->add(*vbox);
745     hbox->add(_font_settings);
746     _getContents()->add(*hbox);
748 //List of SVGFonts declared in a document:
749     _model = Gtk::ListStore::create(_columns);
750     _FontsList.set_model(_model);
751     _FontsList.append_column_editable(_("_Font"), _columns.label);
752     _FontsList.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::on_font_selection_changed));
754     this->update_fonts();
756     Gtk::Notebook *tabs = Gtk::manage(new Gtk::Notebook());
757     tabs->set_scrollable();
759     tabs->append_page(*global_settings_tab(), _("_Global Settings"), true);
760     tabs->append_page(*glyphs_tab(), _("_Glyphs"), true);
761     tabs->append_page(*kerning_tab(), _("_Kerning"), true);
763     _font_settings.add(*tabs);
765 //Text Preview:
766     _preview_entry.signal_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::on_preview_text_changed));
767     _getContents()->add((Gtk::Widget&) _font_da);
768     _preview_entry.set_text("Sample Text");
769     _font_da.set_text("Sample Text");
771     Gtk::HBox* preview_entry_hbox = Gtk::manage(new Gtk::HBox());
772     _getContents()->add(*preview_entry_hbox);
773     preview_entry_hbox->add(*Gtk::manage(new Gtk::Label(_("Preview Text:"))));
774     preview_entry_hbox->add(_preview_entry);
776     _FontsList.signal_button_release_event().connect_notify(sigc::mem_fun(*this, &SvgFontsDialog::fonts_list_button_release));
777     create_fonts_popup_menu(_FontsList, sigc::mem_fun(*this, &SvgFontsDialog::remove_selected_font));
778         
779         _defs_observer.set(SP_DOCUMENT_DEFS(sp_desktop_document(this->getDesktop())));
780         _defs_observer.signal_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::update_fonts));
782     _getContents()->show_all();
785 SvgFontsDialog::~SvgFontsDialog(){}
787 } // namespace Dialog
788 } // namespace UI
789 } // namespace Inkscape
791 #endif //#ifdef ENABLE_SVG_FONTS