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,
|
save_location: ?[]u8 = null,
|
||||||
sample_rate: ?f64 = null,
|
sample_rate: ?f64 = null,
|
||||||
|
show_rulers: bool = true,
|
||||||
|
|
||||||
channels: GenerationalArray(Channel) = .{},
|
channels: GenerationalArray(Channel) = .{},
|
||||||
files: GenerationalArray(File) = .{},
|
files: GenerationalArray(File) = .{},
|
||||||
|
@ -45,10 +45,9 @@ pub var grab_texture: struct {
|
|||||||
} = undefined;
|
} = undefined;
|
||||||
|
|
||||||
pub var dropdown_arrow: rl.Texture2D = undefined;
|
pub var dropdown_arrow: rl.Texture2D = undefined;
|
||||||
|
|
||||||
pub var fullscreen: rl.Texture2D = undefined;
|
pub var fullscreen: rl.Texture2D = undefined;
|
||||||
|
|
||||||
pub var output_generation: rl.Texture2D = undefined;
|
pub var output_generation: rl.Texture2D = undefined;
|
||||||
|
pub var checkbox_mark: rl.Texture2D = undefined;
|
||||||
|
|
||||||
pub fn font(font_id: FontId) FontFace {
|
pub fn font(font_id: FontId) FontFace {
|
||||||
var found_font: ?LoadedFont = null;
|
var found_font: ?LoadedFont = null;
|
||||||
@ -120,38 +119,23 @@ pub fn init(allocator: std.mem.Allocator) !void {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
fullscreen = try loadTextureFromAseprite(allocator, @embedFile("./assets/dropdown-arrow.ase"));
|
||||||
const dropdown_arrow_ase = try Aseprite.init(allocator, @embedFile("./assets/dropdown-arrow.ase"));
|
fullscreen = try loadTextureFromAseprite(allocator, @embedFile("./assets/fullscreen-icon.ase"));
|
||||||
defer dropdown_arrow_ase.deinit();
|
output_generation = try loadTextureFromAseprite(allocator, @embedFile("./assets/output-generation-icon.ase"));
|
||||||
|
checkbox_mark = try loadTextureFromAseprite(allocator, @embedFile("./assets/checkbox-mark.ase"));
|
||||||
|
}
|
||||||
|
|
||||||
const dropdown_image = dropdown_arrow_ase.getFrameImage(0);
|
fn loadTextureFromAseprite(allocator: std.mem.Allocator, memory: []const u8) !rl.Texture {
|
||||||
defer dropdown_image.unload();
|
const ase = try Aseprite.init(allocator, memory);
|
||||||
|
defer ase.deinit();
|
||||||
|
|
||||||
dropdown_arrow = rl.loadTextureFromImage(dropdown_image);
|
const image = ase.getFrameImage(0);
|
||||||
assert(rl.isTextureReady(dropdown_arrow));
|
defer image.unload();
|
||||||
}
|
|
||||||
|
|
||||||
{
|
const texture = rl.loadTextureFromImage(image);
|
||||||
const fullscreen_ase = try Aseprite.init(allocator, @embedFile("./assets/fullscreen-icon.ase"));
|
assert(rl.isTextureReady(texture));
|
||||||
defer fullscreen_ase.deinit();
|
|
||||||
|
|
||||||
const fullscreen_image = fullscreen_ase.getFrameImage(0);
|
return texture;
|
||||||
defer fullscreen_image.unload();
|
|
||||||
|
|
||||||
fullscreen = rl.loadTextureFromImage(fullscreen_image);
|
|
||||||
assert(rl.isTextureReady(fullscreen));
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn loadFont(ttf_data: []const u8, font_size: u32) !rl.Font {
|
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_settings: ?Id = null, // View id
|
||||||
view_fullscreen: ?Id = null, // View id
|
view_fullscreen: ?Id = null, // View id
|
||||||
view_protocol_modal: ?Id = null, // View id
|
view_protocol_modal: ?Id = null, // View id
|
||||||
|
show_ruler: bool = false,
|
||||||
|
|
||||||
pub fn init(project: *App.Project) System {
|
pub fn init(project: *App.Project) System {
|
||||||
return System{
|
return System{
|
||||||
|
@ -48,6 +48,9 @@ fn showGraph(ctx: Context, view_id: Id) *UI.Box {
|
|||||||
.flags = &.{ .clickable, .draggable, .scrollable, .clip_view },
|
.flags = &.{ .clickable, .draggable, .scrollable, .clip_view },
|
||||||
.align_x = .center,
|
.align_x = .center,
|
||||||
.align_y = .center,
|
.align_y = .center,
|
||||||
|
.borders = .{
|
||||||
|
.bottom = .{ .color = srcery.hard_black, .size = 4 }
|
||||||
|
}
|
||||||
});
|
});
|
||||||
graph_box.beginChildren();
|
graph_box.beginChildren();
|
||||||
defer graph_box.endChildren();
|
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);
|
_ = showGraph(ctx, view_id);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -5,6 +5,5 @@ pub const max_channels = 32;
|
|||||||
pub const max_views = 64;
|
pub const max_views = 64;
|
||||||
|
|
||||||
// UI
|
// UI
|
||||||
pub const show_ruler = true;
|
|
||||||
pub const sync_view_controls = true;
|
pub const sync_view_controls = true;
|
||||||
pub const zoom_speed = 0.1;
|
pub const zoom_speed = 0.1;
|
@ -20,22 +20,6 @@ const assert = std.debug.assert;
|
|||||||
const remap = utils.remap;
|
const remap = utils.remap;
|
||||||
const Id = App.Id;
|
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,
|
app: *App,
|
||||||
view_controls: ViewControlsSystem,
|
view_controls: ViewControlsSystem,
|
||||||
|
|
||||||
@ -341,34 +325,43 @@ pub fn showSidePanel(self: *MainScreen) !void {
|
|||||||
|
|
||||||
_ = ui.createBox(.{ .size_y = UI.Sizing.initFixedPixels(ui.rem(1)) });
|
_ = ui.createBox(.{ .size_y = UI.Sizing.initFixedPixels(ui.rem(1)) });
|
||||||
|
|
||||||
var placeholder: ?[]const u8 = null;
|
{ // Sample rate
|
||||||
if (project.getDefaultSampleRate()) |default_sample_rate| {
|
var placeholder: ?[]const u8 = null;
|
||||||
placeholder = try std.fmt.allocPrint(frame_allocator, "{d}", .{ default_sample_rate });
|
if (project.getDefaultSampleRate()) |default_sample_rate| {
|
||||||
}
|
placeholder = try std.fmt.allocPrint(frame_allocator, "{d}", .{ default_sample_rate });
|
||||||
|
}
|
||||||
|
|
||||||
var initial: ?[]const u8 = null;
|
var initial: ?[]const u8 = null;
|
||||||
if (project.sample_rate) |selected_sample_rate| {
|
|
||||||
initial = try std.fmt.allocPrint(frame_allocator, "{d}", .{ selected_sample_rate });
|
|
||||||
}
|
|
||||||
|
|
||||||
_ = ui.label("Sample rate", .{});
|
|
||||||
self.parsed_sample_rate = try ui.numberInput(f64, .{
|
|
||||||
.key = ui.keyFromString("Sample rate input"),
|
|
||||||
.storage = &self.sample_rate_input,
|
|
||||||
.placeholder = placeholder,
|
|
||||||
.initial = initial,
|
|
||||||
.invalid = self.parsed_sample_rate != project.sample_rate,
|
|
||||||
.editable = !self.app.isCollectionInProgress()
|
|
||||||
});
|
|
||||||
project.sample_rate = self.parsed_sample_rate;
|
|
||||||
|
|
||||||
if (project.getAllowedSampleRates()) |allowed_sample_rates| {
|
|
||||||
if (project.sample_rate) |selected_sample_rate| {
|
if (project.sample_rate) |selected_sample_rate| {
|
||||||
if (!allowed_sample_rates.hasInclusive(selected_sample_rate)) {
|
initial = try std.fmt.allocPrint(frame_allocator, "{d}", .{ selected_sample_rate });
|
||||||
project.sample_rate = null;
|
}
|
||||||
|
|
||||||
|
_ = ui.label("Sample rate", .{});
|
||||||
|
self.parsed_sample_rate = try ui.numberInput(f64, .{
|
||||||
|
.key = ui.keyFromString("Sample rate input"),
|
||||||
|
.storage = &self.sample_rate_input,
|
||||||
|
.placeholder = placeholder,
|
||||||
|
.initial = initial,
|
||||||
|
.invalid = self.parsed_sample_rate != project.sample_rate,
|
||||||
|
.editable = !self.app.isCollectionInProgress()
|
||||||
|
});
|
||||||
|
project.sample_rate = self.parsed_sample_rate;
|
||||||
|
|
||||||
|
if (project.getAllowedSampleRates()) |allowed_sample_rates| {
|
||||||
|
if (project.sample_rate) |selected_sample_rate| {
|
||||||
|
if (!allowed_sample_rates.hasInclusive(selected_sample_rate)) {
|
||||||
|
project.sample_rate = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{ // Show ruler checkbox
|
||||||
|
_ = ui.checkbox(.{
|
||||||
|
.value = &project.show_rulers,
|
||||||
|
.label = "Ruler"
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -481,7 +474,6 @@ pub fn tick(self: *MainScreen) !void {
|
|||||||
const scroll_area = ui.beginScrollbar(ui.keyFromString("Channels"));
|
const scroll_area = ui.beginScrollbar(ui.keyFromString("Channels"));
|
||||||
defer ui.endScrollbar();
|
defer ui.endScrollbar();
|
||||||
scroll_area.layout_direction = .top_to_bottom;
|
scroll_area.layout_direction = .top_to_bottom;
|
||||||
scroll_area.layout_gap = 4;
|
|
||||||
|
|
||||||
var view_iter = self.app.project.views.idIterator();
|
var view_iter = self.app.project.views.idIterator();
|
||||||
while (view_iter.next()) |view_id| {
|
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,
|
scientific_precision: u32 = 1,
|
||||||
float_relative_to: ?*Box = null,
|
float_relative_to: ?*Box = null,
|
||||||
draw: ?Draw = null,
|
draw: ?Draw = null,
|
||||||
|
visual_hot: bool = false,
|
||||||
|
visual_active: bool = false,
|
||||||
|
|
||||||
// Variables that you probably shouldn't be touching
|
// Variables that you probably shouldn't be touching
|
||||||
last_used_frame: u64 = 0,
|
last_used_frame: u64 = 0,
|
||||||
@ -731,7 +733,9 @@ pub const BoxOptions = struct {
|
|||||||
float_relative_to: ?*Box = null,
|
float_relative_to: ?*Box = null,
|
||||||
parent: ?*UI.Box = null,
|
parent: ?*UI.Box = null,
|
||||||
texture_color: ?rl.Color = 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$");
|
pub const root_box_key = Key.initString(0, "$root$");
|
||||||
@ -951,11 +955,14 @@ pub fn end(self: *UI) void {
|
|||||||
const box: *Box = _box;
|
const box: *Box = _box;
|
||||||
if (box.key.isNil()) continue;
|
if (box.key.isNil()) continue;
|
||||||
|
|
||||||
const is_hot: f32 = @floatFromInt(@intFromBool(self.isKeyHot(box.key)));
|
const is_hot = self.isKeyHot(box.key) or box.visual_hot;
|
||||||
const is_active: f32 = @floatFromInt(@intFromBool(self.isKeyActive(box.key)));
|
const is_active = self.isKeyActive(box.key) or box.visual_active;
|
||||||
|
|
||||||
box.persistent.hot += fast_rate * (is_hot - box.persistent.hot );
|
const is_hot_f32: f32 = @floatFromInt(@intFromBool(is_hot));
|
||||||
box.persistent.active += fast_rate * (is_active - box.persistent.active);
|
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,
|
.float_relative_to = opts.float_relative_to,
|
||||||
.texture_color = opts.texture_color,
|
.texture_color = opts.texture_color,
|
||||||
.draw = opts.draw,
|
.draw = opts.draw,
|
||||||
|
.visual_hot = opts.visual_hot orelse false,
|
||||||
|
.visual_active = opts.visual_active orelse false,
|
||||||
|
|
||||||
.last_used_frame = self.frame_index,
|
.last_used_frame = self.frame_index,
|
||||||
.key = key,
|
.key = key,
|
||||||
@ -1636,9 +1645,9 @@ fn drawBox(self: *UI, box: *Box) void {
|
|||||||
defer if (do_scissor) self.endScissor();
|
defer if (do_scissor) self.endScissor();
|
||||||
|
|
||||||
var value_shift: f32 = 0;
|
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;
|
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;
|
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));
|
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 = .{
|
const borders_with_coords = .{
|
||||||
.{ box.borders.left , rl.Vector2.init(0, 0), rl.Vector2.init(0, 1), rl.Vector2.init( 1, 0) },
|
.{ 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) },
|
.{ 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| {
|
if (box.draw) |box_draw| {
|
||||||
box_draw.do(box_draw.ctx, box);
|
box_draw.do(box_draw.ctx, box);
|
||||||
}
|
}
|
||||||
@ -2237,6 +2246,11 @@ pub const NumberInputOptions = struct {
|
|||||||
invalid_color: rl.Color = srcery.red
|
invalid_color: rl.Color = srcery.red
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const CheckboxOptions = struct {
|
||||||
|
value: *bool,
|
||||||
|
label: ?[]const u8 = null
|
||||||
|
};
|
||||||
|
|
||||||
pub fn mouseTooltip(self: *UI) *Box {
|
pub fn mouseTooltip(self: *UI) *Box {
|
||||||
const tooltip = self.getBoxByKey(mouse_tooltip_box_key).?;
|
const tooltip = self.getBoxByKey(mouse_tooltip_box_key).?;
|
||||||
|
|
||||||
@ -2688,4 +2702,46 @@ pub fn numberInput(self: *UI, T: type, opts: NumberInputOptions) !?T {
|
|||||||
} else |_| {
|
} else |_| {
|
||||||
return null;
|
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