summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJabier Arraiza Cenoz <jabier.arraiza@marker.es>2013-03-23 19:10:43 +0000
committerJabiertxo Arraiza Zenotz <jtx@jtx.marker.es>2013-03-23 19:10:43 +0000
commit9ce7b44f0e1537769ea50f85675341c42fd18a3d (patch)
treeef5233514dc7cda13091e401d25ed5a09278af1c /src
parentFix weight 0 by widget now give a full cusp node (diff)
parentConvert a couple of C-style pointer casts (diff)
downloadinkscape-9ce7b44f0e1537769ea50f85675341c42fd18a3d.tar.gz
inkscape-9ce7b44f0e1537769ea50f85675341c42fd18a3d.zip
Update to trunk
(bzr r11950.1.71)
Diffstat (limited to 'src')
-rw-r--r--src/display/cairo-templates.h12
-rw-r--r--src/display/drawing-image.cpp126
-rw-r--r--src/display/drawing-image.h3
-rw-r--r--src/extension/internal/cairo-render-context.cpp2
-rw-r--r--src/extension/internal/filter/filter.cpp2
-rw-r--r--src/extension/internal/image-resolution.cpp4
-rw-r--r--src/libgdl/Makefile_insert4
-rw-r--r--src/ui/dialog/filter-effects-dialog.cpp103
-rw-r--r--src/ui/dialog/filter-effects-dialog.h3
-rw-r--r--src/ui/dialog/inkscape-preferences.cpp2
-rw-r--r--src/verbs.cpp2
-rw-r--r--src/widgets/stroke-style.cpp134
-rw-r--r--src/widgets/stroke-style.h51
13 files changed, 340 insertions, 108 deletions
diff --git a/src/display/cairo-templates.h b/src/display/cairo-templates.h
index 45b6790e6..57ec98f81 100644
--- a/src/display/cairo-templates.h
+++ b/src/display/cairo-templates.h
@@ -66,9 +66,9 @@ void ink_cairo_surface_blend(cairo_surface_t *in1, cairo_surface_t *in2, cairo_s
int limit = w * h;
- guint32 *const in1_data = (guint32*) cairo_image_surface_get_data(in1);
- guint32 *const in2_data = (guint32*) cairo_image_surface_get_data(in2);
- guint32 *const out_data = (guint32*) cairo_image_surface_get_data(out);
+ guint32 *const in1_data = reinterpret_cast<guint32*>(cairo_image_surface_get_data(in1));
+ guint32 *const in2_data = reinterpret_cast<guint32*>(cairo_image_surface_get_data(in2));
+ guint32 *const out_data = reinterpret_cast<guint32*>(cairo_image_surface_get_data(out));
// NOTE
// OpenMP probably doesn't help much here.
@@ -199,8 +199,8 @@ void ink_cairo_surface_filter(cairo_surface_t *in, cairo_surface_t *out, Filter
fast_path &= (stridein == w * bppin);
fast_path &= (strideout == w * bppout);
- guint32 *const in_data = (guint32*) cairo_image_surface_get_data(in);
- guint32 *const out_data = (guint32*) cairo_image_surface_get_data(out);
+ guint32 *const in_data = reinterpret_cast<guint32*>(cairo_image_surface_get_data(in));
+ guint32 *const out_data = reinterpret_cast<guint32*>(cairo_image_surface_get_data(out));
#if HAVE_OPENMP
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
@@ -695,4 +695,4 @@ pxclamp(gint32 v, gint32 low, gint32 high) {
fill-column:99
End:
*/
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/display/drawing-image.cpp b/src/display/drawing-image.cpp
index 0c8ac9681..3f1a86ee7 100644
--- a/src/display/drawing-image.cpp
+++ b/src/display/drawing-image.cpp
@@ -23,6 +23,7 @@ DrawingImage::DrawingImage(Drawing &drawing)
, _pixbuf(NULL)
, _surface(NULL)
, _style(NULL)
+ , _new_surface(NULL)
{}
DrawingImage::~DrawingImage()
@@ -30,6 +31,7 @@ DrawingImage::~DrawingImage()
if (_style)
sp_style_unref(_style);
if (_pixbuf) {
+ if (_new_surface) cairo_surface_destroy(_new_surface);
cairo_surface_destroy(_surface);
g_object_unref(_pixbuf);
}
@@ -118,26 +120,126 @@ unsigned DrawingImage::_renderItem(DrawingContext &ct, Geom::IntRect const &/*ar
if (!outline) {
if (!_pixbuf) return RENDER_OK;
-
+
Inkscape::DrawingContext::Save save(ct);
ct.transform(_ctm);
ct.newPath();
ct.rectangle(_clipbox);
ct.clip();
- ct.translate(_origin);
- ct.scale(_scale);
- ct.setSource(_surface, 0, 0);
+ /////////////////////////////////////////////////////////////////////////////
+ // BEGIN: Hack to avoid Cairo bug
+ // The total transform (which is RIGHT-multiplied with the item points to get display points) equals:
+ // scale*translate_origin*_ctm = scale*translate(origin)*expansion*expansionInv*_ctm
+ // = scale*expansion*translate(origin*expansion)*expansionInv*_ctm
+ // To avoid a Cairo bug, we handle the scale*expansion part ourselves.
+ // See https://bugs.launchpad.net/inkscape/+bug/804162
+
+ Geom::Scale expansion(_ctm.expansion());
+ int orgwidth = cairo_image_surface_get_width(_surface);
+ int orgheight = cairo_image_surface_get_height(_surface);
+
+ if (_scale[Geom::X]*expansion[Geom::X]*orgwidth*255.0<1.0 || _scale[Geom::Y]*expansion[Geom::Y]*orgheight*255.0<1.0) {
+ // Resized image too small to actually see anything
+ return RENDER_OK;
+ }
+
+ // Split scale*expansion in a part that is <= 1.0 and a part that is >= 1.0. We only take care of the part <= 1.0.
+ Geom::Scale scaleExpansionSmall(std::min<Geom::Coord>(fabs(_scale[Geom::X]*expansion[Geom::X]),1),std::min<Geom::Coord>(fabs(_scale[Geom::Y]*expansion[Geom::Y]),1));
+ Geom::Scale scaleExpansionLarge(_scale[Geom::X]*expansion[Geom::X]/scaleExpansionSmall[Geom::X],_scale[Geom::Y]*expansion[Geom::Y]/scaleExpansionSmall[Geom::Y]);
+
+ Geom::Point newSize(Geom::Point(orgwidth,orgheight)*scaleExpansionSmall);
+ if ((newSize-Geom::Point(orgwidth,orgheight)).length()<0.1) {
+ // Just use _surface directly.
+ ct.scale(expansion.inverse()); // This should not include scale (see derivation above)
+ ct.translate(_origin*expansion);
+ ct.scale(scaleExpansionLarge);
+ ct.setSource(_surface, 0, 0);
+ } else if (!_new_surface || (newSize-_rescaledSize).length()>0.1) {
+ // Rescaled image is sufficiently different from cached image to recompute
+ if (_new_surface) cairo_surface_destroy(_new_surface);
+ _rescaledSize = newSize;
+
+ // This essentially considers an image to be composed of rectangular pixels (box kernel) and computes the least-squares approximation of the original.
+ // When the scale factor is really large or small this essentially results in using a box filter, while for scale factors approaching 1 it is more like a "tent" kernel.
+ // Although the quality of the result is not great, it is typically better than an ordinary box filter, and it is guaranteed to preserve the overall brightness of the image.
+ // The best improvement would probably be to do the same kind of thing based on a tent kernel, but that's quite a bit more complicated, and probably not worth the trouble for a hack like this.
+ int newwidth = static_cast<int>(floor(orgwidth*scaleExpansionSmall[Geom::X])+1);
+ int newheight = static_cast<int>(floor(orgheight*scaleExpansionSmall[Geom::Y])+1);
+ std::vector<int> xBegin(newwidth, -1), yBegin(newheight, -1);
+ std::vector< std::vector<float> > xCoefs(xBegin.size()), yCoefs(yBegin.size());
+ for(int x=0; x<orgwidth; x++) {
+ double coordBegin = x*static_cast<double>(scaleExpansionSmall[Geom::X]); // x-coord in target coordinates where the current source pixel begins
+ double coordEnd = (x+1)*static_cast<double>(scaleExpansionSmall[Geom::X]); // x-coord in target coordinates where the current source pixel ends
+ int begin = static_cast<int>(floor(coordBegin)); // First pixel (x-coord) affected by the current source pixel
+ int end = static_cast<int>(ceil(coordEnd)); // First pixel (x-coord) NOT affected by the current source pixel (a zero contribution is counted as not affecting the pixel)
+ for(int nx=begin; nx<end; nx++) {
+ // Set xBegin if this is the first source pixel contributing to the target pixel.
+ if (xBegin[nx]==-1) xBegin[nx] = x;
+ // This computes the fraction of the current target pixel (at nx) that is covered by the source pixel (at x).
+ xCoefs[nx].push_back(static_cast<float>(std::min<double>(nx+1,coordEnd) - std::max<double>(nx,coordBegin)));
+ }
+ }
+ for(int y=0; y<orgheight; y++) {
+ double coordBegin = y*static_cast<double>(scaleExpansionSmall[Geom::Y]); // y-coord in target coordinates where the current source pixel begins
+ double coordEnd = (y+1)*static_cast<double>(scaleExpansionSmall[Geom::Y]); // y-coord in target coordinates where the current source pixel ends
+ int begin = static_cast<int>(floor(coordBegin)); // First pixel (y-coord) affected by the current source pixel
+ int end = static_cast<int>(ceil(coordEnd)); // First pixel (y-coord) NOT affected by the current source pixel (a zero contribution is counted as not affecting the pixel)
+ for(int ny=begin; ny<end; ny++) {
+ // Set yBegin if this is the first source pixel contributing to the target pixel.
+ if (yBegin[ny]==-1) yBegin[ny] = y;
+ // This computes the fraction of the current target pixel (at ny) that is covered by the source pixel (at y).
+ yCoefs[ny].push_back(static_cast<float>(std::min<double>(ny+1,coordEnd) - std::max<double>(ny,coordBegin)));
+ }
+ }
+
+ _new_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, newwidth,newheight);
+ unsigned char * orgdata = cairo_image_surface_get_data(_surface);
+ unsigned char * newdata = cairo_image_surface_get_data(_new_surface);
+ int orgstride = cairo_image_surface_get_stride(_surface);
+ int newstride = cairo_image_surface_get_stride(_new_surface);
+
+ cairo_surface_flush(_surface);
+ cairo_surface_flush(_new_surface);
+
+ for(int y=0; y<newheight; y++) {
+ for(int x=0; x<newwidth; x++) {
+ float tempSum[4] = {0,0,0,0};
+ for(int oy=0; oy<static_cast<int>(yCoefs[y].size()); oy++) {
+ for(int ox=0; ox<static_cast<int>(xCoefs[x].size()); ox++) {
+ for(int c=0; c<4; c++) {
+ tempSum[c] += xCoefs[x][ox]*yCoefs[y][oy]*orgdata[c+4*(xBegin[x]+ox)+orgstride*(yBegin[y]+oy)];
+ }
+ }
+ }
+ for(int c=0; c<4; c++) {
+ newdata[c+4*x+newstride*y] = static_cast<unsigned char>(tempSum[c]);
+ }
+ }
+ }
+
+ cairo_surface_mark_dirty(_new_surface);
+
+ ct.scale(expansion.inverse()); // This should not include scale (see derivation above)
+ ct.translate(_origin*expansion);
+ ct.scale(scaleExpansionLarge);
+ ct.setSource(_new_surface, 0, 0);
+ } else {
+ // No need to regenerate, but we do draw from _new_surface.
+ ct.scale(expansion.inverse()); // This should not include scale (see derivation above)
+ ct.translate(_origin*expansion);
+ ct.scale(scaleExpansionLarge);
+ ct.setSource(_new_surface, 0, 0);
+ }
+
+ // END: Hack to avoid Cairo bug
+ /////////////////////////////////////////////////////////////////////////////
- cairo_matrix_t tt;
- Geom::Affine total;
- cairo_get_matrix(ct.raw(), &tt);
- ink_matrix_to_2geom(total, tt);
+ // TODO: If Cairo's problems are gone, uncomment the following:
+ //ct.translate(_origin);
+ //ct.scale(_scale);
+ //ct.setSource(_surface, 0, 0);
- if (total.expansionX() > 1.0 || total.expansionY() > 1.0) {
- cairo_pattern_t *p = cairo_get_source(ct.raw());
- cairo_pattern_set_filter(p, CAIRO_FILTER_NEAREST);
- }
//ct.paint(_opacity);
ct.paint();
diff --git a/src/display/drawing-image.h b/src/display/drawing-image.h
index 306096d0e..593185c97 100644
--- a/src/display/drawing-image.h
+++ b/src/display/drawing-image.h
@@ -45,6 +45,9 @@ protected:
cairo_surface_t *_surface;
SPStyle *_style;
+ cairo_surface_t *_new_surface; // Part of hack around Cairo bug
+ Geom::Point _rescaledSize; // Part of hack around Cairo bug
+
// TODO: the following three should probably be merged into a new Geom::Viewbox object
Geom::Rect _clipbox; ///< for preserveAspectRatio
Geom::Point _origin;
diff --git a/src/extension/internal/cairo-render-context.cpp b/src/extension/internal/cairo-render-context.cpp
index b6a58c526..cf6730650 100644
--- a/src/extension/internal/cairo-render-context.cpp
+++ b/src/extension/internal/cairo-render-context.cpp
@@ -708,7 +708,7 @@ CairoRenderContext::popLayer(void)
for (int row = 0 ; row < height; row++) {
unsigned char *row_data = pixels + (row * stride);
for (int i = 0 ; i < width; i++) {
- guint32 *pixel = (guint32 *)row_data + i;
+ guint32 *pixel = reinterpret_cast<guint32 *>(row_data) + i;
float lum_alpha = (((*pixel & 0x00ff0000) >> 16) * coeff_r +
((*pixel & 0x0000ff00) >> 8) * coeff_g +
((*pixel & 0x000000ff) ) * coeff_b );
diff --git a/src/extension/internal/filter/filter.cpp b/src/extension/internal/filter/filter.cpp
index 9f7a45f7f..a2c565699 100644
--- a/src/extension/internal/filter/filter.cpp
+++ b/src/extension/internal/filter/filter.cpp
@@ -144,11 +144,11 @@ void Filter::effect(Inkscape::Extension::Effect *module, Inkscape::UI::View::Vie
if (filter == NULL) {
Inkscape::XML::Node * newfilterroot = xmldoc->createElement("svg:filter");
+ merge_filters(newfilterroot, filterdoc->root(), xmldoc);
defsrepr->appendChild(newfilterroot);
Glib::ustring url = "url(#"; url += newfilterroot->attribute("id"); url += ")";
- merge_filters(newfilterroot, filterdoc->root(), xmldoc);
Inkscape::GC::release(newfilterroot);
diff --git a/src/extension/internal/image-resolution.cpp b/src/extension/internal/image-resolution.cpp
index 3b3b85d06..51a3fe9c1 100644
--- a/src/extension/internal/image-resolution.cpp
+++ b/src/extension/internal/image-resolution.cpp
@@ -159,10 +159,10 @@ static double exifDouble(ExifEntry *entry, ExifByteOrder byte_order) {
return double(r.numerator) / double(r.denominator);
}
case EXIF_FORMAT_FLOAT: {
- return double(((float *)entry->data)[0]);
+ return double((reinterpret_cast<float *>(entry->data))[0]);
}
case EXIF_FORMAT_DOUBLE: {
- return ((double *)entry->data)[0];
+ return (reinterpret_cast<double *>(entry->data))[0];
}
default: {
return nan(0);
diff --git a/src/libgdl/Makefile_insert b/src/libgdl/Makefile_insert
index 6669a28fa..e4cab95fc 100644
--- a/src/libgdl/Makefile_insert
+++ b/src/libgdl/Makefile_insert
@@ -49,9 +49,9 @@ libgdl/clean:
# of changes we make to GDL than to fix these minor issues in trunk.
if CC_WNO_UNUSED_BUT_SET_VARIABLE_SUPPORTED
-libgdl_libgdl_a_CFLAGS = -Wno-unused-parameter -Wno-sign-compare -Wno-unused-variable -Wno-unused-but-set-variable $(AM_CFLAGS)
+libgdl_libgdl_a_CFLAGS = -Wno-unused-parameter -Wno-sign-compare -Wno-unused-variable -Wno-unused-but-set-variable -Wno-missing-field-initializers $(AM_CFLAGS)
else
-libgdl_libgdl_a_CFLAGS = -Wno-unused-parameter -Wno-sign-compare -Wno-unused-variable $(AM_CFLAGS)
+libgdl_libgdl_a_CFLAGS = -Wno-unused-parameter -Wno-sign-compare -Wno-unused-variable -Wno-missing-field-initializers $(AM_CFLAGS)
endif
libgdl_libgdl_a_SOURCES = \
diff --git a/src/ui/dialog/filter-effects-dialog.cpp b/src/ui/dialog/filter-effects-dialog.cpp
index 5afc85f10..d65f5c48c 100644
--- a/src/ui/dialog/filter-effects-dialog.cpp
+++ b/src/ui/dialog/filter-effects-dialog.cpp
@@ -1149,7 +1149,9 @@ FilterEffectsDialog::FilterModifier::FilterModifier(FilterEffectsDialog& d)
((Gtk::CellRendererText*)_list.get_column(1)->get_first_cell())->
signal_edited().connect(sigc::mem_fun(*this, &FilterEffectsDialog::FilterModifier::on_name_edited));
- sw->set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
+ sw->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
+ _list.get_column(1)->set_resizable(true);
+
sw->set_shadow_type(Gtk::SHADOW_IN);
show_all_children();
_add.signal_clicked().connect(sigc::mem_fun(*this, &FilterModifier::add_filter));
@@ -1554,6 +1556,7 @@ FilterEffectsDialog::PrimitiveList::PrimitiveList(FilterEffectsDialog& d)
set_model(_model);
append_column(_("_Effect"), _columns.type);
+ get_column(0)->set_resizable(true);
set_headers_visible();
_observer->signal_changed().connect(signal_primitive_changed().make_slot());
@@ -1724,7 +1727,6 @@ bool FilterEffectsDialog::PrimitiveList::on_expose_signal(GdkEventExpose * /*evt
bool FilterEffectsDialog::PrimitiveList::on_draw_signal(const Cairo::RefPtr<Cairo::Context> & cr)
{
cr->set_line_width(1.0);
-
#if GTK_CHECK_VERSION(3,0,0)
// In GTK+ 3, the draw function receives the widget window, not the
// bin_window (i.e., just the area under the column headers). We
@@ -1836,6 +1838,7 @@ bool FilterEffectsDialog::PrimitiveList::on_draw_signal(const Cairo::RefPtr<Cair
std::vector<Gdk::Point> con_poly;
int con_drag_y = 0;
+ int con_drag_x = 0;
bool inside;
const SPFilterPrimitive* row_prim = (*row)[_columns.primitive];
const int inputs = input_count(row_prim);
@@ -1863,16 +1866,22 @@ bool FilterEffectsDialog::PrimitiveList::on_draw_signal(const Cairo::RefPtr<Cair
cr->restore();
if(_in_drag == (i + 1))
+ {
con_drag_y = con_poly[2].get_y();
+ con_drag_x = con_poly[2].get_x();
+ }
if(_in_drag != (i + 1) || row_prim != prim)
+ {
draw_connection(cr, row, i, text_start_x, outline_x, con_poly[2].get_y(), row_count);
+ }
}
}
else {
// Draw "in" shape
inside = do_connection_node(row, 0, con_poly, mx, my);
con_drag_y = con_poly[2].get_y();
+ con_drag_x = con_poly[2].get_x();
cr->save();
@@ -1894,13 +1903,18 @@ bool FilterEffectsDialog::PrimitiveList::on_draw_signal(const Cairo::RefPtr<Cair
// Draw "in" connection
if(_in_drag != 1 || row_prim != prim)
+ {
draw_connection(cr, row, SP_ATTR_IN, text_start_x, outline_x, con_poly[2].get_y(), row_count);
+ }
if(inputs == 2) {
// Draw "in2" shape
inside = do_connection_node(row, 1, con_poly, mx, my);
if(_in_drag == 2)
+ {
con_drag_y = con_poly[2].get_y();
+ con_drag_x = con_poly[2].get_x();
+ }
cr->save();
@@ -1922,7 +1936,9 @@ bool FilterEffectsDialog::PrimitiveList::on_draw_signal(const Cairo::RefPtr<Cair
// Draw "in2" connection
if(_in_drag != 2 || row_prim != prim)
+ {
draw_connection(cr, row, SP_ATTR_IN2, text_start_x, outline_x, con_poly[2].get_y(), row_count);
+ }
}
}
@@ -1930,8 +1946,8 @@ bool FilterEffectsDialog::PrimitiveList::on_draw_signal(const Cairo::RefPtr<Cair
if(row_prim == prim && _in_drag) {
cr->save();
cr->set_source_rgb(0.0, 0.0, 0.0);
- cr->move_to(outline_x, con_drag_y);
- cr->line_to(mx, con_drag_y);
+ cr->move_to(con_drag_x, con_drag_y);
+ cr->line_to(mx, con_drag_y);
cr->line_to(mx, my);
cr->stroke();
cr->restore();
@@ -2153,7 +2169,8 @@ bool FilterEffectsDialog::PrimitiveList::on_button_press_event(GdkEventButton* e
if(_in_drag) {
_scroll_connection = Glib::signal_timeout().connect(sigc::mem_fun(*this, &PrimitiveList::on_scroll_timeout), 150);
- _autoscroll = 0;
+ _autoscroll_x = 0;
+ _autoscroll_y = 0;
get_selection()->select(path);
return true;
}
@@ -2169,22 +2186,43 @@ bool FilterEffectsDialog::PrimitiveList::on_motion_notify_event(GdkEventMotion*
Gdk::Rectangle vis;
get_visible_rect(vis);
int vis_x, vis_y;
+
+ int vis_x2, vis_y2; // NOTE: insaner added -- necessary to get the scrolling while dragging to work
+ convert_widget_to_tree_coords(vis.get_x(), vis.get_y(), vis_x2, vis_y2);
+
convert_tree_to_widget_coords(vis.get_x(), vis.get_y(), vis_x, vis_y);
const int top = vis_y + vis.get_height();
+ const int right_edge = vis_x + vis.get_width();
// When autoscrolling during a connection drag, set the speed based on
// where the mouse is in relation to the edges.
if(e->y < vis_y)
- _autoscroll = -(int)(speed + (vis_y - e->y) / 5);
+ _autoscroll_y = -(int)(speed + (vis_y - e->y) / 5);
else if(e->y < vis_y + limit)
- _autoscroll = -speed;
+ _autoscroll_y = -speed;
else if(e->y > top)
- _autoscroll = (int)(speed + (e->y - top) / 5);
+ _autoscroll_y = (int)(speed + (e->y - top) / 5);
else if(e->y > top - limit)
- _autoscroll = speed;
+ _autoscroll_y = speed;
else
- _autoscroll = 0;
-
+ _autoscroll_y = 0;
+
+ // NOTE: insaner added -- necessary to get the scrolling while dragging to work
+ double e2 = ( e->x - vis_x2/2);
+ // horizontal scrolling
+ if(e2 < vis_x)
+ _autoscroll_x = -(int)(speed + (vis_x - e2) / 5);
+ else if(e2 < vis_x + limit)
+ _autoscroll_x = -speed;
+ else if(e2 > right_edge)
+ _autoscroll_x = (int)(speed + (e2 - right_edge) / 5);
+ else if(e2 > right_edge - limit)
+ _autoscroll_x = speed;
+ else
+ _autoscroll_x = 0;
+
+
+
queue_draw();
return Gtk::TreeView::on_motion_notify_event(e);
@@ -2379,10 +2417,10 @@ void FilterEffectsDialog::PrimitiveList::on_drag_end(const Glib::RefPtr<Gdk::Dra
// If a connection is dragged towards the top or bottom of the list, the list should scroll to follow.
bool FilterEffectsDialog::PrimitiveList::on_scroll_timeout()
{
- if(_autoscroll) {
+ if(_autoscroll_y) {
#if WITH_GTKMM_3_0
Glib::RefPtr<Gtk::Adjustment> a = dynamic_cast<Gtk::ScrolledWindow*>(get_parent())->get_vadjustment();
- double v = a->get_value() + _autoscroll;
+ double v = a->get_value() + _autoscroll_y;
if(v < 0)
v = 0;
@@ -2392,7 +2430,7 @@ bool FilterEffectsDialog::PrimitiveList::on_scroll_timeout()
a->set_value(v);
#else
Gtk::Adjustment& a = *dynamic_cast<Gtk::ScrolledWindow*>(get_parent())->get_vadjustment();
- double v = a.get_value() + _autoscroll;
+ double v = a.get_value() + _autoscroll_y;
if(v < 0)
v = 0;
@@ -2405,6 +2443,34 @@ bool FilterEffectsDialog::PrimitiveList::on_scroll_timeout()
queue_draw();
}
+
+ if(_autoscroll_x) {
+#if WITH_GTKMM_3_0
+ Glib::RefPtr<Gtk::Adjustment> a_h = dynamic_cast<Gtk::ScrolledWindow*>(get_parent())->get_hadjustment();
+ double h = a_h->get_value() + _autoscroll_x;
+
+ if(h < 0)
+ h = 0;
+ if(h > a_h->get_upper() - a_h->get_page_size())
+ h = a_h->get_upper() - a_h->get_page_size();
+
+ a_h->set_value(h);
+#else
+ Gtk::Adjustment& a_h = *dynamic_cast<Gtk::ScrolledWindow*>(get_parent())->get_hadjustment();
+ double h = a_h.get_value() + _autoscroll_x;
+
+ if(h < 0)
+ h = 0;
+ if(h > a_h.get_upper() - a_h.get_page_size())
+ h = a_h.get_upper() - a_h.get_page_size();
+
+ a_h.set_value(h);
+
+#endif
+
+ queue_draw();
+ }
+
return true;
}
@@ -2452,6 +2518,7 @@ FilterEffectsDialog::FilterEffectsDialog()
#endif
Gtk::ScrolledWindow* sw_prims = Gtk::manage(new Gtk::ScrolledWindow);
+ Gtk::ScrolledWindow* sw_infobox = Gtk::manage(new Gtk::ScrolledWindow);
Gtk::HBox* infobox = Gtk::manage(new Gtk::HBox(/*homogeneous:*/false, /*spacing:*/4));
Gtk::HBox* hb_prims = Gtk::manage(new Gtk::HBox);
@@ -2460,13 +2527,15 @@ FilterEffectsDialog::FilterEffectsDialog()
hpaned->pack2(_primitive_box);
_primitive_box.pack_start(*sw_prims);
_primitive_box.pack_start(*hb_prims, false, false);
- _primitive_box.pack_start(*infobox,false, false);
+ _primitive_box.pack_start(*sw_infobox, false, false);
sw_prims->add(_primitive_list);
+ sw_infobox->add(*infobox);
infobox->pack_start(_infobox_icon, false, false);
infobox->pack_start(_infobox_desc, false, false);
_infobox_desc.set_line_wrap(true);
_infobox_desc.set_size_request(200, -1);
+
hb_prims->pack_start(_add_primitive, false, false);
hb_prims->pack_start(_add_primitive_type, false, false);
_getContents()->pack_start(_settings_tabs, false, false);
@@ -2481,8 +2550,10 @@ FilterEffectsDialog::FilterEffectsDialog()
_add_primitive_type.signal_changed().connect(
sigc::mem_fun(*this, &FilterEffectsDialog::update_primitive_infobox));
- sw_prims->set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
+ sw_prims->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); /* NOTE: insaner -- SCROLL the connections panel thing!!! */
sw_prims->set_shadow_type(Gtk::SHADOW_IN);
+ sw_infobox->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_NEVER);
+
// al_settings->set_padding(0, 0, 12, 0);
// fr_settings->set_shadow_type(Gtk::SHADOW_NONE);
// ((Gtk::Label*)fr_settings->get_label_widget())->set_use_markup();
diff --git a/src/ui/dialog/filter-effects-dialog.h b/src/ui/dialog/filter-effects-dialog.h
index 355a8b1b2..658aac790 100644
--- a/src/ui/dialog/filter-effects-dialog.h
+++ b/src/ui/dialog/filter-effects-dialog.h
@@ -236,7 +236,8 @@ private:
SPFilterPrimitive* _drag_prim;
sigc::signal<void> _signal_primitive_changed;
sigc::connection _scroll_connection;
- int _autoscroll;
+ int _autoscroll_y;
+ int _autoscroll_x;
std::auto_ptr<Inkscape::XML::SignalObserver> _observer;
int _input_type_width;
int _input_type_height;
diff --git a/src/ui/dialog/inkscape-preferences.cpp b/src/ui/dialog/inkscape-preferences.cpp
index fb814e066..34a908995 100644
--- a/src/ui/dialog/inkscape-preferences.cpp
+++ b/src/ui/dialog/inkscape-preferences.cpp
@@ -598,7 +598,7 @@ void InkscapePreferences::initPageUI()
_("When on, will allow dynamic layout of components that are not completely finished being refactored"), true);
/* show infobox */
- _show_filters_info_box.init( _("Show filter primitives infobox"), "/options/showfiltersinfobox/value", true);
+ _show_filters_info_box.init( _("Show filter primitives infobox (requires restart)"), "/options/showfiltersinfobox/value", true);
_page_ui.add_line(false, "", _show_filters_info_box, "",
_("Show icons and descriptions for the filter primitives available at the filter effects dialog"));
diff --git a/src/verbs.cpp b/src/verbs.cpp
index f8bfbab40..b8e72bc9b 100644
--- a/src/verbs.cpp
+++ b/src/verbs.cpp
@@ -2793,7 +2793,7 @@ Verb *Verb::_base_verbs[] = {
new DialogVerb(SP_VERB_DIALOG_LIVE_PATH_EFFECT, "DialogLivePathEffect", N_("Path E_ffects ..."),
N_("Manage, edit, and apply path effects"), NULL),
new DialogVerb(SP_VERB_DIALOG_FILTER_EFFECTS, "DialogFilterEffects", N_("Filter _Editor..."),
- N_("Manage, edit, and apply SVG filters"), NULL),
+ N_("Manage, edit, and apply SVG filters"), INKSCAPE_ICON("dialog-filters")),
new DialogVerb(SP_VERB_DIALOG_SVG_FONTS, "DialogSVGFonts", N_("SVG Font Editor..."),
N_("Edit SVG fonts"), NULL),
new DialogVerb(SP_VERB_DIALOG_PRINT_COLORS_PREVIEW, "DialogPrintColorsPreview", N_("Print Colors..."),
diff --git a/src/widgets/stroke-style.cpp b/src/widgets/stroke-style.cpp
index 0f79a609b..c6934f0a6 100644
--- a/src/widgets/stroke-style.cpp
+++ b/src/widgets/stroke-style.cpp
@@ -87,6 +87,33 @@ SPObject* getMarkerObj(gchar const *n, SPDocument *doc)
namespace Inkscape {
+
+/**
+ * Construct a stroke-style radio button with a given icon
+ *
+ * \param[in] grp The Gtk::RadioButtonGroup to which to add the new button
+ * \param[in] icon The icon to use for the button
+ * \param[in] button_type The type of stroke-style radio button (join/cap)
+ * \param[in] stroke_style The style attribute to associate with the button
+ */
+StrokeStyle::StrokeStyleButton::StrokeStyleButton(Gtk::RadioButtonGroup &grp,
+ char const *icon,
+ StrokeStyleButtonType button_type,
+ gchar const *stroke_style)
+ :
+ Gtk::RadioButton(grp),
+ button_type(button_type),
+ stroke_style(stroke_style)
+{
+ show();
+ set_mode(false);
+
+ Gtk::Widget *px = manage(Glib::wrap(sp_icon_new(Inkscape::ICON_SIZE_LARGE_TOOLBAR, icon)));
+ g_assert(px != NULL);
+ px->show();
+ add(*px);
+}
+
/**
* Create the fill or stroke style widget, and hook up all the signals.
*/
@@ -194,24 +221,27 @@ StrokeStyle::StrokeStyle() :
hb = spw_hbox(table, 3, 1, i);
- //tb = NULL;
+ Gtk::RadioButtonGroup joinGrp;
+
+ joinMiter = makeRadioButton(joinGrp, INKSCAPE_ICON("stroke-join-miter"),
+ hb, STROKE_STYLE_BUTTON_JOIN, "miter");
- joinMiter = makeRadioButton(NULL, INKSCAPE_ICON("stroke-join-miter"),
- hb, "join", "miter");
// TRANSLATORS: Miter join: joining lines with a sharp (pointed) corner.
// For an example, draw a triangle with a large stroke width and modify the
// "Join" option (in the Fill and Stroke dialog).
joinMiter->set_tooltip_text(_("Miter join"));
- joinRound = makeRadioButton(joinMiter, INKSCAPE_ICON("stroke-join-round"),
- hb, "join", "round");
+ joinRound = makeRadioButton(joinGrp, INKSCAPE_ICON("stroke-join-round"),
+ hb, STROKE_STYLE_BUTTON_JOIN, "round");
+
// TRANSLATORS: Round join: joining lines with a rounded corner.
// For an example, draw a triangle with a large stroke width and modify the
// "Join" option (in the Fill and Stroke dialog).
joinRound->set_tooltip_text(_("Round join"));
- joinBevel = makeRadioButton(joinMiter, INKSCAPE_ICON("stroke-join-bevel"),
- hb, "join", "bevel");
+ joinBevel = makeRadioButton(joinGrp, INKSCAPE_ICON("stroke-join-bevel"),
+ hb, STROKE_STYLE_BUTTON_JOIN, "bevel");
+
// TRANSLATORS: Bevel join: joining lines with a blunted (flattened) corner.
// For an example, draw a triangle with a large stroke width and modify the
// "Join" option (in the Fill and Stroke dialog).
@@ -260,20 +290,25 @@ StrokeStyle::StrokeStyle() :
hb = spw_hbox(table, 3, 1, i);
- capButt = makeRadioButton(capButt, INKSCAPE_ICON("stroke-cap-butt"),
- hb, "cap", "butt");
+ Gtk::RadioButtonGroup capGrp;
+
+ capButt = makeRadioButton(capGrp, INKSCAPE_ICON("stroke-cap-butt"),
+ hb, STROKE_STYLE_BUTTON_CAP, "butt");
+
// TRANSLATORS: Butt cap: the line shape does not extend beyond the end point
// of the line; the ends of the line are square
capButt->set_tooltip_text(_("Butt cap"));
- capRound = makeRadioButton(capButt, INKSCAPE_ICON("stroke-cap-round"),
- hb, "cap", "round");
+ capRound = makeRadioButton(capGrp, INKSCAPE_ICON("stroke-cap-round"),
+ hb, STROKE_STYLE_BUTTON_CAP, "round");
+
// TRANSLATORS: Round cap: the line shape extends beyond the end point of the
// line; the ends of the line are rounded
capRound->set_tooltip_text(_("Round cap"));
- capSquare = makeRadioButton(capButt, INKSCAPE_ICON("stroke-cap-square"),
- hb, "cap", "square");
+ capSquare = makeRadioButton(capGrp, INKSCAPE_ICON("stroke-cap-square"),
+ hb, STROKE_STYLE_BUTTON_CAP, "square");
+
// TRANSLATORS: Square cap: the line shape extends beyond the end point of the
// line; the ends of the line are square
capSquare->set_tooltip_text(_("Square cap"));
@@ -394,39 +429,36 @@ void StrokeStyle::setDesktop(SPDesktop *desktop)
/**
- * Helper function for creating radio buttons. This should probably be re-thought out
- * when reimplementing this with Gtkmm.
+ * Helper function for creating stroke-style radio buttons.
+ *
+ * \param[in] grp The Gtk::RadioButtonGroup in which to add the button
+ * \param[in] icon The icon for the button
+ * \param[in] hb The Gtk::Box container in which to add the button
+ * \param[in] button_type The type (join/cap) for the button
+ * \param[in] stroke_style The style attribute to associate with the button
+ *
+ * \details After instantiating the button, it is added to a container box and
+ * a handler for the toggle event is connected.
*/
-Gtk::RadioButton *
-StrokeStyle::makeRadioButton(Gtk::RadioButton *tb, char const *icon,
- Gtk::HBox *hb, gchar const *key, gchar const *data)
+StrokeStyle::StrokeStyleButton *
+StrokeStyle::makeRadioButton(Gtk::RadioButtonGroup &grp,
+ char const *icon,
+ Gtk::HBox *hb,
+ StrokeStyleButtonType button_type,
+ gchar const *stroke_style)
{
g_assert(icon != NULL);
g_assert(hb != NULL);
- if (tb == NULL) {
- tb = new Gtk::RadioButton();
- } else {
- Gtk::RadioButtonGroup grp = tb->get_group();
- tb = new Gtk::RadioButton(grp);
- }
+ StrokeStyleButton *tb = new StrokeStyleButton(grp, icon, button_type, stroke_style);
- tb->show();
- tb->set_mode(false);
hb->pack_start(*tb, false, false, 0);
set_data(icon, tb);
- tb->set_data(key, (gpointer*)data);
- tb->signal_toggled().connect(sigc::bind<Gtk::RadioButton *, StrokeStyle *>(
+ tb->signal_toggled().connect(sigc::bind<StrokeStyleButton *, StrokeStyle *>(
sigc::ptr_fun(&StrokeStyle::buttonToggledCB), tb, this));
- Gtk::Widget *px = manage(Glib::wrap(sp_icon_new(Inkscape::ICON_SIZE_LARGE_TOOLBAR, icon)));
- g_assert(px != NULL);
- px->show();
- tb->add(*px);
-
return tb;
-
}
/**
@@ -1120,38 +1152,30 @@ StrokeStyle::lineDashChangedCB()
* calls the respective routines to update css properties, etc.
*
*/
-void StrokeStyle::buttonToggledCB(Gtk::ToggleButton *tb, StrokeStyle *spw)
+void StrokeStyle::buttonToggledCB(StrokeStyleButton *tb, StrokeStyle *spw)
{
if (spw->update) {
return;
}
if (tb->get_active()) {
-
- gchar const *join
- = static_cast<gchar const *>(tb->get_data("join"));
- gchar const *cap
- = static_cast<gchar const *>(tb->get_data("cap"));
-
- if (join) {
- spw->miterLimitSpin->set_sensitive(!strcmp(join, "miter"));
+ if (tb->get_button_type() == STROKE_STYLE_BUTTON_JOIN) {
+ spw->miterLimitSpin->set_sensitive(!strcmp(tb->get_stroke_style(), "miter"));
}
/* TODO: Create some standardized method */
SPCSSAttr *css = sp_repr_css_attr_new();
- if (join) {
- sp_repr_css_set_property(css, "stroke-linejoin", join);
-
- sp_desktop_set_style (spw->desktop, css);
-
- spw->setJoinButtons(tb);
- } else if (cap) {
- sp_repr_css_set_property(css, "stroke-linecap", cap);
-
- sp_desktop_set_style (spw->desktop, css);
-
- spw->setCapButtons(tb);
+ switch (tb->get_button_type()) {
+ case STROKE_STYLE_BUTTON_JOIN:
+ sp_repr_css_set_property(css, "stroke-linejoin", tb->get_stroke_style());
+ sp_desktop_set_style (spw->desktop, css);
+ spw->setJoinButtons(tb);
+ break;
+ case STROKE_STYLE_BUTTON_CAP:
+ sp_repr_css_set_property(css, "stroke-linecap", tb->get_stroke_style());
+ sp_desktop_set_style (spw->desktop, css);
+ spw->setCapButtons(tb);
}
sp_repr_css_attr_unref(css);
diff --git a/src/widgets/stroke-style.h b/src/widgets/stroke-style.h
index 5f05b97d1..fd9940db1 100644
--- a/src/widgets/stroke-style.h
+++ b/src/widgets/stroke-style.h
@@ -104,6 +104,7 @@ void sp_stroke_style_widget_set_desktop(Gtk::Widget *widget, SPDesktop *desktop)
SPObject *getMarkerObj(gchar const *n, SPDocument *doc);
namespace Inkscape {
+class StrokeStyleButton;
class StrokeStyle : public Gtk::VBox
{
@@ -113,7 +114,33 @@ public:
void setDesktop(SPDesktop *desktop);
private:
-
+ /** List of valid types for the stroke-style radio-button widget */
+ enum StrokeStyleButtonType {
+ STROKE_STYLE_BUTTON_JOIN, ///< A button to set the line-join style
+ STROKE_STYLE_BUTTON_CAP ///< A button to set the line-cap style
+ };
+
+ /**
+ * A custom radio-button for setting the stroke style. It can be configured
+ * to set either the join or cap style by setting the button_type field.
+ */
+ class StrokeStyleButton : public Gtk::RadioButton {
+ public:
+ StrokeStyleButton(Gtk::RadioButtonGroup &grp,
+ char const *icon,
+ StrokeStyleButtonType button_type,
+ gchar const *stroke_style);
+
+ /** Get the type (line/cap) of the stroke-style button */
+ inline StrokeStyleButtonType get_button_type() {return button_type;}
+
+ /** Get the stroke style attribute associated with the button */
+ inline gchar const * get_stroke_style() {return stroke_style;}
+
+ private:
+ StrokeStyleButtonType button_type; ///< The type (line/cap) of the button
+ gchar const *stroke_style; ///< The stroke style associated with the button
+ };
void updateLine();
void updateAllMarkers(GSList const *objects);
@@ -129,8 +156,12 @@ private:
SPObject *forkMarker(SPObject *marker, int loc, SPItem *item);
const char *getItemColorForMarker(SPItem *item, Inkscape::PaintTarget fill_or_stroke, int loc);
- Gtk::RadioButton * makeRadioButton(Gtk::RadioButton *tb, char const *icon,
- Gtk::HBox *hb, gchar const *key, gchar const *data);
+ StrokeStyleButton * makeRadioButton(Gtk::RadioButtonGroup &grp,
+ char const *icon,
+ Gtk::HBox *hb,
+ StrokeStyleButtonType button_type,
+ gchar const *stroke_style);
+
static gboolean setStrokeWidthUnit(SPUnitSelector *,
SPUnit const *old,
SPUnit const *new_units,
@@ -143,7 +174,7 @@ private:
void miterLimitChangedCB();
void lineDashChangedCB();
static void markerSelectCB(MarkerComboBox *marker_combo, StrokeStyle *spw, SPMarkerLoc const which);
- static void buttonToggledCB(Gtk::ToggleButton *tb, StrokeStyle *spw);
+ static void buttonToggledCB(StrokeStyleButton *tb, StrokeStyle *spw);
MarkerComboBox *startMarkerCombo;
@@ -161,12 +192,12 @@ private:
Inkscape::UI::Widget::SpinButton *miterLimitSpin;
Inkscape::UI::Widget::SpinButton *widthSpin;
GtkWidget *unitSelector;
- Gtk::RadioButton *joinMiter;
- Gtk::RadioButton *joinRound;
- Gtk::RadioButton *joinBevel;
- Gtk::RadioButton *capButt;
- Gtk::RadioButton *capRound;
- Gtk::RadioButton *capSquare;
+ StrokeStyleButton *joinMiter;
+ StrokeStyleButton *joinRound;
+ StrokeStyleButton *joinBevel;
+ StrokeStyleButton *capButt;
+ StrokeStyleButton *capRound;
+ StrokeStyleButton *capSquare;
SPDashSelector *dashSelector;
gboolean update;