diff options
Diffstat (limited to 'src/actions')
-rw-r--r-- | src/actions/CMakeLists.txt | 12 | ||||
-rw-r--r-- | src/actions/README | 26 | ||||
-rw-r--r-- | src/actions/actions-base.cpp | 281 | ||||
-rw-r--r-- | src/actions/actions-base.h | 19 | ||||
-rw-r--r-- | src/actions/actions-extra-data.cpp | 67 | ||||
-rw-r--r-- | src/actions/actions-extra-data.h | 64 | ||||
-rw-r--r-- | src/actions/actions-file.cpp | 142 | ||||
-rw-r--r-- | src/actions/actions-file.h | 31 | ||||
-rw-r--r-- | src/actions/actions-helper.cpp | 48 | ||||
-rw-r--r-- | src/actions/actions-helper.h | 34 | ||||
-rw-r--r-- | src/actions/actions-object.cpp | 159 | ||||
-rw-r--r-- | src/actions/actions-object.h | 30 | ||||
-rw-r--r-- | src/actions/actions-output.cpp | 309 | ||||
-rw-r--r-- | src/actions/actions-output.h | 31 | ||||
-rw-r--r-- | src/actions/actions-selection.cpp | 286 | ||||
-rw-r--r-- | src/actions/actions-selection.h | 30 | ||||
-rw-r--r-- | src/actions/actions-transform.cpp | 132 | ||||
-rw-r--r-- | src/actions/actions-transform.h | 30 | ||||
-rw-r--r-- | src/actions/actions-window.cpp | 96 | ||||
-rw-r--r-- | src/actions/actions-window.h | 31 |
20 files changed, 1858 insertions, 0 deletions
diff --git a/src/actions/CMakeLists.txt b/src/actions/CMakeLists.txt new file mode 100644 index 0000000..d5b8339 --- /dev/null +++ b/src/actions/CMakeLists.txt @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +set(actions_SRC + # actions-base.cpp + # actions-selection.cpp + + # HEADERS + # actions-base.h + # actions-selection.h + ) + +add_inkscape_source("${actions_SRC}") diff --git a/src/actions/README b/src/actions/README new file mode 100644 index 0000000..b6806d8 --- /dev/null +++ b/src/actions/README @@ -0,0 +1,26 @@ + +This directory contains Gio::Actions. + +"A GAction (Gio::Action) is a representation of a single +user-interesting action in an application." +(https://wiki.gnome.org/HowDoI/GAction) + +In more layman terms, it provides a uniform interface for calling +functions with an optional single parameter that is not tied to the +GUI. + +Actions provide two operations: + +* activation (which results in calling the function), +* state change (if the action supports a state). + +While actions are defined independent of the GUI (unlike GtkAction), +the can be used by "actionable widgets" (menus, buttons, etc.) by +simply referring to them by name. They can also be remotely activated +by D-Bus and GNotifications. + +To do: + +* Convert 'verbs' to Gio::Actions. +* Update command line to use actions. +* Update GUI to use actions. diff --git a/src/actions/actions-base.cpp b/src/actions/actions-base.cpp new file mode 100644 index 0000000..4af8113 --- /dev/null +++ b/src/actions/actions-base.cpp @@ -0,0 +1,281 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Gio::Actions tied to the application and independent of GUI. + * + * Copyright (C) 2018 Tavmjong Bah + * + * The contents of this file may be used under the GNU General Public License Version 2 or later. + * + */ + +#include <iostream> + +#include <giomm.h> // Not <gtkmm.h>! To eventually allow a headless version! +#include <glibmm/i18n.h> + +#include "actions-base.h" +#include "actions-helper.h" + +#include "inkscape-application.h" + +#include "inkscape.h" // Inkscape::Application +#include "inkscape-version.h" // Inkscape version +#include "path-prefix.h" // Extension directory +#include "extension/init.h" // List verbs +#include "verbs.h" // List verbs +#include "selection.h" // Selection +#include "object/sp-root.h" // query_all() +#include "file.h" // dpi convert method +#include "io/resource.h" + +void +print_inkscape_version() +{ + std::cout << "Inkscape " << Inkscape::version_string << std::endl; + std::cerr << " Pango version: " << pango_version_string() << std::endl; +} + +void +print_system_data_directory() +{ + std::cout << INKSCAPE_SYSTEMDIR << std::endl; +} + +void +print_user_data_directory() +{ + std::cout << Inkscape::IO::Resource::profile_path("") << std::endl; +} + +void +print_verb_list() +{ + // This really shouldn't go here, we should init the app. + // But, since we're just exiting in this path, there is + // no harm, and this is really a better place to put + // everything else. + Inkscape::Extension::init(); // extension/init.h + Inkscape::Verb::list(); // verbs.h +} + +// Helper function for query_x(), query_y(), query_width(), and query_height(). +void +query_dimension(InkscapeApplication* app, bool extent, Geom::Dim2 const axis) +{ + SPDocument* document = nullptr; + Inkscape::Selection* selection = nullptr; + if (!get_document_and_selection(app, &document, &selection)) { + return; + } + + if (selection->isEmpty()) { + selection->add(document->getRoot()); + } + + bool first = true; + auto items = selection->items(); + for (auto item : items) { + if (!first) { + std::cout << ","; + } + first = false; + Geom::OptRect area = item->documentVisualBounds(); + if (area) { + if (extent) { + std::cout << area->dimensions()[axis]; + } else { + std::cout << area->min()[axis]; + } + } else { + std::cout << "0"; + } + } + std::cout << std::endl; +} + +void +query_x(InkscapeApplication* app) +{ + query_dimension(app, false, Geom::X); +} + +void +query_y(InkscapeApplication* app) +{ + query_dimension(app, false, Geom::Y); +} + +void +query_width(InkscapeApplication* app) +{ + query_dimension(app, true, Geom::X); +} + +void +query_height(InkscapeApplication* app) +{ + query_dimension(app, true, Geom::Y); +} + +// Helper for query_all() +void +query_all_recurse (SPObject *o) +{ + SPItem *item = dynamic_cast<SPItem*>(o); + if (item && item->getId()) { + Geom::OptRect area = item->documentVisualBounds(); + if (area) { + std::cout << item->getId() << "," + << area->min()[Geom::X] << "," + << area->min()[Geom::Y] << "," + << area->dimensions()[Geom::X] << "," + << area->dimensions()[Geom::Y] << std::endl; + } + + for (auto& child: o->children) { + query_all_recurse (&child); + } + } +} + +void +query_all(InkscapeApplication* app) +{ + SPDocument* doc = app->get_active_document(); + if (!doc) { + std::cerr << "query_all: no document!" << std::endl; + return; + } + + SPObject *o = doc->getRoot(); + if (o) { + query_all_recurse(o); + } +} + +void +pdf_page(int page) +{ + INKSCAPE.set_pdf_page(page); +} + +void +convert_dpi_method(Glib::ustring method) +{ + if (method == "none") { + sp_file_convert_dpi_method_commandline = FILE_DPI_UNCHANGED; + } else if (method == "scale-viewbox") { + sp_file_convert_dpi_method_commandline = FILE_DPI_VIEWBOX_SCALED; + } else if (method == "scale-document") { + sp_file_convert_dpi_method_commandline = FILE_DPI_DOCUMENT_SCALED; + } else { + std::cerr << "dpi_convert_method: invalid option" << std::endl; + } +} + +void +no_convert_baseline() +{ + sp_no_convert_text_baseline_spacing = true; +} + +// Temporary: Verbs are to be replaced by Gio::Actions! +void +verbs(Glib::ustring verblist, InkscapeApplication* app) +{ + auto tokens = Glib::Regex::split_simple("\\s*;\\s*", verblist); + for (auto token : tokens) { + std::vector<Glib::ustring> parts = Glib::Regex::split_simple("\\s*:\\s*", token); // Second part is always ignored... we could implement it but better to switch to Gio::Actions + if (!parts.empty() && !parts[0].empty()) { + Inkscape::Verb* verb = Inkscape::Verb::getbyid(parts[0].c_str()); + if (verb == nullptr) { + std::cerr << "verbs_action: Invalid verb: " << parts[0] << std::endl; + break; + } + // Inkscape::ActionContext context = INKSCAPE.action_context_for_document(*document); + SPAction* action = verb->get_action(INKSCAPE.active_action_context()); + sp_action_perform(action, nullptr); // Data is ignored! + } + } +} + +void +vacuum_defs(InkscapeApplication* app) +{ + SPDocument* document = nullptr; + Inkscape::Selection* selection = nullptr; + if (!get_document_and_selection(app, &document, &selection)) { + return; + } + document->vacuumDocument(); +} + +void +quit_inkscape(InkscapeApplication* app) +{ + app->on_quit(); +} + +std::vector<std::vector<Glib::ustring>> raw_data_base = +{ + {"inkscape-version", "InkscapeVersion", "Base", N_("Print Inkscape version and exit.") }, + {"system-data-directory", "InkscapeSystemDir", "Base", N_("Print system data directory and exit.") }, + {"user-data-directory", "InkscapeUserDir", "Base", N_("Print user data directory and exit.") }, + {"action-list", "InkscapeActions", "Base", N_("Print a list of actions and exit.") }, + {"verb-list", "InkscapeVerbs", "Base", N_("Print a list of verbs and exit.") }, + {"verb", "Verb", "Base", N_("Execute verb(s).") }, + {"vacuum-defs", "VacuumDefs", "Base", N_("Remove unused definitions (gradients, etc.).") }, + {"quit-inkscape", "QuitInkscape", "Base", N_("Immediately quit Inkscape.") }, + + {"open-page", "ImportPageNumber", "Import", N_("Import page number.") }, + {"convert-dpi-method", "ImportDPIMethod", "Import", N_("Import DPI convert method.") }, + {"no-convert-baseline", "ImportBaselineConvert", "Import", N_("Import convert text baselines.") }, + + {"query-x", "QueryX", "Query", N_("Query 'x' value(s) of selected objects.") }, + {"query-y", "QueryY", "Query", N_("Query 'y' value(s) of selected objects.") }, + {"query-width", "QueryWidth", "Query", N_("Query 'width' value(s) of object(s).") }, + {"query-height", "QueryHeight", "Query", N_("Query 'height' value(s) of object(s).") }, + {"query-all", "QueryAll", "Query", N_("Query 'x', 'y', 'width', and 'height'.") } +}; + +template<class T> +void +add_actions_base(ConcreteInkscapeApplication<T>* app) +{ + // Note: "radio" actions are just an easy way to set type without using templating. + app->add_action( "inkscape-version", sigc::ptr_fun(&print_inkscape_version) ); + app->add_action( "system-data-directory", sigc::ptr_fun(&print_system_data_directory) ); + app->add_action( "user-data-directory", sigc::ptr_fun(&print_user_data_directory) ); + app->add_action( "action-list", sigc::mem_fun(app, &ConcreteInkscapeApplication<T>::print_action_list) ); + app->add_action( "verb-list", sigc::ptr_fun(&print_verb_list) ); + app->add_action_radio_string( "verb", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&verbs), app), "null"); + app->add_action( "vacuum-defs", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&vacuum_defs), app) ); + app->add_action( "quit-inkscape", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&quit_inkscape), app) ); + + app->add_action_radio_integer( "open-page", sigc::ptr_fun(&pdf_page), 0); + app->add_action_radio_string( "convert-dpi-method", sigc::ptr_fun(&convert_dpi_method), "none"); + app->add_action( "no-convert-baseline", sigc::ptr_fun(&no_convert_baseline) ); + + + app->add_action( "query-x", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&query_x), app) ); + app->add_action( "query-y", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&query_y), app) ); + app->add_action( "query-width", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&query_width), app) ); + app->add_action( "query-height", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&query_height), app) ); + app->add_action( "query-all", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&query_all), app) ); + + app->get_action_extra_data().add_data(raw_data_base); +} + +template void add_actions_base(ConcreteInkscapeApplication<Gio::Application>* app); +template void add_actions_base(ConcreteInkscapeApplication<Gtk::Application>* app); + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/actions/actions-base.h b/src/actions/actions-base.h new file mode 100644 index 0000000..cf43b8e --- /dev/null +++ b/src/actions/actions-base.h @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Gio::Actions tied to the application and without GUI. + * + * Copyright (C) 2018 Tavmjong Bah + * + * The contents of this file may be used under the GNU General Public License Version 2 or later. + * + */ + +#ifndef INK_ACTIONS_BASE_H +#define INK_ACTIONS_BASE_H + +template<class T> class ConcreteInkscapeApplication; + +template<class T> +void add_actions_base(ConcreteInkscapeApplication<T>* app); + +#endif // INK_ACTIONS_BASE_H diff --git a/src/actions/actions-extra-data.cpp b/src/actions/actions-extra-data.cpp new file mode 100644 index 0000000..45094d7 --- /dev/null +++ b/src/actions/actions-extra-data.cpp @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Extra data associated with actions: Label, Section, Tooltip. + * + * Copyright (C) 2020 Tavmjong Bah + * + * The contents of this file may be used under the GNU General Public License Version 2 or later. + * + */ + +#include "actions-extra-data.h" + +#include <iostream> + +Glib::ustring +InkActionExtraData::get_label_for_action(Glib::ustring& action_name) +{ + Glib::ustring value; + auto search = data.find(action_name); + if (search != data.end()) { + value = search->second.get_label(); + } + return value; +} + +Glib::ustring +InkActionExtraData::get_section_for_action(Glib::ustring& action_name) { + + Glib::ustring value; + auto search = data.find(action_name); + if (search != data.end()) { + value = search->second.get_section(); + } + return value; +} + +Glib::ustring +InkActionExtraData::get_tooltip_for_action(Glib::ustring& action_name) { + + Glib::ustring value; + auto search = data.find(action_name); + if (search != data.end()) { + value = search->second.get_tooltip(); + } + return value; +} + +void +InkActionExtraData::add_data(std::vector<std::vector<Glib::ustring>> &raw_data) +{ + for (auto raw : raw_data) { + InkActionExtraDatum datum(raw[1], raw[2], raw[3]); + data.emplace(raw[0], datum); + } +} + + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/actions/actions-extra-data.h b/src/actions/actions-extra-data.h new file mode 100644 index 0000000..e96234e --- /dev/null +++ b/src/actions/actions-extra-data.h @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Extra data associated with actions: Label, Section, Tooltip. + * + * Copyright (C) 2020 Tavmjong Bah + * + * The contents of this file may be used under the GNU General Public License Version 2 or later. + * + */ + +#ifndef INK_ACTIONS_EXTRA_DATA_H +#define INK_ACTIONS_EXTRA_DATA_H + +#include <map> +#include <vector> + +#include <glibmm/ustring.h> + +class InkActionExtraDatum { + public: + InkActionExtraDatum(Glib::ustring& label, Glib::ustring& section, Glib::ustring& tooltip) + : action_label(label) + , action_section(section) + , action_tooltip(tooltip) + { + } + + Glib::ustring get_label() { return action_label; } + Glib::ustring get_section() { return action_section; } + Glib::ustring get_tooltip() { return action_tooltip; } + + private: + Glib::ustring action_label; + Glib::ustring action_section; + Glib::ustring action_tooltip; +}; + +class InkActionExtraData { + + public: + InkActionExtraData() = default; + + void add_data(std::vector<std::vector<Glib::ustring>> &raw_data); + + Glib::ustring get_label_for_action(Glib::ustring& action_name); + Glib::ustring get_section_for_action(Glib::ustring& action_name); + Glib::ustring get_tooltip_for_action(Glib::ustring& action_name); + + private: + std::map<Glib::ustring, InkActionExtraDatum> data; +}; + +#endif // INK_ACTIONS_EXTRA_DATA_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/actions/actions-file.cpp b/src/actions/actions-file.cpp new file mode 100644 index 0000000..0cf05f1 --- /dev/null +++ b/src/actions/actions-file.cpp @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Gio::Actions for file handling tied to the application and without GUI. + * + * Copyright (C) 2020 Tavmjong Bah + * + * The contents of this file may be used under the GNU General Public License Version 2 or later. + * + */ + +#include <iostream> + +#include <giomm.h> // Not <gtkmm.h>! To eventually allow a headless version! +#include <glibmm/i18n.h> + +#include "actions-file.h" +#include "actions-helper.h" +#include "inkscape-application.h" + +#include "inkscape.h" // Inkscape::Application +#include "helper/action-context.h" + +// Actions for file handling (should be integrated with file dialog). + +void +file_open(const Glib::VariantBase& value, InkscapeApplication *app) +{ + Glib::Variant<Glib::ustring> s = Glib::VariantBase::cast_dynamic<Glib::Variant<Glib::ustring> >(value); + + Glib::RefPtr<Gio::File> file = Gio::File::create_for_path(s.get()); + if (!file->query_exists()) { + std::cerr << "file_open: file '" << s.get() << "' does not exist." << std::endl; + return; + } + + SPDocument *document = app->document_open(file); + INKSCAPE.add_document(document); + + Inkscape::ActionContext context = INKSCAPE.action_context_for_document(document); + app->set_active_document(document); + app->set_active_selection(context.getSelection()); + app->set_active_view(context.getView()); + + document->ensureUpToDate(); +} + +void +file_new(const Glib::VariantBase& value, InkscapeApplication *app) +{ + Glib::Variant<Glib::ustring> s = Glib::VariantBase::cast_dynamic<Glib::Variant<Glib::ustring> >(value); + + SPDocument *document = app->document_new(s.get()); + INKSCAPE.add_document(document); + + Inkscape::ActionContext context = INKSCAPE.action_context_for_document(document); + app->set_active_document(document); + app->set_active_selection(context.getSelection()); + app->set_active_view(context.getView()); + + document->ensureUpToDate(); +} + +// Need to redo document_revert so that it doesn't depend on windows. +// void +// file_revert(InkscapeApplication *app) +// { +// app->document_revert(app->get_current_document()); +// } + +void +file_close(InkscapeApplication *app) +{ + SPDocument *document = app->get_active_document(); + app->document_close(document); + + app->set_active_document(nullptr); + app->set_active_selection(nullptr); + app->set_active_view(nullptr); +} + +// TODO: +// file_open +// file_new + +// The following might be best tied to the file rather than app. +// file_revert +// file_save +// file_saveas +// file_saveacopy +// file_print +// file_vacuum +// file_import +// file_close +// file_quit ... should just be quit +// file_template + +std::vector<std::vector<Glib::ustring>> raw_data_file = +{ + {"file-open", "FileOpen", "File", N_("Open file.") }, + {"file-new", "FileNew", "File", N_("Open new document using template.") }, + {"file-close", "FileClose", "File", N_("Close active document.") } +}; + +template <class T> +void +add_actions_file(ConcreteInkscapeApplication<T>* app) +{ + Glib::VariantType Bool( Glib::VARIANT_TYPE_BOOL); + Glib::VariantType Int( Glib::VARIANT_TYPE_INT32); + Glib::VariantType Double(Glib::VARIANT_TYPE_DOUBLE); + Glib::VariantType String(Glib::VARIANT_TYPE_STRING); + Glib::VariantType BString(Glib::VARIANT_TYPE_BYTESTRING); + + // Debian 9 has 2.50.0 +#if GLIB_CHECK_VERSION(2, 52, 0) + + app->add_action_with_parameter( "file-open", String, sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&file_open), app)); + app->add_action_with_parameter( "file-new", String, sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&file_new), app)); + app->add_action( "file-close", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&file_close), app)); +#else + std::cerr << "add_actions: Some actions require Glibmm 2.52, compiled with: " << glib_major_version << "." << glib_minor_version << std::endl; +#endif + + app->get_action_extra_data().add_data(raw_data_file); +} + + +template void add_actions_file(ConcreteInkscapeApplication<Gio::Application>* app); +template void add_actions_file(ConcreteInkscapeApplication<Gtk::Application>* app); + + + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/actions/actions-file.h b/src/actions/actions-file.h new file mode 100644 index 0000000..b4a0b22 --- /dev/null +++ b/src/actions/actions-file.h @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Gio::Actions for file handling tied to the application and without GUI. + * + * Copyright (C) 2020 Tavmjong Bah + * + * The contents of this file may be used under the GNU General Public License Version 2 or later. + * + */ + +#ifndef INK_ACTIONS_FILE_H +#define INK_ACTIONS_FILE_H + +class InkscapeApplication; +template<class T> class ConcreteInkscapeApplication; + +template<class T> +void add_actions_file(ConcreteInkscapeApplication<T>* app); + +#endif // INK_ACTIONS_FILE_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/actions/actions-helper.cpp b/src/actions/actions-helper.cpp new file mode 100644 index 0000000..e72a15d --- /dev/null +++ b/src/actions/actions-helper.cpp @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Gio::Actions for selection tied to the application and without GUI. + * + * Copyright (C) 2018 Tavmjong Bah + * + * The contents of this file may be used under the GNU General Public License Version 2 or later. + * + */ + +#include "actions-helper.h" + +#include "inkscape-application.h" +#include "inkscape.h" +#include "selection.h" + +// Helper function: returns true if both document and selection found. Maybe this should +// work on current view. Or better, application could return the selection of the current view. +bool +get_document_and_selection(InkscapeApplication* app, SPDocument** document, Inkscape::Selection** selection) +{ + *document = app->get_active_document(); + if (!(*document)) { + std::cerr << "get_document_and_selection: No document!" << std::endl; + return false; + } + + // To do: get selection from active view (which could be from desktop or not). + Inkscape::ActionContext context = INKSCAPE.action_context_for_document(*document); + *selection = context.getSelection(); + if (!*selection) { + std::cerr << "get_document_and_selection: No selection!" << std::endl; + return false; + } + + return true; +} + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/actions/actions-helper.h b/src/actions/actions-helper.h new file mode 100644 index 0000000..da65e10 --- /dev/null +++ b/src/actions/actions-helper.h @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Gio::Actions for selection tied to the application and without GUI. + * + * Copyright (C) 2018 Tavmjong Bah + * + * The contents of this file may be used under the GNU General Public License Version 2 or later. + * + */ + +#ifndef INK_ACTIONS_HELPER_H +#define INK_ACTIONS_HELPER_H + +class InkscapeApplication; +class SPDocument; +namespace Inkscape { + class Selection; +} + +bool get_document_and_selection(InkscapeApplication* app, SPDocument** document, Inkscape::Selection** selection); + + +#endif // INK_ACTIONS_HELPER_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/actions/actions-object.cpp b/src/actions/actions-object.cpp new file mode 100644 index 0000000..d0c6d06 --- /dev/null +++ b/src/actions/actions-object.cpp @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Gio::Actions for working with objects without GUI. + * + * Copyright (C) 2020 Tavmjong Bah + * + * The contents of this file may be used under the GNU General Public License Version 2 or later. + * + */ + +#include <iostream> + +#include <giomm.h> // Not <gtkmm.h>! To eventually allow a headless version! +#include <glibmm/i18n.h> + +#include "actions-object.h" +#include "actions-helper.h" +#include "document-undo.h" +#include "inkscape-application.h" + +#include "inkscape.h" // Inkscape::Application +#include "selection.h" // Selection + + +// No sanity checking is done... should probably add. +void +object_set_attribute(const Glib::VariantBase& value, InkscapeApplication *app) +{ + Glib::Variant<Glib::ustring> s = Glib::VariantBase::cast_dynamic<Glib::Variant<Glib::ustring> >(value); + + std::vector<Glib::ustring> tokens = Glib::Regex::split_simple(",", s.get()); + if (tokens.size() != 2) { + std::cerr << "action:object_set_attribute: requires 'attribute name, attribute value'" << std::endl; + return; + } + + auto selection = app->get_active_selection(); + if (selection->isEmpty()) { + std::cerr << "action:object_set_attribute: selection empty!" << std::endl; + return; + } + + // Should this be a selection member function? + auto items = selection->items(); + for (auto i = items.begin(); i != items.end(); ++i) { + Inkscape::XML::Node *repr = (*i)->getRepr(); + repr->setAttribute(tokens[0], tokens[1]); + } + + // Needed to update repr (is this the best way?). + Inkscape::DocumentUndo::done(app->get_active_document(), 0, "ActionObjectSetAttribute"); +} + + +// No sanity checking is done... should probably add. +void +object_set_property(const Glib::VariantBase& value, InkscapeApplication *app) +{ + Glib::Variant<Glib::ustring> s = Glib::VariantBase::cast_dynamic<Glib::Variant<Glib::ustring> >(value); + + std::vector<Glib::ustring> tokens = Glib::Regex::split_simple(",", s.get()); + if (tokens.size() != 2) { + std::cerr << "action:object_set_property: requires 'property name, property value'" << std::endl; + return; + } + + auto selection = app->get_active_selection(); + if (selection->isEmpty()) { + std::cerr << "action:object_set_property: selection empty!" << std::endl; + return; + } + + // Should this be a selection member function? + auto items = selection->items(); + for (auto i = items.begin(); i != items.end(); ++i) { + Inkscape::XML::Node *repr = (*i)->getRepr(); + SPCSSAttr *css = sp_repr_css_attr(repr, "style"); + sp_repr_css_set_property(css, tokens[0].c_str(), tokens[1].c_str()); + sp_repr_css_set(repr, css, "style"); + sp_repr_css_attr_unref(css); + } + + // Needed to update repr (is this the best way?). + Inkscape::DocumentUndo::done(app->get_active_document(), 0, "ActionObjectSetProperty"); +} + + +void +object_unlink_clones(InkscapeApplication *app) +{ + auto selection = app->get_active_selection(); + + // We should not have to do this! + auto document = app->get_active_document(); + selection->setDocument(document); + + selection->unlink(); +} + + +void +object_to_path(InkscapeApplication *app) +{ + auto selection = app->get_active_selection(); + + // We should not have to do this! + auto document = app->get_active_document(); + selection->setDocument(document); + + selection->toCurves(); +} + + +std::vector<std::vector<Glib::ustring>> raw_data_object = +{ + {"object-set-attribute", "ObjectSetAttribute", "Object", N_("Set or update an attribute on selected objects. Usage: object-set-attribute:attribute name, attribute value;")}, + {"object-set-property", "ObjectSetProperty", "Object", N_("Set or update a property on selected objects. Usage: object-set-property:property name, property value;")}, + {"object-unlink-clones", "ObjectUnlinkClones", "Object", N_("Unlink clones and symbols.") }, + {"object-to-path", "ObjectToPath", "Object", N_("Convert shapes to paths.") }, +}; + +template<class T> +void +add_actions_object(ConcreteInkscapeApplication<T>* app) +{ + Glib::VariantType Bool( Glib::VARIANT_TYPE_BOOL); + Glib::VariantType Int( Glib::VARIANT_TYPE_INT32); + Glib::VariantType Double(Glib::VARIANT_TYPE_DOUBLE); + Glib::VariantType String(Glib::VARIANT_TYPE_STRING); + + // Debian 9 has 2.50.0 +#if GLIB_CHECK_VERSION(2, 52, 0) + + app->add_action_with_parameter( "object-set-attribute", String, sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&object_set_attribute), app)); + app->add_action_with_parameter( "object-set-property", String, sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&object_set_property), app)); + app->add_action( "object-unlink-clones", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&object_unlink_clones), app)); + app->add_action( "object-to-path", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&object_to_path), app)); + +#endif + + app->get_action_extra_data().add_data(raw_data_object); +} + + +template void add_actions_object(ConcreteInkscapeApplication<Gio::Application>* app); +template void add_actions_object(ConcreteInkscapeApplication<Gtk::Application>* app); + + + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/actions/actions-object.h b/src/actions/actions-object.h new file mode 100644 index 0000000..dbde543 --- /dev/null +++ b/src/actions/actions-object.h @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Gio::Actions for working with objects not tied to GUI. + * + * Copyright (C) 2020 Tavmjong Bah + * + * The contents of this file may be used under the GNU General Public License Version 2 or later. + * + */ + +#ifndef INK_ACTIONS_OBJECT_H +#define INK_ACTIONS_OBJECT_H + +template<class T> class ConcreteInkscapeApplication; + +template<class T> +void add_actions_object(ConcreteInkscapeApplication<T>* app); + +#endif // INK_ACTIONS_OBJECT_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/actions/actions-output.cpp b/src/actions/actions-output.cpp new file mode 100644 index 0000000..559bd6b --- /dev/null +++ b/src/actions/actions-output.cpp @@ -0,0 +1,309 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Gio::Actions for output tied to the application and without GUI. + * + * Copyright (C) 2018 Tavmjong Bah + * + * The contents of this file may be used under the GNU General Public License Version 2 or later. + * + */ + +#include <iostream> + +#include <giomm.h> // Not <gtkmm.h>! To eventually allow a headless version! +#include <glibmm/i18n.h> + +#include "actions-output.h" +#include "actions-helper.h" +#include "inkscape-application.h" + +#include "inkscape.h" // Inkscape::Application + +// Actions for command line output (should be integrated with file dialog). + +// These actions are currently stateless and result in changes to an instance of the +// InkFileExportCmd class owned by the application. + +void +export_type(const Glib::VariantBase& value, InkscapeApplication *app) +{ + Glib::Variant<Glib::ustring> s = Glib::VariantBase::cast_dynamic<Glib::Variant<Glib::ustring> >(value); + app->file_export()->export_type = s.get(); + // std::cout << "export-type: " << s.get() << std::endl; +} + +void +export_filename(const Glib::VariantBase& value, InkscapeApplication *app) +{ + Glib::Variant<std::string> s = Glib::VariantBase::cast_dynamic<Glib::Variant<std::string> >(value); + app->file_export()->export_filename = s.get(); + // std::cout << "export-filename: " << s.get() << std::endl; +} + +void +export_overwrite(const Glib::VariantBase& value, InkscapeApplication *app) +{ + Glib::Variant<bool> b = Glib::VariantBase::cast_dynamic<Glib::Variant<bool> >(value); + app->file_export()->export_overwrite = b.get(); + // std::cout << "export-overwrite: " << std::boolalpha << b.get() << std::endl; +} + +void +export_area(const Glib::VariantBase& value, InkscapeApplication *app) +{ + Glib::Variant<std::string> s = Glib::VariantBase::cast_dynamic<Glib::Variant<std::string> >(value); + app->file_export()->export_area = s.get(); + // std::cout << "export-area: " << s.get() << std::endl; +} + +void +export_area_drawing(const Glib::VariantBase& value, InkscapeApplication *app) +{ + Glib::Variant<bool> b = Glib::VariantBase::cast_dynamic<Glib::Variant<bool> >(value); + app->file_export()->export_area_drawing = b.get(); + // std::cout << "export-area-drawing: " << std::boolalpha << b.get() << std::endl; +} + +void +export_area_page(const Glib::VariantBase& value, InkscapeApplication *app) +{ + Glib::Variant<bool> b = Glib::VariantBase::cast_dynamic<Glib::Variant<bool> >(value); + app->file_export()->export_area_page = b.get(); + // std::cout << "export-area-page: " << std::boolalpha << b.get() << std::endl; +} + +void +export_margin(const Glib::VariantBase& value, InkscapeApplication *app) +{ + Glib::Variant<int> i = Glib::VariantBase::cast_dynamic<Glib::Variant<int> >(value); + app->file_export()->export_margin = i.get(); + // std::cout << "export-margin: " << i.get() << std::endl; +} + +void +export_area_snap(const Glib::VariantBase& value, InkscapeApplication *app) +{ + Glib::Variant<bool> b = Glib::VariantBase::cast_dynamic<Glib::Variant<bool> >(value); + app->file_export()->export_area_snap = b.get(); + // std::cout << "export-area-snap: " << std::boolalpha << b.get() << std::endl; +} + +void +export_width(const Glib::VariantBase& value, InkscapeApplication *app) +{ + Glib::Variant<int> i = Glib::VariantBase::cast_dynamic<Glib::Variant<int> >(value); + app->file_export()->export_width = i.get(); + // std::cout << "export-width: " << i.get() << std::endl; +} + +void +export_height(const Glib::VariantBase& value, InkscapeApplication *app) +{ + Glib::Variant<int> i = Glib::VariantBase::cast_dynamic<Glib::Variant<int> >(value); + app->file_export()->export_height = i.get(); + // std::cout << "export-height: " << i.get() << std::endl; +} + +void +export_id(const Glib::VariantBase& value, InkscapeApplication *app) +{ + Glib::Variant<std::string> s = Glib::VariantBase::cast_dynamic<Glib::Variant<std::string> >(value); + app->file_export()->export_id = s.get(); + // std::cout << "export-id: " << s.get() << std::endl; +} + +void +export_id_only(const Glib::VariantBase& value, InkscapeApplication *app) +{ + Glib::Variant<bool> b = Glib::VariantBase::cast_dynamic<Glib::Variant<bool> >(value); + app->file_export()->export_id_only = b.get(); + // std::cout << "export-id-only: " << std::boolalpha << b.get() << std::endl; +} + +void +export_plain_svg(const Glib::VariantBase& value, InkscapeApplication *app) +{ + Glib::Variant<bool> b = Glib::VariantBase::cast_dynamic<Glib::Variant<bool> >(value); + app->file_export()->export_plain_svg = b.get(); + // std::cout << "export-plain-svg: " << std::boolalpha << b.get() << std::endl; +} + +void +export_dpi(const Glib::VariantBase& value, InkscapeApplication *app) +{ + Glib::Variant<double> d = Glib::VariantBase::cast_dynamic<Glib::Variant<double> >(value); + app->file_export()->export_dpi = d.get(); + // std::cout << "export-dpi: " << d.get() << std::endl; +} + +void +export_ignore_filters(const Glib::VariantBase& value, InkscapeApplication *app) +{ + Glib::Variant<bool> b = Glib::VariantBase::cast_dynamic<Glib::Variant<bool> >(value); + app->file_export()->export_ignore_filters = b.get(); + // std::cout << "export-ignore-filters: " << std::boolalpha << b.get() << std::endl; +} + +void +export_text_to_path(const Glib::VariantBase& value, InkscapeApplication *app) +{ + Glib::Variant<bool> b = Glib::VariantBase::cast_dynamic<Glib::Variant<bool> >(value); + app->file_export()->export_text_to_path = b.get(); + // std::cout << "export-text-to-path: " << std::boolalpha << b.get() << std::endl; +} + +void +export_ps_level(const Glib::VariantBase& value, InkscapeApplication *app) +{ + Glib::Variant<int> i = Glib::VariantBase::cast_dynamic<Glib::Variant<int> >(value); + app->file_export()->export_ps_level = i.get(); + // std::cout << "export-ps-level: " << i.get() << std::endl; +} + +void +export_pdf_level(const Glib::VariantBase& value, InkscapeApplication *app) +{ + Glib::Variant<Glib::ustring> s = Glib::VariantBase::cast_dynamic<Glib::Variant<Glib::ustring> >(value); + app->file_export()->export_pdf_level = s.get(); + // std::cout << "export-pdf-level" << s.get() << std::endl; +} + +void +export_latex(const Glib::VariantBase& value, InkscapeApplication *app) +{ + Glib::Variant<bool> b = Glib::VariantBase::cast_dynamic<Glib::Variant<bool> >(value); + app->file_export()->export_latex = b.get(); + // std::cout << "export-latex: " << std::boolalpha << b.get() << std::endl; +} + +void +export_use_hints(const Glib::VariantBase& value, InkscapeApplication *app) +{ + Glib::Variant<bool> b = Glib::VariantBase::cast_dynamic<Glib::Variant<bool> >(value); + app->file_export()->export_use_hints = b.get(); + // std::cout << "export-use-hints: " << std::boolalpha << b.get() << std::endl; +} + +void +export_background(const Glib::VariantBase& value, InkscapeApplication *app) +{ + Glib::Variant<std::string> s = Glib::VariantBase::cast_dynamic<Glib::Variant<std::string> >(value); + app->file_export()->export_background = s.get(); + // std::cout << "export-background: " << s.get() << std::endl; +} + +void +export_background_opacity(const Glib::VariantBase& value, InkscapeApplication *app) +{ + Glib::Variant<double> d = Glib::VariantBase::cast_dynamic<Glib::Variant<double> >(value); + app->file_export()->export_background_opacity = d.get(); + // std::cout << d.get() << std::endl; +} + +void +export_do(InkscapeApplication *app) +{ + SPDocument* document = app->get_active_document(); + std::string filename; + if (document->getDocumentURI()) { + filename = document->getDocumentURI(); + } + app->file_export()->do_export(document, filename); +} + +std::vector<std::vector<Glib::ustring>> raw_data_output = +{ + {"export-type", "ExportType", "Export", N_("Export file type.") }, + {"export-filename", "ExportFileName", "Export", N_("Export file name.") }, + {"export-overwrite", "ExportOverWrite", "Export", N_("Export over-write file.") }, + + {"export-area", "ExportArea", "Export", N_("Export area.") }, + {"export-area-drawing", "ExportAreaDrawing", "Export", N_("Export drawing area.") }, + {"export-area-page", "ExportAreaPage", "Export", N_("Export page area.") }, + {"export-margin", "ExportMargin", "Export", N_("Export margin.") }, + {"export-area-snap", "ExportAreaSnap", "Export", N_("Export snap area to integer values.") }, + {"export-width", "ExportWidth", "Export", N_("Export width.") }, + {"export-height", "ExportHeight", "Export", N_("Export height.") }, + + {"export-id", "ExportID", "Export", N_("Export id(s).") }, + {"export-id-only", "ExportIDOnly", "Export", N_("Export id(s) only.") }, + + {"export-plain-svg", "ExportPlanSVG", "Export", N_("Export as plain SVG.") }, + {"export-dpi", "ExportDPI", "Export", N_("Export DPI.") }, + {"export-ignore-filters", "ExportIgnoreFilters", "Export", N_("Export ignore filters.") }, + {"export-text-to-path", "ExportTextToPath", "Export", N_("Export convert text to paths.") }, + {"export-ps-level", "ExportPSLevel", "Export", N_("Export PostScript level.") }, + {"export-pdf-version", "ExportPSVersion", "Export", N_("Export PDF version.") }, + {"export-latex", "ExportLaTeX", "Export", N_("Export LaTeX.") }, + {"export-use-hints", "ExportUseHInts", "Export", N_("Export using saved hints.") }, + {"export-background", "ExportBackground", "Export", N_("Export background color.") }, + {"export-background-opacity", "ExportBackgroundOpacity", "Export", N_("Export background opacity.") }, + + {"export-do", "ExportDo", "Export", N_("Do export.") } +}; + +template <class T> +void +add_actions_output(ConcreteInkscapeApplication<T>* app) +{ + Glib::VariantType Bool( Glib::VARIANT_TYPE_BOOL); + Glib::VariantType Int( Glib::VARIANT_TYPE_INT32); + Glib::VariantType Double(Glib::VARIANT_TYPE_DOUBLE); + Glib::VariantType String(Glib::VARIANT_TYPE_STRING); + Glib::VariantType BString(Glib::VARIANT_TYPE_BYTESTRING); + + // Debian 9 has 2.50.0 +#if GLIB_CHECK_VERSION(2, 52, 0) + + // Matches command line options + app->add_action_with_parameter( "export-type", String, sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&export_type), app)); + app->add_action_with_parameter( "export-filename", String, sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&export_filename), app)); // MAY NOT WORK DUE TO std::string + app->add_action_with_parameter( "export-overwrite", Bool, sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&export_overwrite), app)); + + app->add_action_with_parameter( "export-area", String, sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&export_area), app)); + app->add_action_with_parameter( "export-area-drawing", Bool, sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&export_area_drawing), app)); + app->add_action_with_parameter( "export-area-page", Bool, sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&export_area_page), app)); + app->add_action_with_parameter( "export-margin", Int, sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&export_margin), app)); + app->add_action_with_parameter( "export-area-snap", Bool, sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&export_area_snap), app)); + app->add_action_with_parameter( "export-width", Int, sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&export_width), app)); + app->add_action_with_parameter( "export-height", Int, sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&export_height), app)); + + app->add_action_with_parameter( "export-id", String, sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&export_id), app)); + app->add_action_with_parameter( "export-id-only", Bool, sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&export_id_only), app)); + + app->add_action_with_parameter( "export-plain-svg", Bool, sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&export_plain_svg), app)); + app->add_action_with_parameter( "export-dpi", Double, sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&export_dpi), app)); + app->add_action_with_parameter( "export-ignore-filters", Bool, sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&export_plain_svg), app)); + app->add_action_with_parameter( "export-text-to-path", Bool, sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&export_text_to_path), app)); + app->add_action_with_parameter( "export-ps-level", Int, sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&export_ps_level), app)); + app->add_action_with_parameter( "export-pdf-version", String, sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&export_pdf_level), app)); + app->add_action_with_parameter( "export-latex", Bool, sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&export_latex), app)); + app->add_action_with_parameter( "export-use-hints", Bool, sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&export_use_hints), app)); + app->add_action_with_parameter( "export-background", String, sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&export_background), app)); + app->add_action_with_parameter( "export-background-opacity",Double, sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&export_background_opacity), app)); + + // Extra + app->add_action( "export-do", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&export_do), app)); +#else + std::cerr << "add_actions: Some actions require Glibmm 2.52, compiled with: " << glib_major_version << "." << glib_minor_version << std::endl; +#endif + + app->get_action_extra_data().add_data(raw_data_output); +} + + +template void add_actions_output(ConcreteInkscapeApplication<Gio::Application>* app); +template void add_actions_output(ConcreteInkscapeApplication<Gtk::Application>* app); + + + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/actions/actions-output.h b/src/actions/actions-output.h new file mode 100644 index 0000000..01ea455 --- /dev/null +++ b/src/actions/actions-output.h @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Gio::Actions for output tied to the application and without GUI. + * + * Copyright (C) 2018 Tavmjong Bah + * + * The contents of this file may be used under the GNU General Public License Version 2 or later. + * + */ + +#ifndef INK_ACTIONS_OUTPUT_H +#define INK_ACTIONS_OUTPUT_H + +class InkscapeApplication; +template<class T> class ConcreteInkscapeApplication; + +template<class T> +void add_actions_output(ConcreteInkscapeApplication<T>* app); + +#endif // INK_ACTIONS_OUTPUT_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/actions/actions-selection.cpp b/src/actions/actions-selection.cpp new file mode 100644 index 0000000..377ab0c --- /dev/null +++ b/src/actions/actions-selection.cpp @@ -0,0 +1,286 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Gio::Actions for selection tied to the application and without GUI. + * + * Copyright (C) 2018 Tavmjong Bah + * + * The contents of this file may be used under the GNU General Public License Version 2 or later. + * + */ + +#include <iostream> + +#include <giomm.h> // Not <gtkmm.h>! To eventually allow a headless version! +#include <glibmm/i18n.h> + +#include "actions-selection.h" +#include "actions-helper.h" +#include "inkscape-application.h" + +#include "inkscape.h" // Inkscape::Application +#include "selection.h" // Selection + +#include "object/sp-root.h" // select_all: document->getRoot(); +#include "object/sp-item-group.h" // select_all + +void +select_clear(InkscapeApplication* app) +{ + SPDocument* document = nullptr; + Inkscape::Selection* selection = nullptr; + if (!get_document_and_selection(app, &document, &selection)) { + return; + } + selection->clear(); +} + +void +select_by_id(Glib::ustring ids, InkscapeApplication* app) +{ + SPDocument* document = nullptr; + Inkscape::Selection* selection = nullptr; + if (!get_document_and_selection(app, &document, &selection)) { + return; + } + + auto tokens = Glib::Regex::split_simple("\\s*,\\s*", ids); + for (auto id : tokens) { + SPObject* object = document->getObjectById(id); + if (object) { + selection->add(object); + } else { + std::cerr << "select_by_id: Did not find object with id: " << id << std::endl; + } + } +} + +void +unselect_by_id(Glib::ustring ids, InkscapeApplication* app) +{ + SPDocument* document = nullptr; + Inkscape::Selection* selection = nullptr; + if (!get_document_and_selection(app, &document, &selection)) { + return; + } + + auto tokens = Glib::Regex::split_simple("\\s*,\\s*", ids); + for (auto id : tokens) { + SPObject* object = document->getObjectById(id); + if (object) { + selection->remove(object); + } else { + std::cerr << "unselect_by_id: Did not find object with id: " << id << std::endl; + } + } +} + +void +select_by_class(Glib::ustring klass, InkscapeApplication* app) +{ + SPDocument* document = nullptr; + Inkscape::Selection* selection = nullptr; + if (!get_document_and_selection(app, &document, &selection)) { + return; + } + + auto objects = document->getObjectsByClass(klass); + selection->add(objects.begin(), objects.end()); +} + +void +select_by_element(Glib::ustring element, InkscapeApplication* app) +{ + SPDocument* document = nullptr; + Inkscape::Selection* selection = nullptr; + if (!get_document_and_selection(app, &document, &selection)) { + return; + } + auto objects = document->getObjectsByElement(element); + selection->add(objects.begin(), objects.end()); +} + +void +select_by_selector(Glib::ustring selector, InkscapeApplication* app) +{ + SPDocument* document = nullptr; + Inkscape::Selection* selection = nullptr; + if (!get_document_and_selection(app, &document, &selection)) { + return; + } + + auto objects = document->getObjectsBySelector(selector); + selection->add(objects.begin(), objects.end()); +} + + +// Helper +void +get_all_items_recursive(std::vector<SPObject *> &objects, SPObject *object, Glib::ustring &condition) +{ + for (auto &o : object->childList(false)) { + if (dynamic_cast<SPItem *>(o)) { + SPGroup *group = dynamic_cast<SPGroup *>(o); + if (condition == "layers") { + if (group && group->layerMode() == SPGroup::LAYER) { + objects.emplace_back(o); + continue; // Layers cannot contain layers. + } + } else if (condition == "no-layers") { + if (group && group->layerMode() == SPGroup::LAYER) { + // recurse one level + } else { + objects.emplace_back(o); + continue; + } + } else if (condition == "groups") { + if (group) { + objects.emplace_back(o); + } + } else if (condition == "all") { + objects.emplace_back(o); + } else { + // no-groups, default + if (!group) { + objects.emplace_back(o); + continue; // Non-groups cannot contain items. + } + } + get_all_items_recursive(objects, o, condition); + } + } +} + + +/* + * 'layers': All layers. + * 'groups': All groups (including layers). + * 'no-layers': All top level objects in all layers (matches GUI "Select All in All Layers"). + * 'no-groups': All objects other than groups (and layers). + * 'all': All objects including groups and their decendents. + * + * Note: GUI "Select All" requires knowledge of selected layer, which is a desktop property. + */ +void +select_all(Glib::ustring condition, InkscapeApplication* app) +{ + if (condition != "" && condition != "layers" && condition != "no-layers" && + condition != "groups" && condition != "no-groups" && condition != "all") { + std::cerr << "select_all: allowed options are '', 'all', 'layers', 'no-layers', 'groups', and 'no-groups'" << std::endl; + return; + } + + SPDocument* document = nullptr; + Inkscape::Selection* selection = nullptr; + if (!get_document_and_selection(app, &document, &selection)) { + return; + } + + std::vector<SPObject *> objects; + get_all_items_recursive(objects, document->getRoot(), condition); + + selection->setList(objects); +} + +/* See above for conditions. */ +void +select_invert(Glib::ustring condition, InkscapeApplication* app) +{ + if (condition != "" && condition != "layers" && condition != "no-layers" && + condition != "groups" && condition != "no-groups" && condition != "all") { + std::cerr << "select_all: allowed options are '', 'all', 'layers', 'no-layers', 'groups', and 'no-groups'" << std::endl; + return; + } + + SPDocument* document = nullptr; + Inkscape::Selection* selection = nullptr; + if (!get_document_and_selection(app, &document, &selection)) { + return; + } + + // Find all objects that match condition. + std::vector<SPObject *> objects; + get_all_items_recursive(objects, document->getRoot(), condition); + + // Get current selection. + std::vector<SPObject *> current(selection->items().begin(), selection->items().end()); + + // Remove current selection from object vector (using "erase remove_if idiom"). + objects.erase( + std::remove_if(std::begin(objects), std::end(objects), [¤t](const SPObject *x) + { + return (std::find(current.begin(), current.end(), x) != current.end()); + }), objects.end()); + + // Set selection to object vector. + selection->setList(objects); +} + + +// Debug... print selected items +void +select_list(InkscapeApplication* app) +{ + SPDocument* document = nullptr; + Inkscape::Selection* selection = nullptr; + if (!get_document_and_selection(app, &document, &selection)) { + return; + } + + auto items = selection->items(); + for (auto i = items.begin(); i != items.end(); ++i) { + std::cout << **i << std::endl; + } +} + + +std::vector<std::vector<Glib::ustring>> raw_data_selection = +{ + {"select-clear", "SelectClear", "Select", N_("Selection clear") }, + {"select", "Select", "Select", N_("Select by ID (Deprecated)") }, + {"unselect", "UnSelect", "Select", N_("Unselect by ID (Deprecated)") }, + {"select-by-id", "SelectById", "Select", N_("Select by ID") }, + {"unselect-by-id", "UnselectById", "Select", N_("Unselect by ID") }, + {"select-by-class", "SelectByClass", "Select", N_("Select by class") }, + {"select-by-element", "SelectByElement", "Select", N_("Select by SVG element (e.g. 'rect').") }, + {"select-by-selector", "SelectBySelector", "Select", N_("Select by CSS selector") }, + {"select-all", "SelectAll", "Select", N_("Select all. Options: 'all' (every object including groups), 'layers', 'no-layers' (top level objects in layers), 'groups' (all groups including layers), 'no-groups' (all objects other than groups and layers, default).")}, + {"select-invert", "SelectInvert", "Select", N_("Invert selection. Options: 'all', 'layers', 'no-layers', 'groups', 'no-groups' (default).")}, + {"select-list", "SelectList", "Select", N_("Print a list of objects in current selection.") } +}; + +template<class T> +void +add_actions_selection(ConcreteInkscapeApplication<T>* app) +{ + app->add_action( "select-clear", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&select_clear), app) ); + app->add_action_radio_string( "select", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&select_by_id), app), "null"); // Backwards compatible. + app->add_action_radio_string( "unselect", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&unselect_by_id), app), "null"); // Match select. + app->add_action_radio_string( "select-by-id", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&select_by_id), app), "null"); + app->add_action_radio_string( "unselect-by-id", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&unselect_by_id), app), "null"); + app->add_action_radio_string( "select-by-class", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&select_by_class), app), "null"); + app->add_action_radio_string( "select-by-element", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&select_by_element), app), "null"); + app->add_action_radio_string( "select-by-selector",sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&select_by_selector), app), "null"); + app->add_action_radio_string( "select-all", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&select_all), app), "null"); + app->add_action_radio_string( "select-invert", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&select_invert), app), "null"); + app->add_action( "select-list", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&select_list), app) ); + + app->get_action_extra_data().add_data(raw_data_selection); +} + +template void add_actions_selection(ConcreteInkscapeApplication<Gio::Application>* app); +template void add_actions_selection(ConcreteInkscapeApplication<Gtk::Application>* app); + + + + + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/actions/actions-selection.h b/src/actions/actions-selection.h new file mode 100644 index 0000000..f792a5c --- /dev/null +++ b/src/actions/actions-selection.h @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Gio::Actions for selection tied to the application and without GUI. + * + * Copyright (C) 2018 Tavmjong Bah + * + * The contents of this file may be used under the GNU General Public License Version 2 or later. + * + */ + +#ifndef INK_ACTIONS_SELECTION_H +#define INK_ACTIONS_SELECTION_H + +template<class T> class ConcreteInkscapeApplication; + +template<class T> +void add_actions_selection(ConcreteInkscapeApplication<T>* app); + +#endif // INK_ACTIONS_SELECTION_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/actions/actions-transform.cpp b/src/actions/actions-transform.cpp new file mode 100644 index 0000000..a6127da --- /dev/null +++ b/src/actions/actions-transform.cpp @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Gio::Actions for selection tied to the application and without GUI. + * + * Copyright (C) 2018 Tavmjong Bah + * + * The contents of this file may be used under the GNU General Public License Version 2 or later. + * + */ + +#include <iostream> + +#include <giomm.h> // Not <gtkmm.h>! To eventually allow a headless version! +#include <glibmm/i18n.h> + +#include "actions-transform.h" +#include "actions-helper.h" +#include "document-undo.h" +#include "inkscape-application.h" + +#include "inkscape.h" // Inkscape::Application +#include "selection.h" // Selection + +void +transform_translate(const Glib::VariantBase& value, InkscapeApplication *app) +{ + Glib::Variant<Glib::ustring> s = Glib::VariantBase::cast_dynamic<Glib::Variant<Glib::ustring> >(value); + + std::vector<Glib::ustring> tokens = Glib::Regex::split_simple(",", s.get()); + if (tokens.size() != 2) { + std::cerr << "action:transform_translate: requires two comma separated numbers" << std::endl; + return; + } + double dx = 0; + double dy = 0; + + try { + dx = std::stod(tokens[0]); + dy = std::stod(tokens[1]); + } catch (...) { + std::cerr << "action:transform-move: invalid arguments" << std::endl; + return; + } + + auto selection = app->get_active_selection(); + selection->move(dx, dy); + + // Needed to update repr (is this the best way?). + Inkscape::DocumentUndo::done(app->get_active_document(), 0, "ActionTransformTranslate"); +} + +void +transform_rotate(const Glib::VariantBase& value, InkscapeApplication *app) +{ + + Glib::Variant<double> d = Glib::VariantBase::cast_dynamic<Glib::Variant<double> >(value); + auto selection = app->get_active_selection(); + + selection->rotate(d.get()); + + // Needed to update repr (is this the best way?). + Inkscape::DocumentUndo::done(app->get_active_document(), 0, "ActionTransformRotate"); +} + +void +transform_scale(const Glib::VariantBase& value, InkscapeApplication *app) +{ + Glib::Variant<double> d = Glib::VariantBase::cast_dynamic<Glib::Variant<double> >(value); + auto selection = app->get_active_selection(); + selection->scale(d.get()); + + // Needed to update repr (is this the best way?). + Inkscape::DocumentUndo::done(app->get_active_document(), 0, "ActionTransformScale"); +} + +void +transform_remove(InkscapeApplication *app) +{ + auto selection = app->get_active_selection(); + selection->removeTransform(); + + // Needed to update repr (is this the best way?). + Inkscape::DocumentUndo::done(app->get_active_document(), 0, "ActionTransformRemoveTransform"); +} + + +std::vector<std::vector<Glib::ustring>> raw_data_transform = +{ + {"transform-translate", "TransformTranslate", "Transform", N_("Translate selected objects (dx,dy).") }, + {"transform-rotate", "TransformRotate", "Transform", N_("Rotate selected objects by degrees.") }, + {"transform-scale", "TransformScale", "Transform", N_("Scale selected objects by scale factor.") }, + {"transform-remove", "TransformRemove", "Transform", N_("Remove any transforms from selected objects.") } +}; + +template<class T> +void +add_actions_transform(ConcreteInkscapeApplication<T>* app) +{ + Glib::VariantType Bool( Glib::VARIANT_TYPE_BOOL); + Glib::VariantType Int( Glib::VARIANT_TYPE_INT32); + Glib::VariantType Double(Glib::VARIANT_TYPE_DOUBLE); + Glib::VariantType String(Glib::VARIANT_TYPE_STRING); + + // Debian 9 has 2.50.0 +#if GLIB_CHECK_VERSION(2, 52, 0) + + app->add_action_with_parameter( "transform-translate", String, sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&transform_translate), app)); + app->add_action_with_parameter( "transform-rotate", Double, sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&transform_rotate), app)); + app->add_action_with_parameter( "transform-scale", Double, sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&transform_scale), app)); + app->add_action( "transform-remove", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&transform_remove), app)); + +#endif + + app->get_action_extra_data().add_data(raw_data_transform); +} + + +template void add_actions_transform(ConcreteInkscapeApplication<Gio::Application>* app); +template void add_actions_transform(ConcreteInkscapeApplication<Gtk::Application>* app); + + + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/actions/actions-transform.h b/src/actions/actions-transform.h new file mode 100644 index 0000000..03c2afd --- /dev/null +++ b/src/actions/actions-transform.h @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Gio::Actions for selection tied to the application and without GUI. + * + * Copyright (C) 2018 Tavmjong Bah + * + * The contents of this file may be used under the GNU General Public License Version 2 or later. + * + */ + +#ifndef INK_ACTIONS_TRANSFORM_H +#define INK_ACTIONS_TRANSFORM_H + +template<class T> class ConcreteInkscapeApplication; + +template<class T> +void add_actions_transform(ConcreteInkscapeApplication<T>* app); + +#endif // INK_ACTIONS_TRANSFORM_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/actions/actions-window.cpp b/src/actions/actions-window.cpp new file mode 100644 index 0000000..abde33b --- /dev/null +++ b/src/actions/actions-window.cpp @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Gio::Actions for window handling tied to the application and with GUI. + * + * Copyright (C) 2020 Tavmjong Bah + * + * The contents of this file may be used under the GNU General Public License Version 2 or later. + * + */ + +#include <iostream> + +#include <giomm.h> // Not <gtkmm.h>! To eventually allow a headless version! +#include <gtkmm.h> +#include <glibmm/i18n.h> + +#include "actions-window.h" +#include "actions-helper.h" +#include "inkscape-application.h" +#include "inkscape-window.h" + +#include "inkscape.h" // Inkscape::Application +#include "helper/action-context.h" + +// Actions for window handling (should be integrated with file dialog). + +class InkscapeWindow; + +// Open a window for current document +void +window_open(InkscapeApplication *app) +{ + SPDocument *document = app->get_active_document(); + if (document) { + InkscapeWindow* window = app->get_active_window(); + if (window && window->get_document() && window->get_document()->getVirgin()) { + // We have a window with an untouched template document, use this window. + app->document_swap (window, document); + } else { + app->window_open(document); + } + } else { + std::cerr << "window_open(): failed to find document!" << std::endl; + } +} + +void +window_close(InkscapeApplication *app) +{ + app->window_close_active(); +} + +std::vector<std::vector<Glib::ustring>> raw_data_window = +{ + {"window-open", "WindowOpen", "Window", N_("Open a window for the active document. GUI only.") }, + {"window-close", "WindowClose", "Window", N_("Close the active window.") } +}; + +template <class T> +void +add_actions_window(ConcreteInkscapeApplication<T>* app) +{ + Glib::VariantType Bool( Glib::VARIANT_TYPE_BOOL); + Glib::VariantType Int( Glib::VARIANT_TYPE_INT32); + Glib::VariantType Double(Glib::VARIANT_TYPE_DOUBLE); + Glib::VariantType String(Glib::VARIANT_TYPE_STRING); + Glib::VariantType BString(Glib::VARIANT_TYPE_BYTESTRING); + + // Debian 9 has 2.50.0 +#if GLIB_CHECK_VERSION(2, 52, 0) + + app->add_action( "window-open", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&window_open), app)); + app->add_action( "window-close", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&window_close), app)); +#else + std::cerr << "add_actions: Some actions require Glibmm 2.52, compiled with: " << glib_major_version << "." << glib_minor_version << std::endl; +#endif + + app->get_action_extra_data().add_data(raw_data_window); +} + + +template void add_actions_window(ConcreteInkscapeApplication<Gio::Application>* app); +template void add_actions_window(ConcreteInkscapeApplication<Gtk::Application>* app); + + + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/actions/actions-window.h b/src/actions/actions-window.h new file mode 100644 index 0000000..a9f7418 --- /dev/null +++ b/src/actions/actions-window.h @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Gio::Actions for window handling tied to the application and with GUI. + * + * Copyright (C) 2020 Tavmjong Bah + * + * The contents of this file may be used under the GNU General Public License Version 2 or later. + * + */ + +#ifndef INK_ACTIONS_WINDOW_H +#define INK_ACTIONS_WINDOW_H + +class InkscapeApplication; +template<class T> class ConcreteInkscapeApplication; + +template<class T> +void add_actions_window(ConcreteInkscapeApplication<T>* app); + +#endif // INK_ACTIONS_WINDOW_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : |