diff --git a/src/live_effects/parameter/originalpatharray.cpp b/src/live_effects/parameter/originalpatharray.cpp index 874ea56317831cc69398fcb475149cefa5b025fc..efca62a13e3869a1a29fc853f48eda28b5802794 100644 --- a/src/live_effects/parameter/originalpatharray.cpp +++ b/src/live_effects/parameter/originalpatharray.cpp @@ -70,51 +70,12 @@ OriginalPathArrayParam::OriginalPathArrayParam( const Glib::ustring& label, Inkscape::UI::Widget::Registry* wr, Effect* effect ) : Parameter(label, tip, key, wr, effect), - _vector(), - _tree(), - _text_renderer(), - _toggle_reverse(), - _toggle_visible(), - _scroller() + _vector() { - _model = new ModelColumns(); - _store = Gtk::TreeStore::create(*_model); - _tree.set_model(_store); + initui(); - _tree.set_reorderable(true); - _tree.enable_model_drag_dest (Gdk::ACTION_MOVE); - Gtk::CellRendererToggle * _toggle_reverse = manage(new Gtk::CellRendererToggle()); - int reverseColNum = _tree.append_column(_("Reverse"), *_toggle_reverse) - 1; - Gtk::TreeViewColumn* col_reverse = _tree.get_column(reverseColNum); - _toggle_reverse->set_activatable(true); - _toggle_reverse->signal_toggled().connect(sigc::mem_fun(*this, &OriginalPathArrayParam::on_reverse_toggled)); - col_reverse->add_attribute(_toggle_reverse->property_active(), _model->_colReverse); - - - Gtk::CellRendererToggle * _toggle_visible = manage(new Gtk::CellRendererToggle()); - int visibleColNum = _tree.append_column(_("Visible"), *_toggle_visible) - 1; - Gtk::TreeViewColumn* col_visible = _tree.get_column(visibleColNum); - _toggle_visible->set_activatable(true); - _toggle_visible->signal_toggled().connect(sigc::mem_fun(*this, &OriginalPathArrayParam::on_visible_toggled)); - col_visible->add_attribute(_toggle_visible->property_active(), _model->_colVisible); - - _text_renderer = manage(new Gtk::CellRendererText()); - int nameColNum = _tree.append_column(_("Name"), *_text_renderer) - 1; - _name_column = _tree.get_column(nameColNum); - _name_column->add_attribute(_text_renderer->property_text(), _model->_colLabel); - - _tree.set_expander_column( *_tree.get_column(nameColNum) ); - _tree.set_search_column(_model->_colLabel); - - //quick little hack -- newer versions of gtk gave the item zero space allotment - _scroller.set_size_request(-1, 120); - - _scroller.add(_tree); - _scroller.set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC ); - //_scroller.set_shadow_type(Gtk::SHADOW_IN); - oncanvas_editable = true; _from_original_d = false; _allow_only_bspline_spiro = false; @@ -132,6 +93,54 @@ OriginalPathArrayParam::~OriginalPathArrayParam() delete _model; } +void +OriginalPathArrayParam::initui() { + SPDesktop * desktop = SP_ACTIVE_DESKTOP; + if (!desktop) { + return; + } + if (!_tree) { + _tree = manage(new Gtk::TreeView()); + _model = new ModelColumns(); + _store = Gtk::TreeStore::create(*_model); + _tree->set_model(_store); + + _tree->set_reorderable(true); + _tree->enable_model_drag_dest (Gdk::ACTION_MOVE); + + Gtk::CellRendererToggle *toggle_reverse = manage(new Gtk::CellRendererToggle()); + int reverseColNum = _tree->append_column(_("Reverse"), *toggle_reverse) - 1; + Gtk::TreeViewColumn* col_reverse = _tree->get_column(reverseColNum); + toggle_reverse->set_activatable(true); + toggle_reverse->signal_toggled().connect(sigc::mem_fun(*this, &OriginalPathArrayParam::on_reverse_toggled)); + col_reverse->add_attribute(toggle_reverse->property_active(), _model->_colReverse); + + + Gtk::CellRendererToggle *toggle_visible = manage(new Gtk::CellRendererToggle()); + int visibleColNum = _tree->append_column(_("Visible"), *toggle_visible) - 1; + Gtk::TreeViewColumn* col_visible = _tree->get_column(visibleColNum); + toggle_visible->set_activatable(true); + toggle_visible->signal_toggled().connect(sigc::mem_fun(*this, &OriginalPathArrayParam::on_visible_toggled)); + col_visible->add_attribute(toggle_visible->property_active(), _model->_colVisible); + + Gtk::CellRendererText *text_renderer = manage(new Gtk::CellRendererText()); + int nameColNum = _tree->append_column(_("Name"), *text_renderer) - 1; + Gtk::TreeView::Column *name_column = _tree->get_column(nameColNum); + name_column->add_attribute(text_renderer->property_text(), _model->_colLabel); + + _tree->set_expander_column(*_tree->get_column(nameColNum) ); + _tree->set_search_column(_model->_colLabel); + _scroller = Gtk::manage(new Gtk::ScrolledWindow()); + //quick little hack -- newer versions of gtk gave the item zero space allotment + _scroller->set_size_request(-1, 120); + + _scroller->add(*_tree); + _scroller->set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC ); + //_scroller.set_shadow_type(Gtk::SHADOW_IN); + } + param_readSVGValue(param_getSVGValue().c_str()); +} + void OriginalPathArrayParam::on_reverse_toggled(const Glib::ustring& path) { Gtk::TreeModel::iterator iter = _store->get_iter(path); @@ -165,10 +174,13 @@ void OriginalPathArrayParam::param_set_default() Gtk::Widget* OriginalPathArrayParam::param_newWidget() { + Gtk::Box* vbox = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL)); Gtk::Box* hbox = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL)); - - vbox->pack_start(_scroller, Gtk::PACK_EXPAND_WIDGET); + _tree = nullptr; + _scroller = nullptr; + initui(); + vbox->pack_start(*_scroller, Gtk::PACK_EXPAND_WIDGET); { // Paste path to link button @@ -229,7 +241,7 @@ Gtk::Widget* OriginalPathArrayParam::param_newWidget() bool OriginalPathArrayParam::_selectIndex(const Gtk::TreeIter& iter, int* i) { if ((*i)-- <= 0) { - _tree.get_selection()->select(iter); + _tree->get_selection()->select(iter); return true; } return false; @@ -237,7 +249,7 @@ bool OriginalPathArrayParam::_selectIndex(const Gtk::TreeIter& iter, int* i) void OriginalPathArrayParam::on_up_button_click() { - Gtk::TreeModel::iterator iter = _tree.get_selection()->get_selected(); + Gtk::TreeModel::iterator iter = _tree->get_selection()->get_selected(); if (iter) { Gtk::TreeModel::Row row = *iter; @@ -262,7 +274,7 @@ void OriginalPathArrayParam::on_up_button_click() void OriginalPathArrayParam::on_down_button_click() { - Gtk::TreeModel::iterator iter = _tree.get_selection()->get_selected(); + Gtk::TreeModel::iterator iter = _tree->get_selection()->get_selected(); if (iter) { Gtk::TreeModel::Row row = *iter; @@ -290,7 +302,7 @@ void OriginalPathArrayParam::on_down_button_click() void OriginalPathArrayParam::on_remove_button_click() { - Gtk::TreeModel::iterator iter = _tree.get_selection()->get_selected(); + Gtk::TreeModel::iterator iter = _tree->get_selection()->get_selected(); if (iter) { Gtk::TreeModel::Row row = *iter; remove_link(row[_model->_colObject]); @@ -397,7 +409,9 @@ void OriginalPathArrayParam::linked_changed(SPObject */*old_obj*/, SPObject *new } else { to->_pathvector = Geom::PathVector(); SP_OBJECT(param_effect->getLPEObj())->requestModified(SP_OBJECT_MODIFIED_FLAG); - _store->foreach_iter(sigc::bind(sigc::mem_fun(*this, &OriginalPathArrayParam::_updateLink), to)); + if (_store.get()) { + _store->foreach_iter(sigc::bind(sigc::mem_fun(*this, &OriginalPathArrayParam::_updateLink), to)); + } } } @@ -465,7 +479,9 @@ void OriginalPathArrayParam::linked_modified(SPObject *linked_obj, guint flags, } setPathVector(linked_obj, flags, to); SP_OBJECT(param_effect->getLPEObj())->requestModified(SP_OBJECT_MODIFIED_FLAG); - _store->foreach_iter(sigc::bind(sigc::mem_fun(*this, &OriginalPathArrayParam::_updateLink), to)); + if (_store.get()) { + _store->foreach_iter(sigc::bind(sigc::mem_fun(*this, &OriginalPathArrayParam::_updateLink), to)); + } } bool OriginalPathArrayParam::param_readSVGValue(const gchar* strvalue) @@ -477,7 +493,10 @@ bool OriginalPathArrayParam::param_readSVGValue(const gchar* strvalue) _vector.pop_back(); delete w; } - _store->clear(); + + if (_store.get()) { + _store->clear(); + } gchar ** strarray = g_strsplit(strvalue, "|", 0); for (gchar ** iter = strarray; *iter != nullptr; iter++) { @@ -492,15 +511,16 @@ bool OriginalPathArrayParam::param_readSVGValue(const gchar* strvalue) w->ref.attach(URI(w->href)); _vector.push_back(w); - - Gtk::TreeModel::iterator iter = _store->append(); - Gtk::TreeModel::Row row = *iter; - SPObject *obj = w->ref.getObject(); - - row[_model->_colObject] = w; - row[_model->_colLabel] = obj ? ( obj->label() ? obj->label() : obj->getId() ) : w->href; - row[_model->_colReverse] = w->reversed; - row[_model->_colVisible] = w->visibled; + if (_store.get()) { + Gtk::TreeModel::iterator iter = _store->append(); + Gtk::TreeModel::Row row = *iter; + SPObject *obj = w->ref.getObject(); + + row[_model->_colObject] = w; + row[_model->_colLabel] = obj ? ( obj->label() ? obj->label() : obj->getId() ) : w->href; + row[_model->_colReverse] = w->reversed; + row[_model->_colVisible] = w->visibled; + } g_strfreev (substrarray); } } diff --git a/src/live_effects/parameter/originalpatharray.h b/src/live_effects/parameter/originalpatharray.h index 6f58627bdced5bc65bcd163a863a208f1cf633fa..1fcf17f0f08407d107fd771f474f6498e603d05d 100644 --- a/src/live_effects/parameter/originalpatharray.h +++ b/src/live_effects/parameter/originalpatharray.h @@ -94,12 +94,8 @@ protected: ModelColumns *_model; Glib::RefPtr _store; - Gtk::TreeView _tree; - Gtk::CellRendererText *_text_renderer; - Gtk::CellRendererToggle *_toggle_reverse; - Gtk::CellRendererToggle *_toggle_visible; - Gtk::TreeView::Column *_name_column; - Gtk::ScrolledWindow _scroller; + Gtk::TreeView *_tree; + Gtk::ScrolledWindow *_scroller; void on_link_button_click(); void on_remove_button_click(); @@ -112,6 +108,7 @@ private: bool _from_original_d; bool _allow_only_bspline_spiro; void update(); + void initui(); OriginalPathArrayParam(const OriginalPathArrayParam&) = delete; OriginalPathArrayParam& operator=(const OriginalPathArrayParam&) = delete; }; diff --git a/testfiles/CMakeLists.txt b/testfiles/CMakeLists.txt index 1ad1ce9d9c2628b75f4fa191f787bb1dc49de02f..af6a4bc26c77c7d371d21ef0de2f435bddb457b9 100644 --- a/testfiles/CMakeLists.txt +++ b/testfiles/CMakeLists.txt @@ -75,11 +75,11 @@ set(TEST_SOURCES svg-extension-test curve-test 2geom-characterization-test - lpe-bool-test + lpes-test xml-test sp-item-group-test) -add_library(cpp_test_static_library SHARED unittest.cpp doc-per-case-test.cpp) +add_library(cpp_test_static_library SHARED unittest.cpp doc-per-case-test.cpp lpes-test.h) target_link_libraries(cpp_test_static_library PUBLIC ${GTEST_LIBRARIES} inkscape_base) add_custom_target(tests) @@ -97,6 +97,7 @@ endforeach() ### CLI and rendering tests add_subdirectory(cli_tests) add_subdirectory(rendering_tests) +add_subdirectory(lpe_tests) ### Fuzz test diff --git a/testfiles/lpe_tests/CMakeLists.txt b/testfiles/lpe_tests/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..2d665c271b82d032b7d000563d48494bef3df251 --- /dev/null +++ b/testfiles/lpe_tests/CMakeLists.txt @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +file(GLOB files "*.svg") +foreach(file ${files}) + set(testname "lpe_${file}") + add_test(NAME lpe_${file} + COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/test.sh ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_lpes ${file} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/testfiles/lpe_tests) +endforeach() + diff --git a/testfiles/lpe_tests/LPEAttachPathTest_attach_PX_1_0_2.svg b/testfiles/lpe_tests/LPEAttachPathTest_attach_PX_1_0_2.svg new file mode 100644 index 0000000000000000000000000000000000000000..99370f52c34b56a60ae152a800c5a99c7a6b7bc2 --- /dev/null +++ b/testfiles/lpe_tests/LPEAttachPathTest_attach_PX_1_0_2.svg @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + diff --git a/testfiles/lpe_tests/test.sh b/testfiles/lpe_tests/test.sh new file mode 100755 index 0000000000000000000000000000000000000000..be2741e313d3194687ac51d4e8f78b9e651065a1 --- /dev/null +++ b/testfiles/lpe_tests/test.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0-or-later + +if [ "$#" -lt 2 ]; then + echo "pass the path of the inkscape executable as parameter then the name of the test" $# + exit 1 +fi + + +LPES_TESTS_EXE=$1 +exit_status=0 +test=$2 +testname=$(basename $test) + +echo "$(cat $test)" | ${LPES_TESTS_EXE} #2>/dev/null >/dev/null + +exit $exit_status diff --git a/testfiles/lpes-test.h b/testfiles/lpes-test.h new file mode 100644 index 0000000000000000000000000000000000000000..e431d8b5b365ffee42f5ea25d3285b7b8c597260 --- /dev/null +++ b/testfiles/lpes-test.h @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** @file + * LPE test file wrapper + *//* + * Authors: see git history + * + * Copyright (C) 2020 Authors + * + * Released under GNU GPL version 2 or later, read the file 'COPYING' for more information + */ + +#include +#include + +using namespace Inkscape; + +class LPESTest : public ::testing::Test { + protected: + void SetUp() override; + void pathCompare(const gchar *a, const gchar *b, const gchar *id, double precission = 0.001); + void TearDown( ) override; + // you can override custom threshold from svg file using in + // root svg from global and override with per shape "inkscape:test-threshold" + void testDoc(Glib::ustring svg, double precission = 0.001); + std::vector< const gchar *> failed; +}; + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : \ No newline at end of file diff --git a/testfiles/src/lpe-bool-test.cpp b/testfiles/src/lpe-bool-test.cpp deleted file mode 100644 index 31bc3717726a01d76a092fe2d2efd813bb7a91c4..0000000000000000000000000000000000000000 --- a/testfiles/src/lpe-bool-test.cpp +++ /dev/null @@ -1,70 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/** @file - * LPE Boolean operation test - *//* - * Authors: see git history - * - * Copyright (C) 2020 Authors - * - * Released under GNU GPL version 2 or later, read the file 'COPYING' for more information - */ - -#include -#include -#include -#include -#include -#include - - - -using namespace Inkscape; -using namespace Inkscape::LivePathEffect; - -class LPEBoolTest : public ::testing::Test { - protected: - void SetUp() override - { - // setup hidden dependency - Application::create(false); - } -}; - -TEST_F(LPEBoolTest, canBeApplyedToNonSiblingPaths) -{ - std::string svg("\ -\ - \ - \ - \ - \ - \ - \ - \ -"); - - SPDocument *doc = SPDocument::createNewDocFromMem(svg.c_str(), svg.size(), true); - doc->ensureUpToDate(); - - auto lpe_item = dynamic_cast(doc->getObjectById("rect1")); - ASSERT_TRUE(lpe_item != nullptr); - - auto lpe_bool_op_effect = dynamic_cast(lpe_item->getPathEffectOfType(EffectType::BOOL_OP)); - ASSERT_TRUE(lpe_bool_op_effect != nullptr); - - auto operand_path = lpe_bool_op_effect->getParameter("operand-path")->param_getSVGValue(); - auto circle = dynamic_cast(doc->getObjectById(operand_path.substr(1))); - ASSERT_TRUE(circle != nullptr); -} \ No newline at end of file diff --git a/testfiles/src/lpes-test.cpp b/testfiles/src/lpes-test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..af67a698c27338eaedac0f9936f3a7e71f338eaa --- /dev/null +++ b/testfiles/src/lpes-test.cpp @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** @file + * LPE test file wrapper + *//* + * Authors: see git history + * + * Copyright (C) 2020 Authors + * + * Released under GNU GPL version 2 or later, read the file 'COPYING' for more information + */ + +#include +#include +#include +#include +#include + +using namespace Inkscape; + +void LPESTest::SetUp() +{ + // setup hidden dependency + Application::create(false); +} + +void LPESTest::pathCompare(const gchar *a, const gchar *b, const gchar *id, double precission) { + failed.push_back(id); + Geom::PathVector apv = sp_svg_read_pathv(a); + Geom::PathVector bpv = sp_svg_read_pathv(b); + size_t totala = apv.curveCount(); + size_t totalb = bpv.curveCount(); + ASSERT_TRUE(totala == totalb); + std::vector pos; + for (size_t i = 0; i < apv.curveCount(); i++) { + Geom::Point pointa = apv.pointAt(float(i)+0.2); + Geom::Point pointb = bpv.pointAt(float(i)+0.2); + Geom::Point pointc = apv.pointAt(float(i)+0.4); + Geom::Point pointd = bpv.pointAt(float(i)+0.4); + Geom::Point pointe = apv.pointAt(float(i)); + Geom::Point pointf = bpv.pointAt(float(i)); + ASSERT_NEAR(pointa[Geom::X], pointb[Geom::X], precission); + ASSERT_NEAR(pointa[Geom::Y], pointb[Geom::Y], precission); + ASSERT_NEAR(pointc[Geom::X], pointd[Geom::X], precission); + ASSERT_NEAR(pointc[Geom::Y], pointd[Geom::Y], precission); + ASSERT_NEAR(pointe[Geom::X], pointf[Geom::X], precission); + ASSERT_NEAR(pointe[Geom::Y], pointf[Geom::Y], precission); + } + failed.pop_back(); +} + +void LPESTest::TearDown( ) { + Glib::ustring ids = ""; + for (auto fail : failed) { + if (ids != "") { + ids += ","; + } + ids += fail; + } + if (ids != "") { + FAIL() << "[FAILED IDS] " << ids; + } +} + +// you can override custom threshold from svg file using in +// root svg from global and override with per shape "inkscape:test-threshold" +void LPESTest::testDoc(Glib::ustring svg, double precission) { + SPDocument *doc = SPDocument::createNewDocFromMem(svg.c_str(), svg.size(), true); + doc->ensureUpToDate(); + std::vector< SPObject *> objs; + std::vector ds; + for (auto obj : doc->getObjectsByElement("path")) { + if (obj->getAttribute("d")) { + ds.push_back(obj->getAttribute("d")); + objs.push_back(obj); + } + } + for (auto obj : doc->getObjectsByElement("ellipse")) { + if (obj->getAttribute("d")) { + ds.push_back(obj->getAttribute("d")); + objs.push_back(obj); + } + } + for (auto obj : doc->getObjectsByElement("circle")) { + if (obj->getAttribute("d")) { + ds.push_back(obj->getAttribute("d")); + objs.push_back(obj); + } + } + for (auto obj : doc->getObjectsByElement("rect")) { + if (obj->getAttribute("d")) { + ds.push_back(obj->getAttribute("d")); + objs.push_back(obj); + } + } + SPLPEItem *lpeitem = dynamic_cast(doc->getRoot()); + sp_lpe_item_update_patheffect (lpeitem, false, true); + if (lpeitem->getAttribute("inkscape:test-threshold")) { + precission = helperfns_read_number(lpeitem->getAttribute("inkscape:test-threshold")); + } + if (doc->getObjectsByElement("clipPath").size() || doc->getObjectsByElement("mask").size()) { + // we need to double update because clippaths + sp_lpe_item_update_patheffect (lpeitem, false, true); + } + + size_t index = 0; + for (auto obj : objs) { + if (obj->getAttribute("inkscape:test-threshold")) { + precission = helperfns_read_number(obj->getAttribute("inkscape:test-threshold")); + } + if (!obj->getAttribute("inkscape:test-ignore")) { + pathCompare(ds[index], obj->getAttribute("d"), obj->getAttribute("id"), precission); + } + index++; + } +} + + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :