From eeff77979c4769047a384cc445d7523b6f2bb082 Mon Sep 17 00:00:00 2001 From: Leonardo Fadul Date: Fri, 14 Mar 2025 04:05:42 -0300 Subject: [PATCH 1/3] Port Swatches Panel to use GtkSnapshot Rendering Refactored ColorItem to inherit from Gtk::Widget and implemented snapshot_vfunc. Replaced Cairo drawing calls with Gtk::Snapshot methods for rendering colors. Removed the draw_func method from ColorItem, adapting it for the new rendering approach. --- src/ui/dialog/color-item.cpp | 108 ++++++++++++++++++++++++++++++++++- src/ui/dialog/color-item.h | 4 +- 2 files changed, 108 insertions(+), 4 deletions(-) diff --git a/src/ui/dialog/color-item.cpp b/src/ui/dialog/color-item.cpp index 912253fc250..a41f15f54b5 100644 --- a/src/ui/dialog/color-item.cpp +++ b/src/ui/dialog/color-item.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include "colors/dragndrop.h" @@ -137,6 +138,109 @@ ColorItem::ColorItem(Glib::ustring name) ColorItem::~ColorItem() = default; +void ColorItem::snapshot_vfunc(const Glib::RefPtr& snapshot) +{ + std::visit(VariantVisitor{ + [&] (Undefined) { + // there's no color to paint; indicate clearly that there is nothing to select: + + // Calculate the position and size for the rectangle + auto const y = get_allocated_height() / 2 + 0.5; + auto const w = get_allocated_width() / 4; + auto const x = (get_allocated_width() - w) / 2 - 0.5; + auto const h = get_allocated_height(); + + // Get the foreground color and Set the color with 50% opacity + auto const fg = get_color(); + auto const color = Gdk::RGBA(fg.get_red(), fg.get_green(), fg.get_blue(), 0.5); + + // Append a rectangle of the specified color to the snapshot + snapshot->append_color(color, Gdk::Graphene::Rect(x, y, w, 1)); + + // Create a graphene rectangle for the border + graphene_rect_t rect = GRAPHENE_RECT_INIT(0.5f, 0.5f, static_cast(w - 1), static_cast(h - 1)); + + // Create a gsk path builder for the border + auto const builder = gsk_path_builder_new (); + gsk_path_builder_move_to (builder, 0.5, 0.5); + gsk_path_builder_line_to (builder, w - 1.5, 0.5); + gsk_path_builder_line_to (builder, w - 1.5, h - 1.5); + gsk_path_builder_line_to (builder, 0.5, h - 1.5); + gsk_path_builder_close (builder); + + // Create a gsk path + auto path = gsk_path_builder_free_to_path (builder); + + // Create a gsk stroke + auto const stroke = gsk_stroke_new (1.0f); + + // Append the stroke to the snapshot + gtk_snapshot_append_stroke(snapshot->gobj(), path, stroke, color.gobj()); + + // Release resources + gsk_stroke_free (stroke); + gsk_path_unref (path); + }, + [&] (PaintNone) { + if (auto const pixbuf = get_removecolor()) { + auto texture = Gdk::Texture::create_for_pixbuf(pixbuf); + Gdk::Graphene::Rect rect (0, 0, get_allocated_width(), get_allocated_height()); + snapshot->append_texture(texture, rect); + } + }, + [&] (Colors::Color const &color) { + // Convert color to Gdk::RGBA + const Gdk::RGBA gdk_color{static_cast(color.get(0)), static_cast(color.get(1)), static_cast(color.get(2)), color.hasOpacity() ? static_cast(color.getOpacity()) : 1.0f}; + + // Create GTK Graphene Rect with the widget's size + Gdk::Graphene::Rect rect (0, 0, get_allocated_width(), get_allocated_height()); + + snapshot->append_color(gdk_color, rect); + }, + [&] (GradientData graddata) { + // Gradient pointer may be null if the gradient was destroyed. + auto grad = graddata.gradient; + if (!grad) return; + + // Create the rectangle of the widget's size + Gdk::Graphene::Rect rect(0, 0, get_allocated_width(), get_allocated_height()); + + auto const y = get_allocated_height() / 2 + 0.5; + auto const w = get_allocated_width() / 4; + auto const x = (get_allocated_width() - w) / 2 - 0.5; + auto const h = get_allocated_height(); + + // Starting point of the gradient + auto const start = Gdk::Graphene::Point(x, y); + + // Ending point of the gradient + auto const end = Gdk::Graphene::Point(x + w, y); + + // Create the gradient pattern + auto pat_gradient = Cairo::RefPtr(new Cairo::Pattern(grad->create_preview_pattern(w), true)); + + // Define the gradient stops (example with black to white) + GskColorStop stops[] = { + {0.0f, {0.0f, 0.0f, 0.0f, 1.0f}}, // Black at the start + {1.0f, {1.0f, 1.0f, 1.0f, 1.0f}} // White at the end + }; + + // Initialize the rectangle for the gradient + graphene_rect_t graphene_rect = GRAPHENE_RECT_INIT(0.5f, 0.5f, static_cast(w - 1), static_cast(h - 1)); + + // Add the linear gradient to the snapshot + gtk_snapshot_append_linear_gradient( + snapshot->gobj(), + &graphene_rect, + start.gobj(), + end.gobj(), + stops, + G_N_ELEMENTS(stops) + ); + }}, data); +} + + bool ColorItem::is_group() const { return !dialog && color_id == "-" && !description.empty(); } @@ -152,8 +256,6 @@ void ColorItem::common_setup() set_name("ColorItem"); set_tooltip_text(description + (tooltip.empty() ? tooltip : "\n" + tooltip)); - set_draw_func(sigc::mem_fun(*this, &ColorItem::draw_func)); - auto const drag = Gtk::DragSource::create(); drag->set_button(1); // left drag->set_actions(Gdk::DragAction::MOVE | Gdk::DragAction::COPY); @@ -283,7 +385,7 @@ void ColorItem::draw_func(Cairo::RefPtr const &cr, int const w, void ColorItem::size_allocate_vfunc(int width, int height, int baseline) { - Gtk::DrawingArea::size_allocate_vfunc(width, height, baseline); + Gtk::Widget::size_allocate_vfunc(width, height, baseline); cache_dirty = true; } diff --git a/src/ui/dialog/color-item.h b/src/ui/dialog/color-item.h index 3983e17670c..4d70cc8c45c 100644 --- a/src/ui/dialog/color-item.h +++ b/src/ui/dialog/color-item.h @@ -48,7 +48,7 @@ class DialogBase; * * Note: This widget must be outlived by its parent dialog, passed in the constructor. */ -class ColorItem : public Gtk::DrawingArea +class ColorItem : public Gtk::Widget { public: // No fill option @@ -59,6 +59,8 @@ public: ColorItem(Glib::ustring name); ~ColorItem() override; + void snapshot_vfunc(const Glib::RefPtr& snapshot) override; + // Returns true if this is group heading rather than a color bool is_group() const; // Returns true if this is alignment filler item, not a color -- GitLab From a83828d2bbcface2138b286e072b2e8f9d817e23 Mon Sep 17 00:00:00 2001 From: Leonardo Fadul Date: Fri, 14 Mar 2025 12:57:59 -0300 Subject: [PATCH 2/3] Removed draw_func method in ColorItem Removed draw_func, as it was no longer used after migrating to the new rendering model. Left draw_color() unchanged for now, as it is still required for drag-and-drop functionality, which relies on Cairo. Removing it without a proper replacement would result in a placeholder being shown instead of the expected color preview. --- src/ui/dialog/color-item.cpp | 235 ++++++++++++++--------------------- src/ui/dialog/color-item.h | 4 +- 2 files changed, 92 insertions(+), 147 deletions(-) diff --git a/src/ui/dialog/color-item.cpp b/src/ui/dialog/color-item.cpp index a41f15f54b5..cca61607b61 100644 --- a/src/ui/dialog/color-item.cpp +++ b/src/ui/dialog/color-item.cpp @@ -138,6 +138,96 @@ ColorItem::ColorItem(Glib::ustring name) ColorItem::~ColorItem() = default; +bool ColorItem::is_group() const { + return !dialog && color_id == "-" && !description.empty(); +} + +bool ColorItem::is_filler() const { + return !dialog && color_id == "-" && description.empty(); +} + +void ColorItem::common_setup() +{ + containerize(*this); + set_layout_manager(Gtk::BinLayout::create()); + set_name("ColorItem"); + set_tooltip_text(description + (tooltip.empty() ? tooltip : "\n" + tooltip)); + + auto const drag = Gtk::DragSource::create(); + drag->set_button(1); // left + drag->set_actions(Gdk::DragAction::MOVE | Gdk::DragAction::COPY); + drag->signal_prepare().connect([this](auto &&...) { return on_drag_prepare(); }, false); // before + drag->signal_drag_begin().connect([this, &drag = *drag](auto &&...) { on_drag_begin(drag); }); + add_controller(drag); + + auto const motion = Gtk::EventControllerMotion::create(); + motion->set_propagation_phase(Gtk::PropagationPhase::TARGET); + motion->signal_enter().connect([this](auto &&...) { on_motion_enter(); }); + motion->signal_leave().connect([this](auto &&...) { on_motion_leave(); }); + add_controller(motion); + + auto const click = Gtk::GestureClick::create(); + click->signal_pressed().connect(Controller::use_state([this](auto& controller, auto &&...) { return on_click_pressed(controller); }, *click)); + click->signal_released().connect(Controller::use_state([this](auto& controller, auto &&...) { return on_click_released(controller); }, *click)); + add_controller(click); +} + +void ColorItem::set_pinned_pref(const std::string &path) +{ + pinned_pref = path + "/pinned/" + color_id; +} + +void ColorItem::draw_color(Cairo::RefPtr const &cr, int w, int h) const +{ + std::visit(VariantVisitor{ + [&] (Undefined) { + // there's no color to paint; indicate clearly that there is nothing to select: + auto y = h / 2 + 0.5; + auto width = w / 4; + auto x = (w - width) / 2 - 0.5; + cr->move_to(x, y); + cr->line_to(x + width, y); + auto const fg = get_color(); + cr->set_source_rgba(fg.get_red(), fg.get_green(), fg.get_blue(), 0.5); + cr->set_line_width(1); + cr->stroke(); + }, + [&] (PaintNone) { + if (auto const pixbuf = get_removecolor()) { + const auto device_scale = get_scale_factor(); + cr->save(); + cr->scale((double)w / pixbuf->get_width() / device_scale, (double)h / pixbuf->get_height() / device_scale); + Gdk::Cairo::set_source_pixbuf(cr, pixbuf, 0, 0); + cr->paint(); + cr->restore(); + } + }, + [&] (Colors::Color const &color) { + ink_cairo_set_source_color(cr, color); + cr->paint(); + // there's no way to query background color to check if color item stands out, + // so we apply faint outline to let users make out color shapes blending with background + auto const fg = get_color(); + cr->rectangle(0.5, 0.5, w - 1, h - 1); + cr->set_source_rgba(fg.get_red(), fg.get_green(), fg.get_blue(), 0.07); + cr->set_line_width(1); + cr->stroke(); + }, + [&] (GradientData graddata) { + // Gradient pointer may be null if the gradient was destroyed. + auto grad = graddata.gradient; + if (!grad) return; + + auto pat_checkerboard = Cairo::RefPtr(new Cairo::Pattern(ink_cairo_pattern_create_checkerboard(), true)); + auto pat_gradient = Cairo::RefPtr(new Cairo::Pattern(grad->create_preview_pattern(w), true)); + + cr->set_source(pat_checkerboard); + cr->paint(); + cr->set_source(pat_gradient); + cr->paint(); + }}, data); +} + void ColorItem::snapshot_vfunc(const Glib::RefPtr& snapshot) { std::visit(VariantVisitor{ @@ -190,7 +280,7 @@ void ColorItem::snapshot_vfunc(const Glib::RefPtr& snapshot) }, [&] (Colors::Color const &color) { // Convert color to Gdk::RGBA - const Gdk::RGBA gdk_color{static_cast(color.get(0)), static_cast(color.get(1)), static_cast(color.get(2)), color.hasOpacity() ? static_cast(color.getOpacity()) : 1.0f}; + auto const gdk_color = color_to_rgba(color); // Create GTK Graphene Rect with the widget's size Gdk::Graphene::Rect rect (0, 0, get_allocated_width(), get_allocated_height()); @@ -240,149 +330,6 @@ void ColorItem::snapshot_vfunc(const Glib::RefPtr& snapshot) }}, data); } - -bool ColorItem::is_group() const { - return !dialog && color_id == "-" && !description.empty(); -} - -bool ColorItem::is_filler() const { - return !dialog && color_id == "-" && description.empty(); -} - -void ColorItem::common_setup() -{ - containerize(*this); - set_layout_manager(Gtk::BinLayout::create()); - set_name("ColorItem"); - set_tooltip_text(description + (tooltip.empty() ? tooltip : "\n" + tooltip)); - - auto const drag = Gtk::DragSource::create(); - drag->set_button(1); // left - drag->set_actions(Gdk::DragAction::MOVE | Gdk::DragAction::COPY); - drag->signal_prepare().connect([this](auto &&...) { return on_drag_prepare(); }, false); // before - drag->signal_drag_begin().connect([this, &drag = *drag](auto &&...) { on_drag_begin(drag); }); - add_controller(drag); - - auto const motion = Gtk::EventControllerMotion::create(); - motion->set_propagation_phase(Gtk::PropagationPhase::TARGET); - motion->signal_enter().connect([this](auto &&...) { on_motion_enter(); }); - motion->signal_leave().connect([this](auto &&...) { on_motion_leave(); }); - add_controller(motion); - - auto const click = Gtk::GestureClick::create(); - click->signal_pressed().connect(Controller::use_state([this](auto& controller, auto &&...) { return on_click_pressed(controller); }, *click)); - click->signal_released().connect(Controller::use_state([this](auto& controller, auto &&...) { return on_click_released(controller); }, *click)); - add_controller(click); -} - -void ColorItem::set_pinned_pref(const std::string &path) -{ - pinned_pref = path + "/pinned/" + color_id; -} - -void ColorItem::draw_color(Cairo::RefPtr const &cr, int w, int h) const -{ - std::visit(VariantVisitor{ - [&] (Undefined) { - // there's no color to paint; indicate clearly that there is nothing to select: - auto y = h / 2 + 0.5; - auto width = w / 4; - auto x = (w - width) / 2 - 0.5; - cr->move_to(x, y); - cr->line_to(x + width, y); - auto const fg = get_color(); - cr->set_source_rgba(fg.get_red(), fg.get_green(), fg.get_blue(), 0.5); - cr->set_line_width(1); - cr->stroke(); - }, - [&] (PaintNone) { - if (auto const pixbuf = get_removecolor()) { - const auto device_scale = get_scale_factor(); - cr->save(); - cr->scale((double)w / pixbuf->get_width() / device_scale, (double)h / pixbuf->get_height() / device_scale); - Gdk::Cairo::set_source_pixbuf(cr, pixbuf, 0, 0); - cr->paint(); - cr->restore(); - } - }, - [&] (Colors::Color const &color) { - ink_cairo_set_source_color(cr, color); - cr->paint(); - // there's no way to query background color to check if color item stands out, - // so we apply faint outline to let users make out color shapes blending with background - auto const fg = get_color(); - cr->rectangle(0.5, 0.5, w - 1, h - 1); - cr->set_source_rgba(fg.get_red(), fg.get_green(), fg.get_blue(), 0.07); - cr->set_line_width(1); - cr->stroke(); - }, - [&] (GradientData graddata) { - // Gradient pointer may be null if the gradient was destroyed. - auto grad = graddata.gradient; - if (!grad) return; - - auto pat_checkerboard = Cairo::RefPtr(new Cairo::Pattern(ink_cairo_pattern_create_checkerboard(), true)); - auto pat_gradient = Cairo::RefPtr(new Cairo::Pattern(grad->create_preview_pattern(w), true)); - - cr->set_source(pat_checkerboard); - cr->paint(); - cr->set_source(pat_gradient); - cr->paint(); - }}, data); -} - -void ColorItem::draw_func(Cairo::RefPtr const &cr, int const w, int const h) -{ - // Only using caching for none and gradients. None is included because the image is huge. - bool const use_cache = std::holds_alternative(data) || std::holds_alternative(data); - - if (use_cache) { - auto scale = get_scale_factor(); - // Ensure cache exists and has correct size. - if (!cache || cache->get_width() != w * scale || cache->get_height() != h * scale) { - cache = Cairo::ImageSurface::create(Cairo::Surface::Format::ARGB32, w * scale, h * scale); - cairo_surface_set_device_scale(cache->cobj(), scale, scale); - cache_dirty = true; - } - // Ensure cache contents is up-to-date. - if (cache_dirty) { - draw_color(Cairo::Context::create(cache), w * scale, h * scale); - cache_dirty = false; - } - // Paint from cache. - cr->set_source(cache, 0, 0); - cr->paint(); - } else { - // Paint directly. - draw_color(cr, w, h); - } - - // Draw fill/stroke indicators. - if (is_fill || is_stroke) { - double const lightness = Colors::get_perceptual_lightness(getColor()); - auto [gray, alpha] = Colors::get_contrasting_color(lightness); - cr->set_source_rgba(gray, gray, gray, alpha); - - // Scale so that the square -1...1 is the biggest possible square centred in the widget. - auto minwh = std::min(w, h); - cr->translate((w - minwh) / 2.0, (h - minwh) / 2.0); - cr->scale(minwh / 2.0, minwh / 2.0); - cr->translate(1.0, 1.0); - - if (is_fill) { - cr->arc(0.0, 0.0, 0.35, 0.0, 2 * M_PI); - cr->fill(); - } - - if (is_stroke) { - cr->set_fill_rule(Cairo::Context::FillRule::EVEN_ODD); - cr->arc(0.0, 0.0, 0.65, 0.0, 2 * M_PI); - cr->arc(0.0, 0.0, 0.5, 0.0, 2 * M_PI); - cr->fill(); - } - } -} - void ColorItem::size_allocate_vfunc(int width, int height, int baseline) { Gtk::Widget::size_allocate_vfunc(width, height, baseline); diff --git a/src/ui/dialog/color-item.h b/src/ui/dialog/color-item.h index 4d70cc8c45c..382ebeb01e9 100644 --- a/src/ui/dialog/color-item.h +++ b/src/ui/dialog/color-item.h @@ -59,8 +59,6 @@ public: ColorItem(Glib::ustring name); ~ColorItem() override; - void snapshot_vfunc(const Glib::RefPtr& snapshot) override; - // Returns true if this is group heading rather than a color bool is_group() const; // Returns true if this is alignment filler item, not a color @@ -90,7 +88,7 @@ public: sigc::signal& signal_pinned() { return _signal_pinned; }; private: - void draw_func(Cairo::RefPtr const&, int width, int height); + void snapshot_vfunc(const Glib::RefPtr& snapshot) override; void size_allocate_vfunc(int width, int height, int baseline) override; Glib::RefPtr on_drag_prepare(); -- GitLab From 5c1d51c163f92e589ed09e636db6e7f6ab624266 Mon Sep 17 00:00:00 2001 From: Leonardo Fadul Date: Sun, 1 Jun 2025 15:46:06 -0300 Subject: [PATCH 3/3] WIP: Drawing stroke indicators and drawing square on top of another --- src/ui/dialog/color-item.cpp | 88 ++++++++++++++++++++++++------------ 1 file changed, 58 insertions(+), 30 deletions(-) diff --git a/src/ui/dialog/color-item.cpp b/src/ui/dialog/color-item.cpp index cca61607b61..c8f7790ed0a 100644 --- a/src/ui/dialog/color-item.cpp +++ b/src/ui/dialog/color-item.cpp @@ -57,6 +57,7 @@ #include "ui/util.h" #include "util/value-utils.h" #include "util/variant-visitor.h" +#include "object/sp-stop.h" namespace Inkscape::UI::Dialog { namespace { @@ -218,13 +219,22 @@ void ColorItem::draw_color(Cairo::RefPtr const &cr, int w, int h auto grad = graddata.gradient; if (!grad) return; - auto pat_checkerboard = Cairo::RefPtr(new Cairo::Pattern(ink_cairo_pattern_create_checkerboard(), true)); - auto pat_gradient = Cairo::RefPtr(new Cairo::Pattern(grad->create_preview_pattern(w), true)); + auto pat_checkerboard = Cairo::RefPtr( + new Cairo::Pattern(ink_cairo_pattern_create_checkerboard(), true)); + auto pat_gradient = Cairo::RefPtr( + new Cairo::Pattern(grad->create_preview_pattern(w), true)); cr->set_source(pat_checkerboard); cr->paint(); cr->set_source(pat_gradient); cr->paint(); + + // Draw + auto const fg = get_color(); + cr->rectangle(0.5, 0.5, w - 1, h - 1); + cr->set_source_rgba(fg.get_red(), fg.get_green(), fg.get_blue(), 0.07); + cr->set_line_width(1); + cr->stroke(); }}, data); } @@ -234,42 +244,45 @@ void ColorItem::snapshot_vfunc(const Glib::RefPtr& snapshot) [&] (Undefined) { // there's no color to paint; indicate clearly that there is nothing to select: - // Calculate the position and size for the rectangle + // Calculate the position and size for the horizontal rectangle auto const y = get_allocated_height() / 2 + 0.5; auto const w = get_allocated_width() / 4; auto const x = (get_allocated_width() - w) / 2 - 0.5; auto const h = get_allocated_height(); - // Get the foreground color and Set the color with 50% opacity + // Define the color for the line and border auto const fg = get_color(); auto const color = Gdk::RGBA(fg.get_red(), fg.get_green(), fg.get_blue(), 0.5); - // Append a rectangle of the specified color to the snapshot + // Append a horizontal line to the snapshot snapshot->append_color(color, Gdk::Graphene::Rect(x, y, w, 1)); - // Create a graphene rectangle for the border - graphene_rect_t rect = GRAPHENE_RECT_INIT(0.5f, 0.5f, static_cast(w - 1), static_cast(h - 1)); - - // Create a gsk path builder for the border - auto const builder = gsk_path_builder_new (); - gsk_path_builder_move_to (builder, 0.5, 0.5); - gsk_path_builder_line_to (builder, w - 1.5, 0.5); - gsk_path_builder_line_to (builder, w - 1.5, h - 1.5); - gsk_path_builder_line_to (builder, 0.5, h - 1.5); - gsk_path_builder_close (builder); + // Define the outer rectangle (border) + graphene_rect_t outer = GRAPHENE_RECT_INIT( + 0.5f, 0.5f, + static_cast(w - 1), + static_cast(h - 1) + ); - // Create a gsk path - auto path = gsk_path_builder_free_to_path (builder); + // Draw the border as a filled rectangle + snapshot->append_color(color, &outer); - // Create a gsk stroke - auto const stroke = gsk_stroke_new (1.0f); + // Set the thickness of the border + constexpr float thickness = 1.0f; - // Append the stroke to the snapshot - gtk_snapshot_append_stroke(snapshot->gobj(), path, stroke, color.gobj()); + // Define the inner rectangle (the part that is transparent inside the border) + graphene_rect_t inner = GRAPHENE_RECT_INIT( + outer.origin.x + thickness, + outer.origin.y + thickness, + outer.size.width - 2 * thickness, + outer.size.height - 2 * thickness + ); - // Release resources - gsk_stroke_free (stroke); - gsk_path_unref (path); + // Draw the interior with transparency (or background color) + if (inner.size.width > 0 && inner.size.height > 0) { + auto bg = Gdk::RGBA(0, 0, 0, 0); + snapshot->append_color(bg, &inner); + } }, [&] (PaintNone) { if (auto const pixbuf = get_removecolor()) { @@ -309,11 +322,26 @@ void ColorItem::snapshot_vfunc(const Glib::RefPtr& snapshot) // Create the gradient pattern auto pat_gradient = Cairo::RefPtr(new Cairo::Pattern(grad->create_preview_pattern(w), true)); - // Define the gradient stops (example with black to white) - GskColorStop stops[] = { - {0.0f, {0.0f, 0.0f, 0.0f, 1.0f}}, // Black at the start - {1.0f, {1.0f, 1.0f, 1.0f, 1.0f}} // White at the end - }; + // Define the gradient stops + int stop_count = grad->getStopCount(); + std::vector stops(stop_count); + for (int i = 0; i < stop_count; ++i) { + auto const stop = grad->getFirstStop(); + if (stop) { + stops[i].offset = stop->offset; + stops[i].color.red = stop->getColor().get(0); + stops[i].color.green = stop->getColor().get(1); + stops[i].color.blue = stop->getColor().get(2); + stops[i].color.alpha = stop->getColor().get(3); + } else { + // If there are no stops, use a Black color + stops[i].offset = 0.0f; + stops[i].color.red = 0.0f; + stops[i].color.green = 0.0f; + stops[i].color.blue = 0.0f; + stops[i].color.alpha = 1.0f; + } + } // Initialize the rectangle for the gradient graphene_rect_t graphene_rect = GRAPHENE_RECT_INIT(0.5f, 0.5f, static_cast(w - 1), static_cast(h - 1)); @@ -324,7 +352,7 @@ void ColorItem::snapshot_vfunc(const Glib::RefPtr& snapshot) &graphene_rect, start.gobj(), end.gobj(), - stops, + stops.data(), G_N_ELEMENTS(stops) ); }}, data); -- GitLab