valueSaturationBox
Returns true if the color was changed
Parameters
- src:std.builtin.SourceLocation
- std.builtin.SourceLocation
- hsv:*Color.HSV
- *Color.HSV
- opts:Options
- Options
Source
Implementation
pub fn valueSaturationBox(src: std.builtin.SourceLocation, hsv: *Color.HSV, opts: Options) bool {
const options = value_saturation_box_defaults.override(opts);
var b = dvui.box(src, .{ .dir = .horizontal }, options);
defer b.deinit();
// Accessibility TODO: Needs 2d-slider support from AccessKit. It's not possible to attach
// a horizontal and vertical value to a single widget.
dvui.tabIndexSet(b.data().id, options.tab_index, b.data().rectScale().r);
const rs = b.data().contentRectScale();
const texture = getValueSaturationTexture(hsv.h) catch |err| blk: {
dvui.logError(@src(), err, "Could not get value saturation texture", .{});
break :blk null;
};
if (texture) |tex| {
dvui.renderTexture(tex, rs, .{
.corners = options.cornersGet(),
.uv = .{ .x = 0.25, .y = 0.25, .w = 0.5, .h = 0.5 },
}) catch |err| {
dvui.logError(@src(), err, "Could not render value saturation texture", .{});
};
}
const mouse_rect = b.data().contentRect().justSize().outsetAll(5);
const mouse_rs = b.widget().screenRectScale(mouse_rect);
var changed = false;
const evts = dvui.events();
for (evts) |*e| {
if (!dvui.eventMatch(e, .{ .id = b.data().id, .r = mouse_rs.r }))
continue;
switch (e.evt) {
.mouse => |me| {
var p: ?dvui.Point.Physical = null;
if (me.action == .focus) {
e.handle(@src(), b.data());
dvui.focusWidget(b.data().id, null, e.num);
} else if (me.action == .press and me.button.pointer()) {
// capture
dvui.captureMouse(b.data(), e.num);
e.handle(@src(), b.data());
p = me.p;
} else if (me.action == .release and me.button.pointer()) {
// stop capture
dvui.captureMouse(null, e.num);
dvui.dragEnd();
e.handle(@src(), b.data());
} else if (me.action == .motion and dvui.captured(b.data().id)) {
// handle only if we have capture
e.handle(@src(), b.data());
p = me.p;
} else if (me.action == .position) {
dvui.cursorSet(.arrow);
}
if (p) |pp| {
hsv.s = std.math.clamp((pp.x - rs.r.x) / rs.r.w, 0, 1);
hsv.v = std.math.clamp(1 - (pp.y - rs.r.y) / rs.r.h, 0, 1);
changed = true;
}
},
.key => |ke| {
if (ke.action == .down or ke.action == .repeat) {
switch (ke.code) {
.left => {
e.handle(@src(), b.data());
hsv.s = std.math.clamp(hsv.s - 0.05, 0, 1);
changed = true;
},
.right => {
e.handle(@src(), b.data());
hsv.s = std.math.clamp(hsv.s + 0.05, 0, 1);
changed = true;
},
.up => {
e.handle(@src(), b.data());
// hsv.v is inverted, up is positive
hsv.v = std.math.clamp(hsv.v + 0.05, 0, 1);
changed = true;
},
.down => {
e.handle(@src(), b.data());
// hsv.v is inverted, down is negative
hsv.v = std.math.clamp(hsv.v - 0.05, 0, 1);
changed = true;
},
else => {},
}
}
},
else => {},
}
}
const br = b.data().contentRect();
const current_point: dvui.Point = .{ .x = br.w * hsv.s, .y = br.h * (1 - hsv.v) };
var indicator = dvui.box(@src(), .{ .dir = .horizontal }, .{
.rect = dvui.Rect.fromPoint(current_point).toSize(.all(10)).offsetNeg(.all(5)),
.padding = .{},
.margin = .{},
.background = true,
.border = .all(1),
.corners = .all(100),
.color_fill = hsv.toColor(),
});
if (b.data().id == dvui.focusedWidgetId()) {
indicator.data().focusBorder();
}
indicator.deinit();
return changed;
}