diff --git a/build.zig b/build.zig index 49f795a..23771f8 100644 --- a/build.zig +++ b/build.zig @@ -28,8 +28,18 @@ pub fn build(b: *std.Build) !void { exe.linkSystemLibrary("nidaqmx"); + // TODO: Emebed all assets using build.zig + // https://github.com/ziglang/zig/issues/14637#issuecomment-1428689051 + if (target.result.os.tag == .windows) { exe.subsystem = if (optimize == .Debug) .Console else .Windows; + + const resource_file = b.addWriteFiles(); + + // TODO: Generate icon file at build time + exe.addWin32ResourceFile(.{ + .file = resource_file.add("daq-view.rc", "IDI_ICON ICON \"./src/assets/icon.ico\""), + }); } b.installArtifact(exe); @@ -42,7 +52,6 @@ pub fn build(b: *std.Build) !void { const run_step = b.step("run", "Run the program"); run_step.dependOn(&run_cmd.step); - const unit_tests = b.addTest(.{ .root_source_file = b.path("src/main.zig"), .target = target, diff --git a/src/assets/icon.ico b/src/assets/icon.ico new file mode 100644 index 0000000..23dc780 Binary files /dev/null and b/src/assets/icon.ico differ diff --git a/src/assets/icon.png b/src/assets/icon.png new file mode 100644 index 0000000..6aba798 Binary files /dev/null and b/src/assets/icon.png differ diff --git a/src/assets/icon.xcf b/src/assets/icon.xcf new file mode 100644 index 0000000..0439a64 Binary files /dev/null and b/src/assets/icon.xcf differ diff --git a/src/main.zig b/src/main.zig index 5a319f8..6071e32 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,13 +1,8 @@ const std = @import("std"); -const builtin = @import("builtin"); const rl = @import("raylib"); const NIDaq = @import("ni-daq.zig"); const TaskPool = @import("./task-pool.zig"); -const windows = @cImport({ - @cDefine("_WIN32_WINNT", "0x0500"); - @cInclude("windows.h"); -}); - +const Platform = @import("./platform.zig"); const raylib_h = @cImport({ @cInclude("stdio.h"); @cInclude("raylib.h"); @@ -20,6 +15,8 @@ const FontFace = @import("font-face.zig"); const assert = std.debug.assert; const Vec2 = rl.Vector2; +const icon_png = @embedFile("./assets/icon.png"); + fn toRaylibTraceLogLevel(log_level: std.log.Level) rl.TraceLogLevel { return switch (log_level) { .err => rl.TraceLogLevel.log_error, @@ -48,14 +45,16 @@ fn raylibTraceLogCallback(logType: c_int, text: [*c]const u8, args: raylib_h.va_ const max_tracelog_msg_length = 256; // from utils.c in raylib var buffer: [max_tracelog_msg_length:0]u8 = undefined; @memset(&buffer, 0); - _ = raylib_h.vsnprintf(&buffer, buffer.len, text, args); + const text_length = raylib_h.vsnprintf(&buffer, buffer.len, text, args); + + const formatted_text = buffer[0..@intCast(text_length)]; const raylib_log = std.log.scoped(.raylib); switch (log_level) { - .debug => raylib_log.debug("{s}", .{ buffer }), - .info => raylib_log.info("{s}", .{ buffer }), - .warn => raylib_log.warn("{s}", .{ buffer }), - .err => raylib_log.err("{s}", .{ buffer }) + .debug => raylib_log.debug("{s}", .{ formatted_text }), + .info => raylib_log.info("{s}", .{ formatted_text }), + .warn => raylib_log.warn("{s}", .{ formatted_text }), + .err => raylib_log.err("{s}", .{ formatted_text }) } } @@ -111,13 +110,6 @@ pub fn nanoToSeconds(ns: i128) f32 { pub fn main() !void { const start_time = std.time.nanoTimestamp(); - // if (builtin.os.tag == .windows) { - // const hWnd = windows.GetConsoleWindow(); - // std.debug.print("{any}\n", .{hWnd}); - // //_ = windows.ShowWindow(hWnd, windows.SW_HIDE); - // _ = windows.ShowWindow(hWnd, windows.SW_SHOW); - // } - raylib_h.SetTraceLogCallback(raylibTraceLogCallback); rl.setTraceLogLevel(toRaylibTraceLogLevel(std.log.default_level)); @@ -138,7 +130,7 @@ pub fn main() !void { const devices = try ni_daq.listDeviceNames(); - std.debug.print("NI-DAQ version: {}\n", .{try NIDaq.version()}); + log.info("NI-DAQ version: {}", .{try NIDaq.version()}); std.debug.print("Devices ({}):\n", .{devices.len}); for (devices) |device| { @@ -221,9 +213,13 @@ pub fn main() !void { app.channel_samples = channel_samples; + var icon_image = rl.loadImageFromMemory(".png", icon_png); + defer icon_image.unload(); + rl.initWindow(800, 450, "DAQ view"); defer rl.closeWindow(); rl.setWindowState(.{ .window_resizable = true }); + rl.setWindowIcon(icon_image); rl.setTargetFPS(60); @@ -301,6 +297,10 @@ pub fn main() !void { zoom *= 0.9; } + if (rl.isKeyPressed(rl.KeyboardKey.key_f3)) { + Platform.toggleConsoleWindow(); + } + const now_ns = std.time.nanoTimestamp(); const now_since_start = nanoToSeconds(now_ns - start_time); const now_since_samping_start = nanoToSeconds(now_ns - channel_samples.started_sampling_ns.?); diff --git a/src/platform.zig b/src/platform.zig new file mode 100644 index 0000000..863899f --- /dev/null +++ b/src/platform.zig @@ -0,0 +1,33 @@ +const std = @import("std"); +const builtin = @import("builtin"); +const windows_h = @cImport({ + @cDefine("_WIN32_WINNT", "0x0500"); + @cInclude("windows.h"); +}); + +const assert = std.debug.assert; +const log = std.log.scoped(.platform); + +pub fn toggleConsoleWindow() void { + if (builtin.os.tag != .windows) { + return; + } + + var hWnd = windows_h.GetConsoleWindow(); + if (hWnd == null) { + if (windows_h.AllocConsole() == 0) { + // TODO: Use windows.FormatMessages + log.err("AllocConsole() failed: {}", .{ windows_h.GetLastError() }); + return; + } + + hWnd = windows_h.GetConsoleWindow(); + assert(hWnd != null); + } + + if (windows_h.IsWindowVisible(hWnd) != 0) { + _ = windows_h.ShowWindow(hWnd, windows_h.SW_HIDE); + } else { + _ = windows_h.ShowWindow(hWnd, windows_h.SW_SHOWNOACTIVATE); + } +} \ No newline at end of file