6#include <cairomm/context.h>
8#include <cairomm/refptr.h>
9#include <cairomm/surface.h>
10#include <gtkmm/eventcontrollermotion.h>
11#include <gtkmm/gestureclick.h>
23void circle(
const Cairo::RefPtr<Cairo::Context>& ctx,
const Geom::Point& center,
double radius) {
24 ctx->arc(center.
x(), center.
y(), radius, 0, 2 * M_PI);
31 auto pt = point.
round();
32 ctx->set_line_width(1.0);
34 ctx->set_source_rgb(1, 1, 1);
37 ctx->set_source_rgb(0, 0, 0);
43static void draw_color_plate(
const Cairo::RefPtr<Cairo::Context>& ctx,
const Geom::Rect& area,
double radius,
const Cairo::RefPtr<Cairo::ImageSurface>&
preview,
bool circular) {
44 if (area.
width() <= 0 || area.
height() <= 0)
return;
68 offset += {-1.0 * s, -1.0 * s};
83 auto scale_x = area.
width() / (
preview->get_width() - 2);
100 auto angle = (val1 * 2 * M_PI) - M_PI;
101 auto x = sin(angle) * val2;
102 auto y = cos(angle) * val2;
107 return {val1, 1 - val2};
113 auto dist = std::hypot(x, y);
114 auto angle = (atan2(x, y) + M_PI) / (2 * M_PI);
115 color.
set(channel1, angle);
116 color.
set(channel2, dist);
120 color.
set(channel1, x);
121 color.
set(channel2, 1 - y);
126 auto fmt = Cairo::ImageSurface::Format::ARGB32;
127 auto stride = Cairo::ImageSurface::format_stride_for_width(
fmt,
size);
133 void* buffer =
data.data();
134 auto src = Cairo::ImageSurface::create(
static_cast<unsigned char*
>(buffer),
fmt,
size,
size,
stride);
135 auto dest = Cairo::ImageSurface::create(
fmt,
size,
size);
136 auto ctx = Cairo::Context::create(dest);
137 ctx->set_source(src, 0, 0);
143static Cairo::RefPtr<Cairo::ImageSurface>
create_color_plate(
unsigned int resolution,
const Color& base,
int channel1,
int channel2) {
144 const double limit = resolution;
145 const int size = resolution + 1;
152 for (
int iy = 0; iy <=
limit; ++iy, ++row) {
154 color.set(channel2, 1 - y);
155 auto index =
static_cast<size_t>(row *
width);
156 for (
int ix = 0; ix <=
limit; ++ix) {
158 color.set(channel1, x);
167static Cairo::RefPtr<Cairo::ImageSurface>
create_color_wheel(
unsigned int resolution,
const Color& base,
int channel1,
int channel2) {
168 const int radius = resolution / 2;
169 const double limit = radius;
170 const int size = radius * 2 + 1;
175 double rsqr = std::pow(1.0 + 1.0/radius, 2);
177 for (
int iy = -radius; iy <= radius; ++iy, ++row) {
181 for (
int ix = -radius; ix <= radius; ++ix, ++
index) {
185 if (sx + sy > rsqr)
continue;
199 point = active.
clamp(point);
232 set_name(
"ColorPlate");
235 set_draw_func([
this](
const Cairo::RefPtr<Cairo::Context>& ctx,
int ,
int ){
239 auto const motion = Gtk::EventControllerMotion::create();
240 motion->set_propagation_phase(Gtk::PropagationPhase::TARGET);
241 motion->signal_motion().connect([
this, &motion = *motion](
auto &&...args) {
on_motion(motion, args...); });
242 add_controller(motion);
244 auto const click = Gtk::GestureClick::create();
245 click->set_button(1);
256 return Gtk::EventSequenceState::CLAIMED;
261 return Gtk::EventSequenceState::NONE;
263 add_controller(click);
268 if (!maybe_area)
return;
270 auto area = *maybe_area;
276 constexpr int resolution = 64;
309 auto alloc = get_allocation();
311 if (alloc.get_width() <= min || alloc.get_height() <= min)
return {};
318 if (!area || area->minExtent() < 1)
return {};
320 return area->shrunkBy(1, 1);
330 if (
_down.has_value()) {
339 auto state = motion.get_current_event_state();
354 remove_css_class(
"rectangular");
355 add_css_class(
"circular");
358 remove_css_class(
"circular");
359 add_css_class(
"rectangular");
CPoint clamp(CPoint const &p) const
Clamp point to the rectangle.
bool contains(GenericRect< C > const &r) const
Check whether the rectangle includes all points in the given rectangle.
CPoint midpoint() const
Get the point in the geometric center of the rectangle.
C height() const
Get the vertical extent of the rectangle.
C minExtent() const
Get the smaller extent (width or height) of the rectangle.
C width() const
Get the horizontal extent of the rectangle.
CPoint min() const
Get the corner of the rectangle with smallest coordinate values.
CPoint dimensions() const
Get rectangle's width and height as a point.
Axis-aligned rectangle that can be empty.
Two-dimensional point that doubles as a vector.
constexpr Coord y() const noexcept
constexpr Coord x() const noexcept
IntPoint round() const
Round to nearest integer coordinates.
Axis aligned, non-empty rectangle.
Rect shrunkBy(Coord amount) const
Return a new rectangle which results from shrinking this one by the same amount along both axes.
uint32_t toARGB(double opacity=1.0) const
Return the RGBA int32 as an ARGB format number.
bool set(unsigned int index, double value)
Set a specific channel in the color.
bool addOpacity(double opacity=1.0)
bool setOpacity(double opacity)
Set the opacity of this color object.
std::shared_ptr< Space::AnySpace > const & getSpace() const
void draw(cairo_t *cr, xAx C, Rect bnd)
Utilities to more easily use Gtk::EventController & subclasses like Gesture.
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).
Geom::Rect rounded_rectangle(const Cairo::RefPtr< Cairo::Context > &ctx, const Geom::Rect &rect, double radius)
bool is_current_theme_dark(Gtk::Widget &widget)
void draw_standard_border(const Cairo::RefPtr< Cairo::Context > &ctx, Geom::Rect rect, bool dark_theme, double radius, int device_scale, bool circular)