Code

Pot and Dutch translation update
[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 <juca@members.fsf.org>
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 <2geom/pathvector.h>
18 #include "document-private.h"
19 #include <gtkmm/notebook.h>
20 #include <glibmm/i18n.h>
21 #include <message-stack.h>
22 #include "selection.h"
23 #include <string.h>
24 #include "svg/svg.h"
25 #include "svg-fonts-dialog.h"
26 #include "xml/node.h"
27 #include "xml/repr.h"
29 SvgFontDrawingArea::SvgFontDrawingArea(){
30     this->text = "";
31     this->svgfont = NULL;
32 }
34 void SvgFontDrawingArea::set_svgfont(SvgFont* svgfont){
35     this->svgfont = svgfont;
36 }
38 void SvgFontDrawingArea::set_text(Glib::ustring text){
39     this->text = text;
40     redraw();
41 }
43 void SvgFontDrawingArea::set_size(int x, int y){
44     this->x = x;
45     this->y = y;
46     ((Gtk::Widget*) this)->set_size_request(x, y);
47 }
49 void SvgFontDrawingArea::redraw(){
50     ((Gtk::Widget*) this)->queue_draw();
51 }
53 bool SvgFontDrawingArea::on_expose_event (GdkEventExpose */*event*/){
54   if (this->svgfont){
55     Glib::RefPtr<Gdk::Window> window = get_window();
56     Cairo::RefPtr<Cairo::Context> cr = window->create_cairo_context();
57     cr->set_font_face( Cairo::RefPtr<Cairo::FontFace>(new Cairo::FontFace(this->svgfont->get_font_face(), false /* does not have reference */)) );
58     cr->set_font_size (this->y-20);
59     cr->move_to (10, 10);
60     cr->show_text (this->text.c_str());
61   }
62   return TRUE;
63 }
65 namespace Inkscape {
66 namespace UI {
67 namespace Dialog {
69 /*
70 Gtk::HBox* SvgFontsDialog::AttrEntry(gchar* lbl, const SPAttributeEnum attr){
71     Gtk::HBox* hbox = Gtk::manage(new Gtk::HBox());
72     hbox->add(* Gtk::manage(new Gtk::Label(lbl)) );
73     Gtk::Entry* entry = Gtk::manage(new Gtk::Entry());
74     hbox->add(* entry );
75     hbox->show_all();
77     entry->signal_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::on_attr_changed));
78     return hbox;
79 }
80 */
82 SvgFontsDialog::AttrEntry::AttrEntry(SvgFontsDialog* d, gchar* lbl, const SPAttributeEnum attr){
83     this->dialog = d;
84     this->attr = attr;
85     this->add(* Gtk::manage(new Gtk::Label(lbl)) );
86     this->add(entry);
87     this->show_all();
89     entry.signal_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::AttrEntry::on_attr_changed));
90 }
92 void SvgFontsDialog::AttrEntry::set_text(char* t){
93     if (!t) return;
94     entry.set_text(t);
95 }
97 void SvgFontsDialog::AttrEntry::on_attr_changed(){
99     SPObject* o = NULL;
100     for(SPObject* node = this->dialog->get_selected_spfont()->children; node; node=node->next){
101         switch(this->attr){
102             case SP_PROP_FONT_FAMILY:
103                 if (SP_IS_FONTFACE(node)){
104                     o = node;
105                     continue;
106                 }
107                 break;
108             default:
109                 o = NULL;
110         }
111     }
113     const gchar* name = (const gchar*)sp_attribute_name(this->attr);
114     if(name && o) {
115         SP_OBJECT_REPR(o)->setAttribute((const gchar*) name, this->entry.get_text().c_str());
116         o->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
118         Glib::ustring undokey = "svgfonts:";
119         undokey += name;
120         sp_document_maybe_done(o->document, undokey.c_str(), SP_VERB_DIALOG_SVG_FONTS,
121                                _("Set SVG Font attribute"));
122     }
126 Gtk::HBox* SvgFontsDialog::AttrCombo(gchar* lbl, const SPAttributeEnum /*attr*/){
127     Gtk::HBox* hbox = Gtk::manage(new Gtk::HBox());
128     hbox->add(* Gtk::manage(new Gtk::Label(lbl)) );
129     hbox->add(* Gtk::manage(new Gtk::ComboBox()) );
130     hbox->show_all();
131     return hbox;
134 /*
135 Gtk::HBox* SvgFontsDialog::AttrSpin(gchar* lbl){
136     Gtk::HBox* hbox = Gtk::manage(new Gtk::HBox());
137     hbox->add(* Gtk::manage(new Gtk::Label(lbl)) );
138     hbox->add(* Gtk::manage(new Gtk::SpinBox()) );
139     hbox->show_all();
140     return hbox;
141 }*/
143 /*** SvgFontsDialog ***/
145 GlyphComboBox::GlyphComboBox(){
148 void GlyphComboBox::update(SPFont* spfont){
149     if (!spfont) return
150 //TODO: figure out why do we need to append_text("") before clearing items properly...
152     this->append_text(""); //Gtk is refusing to clear the combobox when I comment out this line
153     this->clear_items();
155     for(SPObject* node = spfont->children; node; node=node->next){
156         if (SP_IS_GLYPH(node)){
157             this->append_text(((SPGlyph*)node)->unicode);
158         }
159     }
162 void SvgFontsDialog::on_kerning_value_changed(){
163     if (!this->kerning_pair) return;
164     SPDocument* document = sp_desktop_document(this->getDesktop());
166     //TODO: I am unsure whether this is the correct way of calling sp_document_maybe_done
167     Glib::ustring undokey = "svgfonts:hkern:k:";
168     undokey += this->kerning_pair->u1->attribute_string();
169     undokey += ":";
170     undokey += this->kerning_pair->u2->attribute_string();
172     //slider values increase from right to left so that they match the kerning pair preview
173     this->kerning_pair->repr->setAttribute("k", Glib::Ascii::dtostr(get_selected_spfont()->horiz_adv_x - kerning_slider.get_value()).c_str());
174     sp_document_maybe_done(document, undokey.c_str(), SP_VERB_DIALOG_SVG_FONTS, _("Adjust kerning value"));
176     //populate_kerning_pairs_box();
177     kerning_preview.redraw();
178     _font_da.redraw();
181 void SvgFontsDialog::glyphs_list_button_release(GdkEventButton* event)
183     if((event->type == GDK_BUTTON_RELEASE) && (event->button == 3)) {
184         _GlyphsContextMenu.popup(event->button, event->time);
185     }
188 void SvgFontsDialog::kerning_pairs_list_button_release(GdkEventButton* event)
190     if((event->type == GDK_BUTTON_RELEASE) && (event->button == 3)) {
191         _KerningPairsContextMenu.popup(event->button, event->time);
192     }
195 void SvgFontsDialog::fonts_list_button_release(GdkEventButton* event)
197     if((event->type == GDK_BUTTON_RELEASE) && (event->button == 3)) {
198         _FontsContextMenu.popup(event->button, event->time);
199     }
202 void SvgFontsDialog::create_glyphs_popup_menu(Gtk::Widget& parent, sigc::slot<void> rem)
204     Gtk::MenuItem* mi = Gtk::manage(new Gtk::ImageMenuItem(Gtk::Stock::REMOVE));
205     _GlyphsContextMenu.append(*mi);
206     mi->signal_activate().connect(rem);
207     mi->show();
208     _GlyphsContextMenu.accelerate(parent);
211 void SvgFontsDialog::create_kerning_pairs_popup_menu(Gtk::Widget& parent, sigc::slot<void> rem)
213     Gtk::MenuItem* mi = Gtk::manage(new Gtk::ImageMenuItem(Gtk::Stock::REMOVE));
214     _KerningPairsContextMenu.append(*mi);
215     mi->signal_activate().connect(rem);
216     mi->show();
217     _KerningPairsContextMenu.accelerate(parent);
220 void SvgFontsDialog::create_fonts_popup_menu(Gtk::Widget& parent, sigc::slot<void> rem)
222     Gtk::MenuItem* mi = Gtk::manage(new Gtk::ImageMenuItem(Gtk::Stock::REMOVE));
223     _FontsContextMenu.append(*mi);
224     mi->signal_activate().connect(rem);
225     mi->show();
226     _FontsContextMenu.accelerate(parent);
229 void SvgFontsDialog::update_sensitiveness(){
230     if (get_selected_spfont()){
231         global_vbox.set_sensitive(true);
232         glyphs_vbox.set_sensitive(true);
233         kerning_vbox.set_sensitive(true);
234     } else {
235         global_vbox.set_sensitive(false);
236         glyphs_vbox.set_sensitive(false);
237         kerning_vbox.set_sensitive(false);
238     }
241 /* Add all fonts in the document to the combobox. */
242 void SvgFontsDialog::update_fonts()
244     SPDesktop* desktop = this->getDesktop();
245     SPDocument* document = sp_desktop_document(desktop);
246     const GSList* fonts = sp_document_get_resource_list(document, "font");
248     _model->clear();
249     for(const GSList *l = fonts; l; l = l->next) {
250         Gtk::TreeModel::Row row = *_model->append();
251         SPFont* f = (SPFont*)l->data;
252         row[_columns.spfont] = f;
253         row[_columns.svgfont] = new SvgFont(f);
254         const gchar* lbl = f->label();
255         const gchar* id = f->getId();
256         row[_columns.label] = lbl ? lbl : (id ? id : "font");
257     }
259     update_sensitiveness();
262 void SvgFontsDialog::on_preview_text_changed(){
263     _font_da.set_text((gchar*) _preview_entry.get_text().c_str());
264     _font_da.set_text(_preview_entry.get_text());
267 void SvgFontsDialog::on_kerning_pair_selection_changed(){
268     SPGlyphKerning* kern = get_selected_kerning_pair();
269     if (!kern) {
270         kerning_preview.set_text("");
271         return;
272     }
273     Glib::ustring str;
274     str += kern->u1->sample_glyph();
275     str += kern->u2->sample_glyph();
277     kerning_preview.set_text(str);
278     this->kerning_pair = kern;
280     //slider values increase from right to left so that they match the kerning pair preview
281     kerning_slider.set_value(get_selected_spfont()->horiz_adv_x - kern->k);
284 void SvgFontsDialog::update_global_settings_tab(){
285     SPFont* font = get_selected_spfont();
286     if (!font) return;
288     SPObject* obj;
289     for (obj=font->children; obj; obj=obj->next){
290         if (SP_IS_FONTFACE(obj)){
291             _familyname_entry->set_text(((SPFontFace*) obj)->font_family);
292         }
293     }
296 void SvgFontsDialog::on_font_selection_changed(){
297     SPFont* spfont = this->get_selected_spfont();
298     if (!spfont) return;
300     SvgFont* svgfont = this->get_selected_svgfont();
301     first_glyph.update(spfont);
302     second_glyph.update(spfont);
303     kerning_preview.set_svgfont(svgfont);
304     _font_da.set_svgfont(svgfont);
305     _font_da.redraw();
307     double set_width = spfont->horiz_adv_x;
308     setwidth_spin.set_value(set_width);
310     kerning_slider.set_range(0, set_width);
311     kerning_slider.set_draw_value(false);
312     kerning_slider.set_value(0);
314     update_global_settings_tab();
315     populate_glyphs_box();
316     populate_kerning_pairs_box();
317     update_sensitiveness();
320 void SvgFontsDialog::on_setwidth_changed(){
321     SPFont* spfont = this->get_selected_spfont();
322     if (spfont){
323         spfont->horiz_adv_x = setwidth_spin.get_value();
324         //TODO: tell cairo that the glyphs cache has to be invalidated
325         //    The current solution is to recreate the whole cairo svgfont.
326         //    This is not a good solution to the issue because big fonts will result in poor performance.
327         update_glyphs();
328     }
331 SPGlyphKerning* SvgFontsDialog::get_selected_kerning_pair()
333     Gtk::TreeModel::iterator i = _KerningPairsList.get_selection()->get_selected();
334     if(i)
335         return (*i)[_KerningPairsListColumns.spnode];
336     return NULL;
339 SvgFont* SvgFontsDialog::get_selected_svgfont()
341     Gtk::TreeModel::iterator i = _FontsList.get_selection()->get_selected();
342     if(i)
343         return (*i)[_columns.svgfont];
344     return NULL;
347 SPFont* SvgFontsDialog::get_selected_spfont()
349     Gtk::TreeModel::iterator i = _FontsList.get_selection()->get_selected();
350     if(i)
351         return (*i)[_columns.spfont];
352     return NULL;
355 SPGlyph* SvgFontsDialog::get_selected_glyph()
357     Gtk::TreeModel::iterator i = _GlyphsList.get_selection()->get_selected();
358     if(i)
359         return (*i)[_GlyphsListColumns.glyph_node];
360     return NULL;
363 Gtk::VBox* SvgFontsDialog::global_settings_tab(){
364     _familyname_entry = new AttrEntry(this, (gchar*) _("Family Name:"), SP_PROP_FONT_FAMILY);
366     global_vbox.pack_start(*_familyname_entry, false, false);
367 /*    global_vbox->add(*AttrCombo((gchar*) _("Style:"), SP_PROP_FONT_STYLE));
368     global_vbox->add(*AttrCombo((gchar*) _("Variant:"), SP_PROP_FONT_VARIANT));
369     global_vbox->add(*AttrCombo((gchar*) _("Weight:"), SP_PROP_FONT_WEIGHT));
370 */
372 //Set Width (horiz_adv_x):
373     Gtk::HBox* setwidth_hbox = Gtk::manage(new Gtk::HBox());
374     setwidth_hbox->add(*Gtk::manage(new Gtk::Label(_("Set width:"))));
375     setwidth_hbox->add(setwidth_spin);
377     setwidth_spin.signal_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::on_setwidth_changed));
378     setwidth_spin.set_range(0, 4096);
379     setwidth_spin.set_increments(10, 0);
380     global_vbox.pack_start(*setwidth_hbox, false, false);
382     return &global_vbox;
385 void
386 SvgFontsDialog::populate_glyphs_box()
388     if (!_GlyphsListStore) return;
389     _GlyphsListStore->clear();
391     SPFont* spfont = this->get_selected_spfont();
392     _glyphs_observer.set(spfont);
394     for(SPObject* node = spfont->children; node; node=node->next){
395         if (SP_IS_GLYPH(node)){
396             Gtk::TreeModel::Row row = *(_GlyphsListStore->append());
397             row[_GlyphsListColumns.glyph_node] = (SPGlyph*) node;
398             row[_GlyphsListColumns.glyph_name] = ((SPGlyph*) node)->glyph_name;
399             row[_GlyphsListColumns.unicode] = ((SPGlyph*) node)->unicode;
400         }
401     }
404 void
405 SvgFontsDialog::populate_kerning_pairs_box()
407     if (!_KerningPairsListStore) return;
408     _KerningPairsListStore->clear();
410     SPFont* spfont = this->get_selected_spfont();
412     for(SPObject* node = spfont->children; node; node=node->next){
413         if (SP_IS_HKERN(node)){
414             Gtk::TreeModel::Row row = *(_KerningPairsListStore->append());
415             row[_KerningPairsListColumns.first_glyph] = ((SPGlyphKerning*) node)->u1->attribute_string().c_str();
416             row[_KerningPairsListColumns.second_glyph] = ((SPGlyphKerning*) node)->u2->attribute_string().c_str();
417             row[_KerningPairsListColumns.kerning_value] = ((SPGlyphKerning*) node)->k;
418             row[_KerningPairsListColumns.spnode] = (SPGlyphKerning*) node;
419         }
420     }
423 SPGlyph *new_glyph(SPDocument* document, SPFont *font, const int count)
425     g_return_val_if_fail(font != NULL, NULL);
426     Inkscape::XML::Document *xml_doc = sp_document_repr_doc(document);
428     // create a new glyph
429     Inkscape::XML::Node *repr;
430     repr = xml_doc->createElement("svg:glyph");
432     std::ostringstream os;
433     os << _("glyph") << " " << count;
434     repr->setAttribute("glyph-name", os.str().c_str());
436     // Append the new glyph node to the current font
437     SP_OBJECT_REPR(font)->appendChild(repr);
438     Inkscape::GC::release(repr);
440     // get corresponding object
441     SPGlyph *g = SP_GLYPH( document->getObjectByRepr(repr) );
443     g_assert(g != NULL);
444     g_assert(SP_IS_GLYPH(g));
446     return g;
449 void SvgFontsDialog::update_glyphs(){
450     SPFont* font = get_selected_spfont();
451     if (!font) return;
452     populate_glyphs_box();
453     populate_kerning_pairs_box();
454     first_glyph.update(font);
455     second_glyph.update(font);
456     get_selected_svgfont()->refresh();
457     _font_da.redraw();
460 void SvgFontsDialog::add_glyph(){
461     const int count = _GlyphsListStore->children().size();
462     SPDocument* doc = sp_desktop_document(this->getDesktop());
463     /* SPGlyph* glyph =*/ new_glyph(doc, get_selected_spfont(), count+1);
465     sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Add glyph"));
467     update_glyphs();
470 void SvgFontsDialog::set_glyph_description_from_selected_path(){
471     SPDesktop* desktop = this->getDesktop();
472     if (!desktop) {
473         g_warning("SvgFontsDialog: No active desktop");
474         return;
475     }
477     Inkscape::MessageStack *msgStack = sp_desktop_message_stack(desktop);
478     SPDocument* doc = sp_desktop_document(desktop);
479     Inkscape::Selection* sel = sp_desktop_selection(desktop);
480     if (sel->isEmpty()){
481         char *msg = _("Select a <b>path</b> to define the curves of a glyph");
482         msgStack->flash(Inkscape::ERROR_MESSAGE, msg);
483         return;
484     }
486     Inkscape::XML::Node* node = (Inkscape::XML::Node*) g_slist_nth_data((GSList *)sel->reprList(), 0);
487     if (!node) return;//TODO: should this be an assert?
488     if (!node->matchAttributeName("d") || !node->attribute("d")){
489         char *msg = _("The selected object does not have a <b>path</b> description.");
490         msgStack->flash(Inkscape::ERROR_MESSAGE, msg);
491         return;
492     } //TODO: //Is there a better way to tell it to to the user?
494     Geom::PathVector pathv = sp_svg_read_pathv(node->attribute("d"));
496     //This matrix flips the glyph vertically
497     Geom::Matrix m(Geom::Coord(1),Geom::Coord(0),Geom::Coord(0),Geom::Coord(-1),Geom::Coord(0),Geom::Coord(0));
498     pathv*=m;
499     //then we offset it
500     pathv+=Geom::Point(Geom::Coord(0),Geom::Coord(get_selected_spfont()->horiz_adv_x));
502     SPGlyph* glyph = get_selected_glyph();
503     if (!glyph){
504         char *msg = _("No glyph selected in the SVGFonts dialog.");
505         msgStack->flash(Inkscape::ERROR_MESSAGE, msg);
506         return;
507     }
508     glyph->repr->setAttribute("d", (char*) sp_svg_write_path (pathv));
509     sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Set glyph curves"));
511     update_glyphs();
514 void SvgFontsDialog::missing_glyph_description_from_selected_path(){
515     SPDesktop* desktop = this->getDesktop();
516     if (!desktop) {
517         g_warning("SvgFontsDialog: No active desktop");
518         return;
519     }
521     Inkscape::MessageStack *msgStack = sp_desktop_message_stack(desktop);
522     SPDocument* doc = sp_desktop_document(desktop);
523     Inkscape::Selection* sel = sp_desktop_selection(desktop);
524     if (sel->isEmpty()){
525         char *msg = _("Select a <b>path</b> to define the curves of a glyph");
526         msgStack->flash(Inkscape::ERROR_MESSAGE, msg);
527         return;
528     }
530     Inkscape::XML::Node* node = (Inkscape::XML::Node*) g_slist_nth_data((GSList *)sel->reprList(), 0);
531     if (!node) return;//TODO: should this be an assert?
532     if (!node->matchAttributeName("d") || !node->attribute("d")){
533         char *msg = _("The selected object does not have a <b>path</b> description.");
534         msgStack->flash(Inkscape::ERROR_MESSAGE, msg);
535         return;
536     } //TODO: //Is there a better way to tell it to to the user?
538     Geom::PathVector pathv = sp_svg_read_pathv(node->attribute("d"));
540     //This matrix flips the glyph vertically
541     Geom::Matrix m(Geom::Coord(1),Geom::Coord(0),Geom::Coord(0),Geom::Coord(-1),Geom::Coord(0),Geom::Coord(0));
542     pathv*=m;
543     //then we offset it
544 //  pathv+=Geom::Point(Geom::Coord(0),Geom::Coord(get_selected_spfont()->horiz_adv_x));
545     pathv+=Geom::Point(Geom::Coord(0),Geom::Coord(1000));//TODO: use here the units-per-em attribute?
547     SPObject* obj;
548     for (obj = get_selected_spfont()->children; obj; obj=obj->next){
549         if (SP_IS_MISSING_GLYPH(obj)){
550             obj->repr->setAttribute("d", (char*) sp_svg_write_path (pathv));
551             sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Set glyph curves"));
552         }
553     }
555     update_glyphs();
558 void SvgFontsDialog::reset_missing_glyph_description(){
559     SPDesktop* desktop = this->getDesktop();
560     if (!desktop) {
561         g_warning("SvgFontsDialog: No active desktop");
562         return;
563     }
565     SPDocument* doc = sp_desktop_document(desktop);
566     SPObject* obj;
567     for (obj = get_selected_spfont()->children; obj; obj=obj->next){
568         if (SP_IS_MISSING_GLYPH(obj)){
569             obj->repr->setAttribute("d", (char*) "M0,0h1000v1024h-1000z");
570             sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Reset missing-glyph"));
571         }
572     }
574     update_glyphs();
577 void SvgFontsDialog::glyph_name_edit(const Glib::ustring&, const Glib::ustring& str){
578     Gtk::TreeModel::iterator i = _GlyphsList.get_selection()->get_selected();
579     if (!i) return;
581     SPGlyph* glyph = (*i)[_GlyphsListColumns.glyph_node];
582     glyph->repr->setAttribute("glyph-name", str.c_str());
584     SPDocument* doc = sp_desktop_document(this->getDesktop());
585     sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Edit glyph name"));
587     update_glyphs();
590 void SvgFontsDialog::glyph_unicode_edit(const Glib::ustring&, const Glib::ustring& str){
591     Gtk::TreeModel::iterator i = _GlyphsList.get_selection()->get_selected();
592     if (!i) return;
594     SPGlyph* glyph = (*i)[_GlyphsListColumns.glyph_node];
595     glyph->repr->setAttribute("unicode", str.c_str());
597     SPDocument* doc = sp_desktop_document(this->getDesktop());
598     sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Set glyph unicode"));
600     update_glyphs();
603 void SvgFontsDialog::remove_selected_font(){
604     SPFont* font = get_selected_spfont();
605     if (!font) return;
607     sp_repr_unparent(font->repr);
608     SPDocument* doc = sp_desktop_document(this->getDesktop());
609     sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Remove font"));
611     update_fonts();
614 void SvgFontsDialog::remove_selected_glyph(){
615     if(!_GlyphsList.get_selection()) return;
617     Gtk::TreeModel::iterator i = _GlyphsList.get_selection()->get_selected();
618     if(!i) return;
620     SPGlyph* glyph = (*i)[_GlyphsListColumns.glyph_node];
621     sp_repr_unparent(glyph->repr);
623     SPDocument* doc = sp_desktop_document(this->getDesktop());
624     sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Remove glyph"));
626     update_glyphs();
629 void SvgFontsDialog::remove_selected_kerning_pair(){
630     if(!_KerningPairsList.get_selection()) return;
632     Gtk::TreeModel::iterator i = _KerningPairsList.get_selection()->get_selected();
633     if(!i) return;
635     SPGlyphKerning* pair = (*i)[_KerningPairsListColumns.spnode];
636     sp_repr_unparent(pair->repr);
638     SPDocument* doc = sp_desktop_document(this->getDesktop());
639     sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Remove kerning pair"));
641     update_glyphs();
644 Gtk::VBox* SvgFontsDialog::glyphs_tab(){
645     _GlyphsList.signal_button_release_event().connect_notify(sigc::mem_fun(*this, &SvgFontsDialog::glyphs_list_button_release));
646     create_glyphs_popup_menu(_GlyphsList, sigc::mem_fun(*this, &SvgFontsDialog::remove_selected_glyph));
648     Gtk::HBox* missing_glyph_hbox = Gtk::manage(new Gtk::HBox());
649     Gtk::Label* missing_glyph_label = Gtk::manage(new Gtk::Label(_("Missing Glyph:")));
650     missing_glyph_hbox->pack_start(*missing_glyph_label, false,false);
651     missing_glyph_hbox->pack_start(missing_glyph_button, false,false);
652     missing_glyph_hbox->pack_start(missing_glyph_reset_button, false,false);
653     missing_glyph_button.set_label(_("From selection..."));
654     missing_glyph_button.signal_clicked().connect(sigc::mem_fun(*this, &SvgFontsDialog::missing_glyph_description_from_selected_path));
655     missing_glyph_reset_button.set_label(_("Reset"));
656     missing_glyph_reset_button.signal_clicked().connect(sigc::mem_fun(*this, &SvgFontsDialog::reset_missing_glyph_description));
658     glyphs_vbox.pack_start(*missing_glyph_hbox, false,false);
660     glyphs_vbox.add(_GlyphsListScroller);
661     _GlyphsListScroller.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_ALWAYS);
662     _GlyphsListScroller.set_size_request(-1, 290);//It seems that is does not work. Why? I want a box with larger height
663     _GlyphsListScroller.add(_GlyphsList);
664     _GlyphsListStore = Gtk::ListStore::create(_GlyphsListColumns);
665     _GlyphsList.set_model(_GlyphsListStore);
666     _GlyphsList.append_column_editable(_("Glyph name"), _GlyphsListColumns.glyph_name);
667     _GlyphsList.append_column_editable(_("Matching string"), _GlyphsListColumns.unicode);
669     Gtk::HBox* hb = Gtk::manage(new Gtk::HBox());
670     add_glyph_button.set_label(_("Add Glyph"));
671     add_glyph_button.signal_clicked().connect(sigc::mem_fun(*this, &SvgFontsDialog::add_glyph));
673     hb->pack_start(add_glyph_button, false,false);
674     hb->pack_start(glyph_from_path_button, false,false);
676     glyphs_vbox.pack_start(*hb, false, false);
677     glyph_from_path_button.set_label(_("Get curves from selection..."));
678     glyph_from_path_button.signal_clicked().connect(sigc::mem_fun(*this, &SvgFontsDialog::set_glyph_description_from_selected_path));
680     dynamic_cast<Gtk::CellRendererText*>( _GlyphsList.get_column_cell_renderer(0))->signal_edited().connect(
681         sigc::mem_fun(*this, &SvgFontsDialog::glyph_name_edit));
683     dynamic_cast<Gtk::CellRendererText*>( _GlyphsList.get_column_cell_renderer(1))->signal_edited().connect(
684         sigc::mem_fun(*this, &SvgFontsDialog::glyph_unicode_edit));
686     _glyphs_observer.signal_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::update_glyphs));
688     return &glyphs_vbox;
691 void SvgFontsDialog::add_kerning_pair(){
692     if (first_glyph.get_active_text() == "" ||
693         second_glyph.get_active_text() == "") return;
695     //look for this kerning pair on the currently selected font
696     this->kerning_pair = NULL;
697     for(SPObject* node = this->get_selected_spfont()->children; node; node=node->next){
698         //TODO: It is not really correct to get only the first byte of each string.
699         //TODO: We should also support vertical kerning
700         if (SP_IS_HKERN(node) && ((SPGlyphKerning*)node)->u1->contains((gchar) first_glyph.get_active_text().c_str()[0])
701             && ((SPGlyphKerning*)node)->u2->contains((gchar) second_glyph.get_active_text().c_str()[0]) ){
702             this->kerning_pair = (SPGlyphKerning*)node;
703             continue;
704         }
705     }
707     if (this->kerning_pair) return; //We already have this kerning pair
709     SPDocument* document = sp_desktop_document(this->getDesktop());
710     Inkscape::XML::Document *xml_doc = sp_document_repr_doc(document);
712     // create a new hkern node
713     Inkscape::XML::Node *repr;
714     repr = xml_doc->createElement("svg:hkern");
716     repr->setAttribute("u1", first_glyph.get_active_text().c_str());
717     repr->setAttribute("u2", second_glyph.get_active_text().c_str());
718     repr->setAttribute("k", "0");
720     // Append the new hkern node to the current font
721     SP_OBJECT_REPR(get_selected_spfont())->appendChild(repr);
722     Inkscape::GC::release(repr);
724     // get corresponding object
725     this->kerning_pair = SP_HKERN( document->getObjectByRepr(repr) );
727     sp_document_done(document, SP_VERB_DIALOG_SVG_FONTS, _("Add kerning pair"));
730 Gtk::VBox* SvgFontsDialog::kerning_tab(){
731     _KerningPairsList.signal_button_release_event().connect_notify(sigc::mem_fun(*this, &SvgFontsDialog::kerning_pairs_list_button_release));
732     create_kerning_pairs_popup_menu(_KerningPairsList, sigc::mem_fun(*this, &SvgFontsDialog::remove_selected_kerning_pair));
734 //Kerning Setup:
735     kerning_vbox.add(*Gtk::manage(new Gtk::Label(_("Kerning Setup"))));
736     Gtk::HBox* kerning_selector = Gtk::manage(new Gtk::HBox());
737     kerning_selector->add(*Gtk::manage(new Gtk::Label(_("1st Glyph:"))));
738     kerning_selector->add(first_glyph);
739     kerning_selector->add(*Gtk::manage(new Gtk::Label(_("2nd Glyph:"))));
740     kerning_selector->add(second_glyph);
741     kerning_selector->add(add_kernpair_button);
742     add_kernpair_button.set_label(_("Add pair"));
743     add_kernpair_button.signal_clicked().connect(sigc::mem_fun(*this, &SvgFontsDialog::add_kerning_pair));
744     _KerningPairsList.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::on_kerning_pair_selection_changed));
745     kerning_slider.signal_value_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::on_kerning_value_changed));
747     kerning_vbox.pack_start(*kerning_selector, false,false);
749     kerning_vbox.add(_KerningPairsListScroller);
750     _KerningPairsListScroller.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_ALWAYS);
751     _KerningPairsListScroller.add(_KerningPairsList);
752     _KerningPairsListStore = Gtk::ListStore::create(_KerningPairsListColumns);
753     _KerningPairsList.set_model(_KerningPairsListStore);
754     _KerningPairsList.append_column(_("First Unicode range"), _KerningPairsListColumns.first_glyph);
755     _KerningPairsList.append_column(_("Second Unicode range"), _KerningPairsListColumns.second_glyph);
756 //    _KerningPairsList.append_column_numeric_editable(_("Kerning Value"), _KerningPairsListColumns.kerning_value, "%f");
758     kerning_vbox.add((Gtk::Widget&) kerning_preview);
760     Gtk::HBox* kerning_amount_hbox = Gtk::manage(new Gtk::HBox());
761     kerning_vbox.pack_start(*kerning_amount_hbox, false,false);
762     kerning_amount_hbox->add(*Gtk::manage(new Gtk::Label(_("Kerning value:"))));
763     kerning_amount_hbox->add(kerning_slider);
765     kerning_preview.set_size(300 + 20, 150 + 20);
766     _font_da.set_size(150 + 20, 50 + 20);
768     return &kerning_vbox;
771 SPFont *new_font(SPDocument *document)
773     g_return_val_if_fail(document != NULL, NULL);
775     SPDefs *defs = (SPDefs *) SP_DOCUMENT_DEFS(document);
777     Inkscape::XML::Document *xml_doc = sp_document_repr_doc(document);
779     // create a new font
780     Inkscape::XML::Node *repr;
781     repr = xml_doc->createElement("svg:font");
783     //By default, set the horizontal advance to 1024 units
784     repr->setAttribute("horiz-adv-x", "1024");
786     // Append the new font node to defs
787     SP_OBJECT_REPR(defs)->appendChild(repr);
789     //create a missing glyph
790     Inkscape::XML::Node *fontface;
791     fontface = xml_doc->createElement("svg:font-face");
792     fontface->setAttribute("units-per-em", "1024");
793     repr->appendChild(fontface);
795     //create a missing glyph
796     Inkscape::XML::Node *mg;
797     mg = xml_doc->createElement("svg:missing-glyph");
798     mg->setAttribute("d", "M0,0h1000v1024h-1000z");
799     repr->appendChild(mg);
801     // get corresponding object
802     SPFont *f = SP_FONT( document->getObjectByRepr(repr) );
804     g_assert(f != NULL);
805     g_assert(SP_IS_FONT(f));
806     Inkscape::GC::release(mg);
807     Inkscape::GC::release(repr);
808     return f;
811 void set_font_family(SPFont* font, char* str){
812     if (!font) return;
813     SPObject* obj;
814     for (obj=font->children; obj; obj=obj->next){
815         if (SP_IS_FONTFACE(obj)){
816             obj->repr->setAttribute("font-family", str);
817         }
818     }
820     sp_document_done(font->document, SP_VERB_DIALOG_SVG_FONTS, _("Set font family"));
823 void SvgFontsDialog::add_font(){
824     SPDocument* doc = sp_desktop_document(this->getDesktop());
825     SPFont* font = new_font(doc);
827     const int count = _model->children().size();
828     std::ostringstream os, os2;
829     os << _("font") << " " << count;
830     font->setLabel(os.str().c_str());
832     os2 << "SVGFont " << count;
833     SPObject* obj;
834     for (obj=font->children; obj; obj=obj->next){
835         if (SP_IS_FONTFACE(obj)){
836             obj->repr->setAttribute("font-family", os2.str().c_str());
837         }
838     }
840     update_fonts();
841 //    select_font(font);
843     sp_document_done(doc, SP_VERB_DIALOG_SVG_FONTS, _("Add font"));
846 SvgFontsDialog::SvgFontsDialog()
847  : UI::Widget::Panel("", "/dialogs/svgfonts", SP_VERB_DIALOG_SVG_FONTS), _add(Gtk::Stock::NEW)
849     _add.signal_clicked().connect(sigc::mem_fun(*this, &SvgFontsDialog::add_font));
851     Gtk::HBox* hbox = Gtk::manage(new Gtk::HBox());
852     Gtk::VBox* vbox = Gtk::manage(new Gtk::VBox());
854     vbox->pack_start(_FontsList);
855     vbox->pack_start(_add, false, false);
856     hbox->add(*vbox);
857     hbox->add(_font_settings);
858     _getContents()->add(*hbox);
860 //List of SVGFonts declared in a document:
861     _model = Gtk::ListStore::create(_columns);
862     _FontsList.set_model(_model);
863     _FontsList.append_column_editable(_("_Font"), _columns.label);
864     _FontsList.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::on_font_selection_changed));
866     this->update_fonts();
868     Gtk::Notebook *tabs = Gtk::manage(new Gtk::Notebook());
869     tabs->set_scrollable();
871     tabs->append_page(*global_settings_tab(), _("_Global Settings"), true);
872     tabs->append_page(*glyphs_tab(), _("_Glyphs"), true);
873     tabs->append_page(*kerning_tab(), _("_Kerning"), true);
875     _font_settings.add(*tabs);
877 //Text Preview:
878     _preview_entry.signal_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::on_preview_text_changed));
879     _getContents()->add((Gtk::Widget&) _font_da);
880     _preview_entry.set_text(_("Sample Text"));
881     _font_da.set_text(_("Sample Text"));
883     Gtk::HBox* preview_entry_hbox = Gtk::manage(new Gtk::HBox());
884     _getContents()->add(*preview_entry_hbox);
885     preview_entry_hbox->add(*Gtk::manage(new Gtk::Label(_("Preview Text:"))));
886     preview_entry_hbox->add(_preview_entry);
888     _FontsList.signal_button_release_event().connect_notify(sigc::mem_fun(*this, &SvgFontsDialog::fonts_list_button_release));
889     create_fonts_popup_menu(_FontsList, sigc::mem_fun(*this, &SvgFontsDialog::remove_selected_font));
891     _defs_observer.set(SP_DOCUMENT_DEFS(sp_desktop_document(this->getDesktop())));
892     _defs_observer.signal_changed().connect(sigc::mem_fun(*this, &SvgFontsDialog::update_fonts));
894     _getContents()->show_all();
897 SvgFontsDialog::~SvgFontsDialog(){}
899 } // namespace Dialog
900 } // namespace UI
901 } // namespace Inkscape
903 #endif //#ifdef ENABLE_SVG_FONTS
905 /*
906   Local Variables:
907   mode:c++
908   c-file-style:"stroustrup"
909   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
910   indent-tabs-mode:nil
911   fill-column:99
912   End:
913 */
914 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :