add checkbox to toggle rulers
This commit is contained in:
parent
36706ff348
commit
772f35fee7
@ -284,6 +284,7 @@ pub const Project = struct {
|
||||
|
||||
save_location: ?[]u8 = null,
|
||||
sample_rate: ?f64 = null,
|
||||
show_rulers: bool = true,
|
||||
|
||||
channels: GenerationalArray(Channel) = .{},
|
||||
files: GenerationalArray(File) = .{},
|
||||
|
@ -45,10 +45,9 @@ pub var grab_texture: struct {
|
||||
} = undefined;
|
||||
|
||||
pub var dropdown_arrow: rl.Texture2D = undefined;
|
||||
|
||||
pub var fullscreen: rl.Texture2D = undefined;
|
||||
|
||||
pub var output_generation: rl.Texture2D = undefined;
|
||||
pub var checkbox_mark: rl.Texture2D = undefined;
|
||||
|
||||
pub fn font(font_id: FontId) FontFace {
|
||||
var found_font: ?LoadedFont = null;
|
||||
@ -120,38 +119,23 @@ pub fn init(allocator: std.mem.Allocator) !void {
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
const dropdown_arrow_ase = try Aseprite.init(allocator, @embedFile("./assets/dropdown-arrow.ase"));
|
||||
defer dropdown_arrow_ase.deinit();
|
||||
|
||||
const dropdown_image = dropdown_arrow_ase.getFrameImage(0);
|
||||
defer dropdown_image.unload();
|
||||
|
||||
dropdown_arrow = rl.loadTextureFromImage(dropdown_image);
|
||||
assert(rl.isTextureReady(dropdown_arrow));
|
||||
fullscreen = try loadTextureFromAseprite(allocator, @embedFile("./assets/dropdown-arrow.ase"));
|
||||
fullscreen = try loadTextureFromAseprite(allocator, @embedFile("./assets/fullscreen-icon.ase"));
|
||||
output_generation = try loadTextureFromAseprite(allocator, @embedFile("./assets/output-generation-icon.ase"));
|
||||
checkbox_mark = try loadTextureFromAseprite(allocator, @embedFile("./assets/checkbox-mark.ase"));
|
||||
}
|
||||
|
||||
{
|
||||
const fullscreen_ase = try Aseprite.init(allocator, @embedFile("./assets/fullscreen-icon.ase"));
|
||||
defer fullscreen_ase.deinit();
|
||||
fn loadTextureFromAseprite(allocator: std.mem.Allocator, memory: []const u8) !rl.Texture {
|
||||
const ase = try Aseprite.init(allocator, memory);
|
||||
defer ase.deinit();
|
||||
|
||||
const fullscreen_image = fullscreen_ase.getFrameImage(0);
|
||||
defer fullscreen_image.unload();
|
||||
const image = ase.getFrameImage(0);
|
||||
defer image.unload();
|
||||
|
||||
fullscreen = rl.loadTextureFromImage(fullscreen_image);
|
||||
assert(rl.isTextureReady(fullscreen));
|
||||
}
|
||||
const texture = rl.loadTextureFromImage(image);
|
||||
assert(rl.isTextureReady(texture));
|
||||
|
||||
{
|
||||
const output_generation_ase = try Aseprite.init(allocator, @embedFile("./assets/output-generation-icon.ase"));
|
||||
defer output_generation_ase.deinit();
|
||||
|
||||
const output_generation_image = output_generation_ase.getFrameImage(0);
|
||||
defer output_generation_image.unload();
|
||||
|
||||
output_generation = rl.loadTextureFromImage(output_generation_image);
|
||||
assert(rl.isTextureReady(output_generation));
|
||||
}
|
||||
return texture;
|
||||
}
|
||||
|
||||
fn loadFont(ttf_data: []const u8, font_size: u32) !rl.Font {
|
||||
|
@ -125,6 +125,7 @@ cursor: ?ViewAxisPosition = null,
|
||||
view_settings: ?Id = null, // View id
|
||||
view_fullscreen: ?Id = null, // View id
|
||||
view_protocol_modal: ?Id = null, // View id
|
||||
show_ruler: bool = false,
|
||||
|
||||
pub fn init(project: *App.Project) System {
|
||||
return System{
|
||||
|
@ -48,6 +48,9 @@ fn showGraph(ctx: Context, view_id: Id) *UI.Box {
|
||||
.flags = &.{ .clickable, .draggable, .scrollable, .clip_view },
|
||||
.align_x = .center,
|
||||
.align_y = .center,
|
||||
.borders = .{
|
||||
.bottom = .{ .color = srcery.hard_black, .size = 4 }
|
||||
}
|
||||
});
|
||||
graph_box.beginChildren();
|
||||
defer graph_box.endChildren();
|
||||
@ -237,7 +240,7 @@ pub fn show(ctx: Context, view_id: Id, height: UI.Sizing) !Result {
|
||||
}
|
||||
}
|
||||
|
||||
if (!constants.show_ruler) {
|
||||
if (!ctx.app.project.show_rulers) {
|
||||
_ = showGraph(ctx, view_id);
|
||||
|
||||
} else {
|
||||
|
@ -5,6 +5,5 @@ pub const max_channels = 32;
|
||||
pub const max_views = 64;
|
||||
|
||||
// UI
|
||||
pub const show_ruler = true;
|
||||
pub const sync_view_controls = true;
|
||||
pub const zoom_speed = 0.1;
|
@ -20,22 +20,6 @@ const assert = std.debug.assert;
|
||||
const remap = utils.remap;
|
||||
const Id = App.Id;
|
||||
|
||||
const zoom_speed = 0.1;
|
||||
const ruler_size = UI.Sizing.initFixed(.{ .pixels = 32 });
|
||||
const show_ruler = true;
|
||||
const sync_view_controls = true;
|
||||
|
||||
const ViewCommand = struct {
|
||||
view_id: Id,
|
||||
updated_at_ns: i128,
|
||||
action: union(enum) {
|
||||
move_and_zoom: struct {
|
||||
before_x: RangeF64,
|
||||
before_y: RangeF64,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
app: *App,
|
||||
view_controls: ViewControlsSystem,
|
||||
|
||||
@ -341,6 +325,7 @@ pub fn showSidePanel(self: *MainScreen) !void {
|
||||
|
||||
_ = ui.createBox(.{ .size_y = UI.Sizing.initFixedPixels(ui.rem(1)) });
|
||||
|
||||
{ // Sample rate
|
||||
var placeholder: ?[]const u8 = null;
|
||||
if (project.getDefaultSampleRate()) |default_sample_rate| {
|
||||
placeholder = try std.fmt.allocPrint(frame_allocator, "{d}", .{ default_sample_rate });
|
||||
@ -370,6 +355,14 @@ pub fn showSidePanel(self: *MainScreen) !void {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{ // Show ruler checkbox
|
||||
_ = ui.checkbox(.{
|
||||
.value = &project.show_rulers,
|
||||
.label = "Ruler"
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tick(self: *MainScreen) !void {
|
||||
@ -481,7 +474,6 @@ pub fn tick(self: *MainScreen) !void {
|
||||
const scroll_area = ui.beginScrollbar(ui.keyFromString("Channels"));
|
||||
defer ui.endScrollbar();
|
||||
scroll_area.layout_direction = .top_to_bottom;
|
||||
scroll_area.layout_gap = 4;
|
||||
|
||||
var view_iter = self.app.project.views.idIterator();
|
||||
while (view_iter.next()) |view_id| {
|
||||
|
114
src/ui.zig
114
src/ui.zig
@ -513,6 +513,8 @@ pub const Box = struct {
|
||||
scientific_precision: u32 = 1,
|
||||
float_relative_to: ?*Box = null,
|
||||
draw: ?Draw = null,
|
||||
visual_hot: bool = false,
|
||||
visual_active: bool = false,
|
||||
|
||||
// Variables that you probably shouldn't be touching
|
||||
last_used_frame: u64 = 0,
|
||||
@ -731,7 +733,9 @@ pub const BoxOptions = struct {
|
||||
float_relative_to: ?*Box = null,
|
||||
parent: ?*UI.Box = null,
|
||||
texture_color: ?rl.Color = null,
|
||||
draw: ?Box.Draw = null
|
||||
draw: ?Box.Draw = null,
|
||||
visual_hot: ?bool = null,
|
||||
visual_active: ?bool = null
|
||||
};
|
||||
|
||||
pub const root_box_key = Key.initString(0, "$root$");
|
||||
@ -951,11 +955,14 @@ pub fn end(self: *UI) void {
|
||||
const box: *Box = _box;
|
||||
if (box.key.isNil()) continue;
|
||||
|
||||
const is_hot: f32 = @floatFromInt(@intFromBool(self.isKeyHot(box.key)));
|
||||
const is_active: f32 = @floatFromInt(@intFromBool(self.isKeyActive(box.key)));
|
||||
const is_hot = self.isKeyHot(box.key) or box.visual_hot;
|
||||
const is_active = self.isKeyActive(box.key) or box.visual_active;
|
||||
|
||||
box.persistent.hot += fast_rate * (is_hot - box.persistent.hot );
|
||||
box.persistent.active += fast_rate * (is_active - box.persistent.active);
|
||||
const is_hot_f32: f32 = @floatFromInt(@intFromBool(is_hot));
|
||||
const is_active_f32: f32 = @floatFromInt(@intFromBool(is_active));
|
||||
|
||||
box.persistent.hot += fast_rate * (is_hot_f32 - box.persistent.hot );
|
||||
box.persistent.active += fast_rate * (is_active_f32 - box.persistent.active);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1539,6 +1546,8 @@ pub fn createBox(self: *UI, opts: BoxOptions) *Box {
|
||||
.float_relative_to = opts.float_relative_to,
|
||||
.texture_color = opts.texture_color,
|
||||
.draw = opts.draw,
|
||||
.visual_hot = opts.visual_hot orelse false,
|
||||
.visual_active = opts.visual_active orelse false,
|
||||
|
||||
.last_used_frame = self.frame_index,
|
||||
.key = key,
|
||||
@ -1636,9 +1645,9 @@ fn drawBox(self: *UI, box: *Box) void {
|
||||
defer if (do_scissor) self.endScissor();
|
||||
|
||||
var value_shift: f32 = 0;
|
||||
if (box.flags.contains(.draw_active) and self.isKeyActive(box.key)) {
|
||||
if (box.flags.contains(.draw_active) and box.persistent.active > 0.01) {
|
||||
value_shift = -0.5 * box.persistent.active;
|
||||
} else if (box.flags.contains(.draw_hot) and self.isKeyHot(box.key)) {
|
||||
} else if (box.flags.contains(.draw_hot) and box.persistent.hot > 0.01) {
|
||||
value_shift = 0.6 * box.persistent.hot;
|
||||
}
|
||||
|
||||
@ -1646,6 +1655,28 @@ fn drawBox(self: *UI, box: *Box) void {
|
||||
rl.drawRectangleRec(box_rect, utils.shiftColorInHSV(bg, value_shift));
|
||||
}
|
||||
|
||||
if (box.texture) |texture| {
|
||||
const source = rl.Rectangle{
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.width = @floatFromInt(texture.width),
|
||||
.height = @floatFromInt(texture.height)
|
||||
};
|
||||
var destination = box_rect;
|
||||
if (box.texture_size) |texture_size| {
|
||||
destination = rect_utils.initCentered(destination, texture_size.x, texture_size.y);
|
||||
}
|
||||
|
||||
rl.drawTexturePro(
|
||||
texture,
|
||||
source,
|
||||
destination,
|
||||
rl.Vector2.zero(),
|
||||
0,
|
||||
box.texture_color orelse rl.Color.white
|
||||
);
|
||||
}
|
||||
|
||||
const borders_with_coords = .{
|
||||
.{ box.borders.left , rl.Vector2.init(0, 0), rl.Vector2.init(0, 1), rl.Vector2.init( 1, 0) },
|
||||
.{ box.borders.right , rl.Vector2.init(1, 0), rl.Vector2.init(1, 1), rl.Vector2.init(-1, 0) },
|
||||
@ -1669,28 +1700,6 @@ fn drawBox(self: *UI, box: *Box) void {
|
||||
}
|
||||
}
|
||||
|
||||
if (box.texture) |texture| {
|
||||
const source = rl.Rectangle{
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.width = @floatFromInt(texture.width),
|
||||
.height = @floatFromInt(texture.height)
|
||||
};
|
||||
var destination = box_rect;
|
||||
if (box.texture_size) |texture_size| {
|
||||
destination = rect_utils.initCentered(destination, texture_size.x, texture_size.y);
|
||||
}
|
||||
|
||||
rl.drawTexturePro(
|
||||
texture,
|
||||
source,
|
||||
destination,
|
||||
rl.Vector2.zero(),
|
||||
0,
|
||||
box.texture_color orelse rl.Color.white
|
||||
);
|
||||
}
|
||||
|
||||
if (box.draw) |box_draw| {
|
||||
box_draw.do(box_draw.ctx, box);
|
||||
}
|
||||
@ -2237,6 +2246,11 @@ pub const NumberInputOptions = struct {
|
||||
invalid_color: rl.Color = srcery.red
|
||||
};
|
||||
|
||||
pub const CheckboxOptions = struct {
|
||||
value: *bool,
|
||||
label: ?[]const u8 = null
|
||||
};
|
||||
|
||||
pub fn mouseTooltip(self: *UI) *Box {
|
||||
const tooltip = self.getBoxByKey(mouse_tooltip_box_key).?;
|
||||
|
||||
@ -2689,3 +2703,45 @@ pub fn numberInput(self: *UI, T: type, opts: NumberInputOptions) !?T {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn checkbox(self: *UI, opts: CheckboxOptions) void {
|
||||
const container = self.createBox(.{
|
||||
.key = UI.Key.initPtr(opts.value),
|
||||
.size_x = UI.Sizing.initFitChildren(),
|
||||
.size_y = UI.Sizing.initFitChildren(),
|
||||
.flags = &.{ .draw_hot, .draw_active, .clickable },
|
||||
.hot_cursor = .mouse_cursor_pointing_hand,
|
||||
.layout_direction = .left_to_right,
|
||||
.layout_gap = self.rem(0.25)
|
||||
});
|
||||
container.beginChildren();
|
||||
defer container.endChildren();
|
||||
|
||||
const container_signal = self.signal(container);
|
||||
|
||||
const marker = self.createBox(.{
|
||||
.key = self.keyFromString("checkbox marker"),
|
||||
.size_x = UI.Sizing.initFixedPixels(self.rem(1)),
|
||||
.size_y = UI.Sizing.initFixedPixels(self.rem(1)),
|
||||
.background = srcery.bright_white,
|
||||
.visual_hot = container_signal.hot,
|
||||
.visual_active = container_signal.active,
|
||||
.flags = &.{ .draw_hot, .draw_active },
|
||||
});
|
||||
|
||||
if (opts.label) |text| {
|
||||
_ = self.createBox(.{
|
||||
.size_x = Sizing.initFixed(.text),
|
||||
.size_y = Sizing.initFixed(.text),
|
||||
.text = text
|
||||
});
|
||||
}
|
||||
|
||||
if (opts.value.*) {
|
||||
marker.texture = Assets.checkbox_mark;
|
||||
}
|
||||
|
||||
if (container_signal.clicked()) {
|
||||
opts.value.* = !opts.value.*;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user