16#include <sigc++/connection.h>
17#include <sigc++/adaptors/bind.h>
18#include <sigc++/functors/mem_fun.h>
19#include <glibmm/ustring.h>
20#include <gtkmm/adjustment.h>
21#include <gtkmm/droptarget.h>
22#include <gtkmm/gestureclick.h>
23#include <gtkmm/checkbutton.h>
67 32, 16, 10, 8, 6, 4, 3, 2, 1.5, 1, 0.75, 0.5, 0.25, 0.1};
71 static const Glib::ustring type_strings[][2][2] = {
73 {{ _(
"N/A"), _(
"Nothing selected")},
74 { _(
"N/A"), _(
"Nothing selected")}},
75 {{C_(
"Fill",
"<i>None</i>"), _(
"No fill, middle-click for black fill")},
76 {C_(
"Stroke",
"<i>None</i>"), _(
"No stroke, middle-click for black stroke")}},
77 {{ _(
"<b>Unset</b>"), _(
"Unset fill")},
78 { _(
"<b>Unset</b>"), _(
"Unset stroke")}},
79 {{ _(
"≠"), _(
"Different fills")},
80 { _(
"≠"), _(
"Different strokes")}},
81 {{ _(
"Pattern"), _(
"Pattern (fill)")},
82 { _(
"Pattern"), _(
"Pattern (stroke)")}},
83 {{ _(
"Hatch"), _(
"Pattern (fill)")},
84 { _(
"Hatch"), _(
"Pattern (stroke)")}},
85 {{ _(
"<b>L</b>"), _(
"Linear gradient (fill)")},
86 { _(
"<b>L</b>"), _(
"Linear gradient (stroke)")}},
87 {{ _(
"<b>R</b>"), _(
"Radial gradient (fill)")},
88 { _(
"<b>R</b>"), _(
"Radial gradient (stroke)")}},
89 {{ _(
"<b>M</b>"), _(
"Mesh gradient (fill)")},
90 { _(
"<b>M</b>"), _(
"Mesh gradient (stroke)")}},
91 {{ _(
"<b>C</b>"), _(
"Flat color (fill)")},
92 { _(
"<b>C</b>"), _(
"Flat color (stroke)")}}
109 if (flags & (SP_OBJECT_STYLE_MODIFIED_FLAG)) {
116struct SelectedStyleDropTracker final {
131 set_name(
"SelectedStyle");
134 grid = Gtk::make_managed<Gtk::Grid>();
138 for (
int i = 0; i <2; i++) {
139 label[i] = Gtk::make_managed<Gtk::Label>(i == 0 ? _(
"Fill:") : _(
"Stroke:"));
140 label[i]->set_halign(Gtk::Align::END);
143 tag[i] = Gtk::make_managed<Gtk::Label>();
145 tag[i]->set_name(
"Tag");
155 color_preview[i] = std::make_unique<Inkscape::UI::Widget::ColorPreview>(0);
161 swatch[i] = Gtk::make_managed<RotateableSwatch>(
this, i);
162 swatch[i]->set_orientation(Gtk::Orientation::HORIZONTAL);
163 swatch[i]->set_hexpand(
false);
171 drop[i] = std::make_unique<SelectedStyleDropTracker>();
172 drop[i]->parent =
this;
174 auto target = Gtk::DropTarget::create(Util::GlibValue::type<Colors::Paint>(), Gdk::DragAction::COPY | Gdk::DragAction::MOVE);
175 target->signal_drop().connect([
this, i] (Glib::ValueBase
const &value,
double,
double) {
180 auto const &tracker = *
drop[i];
181 auto const paint = Util::GlibValue::get<Colors::Paint>(value);
183 [] (
Colors::Color const &color) {
return color.toString(
false); },
195 swatch[i]->add_controller(target);
197 auto const click = Gtk::GestureClick::create();
200 click->set_button(0);
202 swatch[i]->add_controller(click);
205 grid->attach(*
tag[i], 1, i, 1, 1);
218 auto const click = Gtk::GestureClick::create();
219 click->set_button(0);
229 opacity_sb = Gtk::make_managed<Inkscape::UI::Widget::SpinButton>(0.02, 0);
235 auto opacity_box = Gtk::make_managed<Gtk::Box>();
239 auto const click = Gtk::GestureClick::create();
240 click->set_propagation_phase(Gtk::PropagationPhase::CAPTURE);
241 click->set_button(2);
242 click->signal_pressed().connect([&click = *click](
auto &&...) { click.set_state(Gtk::EventSequenceState::CLAIMED); });
244 opacity_box->add_controller(click);
249 grid->attach(*opacity_box, 4, 0, 1, 2);
251 grid->set_column_spacing(4);
443 auto const display = Gdk::Display::get_default();
444 display->get_primary_clipboard()->set_text(text);
453 auto const display = Gdk::Display::get_default();
454 display->get_primary_clipboard()->set_text(text);
461 auto const display = Gdk::Display::get_default();
462 Glib::RefPtr<Gdk::Clipboard> refClipboard = display->get_primary_clipboard();
466 text = refClipboard->read_text_finish(
result);
467 }
catch (Glib::Error
const &err) {
468 std::cout <<
"Pasting text failed: " << err.what() << std::endl;
471 if (
auto color = Inkscape::Colors::Color::parse(text)) {
481 auto const display = Gdk::Display::get_default();
482 Glib::RefPtr<Gdk::Clipboard> refClipboard = display->get_primary_clipboard();
487 auto const display = Gdk::Display::get_default();
488 Glib::RefPtr<Gdk::Clipboard> refClipboard = display->get_primary_clipboard();
503 fs->showPageStrokePaint();
509 auto const button = click.get_current_button();
513 }
else if (button == 3) {
516 }
else if (button == 2) {
523 return Gtk::EventSequenceState::CLAIMED;
529 auto const button = click.get_current_button();
532 fs->showPageStrokePaint();
533 }
else if (button == 3) {
536 }
else if (button == 2) {
543 return Gtk::EventSequenceState::CLAIMED;
548 auto const button = click.get_current_button();
551 fs->showPageStrokeStyle();
552 }
else if (button == 3) {
554 return mi->get_label() == _sw_unit->abbr;
556 if (it !=
_unit_mis.cend()) (*it)->set_active(
true);
560 }
else if (button == 2) {
563 return Gtk::EventSequenceState::CLAIMED;
566Gtk::EventSequenceState
568 int ,
double ,
double )
570 const char* opacity =
opacity_sb->get_value() < 50?
"0.5" : (
opacity_sb->get_value() == 100?
"0" :
"1");
576 return Gtk::EventSequenceState::CLAIMED;
579template <
typename Slot,
typename ...Args>
583 auto const item = Gtk::make_managed<UI::Widget::PopoverMenuItem>(std::forward<Args>(args)...);
584 item->set_child(*Gtk::make_managed<Gtk::Label>(
label, Gtk::Align::START, Gtk::Align::START));
585 item->signal_activate().connect(std::move(slot));
591 _popup[i] = std::make_unique<UI::Widget::PopoverMenu>(Gtk::PositionType::TOP);
593 auto const add_item = [&](Glib::ustring
const & fill_label,
auto const fill_method,
594 Glib::ustring
const &stroke_label,
auto const stroke_method)
596 auto const &
label = i ==
SS_FILL || stroke_label.empty() ? fill_label : stroke_label ;
597 auto const method = i ==
SS_FILL || stroke_method ==
nullptr ? fill_method : stroke_method;
603 add_item(_(
"Edit Fill..." ) , &SelectedStyle:: on_fill_edit ,
606 _popup[i]->append_separator();
609 add_item(_(
"Last Set Color") , &SelectedStyle:: on_fill_lastused ,
611 add_item(_(
"Last Selected Color") , &SelectedStyle:: on_fill_lastselected,
614 _popup[i]->append_separator();
616 add_item(_(
"Invert") , &SelectedStyle:: on_fill_invert ,
619 _popup[i]->append_separator();
621 add_item(_(
"White") , &SelectedStyle:: on_fill_white ,
623 add_item(_(
"Black") , &SelectedStyle:: on_fill_black ,
626 _popup[i]->append_separator();
629 _(
"Copy Color") , &SelectedStyle:: on_fill_copy ,
633 add_item(_(
"Paste Color") , &SelectedStyle:: on_fill_paste ,
638 _popup[i]->append_separator();
640 add_item(_(
"Make Fill Opaque" ) , &SelectedStyle:: on_fill_opaque ,
643 add_item(_(
"Unset Fill" ) , &SelectedStyle:: on_fill_unset ,
645 add_item(_(
"Remove Fill" ) , &SelectedStyle:: on_fill_remove ,
651 _popup_sw = std::make_unique<UI::Widget::PopoverMenu>(Gtk::PositionType::TOP);
653 _popup_sw->append_section_label(_(
"<b>Stroke Width</b>"));
657 _popup_sw->append_section_label(_(
"Unit"));
658 Gtk::CheckButton *group =
nullptr;
661 auto const item = Gtk::make_managed<UI::Widget::PopoverMenuItem>();
662 auto const radio = Gtk::make_managed<Gtk::CheckButton>(
key);
666 radio->set_group(*group);
668 item->set_child(*radio);
670 auto const u = unit_table.getUnit(
key);
671 item->signal_activate().connect(
678 _popup_sw->append_section_label(_(
"Width"));
679 for (std::size_t i = 0; i <
_sw_presets.size(); ++i) {
749 tag[i]->set_markup(
"");
765 if (paint->set && paint->isPaintserver()) {
766 SPPaintServer *server = (i ==
SS_FILL)? SP_STYLE_FILL_SERVER (&query) : SP_STYLE_STROKE_SERVER (&query);
773 if (is<SPLinearGradient>(server)) {
774 auto vector = cast<SPGradient>(server)->getVector();
782 }
else if (is<SPRadialGradient>(server)) {
783 auto vector = cast<SPGradient>(server)->getVector();
791 }
else if (is<SPMeshGradient>(server)) {
792 auto array = cast<SPGradient>(server)->getArray();
800 }
else if (is<SPPattern>(server)) {
805 }
else if (is<SPHatch>(server)) {
812 g_warning (
"file %s: line %d: Unknown paint server", __FILE__, __LINE__);
814 }
else if (paint->set && paint->isColor()) {
815 auto color = paint->getColor();
816 color.addOpacity(opacity);
823 _(
", drag to adjust, middle-click to remove"));
830 }
else if (paint->set && paint->isNone()) {
834 }
else if (!paint->set) {
843 tag[i]->set_markup(
"<b>a</b>");
844 tag[i]->set_tooltip_text(i == 0 ?
845 _(
"Fill is averaged over selected objects") :
846 _(
"Stroke is averaged over selected objects"));
850 tag[i]->set_markup(
"<b>m</b>");
851 tag[i]->set_tooltip_text(i == 0 ?
852 _(
"Multiple selected objects have same fill") :
853 _(
"Multiple selected objects have same stroke"));
855 tag[i]->set_markup(
"");
856 tag[i]->set_tooltip_text(
"");
877 opacity_sb->set_tooltip_text(_(
"Nothing selected"));
883 opacity_sb->set_tooltip_markup(_(
"<b>Opacity (%)</b>\nMiddle-click cycles through 0%, 50%, 100%"));
907 stroke_width->set_tooltip_text(_(
"Stroke width: Hairline"));
918 gchar *str = g_strdup_printf(
" %#.3g",
w);
919 if (str[strlen(str) - 1] ==
',' || str[strlen(str) - 1] ==
'.') {
920 str[strlen(str)-1] =
'\0';
926 gchar *str = g_strdup_printf(_(
"Stroke width: %.5g%s%s"),
930 _(
" (averaged)") :
"");
950 _popup_opacity = std::make_unique<UI::Widget::PopoverMenu>(Gtk::PositionType::TOP);
951 auto const add_item = [&] (Glib::ustring
const &
label,
auto method) {
991 set_name(
"RotatableSwatch");
998 static int map[4] = {0,2,1,3};
1001 double old = hsl[ch];
1003 hsl.set(ch, old + by * (by > 0 ? (1 - hsl[ch]) : hsl[ch]));
1005 double diff = hsl[ch] - old;
1027 std::string cursor_filename =
"adjust_hue.svg";
1029 cursor_filename =
"adjust_saturation.svg";
1031 cursor_filename =
"adjust_lightness.svg";
1033 cursor_filename =
"adjust_alpha.svg";
1050 _(
"Adjusting <b>alpha</b>: was %.3g, now <b>%.3g</b> (diff %.3g); with <b>Ctrl</b> to adjust lightness, with <b>Shift</b> to adjust saturation, without modifiers to adjust hue"),
1051 ret.first - ret.second, ret.first, ret.second);
1057 _(
"Adjusting <b>saturation</b>: was %.3g, now <b>%.3g</b> (diff %.3g); with <b>Ctrl</b> to adjust lightness, with <b>Alt</b> to adjust alpha, without modifiers to adjust hue"),
1058 ret.first - ret.second, ret.first, ret.second);
1064 _(
"Adjusting <b>lightness</b>: was %.3g, now <b>%.3g</b> (diff %.3g); with <b>Shift</b> to adjust saturation, with <b>Alt</b> to adjust alpha, without modifiers to adjust hue"),
1065 ret.first - ret.second, ret.first, ret.second);
1071 _(
"Adjusting <b>hue</b>: was %.3g, now <b>%.3g</b> (diff %.3g); with <b>Shift</b> to adjust saturation, with <b>Alt</b> to adjust alpha, with <b>Ctrl</b> to adjust lightness"),
1072 ret.first - ret.second, ret.first, ret.second);
1091 if (
auto window =
dynamic_cast<Gtk::Window *
>(get_root())) {
1092 window->set_cursor();
1110 if (!strcmp(
undokey,
"ssrot1")) {
1125 startvalue_set(false),
1138 newval =
current * (std::exp(std::log(max_f-1) * (by+1)) - 1) / (max_f-2);
1141 if (
final && newval < 1e-6) {
1190 if (!strcmp(
undokey,
"swrot1")) {
A thin wrapper around std::ostringstream, but writing floating point numbers in the format required b...
std::optional< Color > converted(Color const &other) const
Return a copy of this color converted to the same format as the other color.
std::shared_ptr< Space::AnySpace > const & getSpace() const
static void done(SPDocument *document, Glib::ustring const &event_description, Glib::ustring const &undo_icon, unsigned int object_modified_tag=0)
static void maybeDone(SPDocument *document, const gchar *keyconst, Glib::ustring const &event_description, Glib::ustring const &undo_icon, unsigned int object_modified_tag=0)
The set of selected SPObjects for a given document and layer model.
sigc::connection connectChanged(sigc::slot< void(Selection *)> slot)
Connects a slot to be notified of selection changes.
DialogBase * get_dialog(const Glib::ustring &dialog_type)
void new_dialog(const Glib::ustring &dialog_type)
Add new dialog to the current container or in a floating window, based on preferences.
static double convert(double from_dist, Unit const *from, Unit const *to)
Convert distances.
Interface for refcounted XML nodes.
virtual char const * attribute(char const *key) const =0
Get the string representation of a node's attribute.
To do: update description of desktop.
Inkscape::UI::Widget::Canvas * getCanvas() const
SPDocument * getDocument() const
SPNamedView * getNamedView() const
Inkscape::UI::Dialog::DialogContainer * getContainer()
Inkscape::Selection * getSelection() const
Inkscape::UI::Tools::ToolBase * getTool() const
Inkscape::Util::Unit const * display_units
Inkscape::XML::Node * getRepr()
Returns the XML representation of tree.
T< SPAttr::FILL, SPIPaint > fill
fill
T< SPAttr::STROKE, SPIPaint > stroke
stroke
T< SPAttr::STROKE_WIDTH, SPILength > stroke_width
stroke-width
T< SPAttr::FILL_OPACITY, SPIScale24 > fill_opacity
fill-opacity
T< SPAttr::STROKE_OPACITY, SPIScale24 > stroke_opacity
stroke-opacity
T< SPAttr::OPACITY, SPIScale24 > opacity
opacity
T< SPAttr::STROKE_EXTENSIONS, SPIStrokeExtensions > stroke_extensions
-inkscape-stroke
System-wide clipboard management - class declaration.
Utilities to more easily use Gtk::EventController & subclasses like Gesture.
TODO: insert short description here.
std::shared_ptr< Css const > css
std::optional< Color > sp_desktop_get_color(SPDesktop *desktop, bool is_fill)
Return the desktop's current color.
void sp_desktop_set_style(SPDesktop *desktop, SPCSSAttr *css, bool change, bool write_current, bool switch_style)
Apply style on selection on desktop.
int sp_desktop_query_style(SPDesktop *desktop, SPStyle *style, int property)
Query the subselection (if any) or selection on the given desktop for the given property,...
@ QUERY_STYLE_PROPERTY_STROKE
@ QUERY_STYLE_PROPERTY_STROKEWIDTH
@ QUERY_STYLE_PROPERTY_FILL
@ QUERY_STYLE_PROPERTY_MASTEROPACITY
@ QUERY_STYLE_MULTIPLE_DIFFERENT
@ QUERY_STYLE_MULTIPLE_AVERAGED
@ QUERY_STYLE_MULTIPLE_SAME
A base class for all dialogs.
A widget that manages DialogNotebook's and other widgets inside a horizontal DialogMultipaned.
static char const *const current
static char const *const parent
TODO: insert short description here.
void sp_gradient_invert_selected_gradients(SPDesktop *desktop, Inkscape::PaintTarget fill_or_stroke)
Macro for icon names used in Inkscape.
Interface for locally managing a current status message.
auto use_state(Slot &&slot)
void on_popup_menu(Gtk::Widget &widget, PopupMenuSlot slot)
Connect slot to a widgetʼs key and button events that traditionally trigger a popup menu,...
std::optional< PopupMenuClick > PopupMenuOptionalClick
Optional: not present if popup wasnʼt triggered by click.
Glib::ustring format_classic(T const &... args)
void set_svg_cursor(Gtk::Widget &widget, std::string const &file_name, std::optional< Colors::Color > fill, std::optional< Colors::Color > stroke)
Loads an SVG cursor from the specified file name, and sets it as the cursor of the given widget.
static cairo_user_data_key_t key
SPCSSAttr * sp_repr_css_attr_new()
Creates an empty SPCSSAttr (a class for manipulating CSS style properties).
void sp_repr_css_set_property_double(SPCSSAttr *css, gchar const *name, double value)
Set a style property to a new float value (e.g.
void sp_repr_css_attr_unref(SPCSSAttr *css)
Unreferences an SPCSSAttr (will be garbage collected if no references remain).
void sp_repr_css_set_property_string(SPCSSAttr *css, char const *name, std::string const &value)
Set a style property to a standard string.
void sp_repr_css_unset_property(SPCSSAttr *css, gchar const *name)
Set a style property to "inkscape:unset".
void sp_repr_css_set_property(SPCSSAttr *css, gchar const *name, gchar const *value)
Set a style property to a new value (e.g.
static void ss_selection_modified(Inkscape::Selection *selection, guint flags, gpointer data)
static const Glib::ustring(* get_type_strings())[2]
static constexpr int SELECTED_STYLE_SB_WIDTH
static constexpr int SELECTED_STYLE_FLAG_WIDTH
static constexpr std::array< double, 15 > _sw_presets
static void ss_selection_changed(Inkscape::Selection *, gpointer data)
static constexpr int SELECTED_STYLE_PLACE_WIDTH
static constexpr int SELECTED_STYLE_STROKE_WIDTH
static constexpr int SELECTED_STYLE_WIDTH
SVG <hatch> implementation.
TODO: insert short description here.
TODO: insert short description here.
SVG <pattern> implementation.
TODO: insert short description here.
SPStyle - a style object for SPItem objects.
Wrapper for the GLib value API.