1#include "color_selector.h"
3#include <cgv/gui/mouse_event.h>
4#include <cgv/gui/theme_info.h>
5#include <cgv/math/interpolate.h>
6#include <cgv_g2d/msdf_gl_font_renderer.h>
7#include <cgv_gl/gl/gl.h>
12color_selector::color_selector() {
17 layout.padding = padding();
21 selector_handles.callback = std::bind(&color_selector::handle_selector_drag,
this, std::placeholders::_1);
22 selector_handles.use_individual_constraints =
true;
27 cgv::g2d::ref_msdf_gl_font_renderer_2d(ctx, -1);
33 text_geometry.destruct(ctx);
41 cgv::g2d::irect hit_rect;
43 if(layout.color_rect.contains(local_mouse_pos)) {
45 hit_rect = layout.color_rect;
48 if(layout.hue_rect.contains(local_mouse_pos)) {
50 hit_rect = layout.hue_rect;
53 if(layout.opacity_rect.contains(local_mouse_pos)) {
55 hit_rect = layout.opacity_rect;
58 if(hit_index > -1 && hit_index < 4) {
59 vec2 hit_rect_realtive_pos =
static_cast<vec2>(local_mouse_pos - hit_rect.position);
60 vec2 val = hit_rect_realtive_pos /
static_cast<vec2>(hit_rect.size);
63 selector_handles[hit_index].val = val;
64 selector_handles[hit_index].update_pos();
85 set_rgb_color(rgb_color);
88 set_rgba_color(rgba_color);
96 cgv::g2d::ref_msdf_gl_font_renderer_2d(ctx, 1);
98 register_shader(
"rectangle", cgv::g2d::shaders::rectangle);
99 register_shader(
"circle", cgv::g2d::shaders::circle);
100 register_shader(
"grid", cgv::g2d::shaders::grid);
104 success &= text_geometry.init(ctx);
106 text_geometry.texts = {
"R",
"0",
"G",
"0",
"B",
"0",
"A",
"0" };
108 text_geometry.create(ctx);
110 for(
size_t i = 0; i < 4; ++i) {
115 text_geometry.positions = std::vector<vec3>(8, { 0.0f });
120 sh.size =
vec2(16.0f);
121 selector_handles.add(sh);
124 sh.is_rectangular =
true;
125 sh.size =
vec2(20.0f, 10.0f);
126 sh.position_is_center =
false;
127 sh.constraint_reference = cgv::g2d::ConstraintReference::kMinPoint;
128 selector_handles.add(sh);
131 selector_handles.add(sh);
134 selector_handles[0].constraint = &layout.color_rect;
135 selector_handles[1].constraint = &layout.hue_constraint;
136 selector_handles[2].constraint = &layout.opacity_constraint;
138 create_hue_texture(ctx);
139 create_color_texture(ctx);
142 set_color(
rgba(0.0f, 0.0f, 0.0f, 1.0f),
true,
true);
144 set_color(
rgb(0.0f),
false,
true);
151 if(ensure_layout(ctx)) {
154 for(
size_t i = 0; i < 3; ++i)
155 selector_handles[i].update_pos();
157 int w = layout.opacity_rect.w();
158 int h = layout.opacity_rect.h();
159 opacity_bg_style.texcoord_scaling =
vec2(1.0f,
static_cast<float>(h) /
static_cast<float>(w));
161 ivec2 text_position =
ivec2(layout.preview_rect.b().x() + 10, layout.preview_rect.center().y());
162 for(
size_t i = 0; i < text_geometry.texts.size(); ++i) {
163 text_geometry.positions[i] =
vec3(text_position, 0.0f);
164 text_position.
x() += i & 1 ? 15 : 40;
174 content_canvas.enable_shader(ctx,
"rectangle");
175 content_canvas.set_style(ctx, border_style);
177 auto& theme = cgv::gui::theme_info::instance();
178 rgba border_color =
rgba(theme.border(), 1.0f);
179 rgba text_background_color =
rgba(theme.text_background(), 1.0f);
180 content_canvas.draw_shape(ctx, layout.border_rect, border_color);
181 content_canvas.draw_shape(ctx, layout.preview_rect, rgb_color);
183 cgv::g2d::irect text_bg = layout.preview_rect;
184 text_bg.size.x() = 48;
185 int n_labels = has_opacity ? 4 : 3;
186 for(
size_t i = 0; i < n_labels; ++i) {
187 text_bg.position.x() =
static_cast<int>(text_geometry.positions[2 * i].x() - 4.0f);
188 content_canvas.draw_shape(ctx, text_bg, text_background_color);
191 content_canvas.set_style(ctx, color_texture_style);
193 content_canvas.draw_shape(ctx, layout.color_rect);
196 content_canvas.set_style(ctx, hue_texture_style);
198 content_canvas.draw_shape(ctx, layout.hue_rect);
202 content_canvas.enable_shader(ctx,
"grid");
203 content_canvas.set_style(ctx, opacity_bg_style);
204 content_canvas.draw_shape(ctx, layout.opacity_rect);
207 glEnable(GL_SCISSOR_TEST);
208 glScissor(layout.color_rect.x(), layout.color_rect.y(), layout.color_rect.w(), layout.color_rect.h());
210 auto& sh = selector_handles;
211 content_canvas.enable_shader(ctx,
"circle");
212 content_canvas.set_style(ctx, color_handle_style);
213 glScissor(layout.color_rect.x(), layout.color_rect.y(), layout.color_rect.w(), layout.color_rect.h());
214 content_canvas.draw_shape(ctx, sh[0].position + 0.5f, sh[0].size);
216 content_canvas.enable_shader(ctx,
"rectangle");
217 content_canvas.set_style(ctx, hue_handle_style);
218 glScissor(layout.hue_rect.x(), layout.hue_rect.y(), layout.hue_rect.w(), layout.hue_rect.h());
219 content_canvas.draw_shape(ctx, sh[1]);
222 glScissor(layout.opacity_rect.x(), layout.opacity_rect.y(), layout.opacity_rect.w(), layout.opacity_rect.h());
224 const auto& r = layout.opacity_rect;
225 content_canvas.enable_shader(ctx,
"rectangle");
226 opacity_color_style.fill_color =
rgba(rgb_color, 1.0f);
227 opacity_color_style.feather_width =
static_cast<float>(r.h());
228 content_canvas.set_style(ctx, opacity_color_style);
229 content_canvas.draw_shape(ctx,
ivec2(r.x(), r.y1() - 1),
ivec2(r.w(), 1));
231 content_canvas.set_style(ctx, hue_handle_style);
232 content_canvas.draw_shape(ctx, sh[2]);
235 content_canvas.disable_current_shader(ctx);
237 glDisable(GL_SCISSOR_TEST);
239 cgv::g2d::ref_msdf_gl_font_renderer_2d(ctx).render(ctx, content_canvas, text_geometry, text_style, 0, 2 * n_labels);
248 add_member_control(
this,
"Size", layout.size,
"value_slider",
"min=120;max=1000;step=1;ticks=true");
259void color_selector::set_rgb_color(
rgb color) {
260 set_color(
rgba(color, 1.0f),
false);
263void color_selector::set_rgba_color(
rgba color) {
264 set_color(color,
true);
270 const int slider_width = 20;
272 l.border_rect.position =
ivec2(l.padding);
273 l.border_rect.size =
ivec2(parent_size - 2 * l.padding);
274 l.border_rect.position.y() += 23;
275 l.border_rect.size.y() -= 23;
277 cgv::g2d::irect content_rect = l.border_rect;
278 content_rect.translate(1, 1);
279 content_rect.size -= 2;
281 int mult = has_opacity ? 2 : 1;
283 l.hue_rect.position =
ivec2(content_rect.x1() - mult* slider_width - (mult-1), content_rect.y());
284 l.hue_rect.size =
ivec2(slider_width, content_rect.h());
287 l.opacity_rect = l.hue_rect;
288 l.opacity_rect.translate(slider_width + 1, 0);
291 l.color_rect = content_rect;
292 l.color_rect.w() -= 21 * mult;
294 l.preview_rect.position =
ivec2(l.padding);
295 l.preview_rect.size =
ivec2(20, 20);
297 l.hue_constraint = l.hue_rect;
298 l.hue_constraint.translate(0, -5);
299 l.hue_constraint.size.x() = 0;
301 l.opacity_constraint = l.opacity_rect;
302 l.opacity_constraint.translate(0, -5);
303 l.opacity_constraint.size.x() = 0;
307void color_selector::init_styles() {
308 auto& theme = cgv::gui::theme_info::instance();
311 border_style.border_width = 0.0f;
312 border_style.use_fill_color =
false;
313 border_style.feather_width = 0.0f;
315 opacity_bg_style.feather_width = 0.0f;
316 opacity_bg_style.fill_color =
rgba(
rgb(0.75f), 1.0f);
317 opacity_bg_style.border_color =
rgba(
rgb(0.9f), 1.0f);
318 opacity_bg_style.pattern = cgv::g2d::grid2d_style::GP_CHECKER;
319 opacity_bg_style.scale = 0.5f;
321 opacity_color_style.use_blending =
true;
322 opacity_color_style.feather_origin = 1.0f;
325 color_texture_style = border_style;
326 color_texture_style.use_texture =
true;
328 hue_texture_style = color_texture_style;
329 color_texture_style.texcoord_scaling =
vec2(0.5f);
330 color_texture_style.texcoord_offset =
vec2(0.25f);
333 color_handle_style.use_blending =
true;
334 color_handle_style.use_fill_color =
true;
335 color_handle_style.position_is_center =
true;
336 color_handle_style.border_color =
rgba(
rgb(1.0f), 0.75f);
337 color_handle_style.border_width = 1.0f;
338 color_handle_style.fill_color =
rgba(
rgb(0.0f), 1.0f);
339 color_handle_style.ring_width = 4.0f;
342 hue_handle_style = color_handle_style;
343 hue_handle_style.position_is_center =
false;
346 text_style.fill_color = theme.text();
347 text_style.font_size = 14.0f;
352 const size_t resolution = 256;
354 std::vector<rgb8> data;
355 data.reserve(resolution);
356 cgv::math::sequence_transform(std::back_inserter(data), [](
float t) {
362 return hue_tex.
create(ctx, data_view, 0);
367 rgb color = { 0.0f };
368 if(selector_handles.size() > 1)
371 std::vector<rgb8> data = {
380 return color_tex.
create(ctx, data_view, 0);
383void color_selector::update_color() {
385 const auto& cp = selector_handles[0];
386 const auto& hp = selector_handles[1];
387 const auto& op = selector_handles[2];
390 float s = cp.val.x();
391 float v = cp.val.y();
393 rgb_color = v * rgb_color;
394 rgb_color = (1.0f - s)*
rgb(v) + s * rgb_color;
396 rgba_color =
rgba(rgb_color, op.val.y());
401 if(on_change_rgba_callback)
402 on_change_rgba_callback(rgba_color);
404 if(on_change_rgb_callback)
405 on_change_rgb_callback(rgb_color);
411void color_selector::update_texts() {
414 components[0] =
static_cast<int>(round(rgba_color.R() * 255.0f));
415 components[1] =
static_cast<int>(round(rgba_color.G() * 255.0f));
416 components[2] =
static_cast<int>(round(rgba_color.B() * 255.0f));
417 components[3] =
static_cast<int>(round(rgba_color.alpha() * 255.0f));
419 components = cgv::math::clamp(components, 0, 255);
421 text_geometry.texts[1] = std::to_string(components[0]);
422 text_geometry.texts[3] = std::to_string(components[1]);
423 text_geometry.texts[5] = std::to_string(components[2]);
424 text_geometry.texts[7] = std::to_string(components[3]);
427 text_geometry.create(*ctx_ptr);
430void color_selector::handle_selector_drag(cgv::g2d::DragAction action) {
432 if(action == cgv::g2d::DragAction::kDrag) {
433 auto* p = selector_handles.get_dragged();
437 if(p == &selector_handles[1]) {
439 create_color_texture(*ctx);
446void color_selector::set_color(
rgba color,
bool opacity,
bool init) {
448 this->rgb_color.R() = color.R();
449 this->rgb_color.G() = color.G();
450 this->rgb_color.B() = color.B();
451 this->rgba_color = color;
454 float v = v = color.S() * std::min(color.L(), 1.0f - color.L()) + color.L();
455 float s = v ? 2.0f - 2.0f * color.L() / v : 0.0f;
457 selector_handles[0].val =
vec2(s, v);
458 selector_handles[1].val.y() = h;
459 selector_handles[2].val.y() = color.alpha();
461 selector_handles[0].update_pos();
462 selector_handles[1].update_pos();
463 selector_handles[2].update_pos();
465 if(has_opacity != opacity) {
467 post_recreate_layout();
469 has_opacity = opacity;
473 create_color_texture(*ctx);
476 if(!
init && auto_show)
void set_name(const std::string &_name)
set a new parent node
the data view gives access to a data array of one, two, three or four dimensions.
class to represent all possible mouse events with the EID_MOUSE
void align(const std::string &_align)
send pure alignment information
bool begin_tree_node(const std::string &label, const T &value, bool initial_visibility=false, const std::string &options="", gui_group_ptr ggp=gui_group_ptr())
Begin a sub tree of a tree structured gui.
virtual void update_member(void *member_ptr)
call this to update all views and controls of a member
data::ref_ptr< control< T > > add_member_control(cgv::base::base *base_ptr, const std::string &label, T &value, const std::string &gui_type="", const std::string &options="", const std::string &align="\n")
add control with callback to cgv::base::on_set method on cgv::gui::control::value_change
void end_tree_node(const T &value)
template specialization that allows to specify value reference plus node_instance by using the result...
virtual void post_recreate_gui()
delayed recreation of gui
T & x()
return first component
bool init(cgv::render::context &ctx) override
this method is called after creation or recreation of the context, return whether all necessary funct...
void clear(cgv::render::context &ctx) override
clear all objects living in the context like textures or display lists
void draw_content(cgv::render::context &ctx) override
draw_content is implemented by decendent classes
bool handle_mouse_event(cgv::gui::mouse_event &e, cgv::ivec2 local_mouse_pos) override
overload this method to handle mouse events; local_mouse_pos is the mouse position in the local coord...
void init_frame(cgv::render::context &ctx) override
this method is called in one pass over all drawables before the draw method
bool init(cgv::render::context &ctx) override
this method is called after creation or recreation of the context, return whether all necessary funct...
void create_gui_impl() override
virtual method to implement the derived class gui creation
void handle_member_change(cgv::data::informed_ptr ptr) override
implement to handle member changes
void clear(cgv::render::context &ctx) override
clear all objects living in the context like textures or display lists
void set_size(const ivec2 &size)
set the default size of the overlay before stretch gets applied
bool blocks_events() const
return whether this overlay blocks events, i.e. does not pass them to the next event handler
void set_visibility(bool visible)
set the visibility of the overlay
cgv::g2d::irect get_rectangle() const
return the current rectangle area (in screen coordinates) of the overlay taking layout into account
void update_layout()
update the layout of the overlay container
ivec2 get_viewport_size() const
return the current viewport size
base class for all drawables, which is independent of the used rendering API.
context * get_context() const
access the current context. The context will be available latestly in the init method but not in the ...
bool create(const context &ctx, TextureType _tt=TT_UNDEF, unsigned width=-1, unsigned height=-1, unsigned depth=-1)
create the texture of dimension and resolution specified in the data format base class.
bool disable(const context &ctx)
disable texture and restore state from before last enable call
bool enable(const context &ctx, int tex_unit=-1)
enable this texture in the given texture unit, -1 corresponds to the current unit.
bool destruct(const context &ctx)
destruct the texture and free texture memory and handle
@ CF_RGB
color format with two components R and G
@ MB_LEFT_BUTTON
left button
@ MA_PRESS
mouse button pressed
@ TA_RIGHT
center of right edge of text bounds
@ TA_LEFT
center of left edge of text bounds
@ TI_UINT8
signed integer stored in 64 bits
this header is dependency free
cgv::media::color< float, cgv::media::RGB, cgv::media::OPACITY > rgba
declare rgba color type with 32 bit components
cgv::math::fvec< int32_t, 4 > ivec4
declare type of 4d 32 bit integer vectors
cgv::media::color< float, cgv::media::RGB > rgb
declare rgb color type with 32 bit components
cgv::math::fvec< int32_t, 2 > ivec2
declare type of 2d 32 bit integer vectors
cgv::media::color< cgv::type::uint8_type, cgv::media::RGB > rgb8
declare rgb color type with 8 bit components
cgv::math::fvec< float, 2 > vec2
declare type of 2d single precision floating point vectors
cgv::math::fvec< float, 3 > vec3
declare type of 3d single precision floating point vectors