add checkbox to toggle view sync controls
This commit is contained in:
parent
772f35fee7
commit
8d1cad16b3
112
src/app.zig
112
src/app.zig
@ -250,6 +250,7 @@ pub const View = struct {
|
|||||||
height: f32 = 300,
|
height: f32 = 300,
|
||||||
follow: bool = false,
|
follow: bool = false,
|
||||||
graph_opts: Graph.ViewOptions = .{},
|
graph_opts: Graph.ViewOptions = .{},
|
||||||
|
sync_controls: bool = false,
|
||||||
|
|
||||||
// Runtime
|
// Runtime
|
||||||
graph_cache: Graph.Cache = .{},
|
graph_cache: Graph.Cache = .{},
|
||||||
@ -359,6 +360,9 @@ pub const Project = struct {
|
|||||||
self.sample_rate = null;
|
self.sample_rate = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const show_rulers_u8 = try readInt(reader, u8);
|
||||||
|
self.show_rulers = show_rulers_u8 == 1;
|
||||||
|
|
||||||
{ // Channels
|
{ // Channels
|
||||||
const channel_count = try readInt(reader, u32);
|
const channel_count = try readInt(reader, u32);
|
||||||
for (0..channel_count) |_| {
|
for (0..channel_count) |_| {
|
||||||
@ -421,6 +425,8 @@ pub const Project = struct {
|
|||||||
|
|
||||||
view.graph_opts.x_range = try readRangeF64(reader);
|
view.graph_opts.x_range = try readRangeF64(reader);
|
||||||
view.graph_opts.y_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,58 +439,70 @@ pub const Project = struct {
|
|||||||
pub fn save(self: *Project) !void {
|
pub fn save(self: *Project) !void {
|
||||||
const save_location = self.save_location orelse return error.NoSaveLocation;
|
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) = .{};
|
||||||
defer f.close();
|
save_tmp_location.appendSliceAssumeCapacity(save_location);
|
||||||
|
save_tmp_location.appendSliceAssumeCapacity("-tmp");
|
||||||
|
|
||||||
const writer = f.writer();
|
const dir = std.fs.cwd();
|
||||||
|
|
||||||
try writeInt(writer, u8, file_format_version);
|
{
|
||||||
try writeFloat(writer, f64, self.sample_rate orelse 0);
|
const f = try dir.createFile(save_tmp_location.slice(), .{});
|
||||||
|
defer f.close();
|
||||||
|
|
||||||
{ // Channels
|
const writer = f.writer();
|
||||||
try writeInt(writer, u32, @intCast(self.channels.count()));
|
|
||||||
var channel_iter = self.channels.idIterator();
|
|
||||||
while (channel_iter.next()) |channel_id| {
|
|
||||||
const channel = self.channels.get(channel_id).?;
|
|
||||||
const channel_name = utils.getBoundedStringZ(&channel.name);
|
|
||||||
|
|
||||||
try writeId(writer, channel_id);
|
try writeInt(writer, u8, file_format_version);
|
||||||
try writeString(writer, channel_name);
|
try writeFloat(writer, f64, self.sample_rate orelse 0);
|
||||||
}
|
try writeInt(writer, u8, @intFromBool(self.show_rulers));
|
||||||
}
|
|
||||||
|
|
||||||
{ // Files
|
{ // Channels
|
||||||
try writeInt(writer, u32, @intCast(self.files.count()));
|
try writeInt(writer, u32, @intCast(self.channels.count()));
|
||||||
var file_iter = self.files.idIterator();
|
var channel_iter = self.channels.idIterator();
|
||||||
while (file_iter.next()) |file_id| {
|
while (channel_iter.next()) |channel_id| {
|
||||||
const file = self.files.get(file_id).?;
|
const channel = self.channels.get(channel_id).?;
|
||||||
|
const channel_name = utils.getBoundedStringZ(&channel.name);
|
||||||
|
|
||||||
try writeId(writer, file_id);
|
try writeId(writer, channel_id);
|
||||||
try writeString(writer, file.path);
|
try writeString(writer, channel_name);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{ // Views
|
|
||||||
try writeInt(writer, u32, @intCast(self.views.count()));
|
|
||||||
var view_iter = self.views.idIterator();
|
|
||||||
while (view_iter.next()) |view_id| {
|
|
||||||
const view = self.views.get(view_id).?;
|
|
||||||
|
|
||||||
try writeId(writer, view_id);
|
|
||||||
try writeInt(writer, u8, @intFromEnum(view.reference));
|
|
||||||
switch (view.reference) {
|
|
||||||
.channel => |channel_id| {
|
|
||||||
try writeInt(writer, u32, channel_id.asInt());
|
|
||||||
},
|
|
||||||
.file => |file_id| {
|
|
||||||
try writeInt(writer, u32, file_id.asInt());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try writeRangeF64(writer, view.graph_opts.x_range);
|
{ // Files
|
||||||
try writeRangeF64(writer, view.graph_opts.y_range);
|
try writeInt(writer, u32, @intCast(self.files.count()));
|
||||||
|
var file_iter = self.files.idIterator();
|
||||||
|
while (file_iter.next()) |file_id| {
|
||||||
|
const file = self.files.get(file_id).?;
|
||||||
|
|
||||||
|
try writeId(writer, file_id);
|
||||||
|
try writeString(writer, file.path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // Views
|
||||||
|
try writeInt(writer, u32, @intCast(self.views.count()));
|
||||||
|
var view_iter = self.views.idIterator();
|
||||||
|
while (view_iter.next()) |view_id| {
|
||||||
|
const view = self.views.get(view_id).?;
|
||||||
|
|
||||||
|
try writeId(writer, view_id);
|
||||||
|
try writeInt(writer, u8, @intFromEnum(view.reference));
|
||||||
|
switch (view.reference) {
|
||||||
|
.channel => |channel_id| {
|
||||||
|
try writeInt(writer, u32, channel_id.asInt());
|
||||||
|
},
|
||||||
|
.file => |file_id| {
|
||||||
|
try writeInt(writer, u32, file_id.asInt());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
fn writeRangeF64(writer: anytype, range: RangeF64) !void {
|
||||||
@ -1083,7 +1101,6 @@ pub fn loadFile(self: *App, id: Id) !void {
|
|||||||
const samples = try readFileF64(self.allocator, samples_file);
|
const samples = try readFileF64(self.allocator, samples_file);
|
||||||
file.samples = samples;
|
file.samples = samples;
|
||||||
|
|
||||||
|
|
||||||
if (samples.len > 0) {
|
if (samples.len > 0) {
|
||||||
file.min_sample = samples[0];
|
file.min_sample = samples[0];
|
||||||
file.max_sample = samples[0];
|
file.max_sample = samples[0];
|
||||||
@ -1255,6 +1272,11 @@ pub fn loadView(self: *App, id: Id) !void {
|
|||||||
|
|
||||||
self.refreshViewAvailableXYRanges(id);
|
self.refreshViewAvailableXYRanges(id);
|
||||||
|
|
||||||
view.graph_opts.x_range = view.available_x_range;
|
if (view.graph_opts.x_range.size() == 0) {
|
||||||
view.graph_opts.y_range = view.available_y_range;
|
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 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 var checkbox_mark: rl.Texture2D = undefined;
|
||||||
|
pub var cross: 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;
|
||||||
@ -123,6 +124,7 @@ pub fn init(allocator: std.mem.Allocator) !void {
|
|||||||
fullscreen = try loadTextureFromAseprite(allocator, @embedFile("./assets/fullscreen-icon.ase"));
|
fullscreen = try loadTextureFromAseprite(allocator, @embedFile("./assets/fullscreen-icon.ase"));
|
||||||
output_generation = try loadTextureFromAseprite(allocator, @embedFile("./assets/output-generation-icon.ase"));
|
output_generation = try loadTextureFromAseprite(allocator, @embedFile("./assets/output-generation-icon.ase"));
|
||||||
checkbox_mark = try loadTextureFromAseprite(allocator, @embedFile("./assets/checkbox-mark.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 {
|
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;
|
const self = optional_self.* orelse return null;
|
||||||
|
|
||||||
if (self.axis != axis) 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)) {
|
if (!self.view_id.eql(view_id)) {
|
||||||
return null;
|
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 {
|
pub fn pushViewMove(self: *System, view_id: Id, x_range: RangeF64, y_range: RangeF64) void {
|
||||||
|
|
||||||
|
|
||||||
var frame: *CommandFrame = undefined;
|
var frame: *CommandFrame = undefined;
|
||||||
{
|
{
|
||||||
var push_new_command = true;
|
var push_new_command = true;
|
||||||
@ -174,11 +177,18 @@ 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) = .{};
|
var view_ids: std.BoundedArray(Id, constants.max_views) = .{};
|
||||||
if (constants.sync_view_controls) {
|
if (sync_controls) {
|
||||||
var iter = self.project.views.idIterator();
|
var iter = self.project.views.idIterator();
|
||||||
while (iter.next()) |id| {
|
while (iter.next()) |id| {
|
||||||
view_ids.appendAssumeCapacity(id);
|
if (self.project.views.get(id).?.sync_controls) {
|
||||||
|
view_ids.appendAssumeCapacity(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
view_ids.appendAssumeCapacity(view_id);
|
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.x = x_range;
|
||||||
command.action.move_and_zoom.y = y_range;
|
command.action.move_and_zoom.y = y_range;
|
||||||
} else {
|
} 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;
|
const view_rect = &view.graph_opts;
|
||||||
|
|
||||||
command = frame.commands.addOneAssumeCapacity();
|
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 {
|
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 {
|
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 {
|
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,6 +117,125 @@ fn showGraph(ctx: Context, view_id: Id) *UI.Box {
|
|||||||
return graph_box;
|
return graph_box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn showToolbar(ctx: Context, view_id: Id) void {
|
||||||
|
var ui = ctx.ui;
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
const view = ctx.app.getView(view_id).?;
|
||||||
|
var view_name: ?[]const u8 = null;
|
||||||
|
|
||||||
|
{
|
||||||
|
const btn = ui.textButton("Settings");
|
||||||
|
btn.background = srcery.hard_black;
|
||||||
|
if (ctx.view_controls.isViewSettingsOpen(view_id)) {
|
||||||
|
btn.borders.bottom = .{
|
||||||
|
.color = srcery.green,
|
||||||
|
.size = 4
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ui.signal(btn).clicked()) {
|
||||||
|
ctx.view_controls.toggleViewSettings(view_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const btn = ui.textButton("Reset view");
|
||||||
|
btn.background = srcery.hard_black;
|
||||||
|
if (ui.signal(btn).clicked()) {
|
||||||
|
ctx.view_controls.pushViewMove(view_id, view.available_x_range, view.available_y_range);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (view.reference == .channel) {
|
||||||
|
const channel_id = view.reference.channel;
|
||||||
|
const channel = ctx.app.getChannel(channel_id).?;
|
||||||
|
const channel_name = utils.getBoundedStringZ(&channel.name);
|
||||||
|
const channel_type = NIDaq.getChannelType(channel_name).?;
|
||||||
|
|
||||||
|
{
|
||||||
|
const follow = ui.textButton("Follow");
|
||||||
|
follow.background = srcery.hard_black;
|
||||||
|
if (view.follow) {
|
||||||
|
follow.borders = UI.Borders.bottom(.{
|
||||||
|
.color = srcery.green,
|
||||||
|
.size = 4
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (ui.signal(follow).clicked()) {
|
||||||
|
view.follow = !view.follow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channel_type == .analog_output) {
|
||||||
|
const button = ui.button(ui.keyFromString("Output generation"));
|
||||||
|
button.texture = Assets.output_generation;
|
||||||
|
button.size.y = UI.Sizing.initGrowFull();
|
||||||
|
|
||||||
|
const signal = ui.signal(button);
|
||||||
|
if (signal.clicked()) {
|
||||||
|
if (ctx.app.isChannelOutputing(channel_id)) {
|
||||||
|
ctx.app.pushCommand(.{
|
||||||
|
.stop_output = channel_id
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
ctx.view_controls.view_protocol_modal = view_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var color = rl.Color.white;
|
||||||
|
if (ctx.app.isChannelOutputing(channel_id)) {
|
||||||
|
color = srcery.red;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (signal.active) {
|
||||||
|
button.texture_color = color.alpha(0.6);
|
||||||
|
} else if (signal.hot) {
|
||||||
|
button.texture_color = color.alpha(0.8);
|
||||||
|
} else {
|
||||||
|
button.texture_color = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
view_name = channel_name;
|
||||||
|
} else if (view.reference == .file) {
|
||||||
|
const file_id = view.reference.file;
|
||||||
|
const file = ctx.app.getFile(file_id).?;
|
||||||
|
|
||||||
|
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()
|
||||||
|
});
|
||||||
|
|
||||||
|
const label = ui.label("{s}", .{text});
|
||||||
|
label.size.y = UI.Sizing.initGrowFull();
|
||||||
|
label.alignment.x = .center;
|
||||||
|
label.alignment.y = .center;
|
||||||
|
label.padding = UI.Padding.horizontal(ui.rem(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn show(ctx: Context, view_id: Id, height: UI.Sizing) !Result {
|
pub fn show(ctx: Context, view_id: Id, height: UI.Sizing) !Result {
|
||||||
var ui = ctx.ui;
|
var ui = ctx.ui;
|
||||||
|
|
||||||
@ -133,112 +252,7 @@ pub fn show(ctx: Context, view_id: Id, height: UI.Sizing) !Result {
|
|||||||
.box = view_box
|
.box = view_box
|
||||||
};
|
};
|
||||||
|
|
||||||
const toolbar = ui.createBox(.{
|
showToolbar(ctx, view_id);
|
||||||
.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();
|
|
||||||
|
|
||||||
const view = ctx.app.getView(view_id).?;
|
|
||||||
var view_name: ?[]const u8 = null;
|
|
||||||
|
|
||||||
{
|
|
||||||
const btn = ui.textButton("Settings");
|
|
||||||
btn.background = srcery.hard_black;
|
|
||||||
if (ctx.view_controls.isViewSettingsOpen(view_id)) {
|
|
||||||
btn.borders.bottom = .{
|
|
||||||
.color = srcery.green,
|
|
||||||
.size = 4
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ui.signal(btn).clicked()) {
|
|
||||||
ctx.view_controls.toggleViewSettings(view_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
const btn = ui.textButton("Reset view");
|
|
||||||
btn.background = srcery.hard_black;
|
|
||||||
if (ui.signal(btn).clicked()) {
|
|
||||||
ctx.view_controls.pushViewMove(view_id, view.available_x_range, view.available_y_range);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (view.reference == .channel) {
|
|
||||||
const channel_id = view.reference.channel;
|
|
||||||
const channel = ctx.app.getChannel(channel_id).?;
|
|
||||||
const channel_name = utils.getBoundedStringZ(&channel.name);
|
|
||||||
const channel_type = NIDaq.getChannelType(channel_name).?;
|
|
||||||
|
|
||||||
{
|
|
||||||
const follow = ui.textButton("Follow");
|
|
||||||
follow.background = srcery.hard_black;
|
|
||||||
if (view.follow) {
|
|
||||||
follow.borders = UI.Borders.bottom(.{
|
|
||||||
.color = srcery.green,
|
|
||||||
.size = 4
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (ui.signal(follow).clicked()) {
|
|
||||||
view.follow = !view.follow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (channel_type == .analog_output) {
|
|
||||||
const button = ui.button(ui.keyFromString("Output generation"));
|
|
||||||
button.texture = Assets.output_generation;
|
|
||||||
button.size.y = UI.Sizing.initGrowFull();
|
|
||||||
|
|
||||||
const signal = ui.signal(button);
|
|
||||||
if (signal.clicked()) {
|
|
||||||
if (ctx.app.isChannelOutputing(channel_id)) {
|
|
||||||
ctx.app.pushCommand(.{
|
|
||||||
.stop_output = channel_id
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
ctx.view_controls.view_protocol_modal = view_id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var color = rl.Color.white;
|
|
||||||
if (ctx.app.isChannelOutputing(channel_id)) {
|
|
||||||
color = srcery.red;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (signal.active) {
|
|
||||||
button.texture_color = color.alpha(0.6);
|
|
||||||
} else if (signal.hot) {
|
|
||||||
button.texture_color = color.alpha(0.8);
|
|
||||||
} else {
|
|
||||||
button.texture_color = color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
view_name = channel_name;
|
|
||||||
} else if (view.reference == .file) {
|
|
||||||
const file_id = view.reference.file;
|
|
||||||
const file = ctx.app.getFile(file_id).?;
|
|
||||||
|
|
||||||
view_name = std.fs.path.stem(file.path);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (view_name) |text| {
|
|
||||||
_ = ui.createBox(.{
|
|
||||||
.size_x = UI.Sizing.initGrowFull()
|
|
||||||
});
|
|
||||||
|
|
||||||
const label = ui.label("{s}", .{text});
|
|
||||||
label.size.y = UI.Sizing.initGrowFull();
|
|
||||||
label.alignment.x = .center;
|
|
||||||
label.alignment.y = .center;
|
|
||||||
label.padding = UI.Padding.horizontal(ui.rem(1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ctx.app.project.show_rulers) {
|
if (!ctx.app.project.show_rulers) {
|
||||||
_ = showGraph(ctx, view_id);
|
_ = showGraph(ctx, view_id);
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
|
|
||||||
|
|
||||||
pub const max_files = 32;
|
pub const max_files = 32;
|
||||||
pub const max_channels = 32;
|
pub const max_channels = 32;
|
||||||
pub const max_views = 64;
|
pub const max_views = 64;
|
||||||
|
|
||||||
// UI
|
// UI
|
||||||
pub const sync_view_controls = true;
|
|
||||||
pub const zoom_speed = 0.1;
|
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.createBox(.{ .size_y = UI.Sizing.initFixedPixels(ui.rem(1)) });
|
||||||
|
|
||||||
|
_ = ui.checkbox(.{
|
||||||
|
.value = &view.sync_controls,
|
||||||
|
.label = "Sync controls"
|
||||||
|
});
|
||||||
|
|
||||||
var sample_count: ?usize = null;
|
var sample_count: ?usize = null;
|
||||||
switch (view.reference) {
|
switch (view.reference) {
|
||||||
.channel => |channel_id| {
|
.channel => |channel_id| {
|
||||||
@ -313,7 +318,6 @@ pub fn showSidePanel(self: *MainScreen) !void {
|
|||||||
_ = ui.label("Duration: {s}", .{ duration_str });
|
_ = ui.label("Duration: {s}", .{ duration_str });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
{
|
{
|
||||||
const label = ui.label("Project", .{});
|
const label = ui.label("Project", .{});
|
||||||
@ -356,12 +360,10 @@ pub fn showSidePanel(self: *MainScreen) !void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // Show ruler checkbox
|
_ = ui.checkbox(.{
|
||||||
_ = ui.checkbox(.{
|
.value = &project.show_rulers,
|
||||||
.value = &project.show_rulers,
|
.label = "Ruler"
|
||||||
.label = "Ruler"
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
23
src/ui.zig
23
src/ui.zig
@ -515,6 +515,7 @@ pub const Box = struct {
|
|||||||
draw: ?Draw = null,
|
draw: ?Draw = null,
|
||||||
visual_hot: bool = false,
|
visual_hot: bool = false,
|
||||||
visual_active: bool = false,
|
visual_active: bool = false,
|
||||||
|
tooltip: ?[]const u8 = null,
|
||||||
|
|
||||||
// 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,
|
||||||
@ -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 {
|
pub fn bringChildToTop(self: *Box, child: *Box) void {
|
||||||
self.removeChild(child);
|
self.removeChild(child);
|
||||||
self.appendChild(child);
|
self.appendChild(child);
|
||||||
@ -942,6 +947,22 @@ pub fn begin(self: *UI) void {
|
|||||||
|
|
||||||
pub fn end(self: *UI) void {
|
pub fn end(self: *UI) void {
|
||||||
const mouse_tooltip = self.getBoxByKey(mouse_tooltip_box_key).?;
|
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().?;
|
const root_box = self.parentBox().?;
|
||||||
root_box.endChildren();
|
root_box.endChildren();
|
||||||
|
|
||||||
@ -1632,7 +1653,7 @@ pub fn draw(self: *UI) void {
|
|||||||
|
|
||||||
self.drawBox(root_box);
|
self.drawBox(root_box);
|
||||||
|
|
||||||
if (mouse_tooltip.tree.first_child_index != null) {
|
if (mouse_tooltip.hasChildren()) {
|
||||||
self.drawBox(mouse_tooltip);
|
self.drawBox(mouse_tooltip);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user