[glabels/vala] Added image object support.
- From: Jim Evins <jimevins src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glabels/vala] Added image object support.
- Date: Sun, 26 Aug 2012 15:54:32 +0000 (UTC)
commit 843e9e53bb083f8b40dac8ac19d4e4eb6c1ddc50
Author: Jim Evins <evins snaught com>
Date: Sun Aug 26 11:52:58 2012 -0400
Added image object support.
configure.ac | 2 +
data/ui/object_editor.ui | 169 ++++++++++++++--
glabels/Makefile.am | 6 +
glabels/TMP_gdk_key.vala | 19 --
glabels/TMP_gdk_pixdata.vapi | 4 +
glabels/field_button.vala | 1 +
glabels/label.vala | 25 ++-
glabels/label_object.vala | 6 +
glabels/label_object_box.vala | 7 +
glabels/label_object_ellipse.vala | 7 +
glabels/label_object_image.vala | 401 +++++++++++++++++++++++++++++++++++++
glabels/label_object_line.vala | 7 +
glabels/label_object_text.vala | 7 +
glabels/object_editor.vala | 120 +++++++++++
glabels/pixbuf_cache.vala | 125 ++++++++++++
glabels/pixmaps.vapi | 13 ++
glabels/pixmaps/checkerboard.xpm | 29 +++
glabels/svg_cache.vala | 191 ++++++++++++++++++
glabels/ui.vala | 21 +--
glabels/view.vala | 28 +++-
glabels/xml_label.vala | 281 ++++++++++++++++++++++++--
21 files changed, 1390 insertions(+), 79 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 629f957..12ac679 100644
--- a/configure.ac
+++ b/configure.ac
@@ -75,6 +75,7 @@ LIBXML_REQUIRED=2.7.8
GEE_REQUIRED=0.6.2.1
CAIRO_REQUIRED=1.10.2
GDK_PIXBUF_REQUIRED=2.24.0
+LIBRSVG_REQUIRED=2.36.0
PKG_CHECK_MODULES(GLABELS, [\
glib-2.0 >= $GLIB_REQUIRED \
@@ -82,6 +83,7 @@ PKG_CHECK_MODULES(GLABELS, [\
gtk+-3.0 >= $GTK_REQUIRED \
libxml-2.0 >= $LIBXML_REQUIRED \
gee-1.0 >= $GEE_REQUIRED \
+ librsvg-2.0 > $LIBRSVG_REQUIRED \
])
AC_SUBST(GLABELS_CFLAGS)
diff --git a/data/ui/object_editor.ui b/data/ui/object_editor.ui
index 9489c0a..768e4f4 100644
--- a/data/ui/object_editor.ui
+++ b/data/ui/object_editor.ui
@@ -8,18 +8,16 @@
<property name="step_increment">0.5</property>
<property name="page_increment">10</property>
</object>
+ <object class="GtkAdjustment" id="line_angle_adjustment">
+ <property name="upper">360</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
<object class="GtkAdjustment" id="line_length_adjustment">
<property name="upper">100</property>
<property name="step_increment">0.01</property>
<property name="page_increment">1</property>
</object>
- <object class="GtkAdjustment" id="line_width_adjustment">
- <property name="lower">0.25</property>
- <property name="upper">10</property>
- <property name="value">1</property>
- <property name="step_increment">0.25</property>
- <property name="page_increment">1</property>
- </object>
<object class="GtkAdjustment" id="line_spacing_adjustment">
<property name="lower">1</property>
<property name="upper">5</property>
@@ -27,6 +25,13 @@
<property name="step_increment">0.10000000000000001</property>
<property name="page_increment">10</property>
</object>
+ <object class="GtkAdjustment" id="line_width_adjustment">
+ <property name="lower">0.25</property>
+ <property name="upper">10</property>
+ <property name="value">1</property>
+ <property name="step_increment">0.25</property>
+ <property name="page_increment">1</property>
+ </object>
<object class="GtkAdjustment" id="shadow_opacity_adjustment">
<property name="upper">100</property>
<property name="value">1</property>
@@ -760,6 +765,139 @@
</packing>
</child>
<child>
+ <object class="GtkBox" id="image_page_box">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">start</property>
+ <property name="border_width">6</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkFrame" id="frame2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">start</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkAlignment" id="alignment10">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkGrid" id="grid9">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">start</property>
+ <property name="hexpand">True</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+ <child>
+ <object class="GtkRadioButton" id="image_file_radio">
+ <property name="label" translatable="yes">File:</property>
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_action_appearance">False</property>
+ <property name="xalign">0</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="image_key_radio">
+ <property name="label" translatable="yes">Key:</property>
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_action_appearance">False</property>
+ <property name="xalign">0</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">image_file_radio</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFileChooserButton" id="image_filebutton">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="orientation">vertical</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="image_key_box">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label18">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes"><b>File</b></property>
+ <property name="use_markup">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label13">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Image</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
<object class="GtkBox" id="line_fill_page_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
@@ -948,7 +1086,7 @@
</child>
</object>
<packing>
- <property name="position">1</property>
+ <property name="position">2</property>
</packing>
</child>
<child type="tab">
@@ -959,7 +1097,7 @@
<property name="label" translatable="yes">Line/Fill</property>
</object>
<packing>
- <property name="position">1</property>
+ <property name="position">2</property>
<property name="tab_fill">False</property>
</packing>
</child>
@@ -1405,7 +1543,7 @@
</child>
</object>
<packing>
- <property name="position">2</property>
+ <property name="position">3</property>
</packing>
</child>
<child type="tab">
@@ -1416,7 +1554,7 @@
<property name="label" translatable="yes">Position/Size</property>
</object>
<packing>
- <property name="position">2</property>
+ <property name="position">3</property>
<property name="tab_fill">False</property>
</packing>
</child>
@@ -1637,7 +1775,7 @@
</child>
</object>
<packing>
- <property name="position">3</property>
+ <property name="position">4</property>
<property name="tab_fill">False</property>
</packing>
</child>
@@ -1649,7 +1787,7 @@
<property name="label" translatable="yes">Shadow</property>
</object>
<packing>
- <property name="position">3</property>
+ <property name="position">4</property>
<property name="tab_fill">False</property>
</packing>
</child>
@@ -1687,11 +1825,6 @@
<widget name="label46"/>
</widgets>
</object>
- <object class="GtkAdjustment" id="line_angle_adjustment">
- <property name="upper">360</property>
- <property name="step_increment">1</property>
- <property name="page_increment">10</property>
- </object>
<object class="GtkSizeGroup" id="page_sizegroup">
<property name="mode">both</property>
<widgets>
diff --git a/glabels/Makefile.am b/glabels/Makefile.am
index 1cf97ae..ad12464 100644
--- a/glabels/Makefile.am
+++ b/glabels/Makefile.am
@@ -7,6 +7,7 @@ SUBDIRS = \
bin_PROGRAMS = glabels-4
glabels_4_SOURCES = \
+ TMP_gdk_pixdata.vapi \
glabels.vala \
color.vala \
color_button.vala \
@@ -34,6 +35,7 @@ glabels_4_SOURCES = \
label_object.vala \
label_object_box.vala \
label_object_ellipse.vala \
+ label_object_image.vala \
label_object_line.vala \
label_object_shape.vala \
label_object_text.vala \
@@ -54,10 +56,13 @@ glabels_4_SOURCES = \
new_label_dialog.vala \
object_editor.vala \
outline.vala \
+ pixbuf_cache.vala \
+ pixmaps.vapi \
prefs.vala \
print_op.vala \
print_op_dialog.vala \
property_editor.vala \
+ svg_cache.vala \
template_history.vala \
text_line.vala \
text_lines.vala \
@@ -88,6 +93,7 @@ VALAFLAGS = \
--pkg gtk+-3.0 \
--pkg libxml-2.0 \
--pkg gee-1.0 \
+ --pkg librsvg-2.0 \
--pkg libglabels-4 \
$(NULL)
diff --git a/glabels/TMP_gdk_pixdata.vapi b/glabels/TMP_gdk_pixdata.vapi
new file mode 100644
index 0000000..860b701
--- /dev/null
+++ b/glabels/TMP_gdk_pixdata.vapi
@@ -0,0 +1,4 @@
+namespace Gdk {
+ [CCode (cheader_filename = "gdk-pixbuf/gdk-pixdata.h", cprefix = "gdk_")]
+ public void pixdata_from_pixbuf( out Gdk.Pixdata pixdata, Gdk.Pixbuf pixbuf, bool use_rle = false );
+}
diff --git a/glabels/field_button.vala b/glabels/field_button.vala
index f3c7e35..ce77bc5 100644
--- a/glabels/field_button.vala
+++ b/glabels/field_button.vala
@@ -55,6 +55,7 @@ namespace glabels
}
else
{
+ klabel.set_text( _("(None)") );
klabel_is_key = true;
}
diff --git a/glabels/label.vala b/glabels/label.vala
index fdbbce7..0a46a06 100644
--- a/glabels/label.vala
+++ b/glabels/label.vala
@@ -41,18 +41,8 @@ namespace glabels
public unowned List<LabelObject> object_list { get; private set; }
-
- private TemplateHistory template_history;
-
- private static int untitled_count;
- private int untitled_instance;
-
- private bool selection_op_flag;
- private bool delayed_change_flag;
-
-
- // TODO: Pixbuf cache
- // TODO: SVG cache
+ public PixbufCache pixbuf_cache { get; private set; }
+ public SvgCache svg_cache { get; private set; }
/**
@@ -203,6 +193,14 @@ namespace glabels
public Color default_fill_color { get; set; }
+ private TemplateHistory template_history;
+
+ private static int untitled_count;
+ private int untitled_instance;
+
+ private bool selection_op_flag;
+ private bool delayed_change_flag;
+
public Label()
{
@@ -210,6 +208,9 @@ namespace glabels
template_history = new TemplateHistory( 5 );
+ pixbuf_cache = new PixbufCache();
+ svg_cache = new SvgCache();
+
// TODO: Set default properties from user prefs
}
diff --git a/glabels/label_object.vala b/glabels/label_object.vala
index 0cf6849..469fc86 100644
--- a/glabels/label_object.vala
+++ b/glabels/label_object.vala
@@ -156,6 +156,12 @@ namespace glabels
/**
+ * Image parameters interface
+ */
+ public virtual TextNode filename_node { get; set; }
+
+
+ /**
* Shape parameters interface
*/
public virtual double line_width { get; set; }
diff --git a/glabels/label_object_box.vala b/glabels/label_object_box.vala
index af1ca2f..eae8a23 100644
--- a/glabels/label_object_box.vala
+++ b/glabels/label_object_box.vala
@@ -27,6 +27,13 @@ namespace glabels
public class LabelObjectBox : LabelObjectShape
{
+ public LabelObjectBox.with_parent( Label parent )
+ {
+ this();
+ parent.add_object( this );
+ }
+
+
public override LabelObject dup()
{
LabelObjectBox copy = new LabelObjectBox();
diff --git a/glabels/label_object_ellipse.vala b/glabels/label_object_ellipse.vala
index 7a21ed0..1e883cd 100644
--- a/glabels/label_object_ellipse.vala
+++ b/glabels/label_object_ellipse.vala
@@ -30,6 +30,13 @@ namespace glabels
private const int ARC_FINE = 2;
+ public LabelObjectEllipse.with_parent( Label parent )
+ {
+ this();
+ parent.add_object( this );
+ }
+
+
public override LabelObject dup()
{
LabelObjectEllipse copy = new LabelObjectEllipse();
diff --git a/glabels/label_object_image.vala b/glabels/label_object_image.vala
new file mode 100644
index 0000000..2180211
--- /dev/null
+++ b/glabels/label_object_image.vala
@@ -0,0 +1,401 @@
+/* label_object_image.vala
+ *
+ * Copyright (C) 2012 Jim Evins <evins snaught com>
+ *
+ * This file is part of gLabels.
+ *
+ * gLabels is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * gLabels is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with gLabels. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+using GLib;
+
+namespace glabels
+{
+
+ public class LabelObjectImage : LabelObject
+ {
+ private const double MIN_IMAGE_SIZE = 1.0;
+
+ private enum FileType { NONE, PIXBUF, SVG }
+
+
+ private static Gdk.Pixbuf? default_pixbuf = null;
+
+
+ public LabelObjectImage.with_parent( Label parent )
+ {
+ this();
+ parent.add_object( this );
+ }
+
+
+ /**
+ * Filename
+ */
+ public override TextNode filename_node
+ {
+ get { return _filename_node; }
+
+ set
+ {
+ if ( (_filename_node == null) || !_filename_node.equal( value ) )
+ {
+ update_filename_node( value );
+ changed();
+ }
+ }
+ }
+ private TextNode _filename_node;
+
+
+ /**
+ * Width
+ */
+ public override double w
+ {
+ get { return base.w; }
+
+ set
+ {
+ if ( value < MIN_IMAGE_SIZE )
+ {
+ base.w = MIN_IMAGE_SIZE;
+ }
+ else
+ {
+ base.w = value;
+ }
+ }
+ }
+
+
+ /**
+ * Height
+ */
+ public override double h
+ {
+ get { return base.h; }
+
+ set
+ {
+ if ( value < MIN_IMAGE_SIZE )
+ {
+ base.h = MIN_IMAGE_SIZE;
+ }
+ else
+ {
+ base.h = value;
+ }
+ }
+ }
+
+
+ private FileType type;
+
+ private Gdk.Pixbuf? pixbuf;
+ private Rsvg.Handle? svg_handle;
+
+
+ public LabelObjectImage()
+ {
+ handles.append( new HandleSouthEast( this ) );
+ handles.append( new HandleSouthWest( this ) );
+ handles.append( new HandleNorthEast( this ) );
+ handles.append( new HandleNorthWest( this ) );
+ handles.append( new HandleEast( this ) );
+ handles.append( new HandleSouth( this ) );
+ handles.append( new HandleWest( this ) );
+ handles.append( new HandleNorth( this ) );
+
+ type = FileType.NONE;
+ pixbuf = null;
+ svg_handle = null;
+
+ if ( default_pixbuf == null )
+ {
+ Gdk.Pixbuf pixbuf = new Gdk.Pixbuf.from_xpm_data( Pixmaps.checkerboard_xpm );
+ default_pixbuf = pixbuf.scale_simple( 128, 128, Gdk.InterpType.NEAREST );
+ }
+ }
+
+
+ public override LabelObject dup()
+ {
+ LabelObjectImage copy = new LabelObjectImage();
+
+ copy.set_common_properties_from_object( this );
+
+ return copy;
+ }
+
+
+ public override void draw_object( Cairo.Context cr, bool in_editor, MergeRecord? record )
+ {
+ cr.save();
+
+ switch (type)
+ {
+
+ case FileType.PIXBUF:
+ double image_w = pixbuf.width;
+ double image_h = pixbuf.height;
+ cr.rectangle( 0, 0, w, h );
+ cr.scale( w/image_w, h/image_h );
+ Gdk.cairo_set_source_pixbuf( cr, pixbuf, 0, 0 );
+ cr.fill();
+ break;
+
+ case FileType.SVG:
+ double image_w = svg_handle.width;
+ double image_h = svg_handle.height;
+ cr.scale( w/image_w, h/image_h );
+ svg_handle.render_cairo( cr );
+ break;
+
+ default:
+ double image_w = default_pixbuf.width;
+ double image_h = default_pixbuf.height;
+ cr.rectangle( 0, 0, w, h );
+ cr.scale( w/image_w, h/image_h );
+ Gdk.cairo_set_source_pixbuf( cr, default_pixbuf, 0, 0 );
+ cr.fill();
+ break;
+
+ }
+
+ cr.restore();
+ }
+
+
+ public override void draw_shadow( Cairo.Context cr, bool in_editor, MergeRecord? record )
+ {
+ Color shadow_color = shadow_color_node.expand( record );
+ if ( shadow_color_node.field_flag && in_editor )
+ {
+ shadow_color = Color.black();
+ }
+ shadow_color.set_opacity( shadow_opacity );
+
+ cr.save();
+
+ switch (type)
+ {
+
+ case FileType.PIXBUF:
+ Gdk.Pixbuf shadow_pixbuf = shadow_pixbuf( pixbuf, shadow_color );
+ double image_w = shadow_pixbuf.width;
+ double image_h = shadow_pixbuf.height;
+ cr.rectangle( 0, 0, w, h );
+ cr.scale( w/image_w, h/image_h );
+ Gdk.cairo_set_source_pixbuf( cr, shadow_pixbuf, 0, 0 );
+ cr.fill();
+ break;
+
+ case FileType.SVG:
+ /* TODO: handle SVG shadows properly. */
+ cr.rectangle( 0, 0, w, h );
+ cr.set_source_rgba( shadow_color.r, shadow_color.g, shadow_color.b, shadow_color.a );
+ cr.fill();
+ break;
+
+ default:
+ cr.rectangle( 0, 0, w, h );
+ cr.set_source_rgba( shadow_color.r, shadow_color.g, shadow_color.b, shadow_color.a );
+ cr.fill();
+ break;
+
+ }
+
+ cr.restore();
+ }
+
+
+ public override bool is_object_located_at( Cairo.Context cr, double x, double y )
+ {
+ cr.new_path();
+ cr.rectangle( 0, 0, w, h );
+
+ if ( cr.in_fill( x, y ) )
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+
+ private void update_filename_node( TextNode new_node )
+ {
+ /* Remove reference to previous image. */
+ switch (type)
+ {
+ case FileType.NONE:
+ break;
+
+ case FileType.PIXBUF:
+ parent.pixbuf_cache.remove_pixbuf( _filename_node.data );
+ break;
+
+ case FileType.SVG:
+ parent.svg_cache.remove_svg( _filename_node.data );
+ break;
+
+ default:
+ assert_not_reached();
+ }
+
+ /* Update */
+ _filename_node = new_node;
+
+ /* Set the new file type and load pixbuf or SVG. */
+ if ( !_filename_node.field_flag && (_filename_node.data != null) )
+ {
+ if ( _filename_node.data.has_suffix( ".svg" ) || _filename_node.data.has_suffix( ".SVG" ) )
+ {
+ svg_handle = parent.svg_cache.get_handle( _filename_node.data );
+ if ( svg_handle != null )
+ {
+ type = FileType.SVG;
+ pixbuf = null;
+ }
+ else
+ {
+ type = FileType.NONE;
+ pixbuf = null;
+ }
+ }
+ else
+ {
+ pixbuf = parent.pixbuf_cache.get_pixbuf( _filename_node.data );
+ if ( pixbuf != null )
+ {
+ type = FileType.PIXBUF;
+ svg_handle = null;
+ }
+ else
+ {
+ type = FileType.NONE;
+ svg_handle = null;
+ }
+ }
+ }
+ else
+ {
+ type = FileType.NONE;
+ svg_handle = null;
+ pixbuf = null;
+ }
+
+ /* Treat current size as a bounding box, scale image to maintain aspect
+ * ratio while fitting it in this bounding box. */
+ double image_w, image_h;
+ switch ( type )
+ {
+ case FileType.PIXBUF:
+ image_w = pixbuf.width;
+ image_h = pixbuf.height;
+ break;
+ case FileType.SVG:
+ image_w = svg_handle.width;
+ image_h = svg_handle.height;
+ break;
+ default:
+ image_w = default_pixbuf.width;
+ image_h = default_pixbuf.height;
+ break;
+ }
+ double aspect_ratio = image_h / image_w;
+ if ( h > w*aspect_ratio )
+ {
+ h = w * aspect_ratio;
+ }
+ else
+ {
+ w = h / aspect_ratio;
+ }
+
+ }
+
+ }
+
+
+ Gdk.Pixbuf? shadow_pixbuf ( Gdk.Pixbuf pixbuf, Color shadow_color )
+ {
+ uchar shadow_r = (uchar)(shadow_color.r * 255.0);
+ uchar shadow_g = (uchar)(shadow_color.g * 255.0);
+ uchar shadow_b = (uchar)(shadow_color.b * 255.0);
+
+ /* extract pixels and parameters from source pixbuf. */
+ uchar* buf_src = pixbuf.pixels;
+ int bits_per_sample = pixbuf.bits_per_sample;
+ int n_channels = pixbuf.n_channels;
+ bool src_has_alpha = pixbuf.has_alpha;
+ int width = pixbuf.width;
+ int height = pixbuf.height;
+ int src_rowstride = pixbuf.rowstride;
+
+ /* validate assumptions about source pixbuf. */
+ if ( buf_src == null) return null;
+ if ( bits_per_sample != 8 ) return null;
+ if ( (n_channels < 3) || (n_channels > 4) ) return null;
+ if ( width <= 0 ) return null;
+ if ( height <= 0 ) return null;
+ if ( src_rowstride <= 0 ) return null;
+
+ /* Allocate a destination pixbuf */
+ Gdk.Pixbuf dest_pixbuf = new Gdk.Pixbuf( Gdk.Colorspace.RGB, true, bits_per_sample, width, height );
+ int dest_rowstride = dest_pixbuf.rowstride;
+ uchar* buf_dest = dest_pixbuf.pixels;
+ if ( buf_dest == null ) {
+ return null;
+ }
+
+ /* Process pixels: set rgb components and composite alpha with shadow_opacity. */
+ uchar* p_src = buf_src;
+ uchar* p_dest = buf_dest;
+ for ( int iy=0; iy < height; iy++ )
+ {
+
+ p_src = buf_src + iy*src_rowstride;
+ p_dest = buf_dest + iy*dest_rowstride;
+
+ for ( int ix=0; ix < width; ix++ )
+ {
+
+ p_src += 3; /* skip RGB */
+
+ *p_dest++ = shadow_r;
+ *p_dest++ = shadow_g;
+ *p_dest++ = shadow_b;
+
+ if ( src_has_alpha )
+ {
+ *p_dest++ = *p_src++ * shadow_color.a;
+ }
+ else
+ {
+ *p_dest++ = shadow_color.a * 255.0;
+ }
+
+
+ }
+
+ }
+
+ return dest_pixbuf;
+ }
+
+
+}
diff --git a/glabels/label_object_line.vala b/glabels/label_object_line.vala
index 65cad48..4c52e2a 100644
--- a/glabels/label_object_line.vala
+++ b/glabels/label_object_line.vala
@@ -29,6 +29,13 @@ namespace glabels
private const double SELECTION_SLOP_PIXELS = 4.0;
+ public LabelObjectLine.with_parent( Label parent )
+ {
+ this();
+ parent.add_object( this );
+ }
+
+
/**
* Line width
*/
diff --git a/glabels/label_object_text.vala b/glabels/label_object_text.vala
index ffff25e..a27af10 100644
--- a/glabels/label_object_text.vala
+++ b/glabels/label_object_text.vala
@@ -40,6 +40,13 @@ namespace glabels
public bool auto_shrink { get; set; default = false; }
+ public LabelObjectText.with_parent( Label parent )
+ {
+ this();
+ parent.add_object( this );
+ }
+
+
/**
* Raw width of bounding box
*/
diff --git a/glabels/object_editor.vala b/glabels/object_editor.vala
index 6445824..472b17a 100644
--- a/glabels/object_editor.vala
+++ b/glabels/object_editor.vala
@@ -40,6 +40,7 @@ namespace glabels
private Gtk.Notebook notebook;
private Gtk.Box text_page_box;
+ private Gtk.Box image_page_box;
private Gtk.Box line_fill_page_box;
private Gtk.Box pos_size_page_box;
private Gtk.Box shadow_page_box;
@@ -63,6 +64,12 @@ namespace glabels
private Gtk.Box text_insert_field_box;
private FieldButton text_insert_field_button;
+ private Gtk.RadioButton image_file_radio;
+ private Gtk.RadioButton image_key_radio;
+ private Gtk.FileChooserButton image_filebutton;
+ private Gtk.Box image_key_box;
+ private FieldButton image_key_button;
+
private Gtk.SpinButton line_width_spin;
private Gtk.Box line_color_box;
private ColorButton line_color_button;
@@ -116,6 +123,9 @@ namespace glabels
private ulong sigid_text_line_spacing_spin_changed;
private ulong sigid_text_insert_field_button_key_selected;
+ private ulong sigid_image_filebutton_selection_changed;
+ private ulong sigid_image_key_button_changed;
+
private ulong sigid_line_width_spin_changed;
private ulong sigid_line_color_button_changed;
@@ -177,6 +187,7 @@ namespace glabels
/* Notebook pages. */
text_page_box = builder.get_object( "text_page_box" ) as Gtk.Box;
+ image_page_box = builder.get_object( "image_page_box" ) as Gtk.Box;
line_fill_page_box = builder.get_object( "line_fill_page_box" ) as Gtk.Box;
pos_size_page_box = builder.get_object( "pos_size_page_box" ) as Gtk.Box;
shadow_page_box = builder.get_object( "shadow_page_box" ) as Gtk.Box;
@@ -238,6 +249,20 @@ namespace glabels
text_insert_field_button.key_selected.connect( on_text_insert_field_button_key_selected );
+ /* Image widgets. */
+ image_file_radio = builder.get_object( "image_file_radio" ) as Gtk.RadioButton;
+ image_key_radio = builder.get_object( "image_key_radio" ) as Gtk.RadioButton;
+ image_filebutton = builder.get_object( "image_filebutton" ) as Gtk.FileChooserButton;
+ image_key_box = builder.get_object( "image_key_box" ) as Gtk.Box;
+
+ image_key_button = new FieldButton( null );
+ image_key_box.pack_start( image_key_button, true, true, 0 );
+
+ sigid_image_filebutton_selection_changed =
+ image_filebutton.selection_changed.connect( on_image_filebutton_selection_changed );
+ sigid_image_key_button_changed = image_key_button.changed.connect( on_image_key_button_changed );
+
+
/* Line widgets. */
line_width_spin = builder.get_object( "line_width_spin" ) as Gtk.SpinButton;
line_color_box = builder.get_object( "line_color_box" ) as Gtk.Box;
@@ -403,6 +428,7 @@ namespace glabels
title_label.set_text( "<b>%s</b>".printf( _("Text object properties") ) );
text_page_box.show_all();
+ image_page_box.hide();
line_fill_page_box.hide();
pos_size_page_box.show_all();
shadow_page_box.show_all();
@@ -416,6 +442,7 @@ namespace glabels
title_label.set_text( "<b>%s</b>".printf( _("Box object properties") ) );
text_page_box.hide();
+ image_page_box.hide();
line_fill_page_box.show_all();
pos_size_page_box.show_all();
shadow_page_box.show_all();
@@ -429,6 +456,7 @@ namespace glabels
title_label.set_text( "<b>%s</b>".printf( _("Ellipse object properties") ) );
text_page_box.hide();
+ image_page_box.hide();
line_fill_page_box.show_all();
pos_size_page_box.show_all();
shadow_page_box.show_all();
@@ -442,6 +470,7 @@ namespace glabels
title_label.set_text( "<b>%s</b>".printf( _("Line object properties") ) );
text_page_box.hide();
+ image_page_box.hide();
line_fill_page_box.show_all();
pos_size_page_box.show_all();
shadow_page_box.show_all();
@@ -450,6 +479,20 @@ namespace glabels
rect_size_frame.hide();
size_reset_image_button.hide();
}
+ else if ( object is LabelObjectImage )
+ {
+ title_image.set_from_icon_name( "glabels-image", Gtk.IconSize.LARGE_TOOLBAR );
+ title_label.set_text( "<b>%s</b>".printf( _("Image object properties") ) );
+
+ text_page_box.hide();
+ image_page_box.show_all();
+ line_fill_page_box.hide();
+ pos_size_page_box.show_all();
+ shadow_page_box.show_all();
+
+ line_size_frame.hide();
+ size_reset_image_button.hide();
+ }
else
{
assert_not_reached();
@@ -465,6 +508,8 @@ namespace glabels
load_text_valign_toggles();
load_text_line_spacing_spin();
load_text_textview();
+ load_image_filebutton();
+ load_image_key_button();
load_line_width_spin();
load_line_color_button();
load_fill_color_button();
@@ -531,18 +576,25 @@ namespace glabels
{
text_color_button.clear_keys();
text_insert_field_button.clear_keys();
+ image_key_button.clear_keys();
line_color_button.clear_keys();
fill_color_button.clear_keys();
shadow_color_button.clear_keys();
+
+ image_file_radio.set_active( true );
+ image_key_radio.set_sensitive( false );
}
else
{
List<string> key_list = model.label.merge.get_key_list();
text_color_button.set_keys( key_list );
text_insert_field_button.set_keys( key_list );
+ image_key_button.set_keys( key_list );
line_color_button.set_keys( key_list );
fill_color_button.set_keys( key_list );
shadow_color_button.set_keys( key_list );
+
+ image_key_radio.set_sensitive( true );
}
}
@@ -948,6 +1000,74 @@ namespace glabels
/******************************
+ * image_filebutton
+ ******************************/
+ private void on_image_filebutton_selection_changed()
+ {
+ if ( object != null )
+ {
+ string filename = image_filebutton.get_filename();
+ if ( filename != null )
+ {
+ object.filename_node = new TextNode( false, filename );
+ }
+ }
+ }
+
+ private void load_image_filebutton()
+ {
+ if ( (object != null) && (object.filename_node != null) )
+ {
+ if ( !object.filename_node.field_flag )
+ {
+ image_file_radio.set_active( true );
+
+ GLib.SignalHandler.block( (void*)image_filebutton, sigid_image_filebutton_selection_changed );
+
+ if ( object.filename_node.data != null )
+ {
+ image_filebutton.set_filename( object.filename_node.data );
+ }
+ else
+ {
+ image_filebutton.unselect_all();
+ }
+
+ GLib.SignalHandler.unblock( (void*)image_filebutton, sigid_image_filebutton_selection_changed );
+ }
+ }
+ }
+
+
+ /******************************
+ * image_key_button
+ ******************************/
+ private void on_image_key_button_changed()
+ {
+ if ( object != null )
+ {
+ object.filename_node = new TextNode( true, image_key_button.get_key() );
+ }
+ }
+
+ private void load_image_key_button()
+ {
+ if ( (object != null) && (object.filename_node != null) )
+ {
+ if ( object.filename_node.field_flag )
+ {
+ image_key_radio.set_active( true );
+
+ GLib.SignalHandler.block( (void*)image_key_button, sigid_image_key_button_changed );
+
+ image_key_button.set_key( object.filename_node.data );
+
+ GLib.SignalHandler.unblock( (void*)image_key_button, sigid_image_key_button_changed );
+ }
+ }
+ }
+
+ /******************************
* line_width_spin
******************************/
private void on_line_width_spin_changed()
diff --git a/glabels/pixbuf_cache.vala b/glabels/pixbuf_cache.vala
new file mode 100644
index 0000000..dd51f5e
--- /dev/null
+++ b/glabels/pixbuf_cache.vala
@@ -0,0 +1,125 @@
+/* pixbuf_cache.vala
+ *
+ * Copyright (C) 2012 Jim Evins <evins snaught com>
+ *
+ * This file is part of gLabels.
+ *
+ * gLabels is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * gLabels is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with gLabels. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+using GLib;
+
+namespace glabels
+{
+
+ public class PixbufCache
+ {
+
+ private class Record : Object
+ {
+ public int use_count;
+ public Gdk.Pixbuf pixbuf;
+
+ public Record( Gdk.Pixbuf pixbuf )
+ {
+ this.use_count = 0;
+ this.pixbuf = pixbuf;
+ }
+
+ public void increment()
+ {
+ use_count++;
+ }
+
+ public int decrement()
+ {
+ use_count--;
+ return use_count;
+ }
+ }
+
+
+ private Gee.HashMap<string,Record> map;
+
+
+ public PixbufCache()
+ {
+ map = new Gee.HashMap<string,Record>();
+ }
+
+
+ public void add_pixbuf( string name, Gdk.Pixbuf pixbuf )
+ {
+ if ( map.has_key( name ) )
+ {
+ /* pixbuf already in the cache. */
+ return;
+ }
+
+ Record record = new Record( pixbuf );
+ map.set( name, record );
+ }
+
+
+ public Gdk.Pixbuf? get_pixbuf( string name )
+ {
+ if ( map.has_key( name ) )
+ {
+ Record record = map.get( name );
+ record.increment();
+ return record.pixbuf;
+ }
+
+ try {
+ Gdk.Pixbuf? pixbuf = new Gdk.Pixbuf.from_file( name );
+ Record record = new Record( pixbuf );
+ record.increment();
+ map.set( name, record );
+
+ return pixbuf;
+ }
+ catch ( Error e )
+ {
+ return null;
+ }
+ }
+
+
+ public void remove_pixbuf( string name )
+ {
+ Record? record = map.get( name );
+ if ( record.decrement() == 0 )
+ {
+ map.unset( name );
+ }
+ }
+
+
+ public List<string> get_name_list()
+ {
+ List<string> list = new List<string>();
+
+ foreach ( string name in map.keys )
+ {
+ list.append( name );
+ }
+
+ return list;
+ }
+
+
+ }
+
+}
diff --git a/glabels/pixmaps.vapi b/glabels/pixmaps.vapi
new file mode 100644
index 0000000..cae016f
--- /dev/null
+++ b/glabels/pixmaps.vapi
@@ -0,0 +1,13 @@
+namespace glabels
+{
+
+ [CCode (prefix = "", lower_case_cprefix = "", cheader_filename = "pixmaps/checkerboard.xpm")]
+ namespace Pixmaps
+ {
+
+ [CCode (array_length = false, type = "char**")]
+ public string[] checkerboard_xpm;
+
+ }
+
+}
diff --git a/glabels/pixmaps/checkerboard.xpm b/glabels/pixmaps/checkerboard.xpm
new file mode 100644
index 0000000..33ab7b5
--- /dev/null
+++ b/glabels/pixmaps/checkerboard.xpm
@@ -0,0 +1,29 @@
+/* XPM */
+static char * checkerboard_xpm[] = {
+"24 24 2 1",
+" c #CCCCCC",
+". c #000000",
+".. .. .. .. .. .. ",
+".. .. .. .. .. .. ",
+" .. .. .. .. .. ..",
+" .. .. .. .. .. ..",
+".. .. .. .. .. .. ",
+".. .. .. .. .. .. ",
+" .. .. .. .. .. ..",
+" .. .. .. .. .. ..",
+".. .. .. .. .. .. ",
+".. .. .. .. .. .. ",
+" .. .. .. .. .. ..",
+" .. .. .. .. .. ..",
+".. .. .. .. .. .. ",
+".. .. .. .. .. .. ",
+" .. .. .. .. .. ..",
+" .. .. .. .. .. ..",
+".. .. .. .. .. .. ",
+".. .. .. .. .. .. ",
+" .. .. .. .. .. ..",
+" .. .. .. .. .. ..",
+".. .. .. .. .. .. ",
+".. .. .. .. .. .. ",
+" .. .. .. .. .. ..",
+" .. .. .. .. .. .."};
diff --git a/glabels/svg_cache.vala b/glabels/svg_cache.vala
new file mode 100644
index 0000000..2cfd0ce
--- /dev/null
+++ b/glabels/svg_cache.vala
@@ -0,0 +1,191 @@
+/* svg_cache.vala
+ *
+ * Copyright (C) 2012 Jim Evins <evins snaught com>
+ *
+ * This file is part of gLabels.
+ *
+ * gLabels is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * gLabels is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with gLabels. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+using GLib;
+
+namespace glabels
+{
+
+ public class SvgCache
+ {
+
+ private class Record : Object
+ {
+ public int use_count;
+ public Rsvg.Handle handle;
+ public string svg;
+
+ public Record( Rsvg.Handle handle, string svg )
+ {
+ this.use_count = 0;
+ this.handle = handle;
+ this.svg = svg;
+ }
+
+ public Record.from_svg( string svg ) throws Error
+ {
+ Rsvg.Handle? handle;
+
+ try {
+ handle = new Rsvg.Handle.from_data( svg.data, svg.length );
+ }
+ catch ( Error e )
+ {
+ handle = null;
+ throw e;
+ }
+
+ this( handle, svg );
+ }
+
+ public Record.from_file( string file_name ) throws Error
+ {
+ Rsvg.Handle? handle;
+ string svg;
+
+ try {
+ FileUtils.get_contents( file_name, out svg );
+ handle = new Rsvg.Handle.from_data( svg.data, svg.length );
+ }
+ catch ( Error e )
+ {
+ handle = null;
+ svg = "";
+ throw e;
+ }
+
+ this( handle, svg );
+ }
+
+ public void increment()
+ {
+ use_count++;
+ }
+
+ public int decrement()
+ {
+ use_count--;
+ return use_count;
+ }
+ }
+
+
+ private Gee.HashMap<string,Record> map;
+
+
+ public SvgCache()
+ {
+ map = new Gee.HashMap<string,Record>();
+ }
+
+
+ public void add_svg( string name, string svg )
+ {
+ if ( map.has_key( name ) )
+ {
+ /* svg already in the cache. */
+ return;
+ }
+
+ try {
+ map.set( name, new Record.from_svg( svg ) );
+ }
+ catch ( Error e )
+ {
+ }
+ }
+
+
+ public string? get_svg( string name )
+ {
+ if ( map.has_key( name ) )
+ {
+ Record record = map.get( name );
+ record.increment();
+ return record.svg;
+ }
+
+ try
+ {
+ Record record = new Record.from_file( name );
+ record.increment();
+ map.set( name, record );
+
+ return record.svg;
+ }
+ catch ( Error e )
+ {
+ return null;
+ }
+ }
+
+
+ public Rsvg.Handle? get_handle( string name )
+ {
+ if ( map.has_key( name ) )
+ {
+ Record record = map.get( name );
+ record.increment();
+ return record.handle;
+ }
+
+ try
+ {
+ Record record = new Record.from_file( name );
+ record.increment();
+ map.set( name, record );
+
+ return record.handle;
+ }
+ catch ( Error e )
+ {
+ return null;
+ }
+ }
+
+
+ public void remove_svg( string name )
+ {
+ Record? record = map.get( name );
+ if ( record.decrement() == 0 )
+ {
+ map.unset( name );
+ record.unref();
+ }
+ }
+
+
+ public List<string> get_name_list()
+ {
+ List<string> list = new List<string>();
+
+ foreach ( string name in map.keys )
+ {
+ list.append( name );
+ }
+
+ return list;
+ }
+
+
+ }
+
+}
diff --git a/glabels/ui.vala b/glabels/ui.vala
index 2b3b82e..973ed4a 100644
--- a/glabels/ui.vala
+++ b/glabels/ui.vala
@@ -1150,15 +1150,15 @@ namespace glabels
}
- private void on_objects_create_text( Gtk.Action action )
+ private void on_objects_create_box( Gtk.Action action )
{
- window.view.create_text_mode();
+ window.view.create_box_mode();
}
- private void on_objects_create_box( Gtk.Action action )
+ private void on_objects_create_ellipse( Gtk.Action action )
{
- window.view.create_box_mode();
+ window.view.create_ellipse_mode();
}
@@ -1168,20 +1168,15 @@ namespace glabels
}
- private void on_objects_create_ellipse( Gtk.Action action )
+ private void on_objects_create_image( Gtk.Action action )
{
- window.view.create_ellipse_mode();
+ window.view.create_image_mode();
}
- private void on_objects_create_image( Gtk.Action action )
+ private void on_objects_create_text( Gtk.Action action )
{
- /*
- if (window->view != NULL) {
- gl_view_object_create_mode (GL_VIEW(window->view),
- GL_LABEL_OBJECT_IMAGE);
- }
- */
+ window.view.create_text_mode();
}
diff --git a/glabels/view.vala b/glabels/view.vala
index d48429d..a22cbf4 100644
--- a/glabels/view.vala
+++ b/glabels/view.vala
@@ -429,6 +429,28 @@ namespace glabels
}
+ public void create_image_mode()
+ {
+ Gdk.Window window = canvas.get_window();
+
+ try
+ {
+ Gdk.Pixbuf pixbuf = Gdk.Pixbuf.from_pixdata( Cursor.image_pixdata, false );
+ Gdk.Cursor cursor = new Gdk.Cursor.from_pixbuf( Gdk.Display.get_default(),
+ pixbuf, CURSOR_X_HOTSPOT, CURSOR_Y_HOTSPOT );
+ window.set_cursor( cursor );
+ }
+ catch ( Error err )
+ {
+ error( "%s\n", err.message );
+ }
+
+ in_object_create_mode = true;
+ create_object_type = CreateType.IMAGE;
+ state = State.IDLE;
+ }
+
+
public void create_text_mode()
{
Gdk.Window window = canvas.get_window();
@@ -909,7 +931,9 @@ namespace glabels
create_object.set_size( x - create_x0, y - create_y0 );
break;
case CreateType.IMAGE:
- /* TODO */
+ create_object.set_position( double.min( x, create_x0 ), double.min( y, create_y0 ) );
+ create_object.set_size( double.max( x, create_x0 ) - double.min( x, create_x0 ),
+ double.max( y, create_y0 ) - double.min( y, create_y0 ) );
break;
case CreateType.TEXT:
create_object.set_position( double.min( x, create_x0 ), double.min( y, create_y0 ) );
@@ -1037,7 +1061,7 @@ namespace glabels
create_object = new LabelObjectLine() as LabelObject;
break;
case CreateType.IMAGE:
- /* TODO */
+ create_object = new LabelObjectImage() as LabelObject;
break;
case CreateType.TEXT:
create_object = new LabelObjectText() as LabelObject;
diff --git a/glabels/xml_label.vala b/glabels/xml_label.vala
index f882558..edb253a 100644
--- a/glabels/xml_label.vala
+++ b/glabels/xml_label.vala
@@ -131,7 +131,7 @@ namespace glabels
{
if ( child->name == "Data" )
{
- /* TODO: xml_parse_data (child_node, label); */
+ parse_data_node( child, label );
}
}
@@ -194,11 +194,11 @@ namespace glabels
break;
case "Object-line":
- /* TODO. */
+ parse_object_line_node( child, label );
break;
case "Object-image":
- /* TODO. */
+ parse_object_image_node( child, label );
break;
case "Object-barcode":
@@ -224,7 +224,7 @@ namespace glabels
private void parse_object_box_node( Xml.Node node,
Label label )
{
- LabelObjectBox object = new LabelObjectBox();
+ LabelObjectBox object = new LabelObjectBox.with_parent( label );
/* position attrs */
@@ -258,15 +258,13 @@ namespace glabels
/* shadow attrs */
parse_shadow_attrs( node, object );
-
- label.add_object( object );
}
private void parse_object_ellipse_node( Xml.Node node,
Label label )
{
- LabelObjectEllipse object = new LabelObjectEllipse();
+ LabelObjectEllipse object = new LabelObjectEllipse.with_parent( label );
/* position attrs */
@@ -300,15 +298,86 @@ namespace glabels
/* shadow attrs */
parse_shadow_attrs( node, object );
+ }
+
+
+ private void parse_object_line_node( Xml.Node node,
+ Label label )
+ {
+ LabelObjectLine object = new LabelObjectLine.with_parent( label );
+
+
+ /* position attrs */
+ object.x0 = XmlUtil.get_prop_length( node, "x", 0.0 );
+ object.y0 = XmlUtil.get_prop_length( node, "y", 0.0 );
+
+ /* size attrs */
+ object.w = XmlUtil.get_prop_length( node, "dx", 0 );
+ object.h = XmlUtil.get_prop_length( node, "dy", 0 );
+
+ /* line attrs */
+ object.line_width = XmlUtil.get_prop_length( node, "line_width", 1.0 );
+
+ {
+ string key = XmlUtil.get_prop_string( node, "line_color_field", null );
+ bool field_flag = key != null;
+ Color color = Color.from_legacy_color( XmlUtil.get_prop_uint( node, "line_color", 0 ) );
+ object.line_color_node = ColorNode( field_flag, color, key );
+ }
+
+ /* affine attrs */
+ parse_affine_attrs( node, object );
+
+ /* shadow attrs */
+ parse_shadow_attrs( node, object );
+ }
+
+
+ private void parse_object_image_node( Xml.Node node,
+ Label label )
+ {
+ LabelObjectImage object = new LabelObjectImage.with_parent( label );
+
+
+ /* position attrs */
+ object.x0 = XmlUtil.get_prop_length( node, "x", 0.0 );
+ object.y0 = XmlUtil.get_prop_length( node, "y", 0.0 );
+
+ /* src or field attrs */
+ string src = XmlUtil.get_prop_string( node, "src", null );
+ if ( src != null )
+ {
+ object.filename_node = new TextNode( false, src );
+ }
+ else
+ {
+ string field = XmlUtil.get_prop_string( node, "field", null );
+ if ( field != null )
+ {
+ object.filename_node = new TextNode( true, field );
+ }
+ else
+ {
+ message( "Missing Object-image src or field attr" );
+ }
+ }
+
+ /* size attrs, must be set after filename because setting filename may adjust these. */
+ object.w = XmlUtil.get_prop_length( node, "w", 0 );
+ object.h = XmlUtil.get_prop_length( node, "h", 0 );
+
+ /* affine attrs */
+ parse_affine_attrs( node, object );
- label.add_object( object );
+ /* shadow attrs */
+ parse_shadow_attrs( node, object );
}
private void parse_object_text_node( Xml.Node node,
Label label )
{
- LabelObjectText object = new LabelObjectText();
+ LabelObjectText object = new LabelObjectText.with_parent( label );
/* position attrs */
@@ -350,8 +419,6 @@ namespace glabels
break;
}
}
-
- label.add_object( object );
}
@@ -475,6 +542,70 @@ namespace glabels
}
+ private void parse_data_node( Xml.Node node,
+ Label label )
+ {
+
+ for ( unowned Xml.Node* child = node.children; child != null; child = child->next )
+ {
+ switch (child->name)
+ {
+
+ case "Pixdata":
+ parse_pixdata_node( child, label );
+ break;
+
+ case "File":
+ parse_file_node( child, label );
+ break;
+
+ default:
+ if ( child->is_text() == 0 )
+ {
+ message( "Unexpected %s child: \"%s\"", node.name, child->name );
+ }
+ break;
+
+ }
+ }
+
+ }
+
+
+ private void parse_pixdata_node( Xml.Node node,
+ Label label )
+ {
+ string name = XmlUtil.get_prop_string( node, "name", null );
+ string base64 = node.get_content();
+
+ uchar[] stream = Base64.decode( base64 );
+ Gdk.Pixdata pixdata = Gdk.Pixdata();
+ if ( pixdata.deserialize( stream ) )
+ {
+ Gdk.Pixbuf pixbuf = Gdk.Pixbuf.from_pixdata( pixdata, true );
+ label.pixbuf_cache.add_pixbuf( name, pixbuf );
+ }
+ }
+
+
+ private void parse_file_node( Xml.Node node,
+ Label label )
+ {
+ string name = XmlUtil.get_prop_string( node, "name", null );
+ string format = XmlUtil.get_prop_string( node, "format", null );
+
+ if ( (format == "SVG") || (format == "Svg") || (format == "svg") )
+ {
+ string content = node.get_content();
+ label.svg_cache.add_svg( name, content );
+ }
+ else
+ {
+ message( "Unknown embedded file format: \"%s\"", format );
+ }
+ }
+
+
public void save_file( Label label,
string utf8_filename ) throws XmlError
{
@@ -552,15 +683,23 @@ namespace glabels
{
if ( object is LabelObjectBox )
{
- create_object_box_node( node, ns, (LabelObjectBox)object );
+ create_object_box_node( node, ns, object as LabelObjectBox );
}
else if ( object is LabelObjectEllipse )
{
- create_object_ellipse_node( node, ns, (LabelObjectEllipse)object );
+ create_object_ellipse_node( node, ns, object as LabelObjectEllipse );
+ }
+ else if ( object is LabelObjectLine )
+ {
+ create_object_line_node( node, ns, object as LabelObjectLine );
+ }
+ else if ( object is LabelObjectImage )
+ {
+ create_object_image_node( node, ns, object as LabelObjectImage );
}
else if ( object is LabelObjectText )
{
- create_object_text_node( node, ns, (LabelObjectText)object );
+ create_object_text_node( node, ns, object as LabelObjectText );
}
else /* TODO: other object types. */
{
@@ -656,6 +795,71 @@ namespace glabels
}
+ private void create_object_line_node( Xml.Node parent,
+ Xml.Ns ns,
+ LabelObjectLine object )
+ {
+ unowned Xml.Node *node = parent.new_child( ns, "Object-line" );
+
+ /* position attrs */
+ XmlUtil.set_prop_length( node, "x", object.x0 );
+ XmlUtil.set_prop_length( node, "y", object.y0 );
+
+ /* size attrs */
+ XmlUtil.set_prop_length( node, "dx", object.w );
+ XmlUtil.set_prop_length( node, "dy", object.h );
+
+ /* line attrs */
+ XmlUtil.set_prop_length( node, "line_width", object.line_width );
+ if ( object.line_color_node.field_flag )
+ {
+ XmlUtil.set_prop_string( node, "line_color_field", object.line_color_node.key );
+ }
+ else
+ {
+ XmlUtil.set_prop_uint_hex( node, "line_color", object.line_color_node.color.to_legacy_color() );
+ }
+
+ /* affine attrs */
+ create_affine_attrs( node, object );
+
+ /* shadow attrs */
+ create_shadow_attrs( node, object );
+ }
+
+
+ private void create_object_image_node( Xml.Node parent,
+ Xml.Ns ns,
+ LabelObjectImage object )
+ {
+ unowned Xml.Node *node = parent.new_child( ns, "Object-image" );
+
+ /* position attrs */
+ XmlUtil.set_prop_length( node, "x", object.x0 );
+ XmlUtil.set_prop_length( node, "y", object.y0 );
+
+ /* size attrs */
+ XmlUtil.set_prop_length( node, "w", object.w );
+ XmlUtil.set_prop_length( node, "h", object.h );
+
+ /* src or field attr */
+ if ( object.filename_node.field_flag )
+ {
+ XmlUtil.set_prop_string( node, "field", object.filename_node.data );
+ }
+ else
+ {
+ XmlUtil.set_prop_string( node, "src", object.filename_node.data );
+ }
+
+ /* affine attrs */
+ create_affine_attrs( node, object );
+
+ /* shadow attrs */
+ create_shadow_attrs( node, object );
+ }
+
+
private void create_object_text_node( Xml.Node parent,
Xml.Ns ns,
LabelObjectText object )
@@ -805,7 +1009,54 @@ namespace glabels
{
unowned Xml.Node *node = root.new_child( ns, "Data" );
- /* TODO */
+ foreach ( string name in label.pixbuf_cache.get_name_list() )
+ {
+ create_pixdata_node( node, ns, label, name );
+ }
+
+ foreach ( string name in label.svg_cache.get_name_list() )
+ {
+ create_file_svg_node( doc, node, ns, label, name );
+ }
+ }
+
+
+ private void create_pixdata_node( Xml.Node root,
+ Xml.Ns ns,
+ Label label,
+ string name )
+ {
+ Gdk.Pixbuf pixbuf = label.pixbuf_cache.get_pixbuf( name );
+ if ( pixbuf != null )
+ {
+ Gdk.Pixdata pixdata = Gdk.Pixdata();
+ Gdk.pixdata_from_pixbuf( out pixdata, pixbuf, false );
+ uint8[] stream = pixdata.serialize();
+ string base64 = GLib.Base64.encode( stream );
+
+ unowned Xml.Node *node = root.new_child( ns, "Pixdata", base64 );
+ XmlUtil.set_prop_string( node, "name", name );
+ XmlUtil.set_prop_string( node, "encoding", "Base64" );
+ }
+ }
+
+
+ private void create_file_svg_node( Xml.Doc doc,
+ Xml.Node root,
+ Xml.Ns ns,
+ Label label,
+ string name )
+ {
+ string? svg_data = label.svg_cache.get_svg( name );
+ if ( svg_data != null )
+ {
+ unowned Xml.Node *node = root.new_child( ns, "File" );
+ XmlUtil.set_prop_string( node, "name", name );
+ XmlUtil.set_prop_string( node, "format", "SVG" );
+
+ unowned Xml.Node *cdata_section_node = doc.new_cdata_block( svg_data, svg_data.length );
+ node->add_child( cdata_section_node );
+ }
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]