17#include <cairomm/context.h>
18#include <cairomm/pattern.h>
19#include <cairomm/surface.h>
20#include <glibmm/bytes.h>
21#include <glibmm/convert.h>
22#include <glibmm/i18n.h>
23#include <giomm/menu.h>
24#include <giomm/menuitem.h>
25#include <giomm/simpleaction.h>
26#include <giomm/simpleactiongroup.h>
27#include <gdkmm/contentprovider.h>
28#include <gdkmm/general.h>
29#include <gdkmm/pixbuf.h>
30#include <gdkmm/texture.h>
31#include <gtkmm/binlayout.h>
32#include <gtkmm/dragsource.h>
33#include <gtkmm/eventcontrollermotion.h>
34#include <gtkmm/gestureclick.h>
35#include <gtkmm/popover.h>
36#include <gtkmm/popovermenu.h>
37#include <sigc++/functors/mem_fun.h>
64Glib::RefPtr<Gdk::Pixbuf> get_removecolor()
67 static const auto remove_color = [] {
69 auto pixbuf = Gdk::Pixbuf::create_from_file(path.pointer());
71 std::cerr <<
"Null pixbuf for " << Glib::filename_to_utf8(path.pointer()) << std::endl;
85 add_css_class(
"paint-none");
96 data = std::move(color);
108 std::get<GradientData>(
data).gradient =
nullptr;
112 if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) {
132 set_name(
"ColorItem");
135 add_css_class(group ?
"group" :
"filler");
151 set_layout_manager(Gtk::BinLayout::create());
152 set_name(
"ColorItem");
157 auto const drag = Gtk::DragSource::create();
159 drag->set_actions(Gdk::DragAction::MOVE | Gdk::DragAction::COPY);
160 drag->signal_prepare().connect([
this](
auto &&...) {
return on_drag_prepare(); },
false);
161 drag->signal_drag_begin().connect([
this, &drag = *drag](
auto &&...) {
on_drag_begin(drag); });
162 add_controller(drag);
164 auto const motion = Gtk::EventControllerMotion::create();
165 motion->set_propagation_phase(Gtk::PropagationPhase::TARGET);
166 motion->signal_enter().connect([
this](
auto &&...) {
on_motion_enter(); });
167 motion->signal_leave().connect([
this](
auto &&...) {
on_motion_leave(); });
168 add_controller(motion);
170 auto const click = Gtk::GestureClick::create();
171 click->set_button(0);
174 add_controller(click);
187 auto y = h / 2 + 0.5;
189 auto x = (
w -
width) / 2 - 0.5;
191 cr->line_to(x +
width, y);
192 auto const fg = get_color();
193 cr->set_source_rgba(fg.get_red(), fg.get_green(), fg.get_blue(), 0.5);
194 cr->set_line_width(1);
198 if (
auto const pixbuf = get_removecolor()) {
199 const auto device_scale = get_scale_factor();
201 cr->scale((
double)
w / pixbuf->get_width() / device_scale, (
double)h / pixbuf->get_height() / device_scale);
202 Gdk::Cairo::set_source_pixbuf(cr, pixbuf, 0, 0);
212 auto const fg = get_color();
213 cr->rectangle(0.5, 0.5,
w - 1, h - 1);
214 cr->set_source_rgba(fg.get_red(), fg.get_green(), fg.get_blue(), 0.07);
215 cr->set_line_width(1);
220 auto grad = graddata.gradient;
224 auto pat_gradient = Cairo::RefPtr<Cairo::Pattern>(
new Cairo::Pattern(grad->create_preview_pattern(
w),
true));
226 cr->set_source(pat_checkerboard);
228 cr->set_source(pat_gradient);
236 bool const use_cache = std::holds_alternative<PaintNone>(
data) || std::holds_alternative<GradientData>(
data);
239 auto scale = get_scale_factor();
242 cache = Cairo::ImageSurface::create(Cairo::Surface::Format::ARGB32,
w *
scale, h *
scale);
252 cr->set_source(
cache, 0, 0);
263 cr->set_source_rgba(gray, gray, gray, alpha);
266 auto minwh = std::min(
w, h);
267 cr->translate((
w - minwh) / 2.0, (h - minwh) / 2.0);
268 cr->scale(minwh / 2.0, minwh / 2.0);
269 cr->translate(1.0, 1.0);
272 cr->arc(0.0, 0.0, 0.35, 0.0, 2 * M_PI);
277 cr->set_fill_rule(Cairo::Context::FillRule::EVEN_ODD);
278 cr->arc(0.0, 0.0, 0.65, 0.0, 2 * M_PI);
279 cr->arc(0.0, 0.0, 0.5, 0.0, 2 * M_PI);
287 Gtk::DrawingArea::size_allocate_vfunc(
width,
height, baseline);
298 auto msg = Glib::ustring::compose(_(
"Color: <b>%1</b>; <b>Click</b> to set fill, <b>Shift+click</b> to set stroke"),
description);
317 if (click.get_current_button() == 3) {
319 return Gtk::EventSequenceState::CLAIMED;
322 return Gtk::EventSequenceState::CLAIMED;
329 auto const button = click.get_current_button();
331 auto const state = click.get_current_event_state();
334 return Gtk::EventSequenceState::CLAIMED;
336 return Gtk::EventSequenceState::NONE;
346 auto attr_name =
stroke ?
"stroke" :
"fill";
352 descr =
stroke ? _(
"Set stroke color to none") : _(
"Set fill color to none");
353 }
else if (
auto const color = std::get_if<Colors::Color>(&
data)) {
355 descr =
stroke ? _(
"Set stroke color from swatch") : _(
"Set fill color from swatch");
356 }
else if (
auto const graddata = std::get_if<GradientData>(&
data)) {
357 auto grad = graddata->gradient;
359 auto colorspec =
"url(#" + Glib::ustring(grad->getId()) +
")";
361 descr =
stroke ? _(
"Set stroke color from swatch") : _(
"Set fill color from swatch");
372 auto const main_actions = Gio::SimpleActionGroup::create();
378 insert_action_group(
"color-item", main_actions);
380 auto const menu = Gio::Menu::create();
383 menu->append(_(
"Set Fill" ),
"color-item.set-fill" );
384 menu->append(_(
"Set Stroke"),
"color-item.set-stroke");
388 if (
auto const graddata = std::get_if<GradientData>(&
data)) {
389 section = Gio::Menu::create();
390 menu->append_section(section);
391 section->append(_(
"Delete" ),
"color-item.delete");
392 section->append(_(
"Edit..."),
"color-item.edit" );
393 section = Gio::Menu::create();
394 menu->append_section(section);
397 section->append(
is_pinned() ? _(
"Unpin Color") : _(
"Pin Color"),
"color-item.toggle-pin");
400 auto grad_names = std::vector<Glib::ustring>{};
402 auto const grad =
static_cast<SPGradient *
>(obj);
403 if (grad->hasStops() && !grad->isSwatch()) {
404 grad_names.emplace_back(grad->getId());
407 if (!grad_names.empty()) {
408 auto const convert_actions = Gio::SimpleActionGroup::create();
409 auto const convert_submenu = Gio::Menu::create();
411 std::sort(grad_names.begin(), grad_names.end());
412 for (
auto const &
name: grad_names) {
414 convert_submenu->append(
name,
"color-item-convert." +
name);
417 insert_action_group(
"color-item-convert", convert_actions);
419 section = Gio::Menu::create();
420 section->append_submenu(_(
"Convert"), convert_submenu);
421 menu->append_section(section);
429 _popover = std::make_unique<Gtk::PopoverMenu>(menu, Gtk::PopoverMenu::Flags::NESTED);
447 auto const grad = std::get<GradientData>(
data).gradient;
450 grad->setSwatch(
false);
451 DocumentUndo::done(grad->document, _(
"Delete swatch"), INKSCAPE_ICON(
"color-gradient"));
456 auto const grad = std::get<GradientData>(
data).gradient;
461 auto items = std::vector<SPItem*>(selection->items().begin(), selection->items().end());
463 if (!
items.empty()) {
467 if (query.fill.isPaintserver()) {
468 if (cast<SPGradient>(query.getFillPaintServer()) == grad) {
482 if (
auto const graddata = std::get_if<GradientData>(&
data)) {
483 auto const grad = graddata->gradient;
496 remove_action_group(
"color-item-convert");
500 auto const it = std::find_if(resources.cbegin(), resources.cend(),
501 [&](
auto &_){ return _->getId() == name; });
502 if (it == resources.cend())
return;
504 auto const grad =
static_cast<SPGradient *
>(*it);
518 return Gdk::ContentProvider::create(Util::GlibValue::create<Colors::Paint>(std::move(paint)));
523 constexpr int w = 32;
524 constexpr int h = 24;
526 auto surface = Cairo::ImageSurface::create(Cairo::Surface::Format::ARGB32,
w, h);
528 auto const pixbuf = Gdk::Pixbuf::create(
surface, 0, 0,
w, h);
529 auto const texture = Gdk::Texture::create_for_pixbuf(pixbuf);
530 source.set_icon(
texture, 0, 0);
547 if (
auto const graddata = std::get_if<GradientData>(&
data)) {
548 auto const grad = graddata->gradient;
549 return grad && grad->isPinned();
573 auto grad = graddata.gradient;
575 auto pat = Cairo::RefPtr<Cairo::Pattern>(
new Cairo::Pattern(grad->create_preview_pattern(1),
true));
576 auto img = Cairo::ImageSurface::create(Cairo::Surface::Format::ARGB32, 1, 1);
577 auto cr = Cairo::Context::create(img);
581 color.setName(grad->getId());
587 return std::holds_alternative<PaintNone>(
data);
void ink_cairo_set_source_color(Cairo::RefPtr< Cairo::Context > ctx, Inkscape::Colors::Color const &color, double opacity)
The following functions interact between Inkscape color model, and cairo surface rendering.
Colors::Color ink_cairo_surface_average_color(cairo_surface_t *surface, cairo_surface_t *mask)
Get the average color from the given surface.
cairo_pattern_t * ink_cairo_pattern_create_checkerboard(guint32 rgba, bool use_alpha)
Cairo integration helpers.
Cairo::RefPtr< Cairo::ImageSurface > surface
std::string getName() const
static void done(SPDocument *document, Glib::ustring const &event_description, Glib::ustring const &undo_icon, unsigned int object_modified_tag=0)
void set(MessageType type, char const *message)
pushes a message on the stack, replacing our old message
void clear()
removes our current message from the stack
bool getBool(Glib::ustring const &pref_path, bool def=false)
Retrieve a Boolean value.
static Preferences * get()
Access the singleton Preferences object.
void setBool(Glib::ustring const &pref_path, bool value)
Set a Boolean value.
bool is_pinned() const
Update whether this item is pinned.
Cairo::RefPtr< Cairo::ImageSurface > cache
Gtk::EventSequenceState on_click_pressed(Gtk::GestureClick const &click)
sigc::signal< void()> _signal_modified
void draw_color(Cairo::RefPtr< Cairo::Context > const &cr, int w, int h) const
bool is_paint_none() const
Glib::RefPtr< Gdk::ContentProvider > on_drag_prepare()
void set_fill(bool)
Update the fill indicator, showing this widget is the fill of the current selection.
std::variant< Undefined, PaintNone, Colors::Color, GradientData > data
void on_drag_begin(Gtk::DragSource &source)
void draw_func(Cairo::RefPtr< Cairo::Context > const &, int width, int height)
void set_stroke(bool)
Update the stroke indicator, showing this widget is the stroke of the current selection.
void size_allocate_vfunc(int width, int height, int baseline) override
void on_click(bool stroke)
Glib::ustring pinned_pref
The pinned preference path.
Glib::ustring description
sigc::signal< void()> _signal_pinned
Gtk::EventSequenceState on_click_released(Gtk::GestureClick const &click)
void action_convert(Glib::ustring const &name)
std::unique_ptr< Gtk::Popover > _popover
void set_pinned_pref(const std::string &path)
Colors::Color getColor() const
Return the average color for this color item.
DialogBase is the base class for the dialog system.
SPDesktop * getDesktop() const
void new_dialog(const Glib::ustring &dialog_type)
Add new dialog to the current container or in a floating window, based on preferences.
SPDocument * getDocument() const
Inkscape::MessageContext * tipsMessageContext() const
Inkscape::UI::Dialog::DialogContainer * getContainer()
Inkscape::Selection * getSelection() const
std::vector< SPObject * > const getResourceList(char const *key)
void setSwatch(bool swatch=true)
SPObject is an abstract base class of all of the document nodes at the SVG document level.
char const * getId() const
Returns the objects current ID string.
sigc::connection connectRelease(sigc::slot< void(SPObject *)> slot)
Connects to the release request signal.
char const * defaultLabel() const
Returns a default label property for this object.
sigc::connection connectModified(sigc::slot< void(SPObject *, unsigned int)> slot)
Connects to the modification notification signal.
Color item used in palettes and swatches UI.
Utilities to more easily use Gtk::EventController & subclasses like Gesture.
std::shared_ptr< Css const > css
Glib::RefPtr< Gdk::Texture > texture
void sp_desktop_set_style(SPDesktop *desktop, SPCSSAttr *css, bool change, bool write_current, bool switch_style)
Apply style on selection on desktop.
int objects_query_fillstroke(const std::vector< SPItem * > &objects, SPStyle *style_res, bool const isfill)
Write to style_res the average fill or stroke of list of objects, if applicable.
@ QUERY_STYLE_MULTIPLE_SAME
A base class for all dialogs.
A widget that manages DialogNotebook's and other widgets inside a horizontal DialogMultipaned.
TODO: insert short description here.
Macro for icon names used in Inkscape.
Interface for locally managing a current status message.
std::variant< NoColor, Color > Paint
std::pair< double, double > get_contrasting_color(double l)
double get_perceptual_lightness(Color const &color)
Return a value for how the light the color appears to be using HSLUV.
double lightness(Color color)
std::string color_to_id(std::optional< Color > const &color)
Create a somewhat unique id for the given color used for palette identification.
Util::ptr_shared get_path(Domain domain, Type type, char const *filename, char const *extra)
auto use_state(Slot &&slot)
bool has_flag(Gdk::ModifierType const state, Gdk::ModifierType const flags)
Helper to query if ModifierType state contains one or more of given flag(s).
void containerize(Gtk::Widget &widget)
Make a custom widget implement sensible memory management for its children.
Singleton class to access the preferences file in a convenient way.
SPCSSAttr * sp_repr_css_attr_new()
Creates an empty SPCSSAttr (a class for manipulating CSS style properties).
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_set_property(SPCSSAttr *css, gchar const *name, gchar const *value)
Set a style property to a new value (e.g.
Inkscape::IO::Resource - simple resource API.
Wrapper for the GLib value API.