aboutsummaryrefslogtreecommitdiffstats
path: root/src/config.zig
blob: 6325b0ba266a565e853a8d7bd5184dc6eb597491 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
const std = @import("std");

const c = @import("c.zig").c;

pub const Config = struct {
    // camera settings
    min_scale: f32 = 0.5,
    scroll_speed: f32 = 1.5,
    drag_friction: f32 = 6.0,
    scale_friction: f32 = 4.0,
    velocity_threshold: f32 = 15.0,
    scale_change_threshold: f32 = 0.5,

    // flashlight settings
    initial_radius: f32 = 200.0,
    initial_delta_radius: f32 = 250.0,
    radius_damping: f32 = 10.0,
    fade_speed: f32 = 6.0,
    max_shadow_opacity: f32 = 0.8,
    radius_change_threshold: f32 = 1.0,
    feather: f32 = 0.0,

    // opengl settings
    texture_filter: i32 = 0,

    // key bindings (KeySym = c_ulong on x86_64 linux)
    key_escape: c_ulong = c.XK_Escape,
    key_flashlight: c_ulong = c.XK_f,
    key_reset: c_ulong = c.XK_0,
    key_mirror: c_ulong = c.XK_m,
    key_zoom_in: c_ulong = c.XK_equal,
    key_zoom_out: c_ulong = c.XK_minus,

    modifier_flashlight: c_uint = c.ControlMask,
    button_drag: c_uint = c.Button1,
    button_zoom_in: c_uint = c.Button4,
    button_zoom_out: c_uint = c.Button5,

    pub fn default() Config {
        return .{};
    }

    pub fn applyValue(self: *Config, key: []const u8, value: f32) void {
        if (std.mem.eql(u8, key, "min_scale")) self.min_scale = value;
        if (std.mem.eql(u8, key, "scroll_speed")) self.scroll_speed = value;
        if (std.mem.eql(u8, key, "drag_friction")) self.drag_friction = value;
        if (std.mem.eql(u8, key, "scale_friction")) self.scale_friction = value;
        if (std.mem.eql(u8, key, "velocity_threshold")) self.velocity_threshold = value;
        if (std.mem.eql(u8, key, "scale_change_threshold")) self.scale_change_threshold = value;
        if (std.mem.eql(u8, key, "initial_radius")) self.initial_radius = value;
        if (std.mem.eql(u8, key, "initial_delta_radius")) self.initial_delta_radius = value;
        if (std.mem.eql(u8, key, "radius_damping")) self.radius_damping = value;
        if (std.mem.eql(u8, key, "fade_speed")) self.fade_speed = value;
        if (std.mem.eql(u8, key, "max_shadow_opacity")) self.max_shadow_opacity = value;
        if (std.mem.eql(u8, key, "radius_change_threshold")) self.radius_change_threshold = value;
        if (std.mem.eql(u8, key, "feather")) self.feather = value;
        if (std.mem.eql(u8, key, "texture_filter")) self.texture_filter = @intFromFloat(value);
    }

    pub fn loadFromFile(self: *Config, path: []const u8) void {
        var path_buf: [1024]u8 = undefined;
        @memcpy(path_buf[0..@min(path.len, path_buf.len - 1)], path);
        path_buf[@min(path.len, path_buf.len - 1)] = 0;
        const path_z: [*:0]const u8 = @ptrCast(&path_buf);

        const f = c.fopen(path_z, "r") orelse return;
        defer _ = c.fclose(f);

        var buf: [4096]u8 = undefined;
        while (c.fgets(&buf, buf.len, f) != null) {
            const raw = buf[0 .. std.mem.indexOfScalar(u8, &buf, 0) orelse buf.len];
            const line = std.mem.trimStart(u8, raw, " \t");
            if (line.len == 0 or line[0] == '#') continue;

            var parts = std.mem.splitScalar(u8, line, '=');
            const key = std.mem.trimEnd(u8, parts.first(), " \t");
            const val_str = if (parts.next()) |v| std.mem.trimStart(u8, v, " \t") else continue;
            const value = std.fmt.parseFloat(f32, val_str) catch continue;

            self.applyValue(key, value);
        }
    }

    pub fn writeDefault(self: Config, path: []const u8) !void {
        var path_buf: [1024]u8 = undefined;
        @memcpy(path_buf[0..@min(path.len, path_buf.len - 1)], path);
        path_buf[@min(path.len, path_buf.len - 1)] = 0;
        const path_z: [*:0]const u8 = @ptrCast(&path_buf);

        const f = c.fopen(path_z, "w") orelse {
            std.debug.print("error: could not write config to {s}\n", .{path});
            return error.ConfigWriteFailed;
        };
        defer _ = c.fclose(f);

        _ = c.fprintf(f, "min_scale = %.1f\n", self.min_scale);
        _ = c.fprintf(f, "scroll_speed = %.1f\n", self.scroll_speed);
        _ = c.fprintf(f, "drag_friction = %.1f\n", self.drag_friction);
        _ = c.fprintf(f, "scale_friction = %.1f\n", self.scale_friction);
        _ = c.fprintf(f, "velocity_threshold = %.1f\n", self.velocity_threshold);
        _ = c.fprintf(f, "scale_change_threshold = %.2f\n", self.scale_change_threshold);
        _ = c.fprintf(f, "initial_radius = %.1f\n", self.initial_radius);
        _ = c.fprintf(f, "initial_delta_radius = %.1f\n", self.initial_delta_radius);
        _ = c.fprintf(f, "radius_damping = %.1f\n", self.radius_damping);
        _ = c.fprintf(f, "fade_speed = %.1f\n", self.fade_speed);
        _ = c.fprintf(f, "max_shadow_opacity = %.2f\n", self.max_shadow_opacity);
        _ = c.fprintf(f, "radius_change_threshold = %.2f\n", self.radius_change_threshold);
        _ = c.fprintf(f, "feather = %.2f\n", self.feather);
        _ = c.fprintf(f, "texture_filter = %d\n", self.texture_filter);
    }

    pub fn defaultConfigPath(alloc: std.mem.Allocator) ?[]const u8 {
        const home = std.c.getenv("HOME") orelse return null;
        const home_slice = std.mem.sliceTo(home, 0);
        const path = std.fs.path.join(alloc, &.{ home_slice, ".config", "boomer", "config" }) catch return null;
        return path;
    }

    pub fn mkdirP(path: []const u8) void {
        var buf: [1024]u8 = undefined;
        const len = @min(path.len, buf.len - 1);
        @memcpy(buf[0..len], path[0..len]);
        buf[len] = 0;
        for (1..len) |i| {
            if (buf[i] == '/') {
                buf[i] = 0;
                _ = std.c.mkdir((buf[0..i :0]).ptr, 0o755);
                buf[i] = '/';
            }
        }
        _ = std.c.mkdir((buf[0..len :0]).ptr, 0o755);
    }
};