summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTavmjong Bah <tavmjong@free.fr>2017-08-05 15:54:12 +0000
committerTavmjong Bah <tavmjong@free.fr>2017-08-05 15:54:12 +0000
commit47865cbb214252f72f9b89a0422fab263b4f1263 (patch)
tree04a84df643e42fa98062cc485979f40ccad8bfa5 /src
parentMerge branch 'feature_hslInDegrees' of gitlab.com:RomanHargrave/inkscape (diff)
downloadinkscape-47865cbb214252f72f9b89a0422fab263b4f1263.tar.gz
inkscape-47865cbb214252f72f9b89a0422fab263b4f1263.zip
Add GUI and code to implement "Line Spacing Modes".
Selecting a Line Spacing Mode allows a user to quickly pick an algorithm for consistant line spacing.
Diffstat (limited to 'src')
-rw-r--r--src/style.cpp20
-rw-r--r--src/style.h6
-rw-r--r--src/widgets/text-toolbar.cpp287
-rw-r--r--src/xml/repr-css.cpp11
-rw-r--r--src/xml/repr.h2
5 files changed, 315 insertions, 11 deletions
diff --git a/src/style.cpp b/src/style.cpp
index ba6fd5f58..36d669301 100644
--- a/src/style.cpp
+++ b/src/style.cpp
@@ -53,8 +53,6 @@ using std::vector;
#define BMAX 8192
-#define SP_CSS_FONT_SIZE_DEFAULT 12.0;
-
struct SPStyleEnum;
int SPStyle::_count = 0;
@@ -1542,9 +1540,15 @@ sp_style_get_css_unit_string(int unit)
* Convert a size in pixels into another CSS unit size
*/
double
-sp_style_css_size_px_to_units(double size, int unit)
+sp_style_css_size_px_to_units(double size, int unit, double font_size)
{
double unit_size = size;
+
+ if (font_size == 0) {
+ g_warning("sp_style_get_css_font_size_units: passed in zero font_size");
+ font_size = SP_CSS_FONT_SIZE_DEFAULT;
+ }
+
switch (unit) {
case SP_CSS_UNIT_NONE: unit_size = size; break;
@@ -1554,9 +1558,9 @@ sp_style_css_size_px_to_units(double size, int unit)
case SP_CSS_UNIT_MM: unit_size = Inkscape::Util::Quantity::convert(size, "px", "mm"); break;
case SP_CSS_UNIT_CM: unit_size = Inkscape::Util::Quantity::convert(size, "px", "cm"); break;
case SP_CSS_UNIT_IN: unit_size = Inkscape::Util::Quantity::convert(size, "px", "in"); break;
- case SP_CSS_UNIT_EM: unit_size = size / SP_CSS_FONT_SIZE_DEFAULT; break;
- case SP_CSS_UNIT_EX: unit_size = size * 2.0 / SP_CSS_FONT_SIZE_DEFAULT ; break;
- case SP_CSS_UNIT_PERCENT: unit_size = size * 100.0 / SP_CSS_FONT_SIZE_DEFAULT; break;
+ case SP_CSS_UNIT_EM: unit_size = size / font_size; break;
+ case SP_CSS_UNIT_EX: unit_size = size * 2.0 / font_size ; break;
+ case SP_CSS_UNIT_PERCENT: unit_size = size * 100.0 / font_size; break;
default:
g_warning("sp_style_get_css_font_size_units conversion to %d not implemented.", unit);
@@ -1571,13 +1575,13 @@ sp_style_css_size_px_to_units(double size, int unit)
* Convert a size in a CSS unit size to pixels
*/
double
-sp_style_css_size_units_to_px(double size, int unit)
+sp_style_css_size_units_to_px(double size, int unit, double font_size)
{
if (unit == SP_CSS_UNIT_PX) {
return size;
}
//g_message("sp_style_css_size_units_to_px %f %d = %f px", size, unit, out);
- return size * (size / sp_style_css_size_px_to_units(size, unit));;
+ return size * (size / sp_style_css_size_px_to_units(size, unit, font_size));;
}
diff --git a/src/style.h b/src/style.h
index fc50c3580..85d07b9ef 100644
--- a/src/style.h
+++ b/src/style.h
@@ -327,8 +327,10 @@ SPStyle *sp_style_unref(SPStyle *style); // SPStyle::unref();
void sp_style_set_to_uri_string (SPStyle *style, bool isfill, const char *uri); // ?
char const *sp_style_get_css_unit_string(int unit); // No change?
-double sp_style_css_size_px_to_units(double size, int unit); // No change?
-double sp_style_css_size_units_to_px(double size, int unit); // No change?
+
+#define SP_CSS_FONT_SIZE_DEFAULT 12.0
+double sp_style_css_size_px_to_units(double size, int unit, double font_size = SP_CSS_FONT_SIZE_DEFAULT); // No change?
+double sp_style_css_size_units_to_px(double size, int unit, double font_size = SP_CSS_FONT_SIZE_DEFAULT); // No change?
SPCSSAttr *sp_css_attr_from_style (SPStyle const *const style, unsigned int flags);
diff --git a/src/widgets/text-toolbar.cpp b/src/widgets/text-toolbar.cpp
index 0c0e75ad0..0cd083432 100644
--- a/src/widgets/text-toolbar.cpp
+++ b/src/widgets/text-toolbar.cpp
@@ -46,6 +46,8 @@
#include "sp-flowtext.h"
#include "sp-root.h"
#include "sp-text.h"
+#include "sp-tspan.h"
+#include "sp-flowdiv.h"
#include "style.h"
#include "svg/css-ostringstream.h"
#include "text-editing.h"
@@ -847,6 +849,169 @@ static void sp_text_lineheight_unit_changed( gpointer /* */, GObject *tbl )
g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
}
+// Set property for object, but unset all descendents
+// Should probably be moved to desktop_style.cpp
+static void recursively_set_properties( SPObject* object, SPCSSAttr *css ) {
+ object->changeCSS (css, "style");
+
+ SPCSSAttr *css_unset = sp_repr_css_attr_unset_all( css );
+ std::vector<SPObject *> children = object->childList(false);
+ for (auto i: children) {
+ recursively_set_properties (i, css_unset);
+ }
+ sp_repr_css_attr_unref (css_unset);
+}
+
+//
+static void sp_text_line_spacing_mode_changed( GObject *tbl, int mode )
+{
+
+ // quit if run by the _changed callbacks
+ if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
+ return;
+ }
+ g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
+
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ prefs->setInt("/tools/text/line_spacing_mode", mode);
+
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+
+ // Note: only <text> and <flowRoot> text elements are in selection!
+ // (No need to worry about <tspan>, <flowPara>, ...)
+ Inkscape::Selection *selection = desktop->getSelection();
+ std::vector<SPItem *> vec(selection->items().begin(), selection->items().end());
+
+ for (auto i: vec) {
+
+ // Only <text> and <flowRoot>, <flowRoot> => SPFlowtext
+ if (dynamic_cast<SPText*>(i) || dynamic_cast<SPFlowtext*>(i)) {
+ SPStyle* text_style = i->style;
+
+ // Make list of <tspan>, <flowPara>, <flowSpan> children
+ std::vector<SPObject *> children = i->childList(false);
+ std::vector<SPItem *> children_item;
+ for (auto j: children) {
+ if (dynamic_cast<SPItem *>(j)) {
+ children_item.push_back( dynamic_cast<SPItem *>(j) );
+ }
+ }
+
+ SPStyle tspans; // Also flowPara/flowSpan
+ int result_numbers = sp_desktop_query_style_from_list (children_item, &tspans, QUERY_STYLE_PROPERTY_FONTNUMBERS);
+
+ Inkscape::CSSOStringStream osfs;
+ if (text_style->line_height.computed != 0 || text_style->line_height.normal) {
+
+ if (mode != 1 || text_style->line_height.unit == SP_CSS_UNIT_NONE || text_style->line_height.normal) {
+ Glib::ustring line_height_string = text_style->line_height.write( SP_STYLE_FLAG_ALWAYS );
+ line_height_string.erase(0, 12); // erase 'line-height:'
+ osfs << line_height_string;
+ } else {
+ // Convert to unitless value
+ double line_height_value = text_style->line_height.value;
+ // Percent values are stored as value/100;
+ if (text_style->line_height.unit == SP_CSS_UNIT_PERCENT) {
+ line_height_value *= 100;
+ }
+ osfs << sp_style_css_size_units_to_px( line_height_value,
+ text_style->line_height.unit,
+ text_style->font_size.computed) /
+ text_style->font_size.computed;
+ }
+
+ } else {
+
+ if (mode != 1 || tspans.line_height.unit == SP_CSS_UNIT_NONE || tspans.line_height.normal) {
+ Glib::ustring line_height_string = tspans.line_height.write( SP_STYLE_FLAG_ALWAYS );
+ line_height_string.erase(0, 12); // erase 'line-height:'
+ osfs << line_height_string;
+ } else {
+ // Convert to unitless value
+ double line_height_value = tspans.line_height.value;
+ // Percent values are stored as value/100;
+ if (tspans.line_height.unit == SP_CSS_UNIT_PERCENT) {
+ line_height_value *= 100;
+ }
+ osfs << sp_style_css_size_units_to_px( line_height_value,
+ tspans.line_height.unit,
+ tspans.font_size.computed) /
+ tspans.font_size.computed;
+ }
+ }
+
+ SPCSSAttr *css_text = sp_repr_css_attr_new();
+ SPCSSAttr *css_tspan = sp_repr_css_attr_new();
+
+ sp_repr_css_set_property (css_text, "line-height", osfs.str().c_str());
+
+ switch (mode) {
+ case 0: // Adaptive
+ // <text>: Zero text
+ sp_repr_css_set_property (css_text, "line-height", "0");
+ // <tspan>: Old text value.
+ sp_repr_css_set_property (css_tspan, "line-height", osfs.str().c_str());
+ break;
+
+ case 1: // Minimum
+ // <text>: Set to old text (unitless) or if old text zero, set to old tspan.
+ sp_repr_css_set_property (css_text, "line-height", osfs.str().c_str());
+ // <tspan>: Unset
+ sp_repr_css_unset_property (css_tspan, "line-height");
+ break;
+
+ case 2: // Even
+ // <text>: Set to old text or if old text zero, set to old tspan.
+ sp_repr_css_set_property (css_text, "line-height", osfs.str().c_str());
+ // <tspan>: Set to zero
+ sp_repr_css_set_property (css_tspan, "line-height", "0");
+ break;
+
+ case 3: // Adjustable
+ // Do nothing ☠
+ break;
+ }
+
+ if (mode != 3) {
+ i->changeCSS (css_text, "style");
+ for (auto j: children) {
+ recursively_set_properties (j, css_tspan);
+ //j->changeCSS (css_tspan, "style");
+ }
+ }
+
+ sp_repr_css_attr_unref (css_text);
+ sp_repr_css_attr_unref (css_tspan);
+ }
+ }
+
+ // Set "Outer Style" toggle to match mode.
+ InkToggleAction* outerStyle = INK_TOGGLE_ACTION(g_object_get_data (tbl, "TextOuterStyleAction"));
+
+ switch (mode) {
+ case 0: // Adaptive
+ gtk_toggle_action_set_active( &(outerStyle->action), false );
+ prefs->setInt("/tools/text/outer_style", false);
+ break;
+
+ case 1: // Minimum
+ case 2: // Even
+ gtk_toggle_action_set_active( &(outerStyle->action), true );
+ prefs->setInt("/tools/text/outer_style", true);
+ break;
+
+ case 3: // Adjustable
+ break;
+ }
+
+ // Update widgets to reflect new state of Text Outer Style button.
+ sp_text_toolbox_selection_changed( NULL, tbl );
+
+ DocumentUndo::done(desktop->getDocument(), SP_VERB_CONTEXT_TEXT,
+ _("Text: Change line spacing mode"));
+
+ g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
+}
static void sp_text_wordspacing_value_changed( GtkAdjustment *adj, GObject *tbl )
{
@@ -1478,6 +1643,79 @@ static void sp_text_toolbox_selection_changed(Inkscape::Selection */*selection*/
gtk_action_set_sensitive(GTK_ACTION(lineHeightUnset), query.line_height.set );
gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(lineHeightUnset), query.line_height.set );
+
+ // Line spacing mode: requires calculating mode for each <text> element and the <tspan>s within.
+ Inkscape::Selection *selection = desktop->getSelection();
+ std::vector<SPItem *> vec(selection->items().begin(), selection->items().end());
+ int mode[4] = {0, 0, 0, 0};
+ for (auto i: vec) {
+ if (dynamic_cast<SPText*>(i) || dynamic_cast<SPFlowtext*>(i) ) {
+ bool text_line_height_set = false;
+ bool text_line_height_zero = false;
+ bool text_line_height_has_units = false;
+ bool tspan_line_height_all_unset = true;
+ bool tspan_line_height_all_zero = true;
+ bool tspan_line_height_all_non_zero = true;
+ if (i->style && i->style->line_height.set) {
+ text_line_height_set = true;
+ if (i->style->line_height.computed == 0 && !(i->style->line_height.normal)) {
+ text_line_height_zero = true;
+ }
+ if (i->style->line_height.unit != SP_CSS_UNIT_NONE && !(i->style->line_height.normal)) {
+ text_line_height_has_units = true;
+ }
+ }
+ // TO DO: recursively check children
+ std::vector<SPObject*> children = i->childList(false);
+ for (auto j: children) {
+ if (dynamic_cast<SPTSpan*>(j) || dynamic_cast<SPFlowpara*>(j) || dynamic_cast<SPFlowtspan*>(j) ) {
+ if (j->style && j->style->line_height.set) {
+ tspan_line_height_all_unset = false;
+ if (j->style->line_height.computed != 0 || j->style->line_height.normal) {
+ tspan_line_height_all_zero = false;
+ } else {
+ tspan_line_height_all_non_zero = false;
+ }
+ }
+ }
+ }
+
+ if ( text_line_height_zero && tspan_line_height_all_non_zero) mode[0]++;
+ else if (!text_line_height_has_units && tspan_line_height_all_unset) mode[1]++;
+ else if ( text_line_height_has_units && tspan_line_height_all_unset) mode[3]++;
+ else if ( tspan_line_height_all_zero ) mode[2]++;
+ else mode[3]++;
+ }
+ }
+
+ int activeButtonLS = 3;
+ if (mode[0] > 0 && mode[1] == 0 && mode[2] == 0 && mode[3] == 0) activeButtonLS = 0;
+ if (mode[0] == 0 && mode[1] > 0 && mode[2] == 0 && mode[3] == 0) activeButtonLS = 1;
+ if (mode[0] == 0 && mode[1] == 0 && mode[2] > 0 && mode[3] == 0) activeButtonLS = 2;
+
+ InkSelectOneAction* textLineSpacingAction =
+ static_cast<InkSelectOneAction*>( g_object_get_data( tbl, "TextLineSpacingAction" ) );
+ textLineSpacingAction->set_active( activeButtonLS );
+
+ // Enable/disable line height widget based on mode and Outer Style toggle.
+ if ( (activeButtonLS == 0 && outer) || // Adaptive
+ (activeButtonLS == 1 && !outer) || // Minimum
+ (activeButtonLS == 2 && !outer) // Even
+ ) {
+ gtk_action_set_sensitive (lineHeightAction, false);
+ } else {
+ gtk_action_set_sensitive (lineHeightAction, true);
+ }
+
+ // In Minimum mode, don't allow unit change (must remain unitless).
+ GtkAction* textLineHeightUnitsAction =
+ static_cast<GtkAction*>(g_object_get_data( tbl, "TextLineHeightUnitsAction") );
+ if (activeButtonLS == 1 && outer) {
+ gtk_action_set_sensitive (textLineHeightUnitsAction, false);
+ } else {
+ gtk_action_set_sensitive (textLineHeightUnitsAction, true);
+ }
+
// Word spacing
double wordSpacing;
if (query.word_spacing.normal) wordSpacing = 0.0;
@@ -2020,6 +2258,55 @@ void sp_text_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObje
GtkAction* act = tracker->createAction( "TextLineHeightUnitsAction", _("Units"), ("") );
gtk_action_group_add_action( mainActions, act );
g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_text_lineheight_unit_changed), holder );
+ g_object_set_data( holder, "TextLineHeightUnitsAction", act );
+ }
+
+ /* Line spacing mode */
+ {
+ InkSelectOneActionColumns columns;
+
+ Glib::RefPtr<Gtk::ListStore> store = Gtk::ListStore::create(columns);
+
+ Gtk::TreeModel::Row row;
+
+ row = *(store->append());
+ row[columns.col_label ] = _("Adaptive");
+ row[columns.col_tooltip ] = _("Line spacing adapts to font size.");
+ row[columns.col_icon ] = INKSCAPE_ICON("text_line_spacing");
+ row[columns.col_sensitive] = true;
+
+ row = *(store->append());
+ row[columns.col_label ] = _("Minimum");
+ row[columns.col_tooltip ] = _("Line spacing adapts to fonts size with set minimum spacing.");
+ row[columns.col_icon ] = INKSCAPE_ICON("text_line_spacing");
+ row[columns.col_sensitive] = true;
+ row = *(store->append());
+ row[columns.col_label ] = _("Even");
+ row[columns.col_tooltip ] = _("Lines evenly spaced.");
+ row[columns.col_icon ] = INKSCAPE_ICON("text_line_spacing");
+ row[columns.col_sensitive] = true;
+
+ row = *(store->append());
+ row[columns.col_label ] = _("Adjustable ☠");
+ row[columns.col_tooltip ] = _("Line spacing fully adjustable");
+ row[columns.col_icon ] = INKSCAPE_ICON("text_line_spacing");
+ row[columns.col_sensitive] = true;
+
+ InkSelectOneAction* act =
+ InkSelectOneAction::create( "TextLineSpacingAction", // Name
+ _("Line Spacing Mode"), // Label
+ _("How should multiple lines be spaced."), // Tooltip
+ "Not Used", // Icon
+ store ); // Tree store
+ act->use_radio( false );
+ act->use_label( true );
+ gint mode = prefs->getInt("/tools/text/line_spacing_mode", 0);
+ act->set_active( mode );
+
+ gtk_action_group_add_action( mainActions, GTK_ACTION( act->gobj() ));
+ g_object_set_data( holder, "TextLineSpacingAction", act );
+
+ act->signal_changed().connect(sigc::bind<0>(sigc::ptr_fun(&sp_text_line_spacing_mode_changed), holder));
}
/* Word spacing */
diff --git a/src/xml/repr-css.cpp b/src/xml/repr-css.cpp
index 9590fa97f..2970c1da5 100644
--- a/src/xml/repr-css.cpp
+++ b/src/xml/repr-css.cpp
@@ -466,6 +466,17 @@ void sp_repr_css_change_recursive(Node *repr, SPCSSAttr *css, gchar const *attr)
}
}
+/**
+ * Return a new SPCSSAttr with all the properties found in the input SPCSSAttr unset.
+ */
+SPCSSAttr* sp_repr_css_attr_unset_all(SPCSSAttr *css)
+{
+ SPCSSAttr* css_unset = sp_repr_css_attr_new();
+ for ( List<AttributeRecord const> iter = css->attributeList() ; iter ; ++iter ) {
+ sp_repr_css_set_property (css_unset, g_quark_to_string(iter->key), "inkscape:unset");
+ }
+ return css_unset;
+}
/*
Local Variables:
diff --git a/src/xml/repr.h b/src/xml/repr.h
index e84b89813..ecc5c02a6 100644
--- a/src/xml/repr.h
+++ b/src/xml/repr.h
@@ -80,6 +80,7 @@ void sp_repr_css_attr_unref(SPCSSAttr *css);
SPCSSAttr *sp_repr_css_attr(Inkscape::XML::Node *repr, char const *attr);
SPCSSAttr *sp_repr_css_attr_parse_color_to_fill(const Glib::ustring &text);
SPCSSAttr *sp_repr_css_attr_inherited(Inkscape::XML::Node *repr, char const *attr);
+SPCSSAttr *sp_repr_css_attr_unset_all(SPCSSAttr *css);
char const *sp_repr_css_property(SPCSSAttr *css, char const *name, char const *defval);
void sp_repr_css_set_property(SPCSSAttr *css, char const *name, char const *value);
@@ -93,7 +94,6 @@ void sp_repr_css_merge(SPCSSAttr *dst, SPCSSAttr *src);
void sp_repr_css_attr_add_from_string(SPCSSAttr *css, const char *data);
void sp_repr_css_change(Inkscape::XML::Node *repr, SPCSSAttr *css, char const *key);
void sp_repr_css_change_recursive(Inkscape::XML::Node *repr, SPCSSAttr *css, char const *key);
-
void sp_repr_css_print(SPCSSAttr *css);
/* Utility finctions */