add checkbox to toggle view sync controls
This commit is contained in:
parent
772f35fee7
commit
8d1cad16b3
26
src/app.zig
26
src/app.zig
@ -250,6 +250,7 @@ pub const View = struct {
|
||||
height: f32 = 300,
|
||||
follow: bool = false,
|
||||
graph_opts: Graph.ViewOptions = .{},
|
||||
sync_controls: bool = false,
|
||||
|
||||
// Runtime
|
||||
graph_cache: Graph.Cache = .{},
|
||||
@ -359,6 +360,9 @@ pub const Project = struct {
|
||||
self.sample_rate = null;
|
||||
}
|
||||
|
||||
const show_rulers_u8 = try readInt(reader, u8);
|
||||
self.show_rulers = show_rulers_u8 == 1;
|
||||
|
||||
{ // Channels
|
||||
const channel_count = try readInt(reader, u32);
|
||||
for (0..channel_count) |_| {
|
||||
@ -421,6 +425,8 @@ pub const Project = struct {
|
||||
|
||||
view.graph_opts.x_range = try readRangeF64(reader);
|
||||
view.graph_opts.y_range = try readRangeF64(reader);
|
||||
const sync_controls = try readInt(reader, u8);
|
||||
view.sync_controls = sync_controls == 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -433,13 +439,21 @@ pub const Project = struct {
|
||||
pub fn save(self: *Project) !void {
|
||||
const save_location = self.save_location orelse return error.NoSaveLocation;
|
||||
|
||||
const f = try std.fs.cwd().createFile(save_location, .{});
|
||||
var save_tmp_location: std.BoundedArray(u8, std.fs.max_path_bytes) = .{};
|
||||
save_tmp_location.appendSliceAssumeCapacity(save_location);
|
||||
save_tmp_location.appendSliceAssumeCapacity("-tmp");
|
||||
|
||||
const dir = std.fs.cwd();
|
||||
|
||||
{
|
||||
const f = try dir.createFile(save_tmp_location.slice(), .{});
|
||||
defer f.close();
|
||||
|
||||
const writer = f.writer();
|
||||
|
||||
try writeInt(writer, u8, file_format_version);
|
||||
try writeFloat(writer, f64, self.sample_rate orelse 0);
|
||||
try writeInt(writer, u8, @intFromBool(self.show_rulers));
|
||||
|
||||
{ // Channels
|
||||
try writeInt(writer, u32, @intCast(self.channels.count()));
|
||||
@ -483,10 +497,14 @@ pub const Project = struct {
|
||||
|
||||
try writeRangeF64(writer, view.graph_opts.x_range);
|
||||
try writeRangeF64(writer, view.graph_opts.y_range);
|
||||
try writeInt(writer, u8, @intFromBool(view.sync_controls));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try std.fs.rename(dir, save_tmp_location.slice(), dir, save_location);
|
||||
}
|
||||
|
||||
fn writeRangeF64(writer: anytype, range: RangeF64) !void {
|
||||
try writeFloat(writer, f64, range.lower);
|
||||
try writeFloat(writer, f64, range.upper);
|
||||
@ -1083,7 +1101,6 @@ pub fn loadFile(self: *App, id: Id) !void {
|
||||
const samples = try readFileF64(self.allocator, samples_file);
|
||||
file.samples = samples;
|
||||
|
||||
|
||||
if (samples.len > 0) {
|
||||
file.min_sample = samples[0];
|
||||
file.max_sample = samples[0];
|
||||
@ -1255,6 +1272,11 @@ pub fn loadView(self: *App, id: Id) !void {
|
||||
|
||||
self.refreshViewAvailableXYRanges(id);
|
||||
|
||||
if (view.graph_opts.x_range.size() == 0) {
|
||||
view.graph_opts.x_range = view.available_x_range;
|
||||
}
|
||||
|
||||
if (view.graph_opts.y_range.size() == 0) {
|
||||
view.graph_opts.y_range = view.available_y_range;
|
||||
}
|
||||
}
|
@ -48,6 +48,7 @@ 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 var cross: rl.Texture2D = undefined;
|
||||
|
||||
pub fn font(font_id: FontId) FontFace {
|
||||
var found_font: ?LoadedFont = null;
|
||||
@ -123,6 +124,7 @@ pub fn init(allocator: std.mem.Allocator) !void {
|
||||
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"));
|
||||
cross = try loadTextureFromAseprite(allocator, @embedFile("./assets/cross.ase"));
|
||||
}
|
||||
|
||||
fn loadTextureFromAseprite(allocator: std.mem.Allocator, memory: []const u8) !rl.Texture {
|
||||
|
@ -30,12 +30,13 @@ pub const ViewAxisPosition = struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn get(optional_self: *?ViewAxisPosition, view_id: Id, axis: UI.Axis) ?f64 {
|
||||
fn get(optional_self: *?ViewAxisPosition, project: *App.Project, view_id: Id, axis: UI.Axis) ?f64 {
|
||||
const self = optional_self.* orelse return null;
|
||||
|
||||
if (self.axis != axis) return null;
|
||||
|
||||
if (!constants.sync_view_controls) {
|
||||
const view = project.views.get(view_id) orelse return null;
|
||||
if (!view.sync_controls) {
|
||||
if (!self.view_id.eql(view_id)) {
|
||||
return null;
|
||||
}
|
||||
@ -152,6 +153,8 @@ fn lastCommandFrame(self: *System) ?*CommandFrame {
|
||||
}
|
||||
|
||||
pub fn pushViewMove(self: *System, view_id: Id, x_range: RangeF64, y_range: RangeF64) void {
|
||||
|
||||
|
||||
var frame: *CommandFrame = undefined;
|
||||
{
|
||||
var push_new_command = true;
|
||||
@ -174,12 +177,19 @@ pub fn pushViewMove(self: *System, view_id: Id, x_range: RangeF64, y_range: Rang
|
||||
}
|
||||
}
|
||||
|
||||
var sync_controls = false;
|
||||
if (self.project.views.get(view_id)) |view| {
|
||||
sync_controls = view.sync_controls;
|
||||
}
|
||||
|
||||
var view_ids: std.BoundedArray(Id, constants.max_views) = .{};
|
||||
if (constants.sync_view_controls) {
|
||||
if (sync_controls) {
|
||||
var iter = self.project.views.idIterator();
|
||||
while (iter.next()) |id| {
|
||||
if (self.project.views.get(id).?.sync_controls) {
|
||||
view_ids.appendAssumeCapacity(id);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
view_ids.appendAssumeCapacity(view_id);
|
||||
}
|
||||
@ -192,7 +202,7 @@ pub fn pushViewMove(self: *System, view_id: Id, x_range: RangeF64, y_range: Rang
|
||||
command.action.move_and_zoom.x = x_range;
|
||||
command.action.move_and_zoom.y = y_range;
|
||||
} else {
|
||||
const view = self.project.views.get(id) orelse return;
|
||||
const view = self.project.views.get(view_id) orelse continue;
|
||||
const view_rect = &view.graph_opts;
|
||||
|
||||
command = frame.commands.addOneAssumeCapacity();
|
||||
@ -264,7 +274,7 @@ pub fn setCursor(self: *System, view_id: Id, axis: UI.Axis, position: ?f64) void
|
||||
}
|
||||
|
||||
pub fn getCursor(self: *System, view_id: Id, axis: UI.Axis) ?f64 {
|
||||
return ViewAxisPosition.get(&self.cursor, view_id, axis);
|
||||
return ViewAxisPosition.get(&self.cursor, self.project, view_id, axis);
|
||||
}
|
||||
|
||||
pub fn setZoomStart(self: *System, view_id: Id, axis: UI.Axis, position: ?f64) void {
|
||||
@ -272,5 +282,5 @@ pub fn setZoomStart(self: *System, view_id: Id, axis: UI.Axis, position: ?f64) v
|
||||
}
|
||||
|
||||
pub fn getZoomStart(self: *System, view_id: Id, axis: UI.Axis) ?f64 {
|
||||
return ViewAxisPosition.get(&self.zoom_start, view_id, axis);
|
||||
return ViewAxisPosition.get(&self.zoom_start, self.project,view_id, axis);
|
||||
}
|
@ -117,29 +117,15 @@ fn showGraph(ctx: Context, view_id: Id) *UI.Box {
|
||||
return graph_box;
|
||||
}
|
||||
|
||||
pub fn show(ctx: Context, view_id: Id, height: UI.Sizing) !Result {
|
||||
fn showToolbar(ctx: Context, view_id: Id) void {
|
||||
var ui = ctx.ui;
|
||||
|
||||
const view_box = ui.createBox(.{
|
||||
.key = UI.Key.initUsize(view_id.asInt()),
|
||||
.layout_direction = .top_to_bottom,
|
||||
.size_x = UI.Sizing.initGrowFull(),
|
||||
.size_y = height,
|
||||
});
|
||||
view_box.beginChildren();
|
||||
defer view_box.endChildren();
|
||||
|
||||
const result = Result{
|
||||
.box = view_box
|
||||
};
|
||||
|
||||
const toolbar = ui.createBox(.{
|
||||
.layout_direction = .left_to_right,
|
||||
.background = srcery.hard_black,
|
||||
.size_x = UI.Sizing.initGrowFull(),
|
||||
.size_y = UI.Sizing.initFixed(.{ .pixels = ui.rem(2) })
|
||||
});
|
||||
{
|
||||
toolbar.beginChildren();
|
||||
defer toolbar.endChildren();
|
||||
|
||||
@ -227,6 +213,16 @@ pub fn show(ctx: Context, view_id: Id, height: UI.Sizing) !Result {
|
||||
view_name = std.fs.path.stem(file.path);
|
||||
}
|
||||
|
||||
if (view.sync_controls) {
|
||||
const btn = ui.button(ui.keyFromString("Disable sync"));
|
||||
btn.texture = Assets.cross;
|
||||
btn.size.y = UI.Sizing.initGrowFull();
|
||||
btn.tooltip = "Disable sync controls";
|
||||
if (ui.signal(btn).clicked()) {
|
||||
view.sync_controls = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (view_name) |text| {
|
||||
_ = ui.createBox(.{
|
||||
.size_x = UI.Sizing.initGrowFull()
|
||||
@ -238,7 +234,25 @@ pub fn show(ctx: Context, view_id: Id, height: UI.Sizing) !Result {
|
||||
label.alignment.y = .center;
|
||||
label.padding = UI.Padding.horizontal(ui.rem(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn show(ctx: Context, view_id: Id, height: UI.Sizing) !Result {
|
||||
var ui = ctx.ui;
|
||||
|
||||
const view_box = ui.createBox(.{
|
||||
.key = UI.Key.initUsize(view_id.asInt()),
|
||||
.layout_direction = .top_to_bottom,
|
||||
.size_x = UI.Sizing.initGrowFull(),
|
||||
.size_y = height,
|
||||
});
|
||||
view_box.beginChildren();
|
||||
defer view_box.endChildren();
|
||||
|
||||
const result = Result{
|
||||
.box = view_box
|
||||
};
|
||||
|
||||
showToolbar(ctx, view_id);
|
||||
|
||||
if (!ctx.app.project.show_rulers) {
|
||||
_ = showGraph(ctx, view_id);
|
||||
|
@ -1,9 +1,7 @@
|
||||
|
||||
|
||||
pub const max_files = 32;
|
||||
pub const max_channels = 32;
|
||||
pub const max_views = 64;
|
||||
|
||||
// UI
|
||||
pub const sync_view_controls = true;
|
||||
pub const zoom_speed = 0.1;
|
@ -272,6 +272,11 @@ pub fn showSidePanel(self: *MainScreen) !void {
|
||||
|
||||
_ = ui.createBox(.{ .size_y = UI.Sizing.initFixedPixels(ui.rem(1)) });
|
||||
|
||||
_ = ui.checkbox(.{
|
||||
.value = &view.sync_controls,
|
||||
.label = "Sync controls"
|
||||
});
|
||||
|
||||
var sample_count: ?usize = null;
|
||||
switch (view.reference) {
|
||||
.channel => |channel_id| {
|
||||
@ -313,7 +318,6 @@ pub fn showSidePanel(self: *MainScreen) !void {
|
||||
_ = ui.label("Duration: {s}", .{ duration_str });
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
{
|
||||
const label = ui.label("Project", .{});
|
||||
@ -356,13 +360,11 @@ pub fn showSidePanel(self: *MainScreen) !void {
|
||||
}
|
||||
}
|
||||
|
||||
{ // Show ruler checkbox
|
||||
_ = ui.checkbox(.{
|
||||
.value = &project.show_rulers,
|
||||
.label = "Ruler"
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tick(self: *MainScreen) !void {
|
||||
|
23
src/ui.zig
23
src/ui.zig
@ -515,6 +515,7 @@ pub const Box = struct {
|
||||
draw: ?Draw = null,
|
||||
visual_hot: bool = false,
|
||||
visual_active: bool = false,
|
||||
tooltip: ?[]const u8 = null,
|
||||
|
||||
// Variables that you probably shouldn't be touching
|
||||
last_used_frame: u64 = 0,
|
||||
@ -699,6 +700,10 @@ pub const Box = struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn hasChildren(self: *const Box) bool {
|
||||
return self.tree.first_child_index != null;
|
||||
}
|
||||
|
||||
pub fn bringChildToTop(self: *Box, child: *Box) void {
|
||||
self.removeChild(child);
|
||||
self.appendChild(child);
|
||||
@ -942,6 +947,22 @@ pub fn begin(self: *UI) void {
|
||||
|
||||
pub fn end(self: *UI) void {
|
||||
const mouse_tooltip = self.getBoxByKey(mouse_tooltip_box_key).?;
|
||||
|
||||
// Add mouse tooltip to hot item
|
||||
if (!mouse_tooltip.hasChildren() and self.hot_box_key != null) {
|
||||
const box = self.getBoxByKey(self.hot_box_key.?).?;
|
||||
if (box.tooltip) |tooltip| {
|
||||
mouse_tooltip.beginChildren();
|
||||
defer mouse_tooltip.endChildren();
|
||||
|
||||
_ = self.createBox(.{
|
||||
.size_x = Sizing.initFixed(.text),
|
||||
.size_y = Sizing.initFixed(.text),
|
||||
.text = tooltip
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const root_box = self.parentBox().?;
|
||||
root_box.endChildren();
|
||||
|
||||
@ -1632,7 +1653,7 @@ pub fn draw(self: *UI) void {
|
||||
|
||||
self.drawBox(root_box);
|
||||
|
||||
if (mouse_tooltip.tree.first_child_index != null) {
|
||||
if (mouse_tooltip.hasChildren()) {
|
||||
self.drawBox(mouse_tooltip);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user