add markers

This commit is contained in:
Rokas Puzonas 2025-05-09 02:41:37 +03:00
parent 88212d001c
commit a2da649d96
6 changed files with 123 additions and 16 deletions

View File

@ -775,6 +775,7 @@ pub const File = struct {
};
pub const View = struct {
pub const max_markers = 32;
pub const max_transforms = 16;
pub const BoundedTransformsArray = std.BoundedArray(Transform, max_transforms);
@ -880,6 +881,7 @@ pub const View = struct {
graph_opts: Graph.ViewOptions = .{},
sync_controls: bool = false,
marked_ranges: std.BoundedArray(MarkedRange, 32) = .{},
markers: std.BoundedArray(f64, max_markers) = .{},
transforms: BoundedTransformsArray = .{},
// Runtime

View File

@ -170,11 +170,15 @@ view_settings: ?Id = null, // View id
view_fullscreen: ?Id = null, // View id
view_protocol_modal: ?Id = null, // View id
show_ruler: bool = false,
selected_tool: enum { move, select } = .move,
selected_tool: enum { move, select, marker } = .move,
show_marked_range: ?struct {
view_id: Id,
index: usize,
} = null,
show_marker: ?struct {
view_id: Id,
index: usize
} = null,
pub fn init(project: *App.Project) System {
return System{
@ -362,4 +366,18 @@ pub fn toggleShownMarkedRange(self: *System, view_id: Id, index: usize) void {
.view_id = view_id,
.index = index,
};
}
pub fn toggleShownMarker(self: *System, view_id: Id, index: usize) void {
if (self.show_marker) |show_marker| {
if (show_marker.view_id.eql(view_id) and show_marker.index == index) {
self.show_marker = null;
return;
}
}
self.show_marker = .{
.view_id = view_id,
.index = index,
};
}

View File

@ -32,14 +32,10 @@ pub const Result = struct {
box: *UI.Box,
};
fn showGraph(ctx: Context, view_id: Id) *UI.Box {
fn createGraphBox(ctx: Context) *UI.Box {
var ui = ctx.ui;
const app = ctx.app;
const view = app.getView(view_id).?;
const view_opts = &view.graph_opts;
const graph_box = ui.createBox(.{
return ui.createBox(.{
.key = ui.keyFromString("Graph"),
.size_x = UI.Sizing.initGrowFull(),
.size_y = UI.Sizing.initGrowFull(),
@ -51,6 +47,16 @@ fn showGraph(ctx: Context, view_id: Id) *UI.Box {
.bottom = .{ .color = srcery.hard_black, .size = 4 }
}
});
}
fn showGraph(ctx: Context, graph_box: *UI.Box, view_id: Id) void {
var ui = ctx.ui;
const app = ctx.app;
const view = app.getView(view_id).?;
const view_opts = &view.graph_opts;
graph_box.beginChildren();
defer graph_box.endChildren();
@ -105,6 +111,9 @@ fn showGraph(ctx: Context, view_id: Id) *UI.Box {
}
} else if (ctx.view_controls.selected_tool == .select) {
// TODO:
} else if (ctx.view_controls.selected_tool == .marker) {
// TODO:
}
@ -129,8 +138,6 @@ fn showGraph(ctx: Context, view_id: Id) *UI.Box {
.size = ui.rem(3)
};
}
return graph_box;
}
fn showToolbar(ctx: Context, view_id: Id) void {
@ -280,7 +287,8 @@ pub fn show(ctx: Context, view_id: Id, height: UI.Sizing) !Result {
showToolbar(ctx, view_id);
if (!ctx.app.project.show_rulers) {
_ = showGraph(ctx, view_id);
const graph_box = createGraphBox(ctx);
showGraph(ctx, graph_box, view_id);
} else {
const ruler_ctx = UIViewRuler.Context{
@ -304,7 +312,7 @@ pub fn show(ctx: Context, view_id: Id, height: UI.Sizing) !Result {
y_ruler = UIViewRuler.createBox(ruler_ctx, ui.keyFromString("Y ruler"), .Y);
graph_box = showGraph(ctx, view_id);
graph_box = createGraphBox(ctx);
}
{
@ -335,6 +343,7 @@ pub fn show(ctx: Context, view_id: Id, height: UI.Sizing) !Result {
try UIViewRuler.show(ruler_ctx, x_ruler, graph_box, view_id, .X);
try UIViewRuler.show(ruler_ctx, y_ruler, graph_box, view_id, .Y);
showGraph(ctx, graph_box, view_id);
}
return result;

View File

@ -304,7 +304,6 @@ pub fn show(ctx: Context, box: *UI.Box, graph_box: *UI.Box, view_id: Id, axis: U
}
{
var selected_range_iter = view.iterMarkedRanges(axis);
while (selected_range_iter.next()) |selected_range| {
var color = srcery.blue;
@ -322,6 +321,7 @@ pub fn show(ctx: Context, box: *UI.Box, graph_box: *UI.Box, view_id: Id, axis: U
showMarkerLine(ui, ruler, selected_range.upper, color);
var hasher = UI.Key.CombineHasher.init();
hasher.update(std.mem.asBytes("Marked ranges"));
hasher.update(std.mem.asBytes(&view_id));
hasher.update(std.mem.asBytes(&axis));
hasher.update(std.mem.asBytes(&index));
@ -341,6 +341,37 @@ pub fn show(ctx: Context, box: *UI.Box, graph_box: *UI.Box, view_id: Id, axis: U
}
}
}
if (axis == .X) {
for (0.., view.markers.constSlice()) |i, marker| {
const color = srcery.cyan;
showMarkerLine(ui, ruler, marker, color);
showMarkerLine(ui, ruler, marker, color);
var hasher = UI.Key.CombineHasher.init();
hasher.update(std.mem.asBytes("Markers"));
hasher.update(std.mem.asBytes(&view_id));
hasher.update(std.mem.asBytes(&axis));
hasher.update(std.mem.asBytes(&i));
const view_size = view.graph_opts.x_range.size();
const clickable_width = view_size * 0.01;
const clickable = ui.createBox(.{
.key = UI.Key.init(hasher.final()),
.float_rect = ruler.getGraphDrawContext().getRect(marker - clickable_width/2, clickable_width, 0, 1),
.float_relative_to = ruler.graph_box,
.parent = ruler.graph_box,
.flags = &.{ .draw_hot, .draw_active, .clickable },
.hot_cursor = .mouse_cursor_pointing_hand,
});
if (ui.signal(clickable).clicked()) {
ctx.view_controls.toggleShownMarker(view_id, i);
}
}
}
}
const signal = ui.signal(box);
@ -421,6 +452,10 @@ pub fn show(ctx: Context, box: *UI.Box, graph_box: *UI.Box, view_id: Id, axis: U
}
}
}
} else if (ctx.view_controls.selected_tool == .marker) {
if (cursor != null and signal.flags.contains(.left_released) and axis == .X) {
view.markers.append(cursor.?) catch {};
}
}
if (signal.flags.contains(.left_released)) {

View File

@ -626,6 +626,34 @@ fn showMarkedRange(self: *MainScreen, view_id: Id, index: usize) void {
}
}
fn showMarker(self: *MainScreen, view_id: Id, index: usize) void {
var ui = &self.app.ui;
const view = self.app.getView(view_id) orelse return;
const marker = view.markers.get(index);
{
const label = ui.label("Selected range", .{});
label.borders.bottom = .{
.color = srcery.blue,
.size = 1
};
_ = ui.createBox(.{ .size_y = UI.Sizing.initFixedPixels(ui.rem(1)) });
}
const sample_rate = self.app.project.getSampleRate();
if (sample_rate != null) {
const duration = utils.formatDuration(ui.frameAllocator(), marker / sample_rate.?) catch "";
_ = ui.label("Position: {s}", .{ duration });
} else {
_ = ui.label("Position: {d:.2}", .{ marker });
}
}
fn showToolbar(self: *MainScreen) void {
var ui = &self.app.ui;
@ -679,7 +707,7 @@ fn showToolbar(self: *MainScreen) void {
btn.borders = UI.Borders.bottom(.{ .size = 4, .color = srcery.green });
}
if (ui.signal(btn).clicked() or ui.isKeyboardPressed(.key_one)) {
if (ui.signal(btn).clicked()) {
self.view_controls.selected_tool = .move;
}
}
@ -690,10 +718,21 @@ fn showToolbar(self: *MainScreen) void {
btn.borders = UI.Borders.bottom(.{ .size = 4, .color = srcery.green });
}
if (ui.signal(btn).clicked() or ui.isKeyboardPressed(.key_two)) {
if (ui.signal(btn).clicked()) {
self.view_controls.selected_tool = .select;
}
}
{
var btn = ui.textButton("Marker");
if (self.view_controls.selected_tool == .marker) {
btn.borders = UI.Borders.bottom(.{ .size = 4, .color = srcery.green });
}
if (ui.signal(btn).clicked()) {
self.view_controls.selected_tool = .marker;
}
}
}
pub fn showSidePanel(self: *MainScreen) !void {
@ -712,9 +751,11 @@ pub fn showSidePanel(self: *MainScreen) !void {
container.beginChildren();
defer container.endChildren();
_ = ui.createBox(.{ .size_x = UI.Sizing.initFixedPixels(ui.rem(12)) });
_ = ui.createBox(.{ .size_x = UI.Sizing.initFixedPixels(ui.rem(18)) });
if (self.view_controls.show_marked_range) |show_marked_range| {
if (self.view_controls.show_marker) |marker| {
self.showMarker(marker.view_id, marker.index);
} else if (self.view_controls.show_marked_range) |show_marked_range| {
self.showMarkedRange(show_marked_range.view_id, show_marked_range.index);
} else if (self.view_controls.view_settings) |view_id| {
try self.showViewSettings(view_id);

View File

@ -510,6 +510,8 @@ pub const Box = struct {
draggable,
draw_hot,
draw_active,
// TODO: Add a way to specify relative to which box should clipping occur.
// Useful for floating boxes
clip_view
};