Merge branch 'zig-0.13'
This commit is contained in:
		
						commit
						4468b4a321
					
				
					 3 changed files with 344 additions and 227 deletions
				
			
		
							
								
								
									
										126
									
								
								src/tui/Fire.zig
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								src/tui/Fire.zig
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,126 @@ | ||||||
|  | const std = @import("std"); | ||||||
|  | const Plane = @import("renderer").Plane; | ||||||
|  | const Widget = @import("Widget.zig"); | ||||||
|  | 
 | ||||||
|  | const px = "▀"; | ||||||
|  | 
 | ||||||
|  | const Fire = @This(); | ||||||
|  | 
 | ||||||
|  | allocator: std.mem.Allocator, | ||||||
|  | plane: Plane, | ||||||
|  | prng: std.Random.DefaultPrng, | ||||||
|  | 
 | ||||||
|  | //scope cache - spread fire | ||||||
|  | spread_px: u8 = 0, | ||||||
|  | spread_rnd_idx: u8 = 0, | ||||||
|  | spread_dst: usize = 0, | ||||||
|  | 
 | ||||||
|  | FIRE_H: u16, | ||||||
|  | FIRE_W: u16, | ||||||
|  | FIRE_SZ: usize, | ||||||
|  | FIRE_LAST_ROW: usize, | ||||||
|  | 
 | ||||||
|  | screen_buf: []u8, | ||||||
|  | 
 | ||||||
|  | const MAX_COLOR = 256; | ||||||
|  | const LAST_COLOR = MAX_COLOR - 1; | ||||||
|  | 
 | ||||||
|  | pub fn init(allocator: std.mem.Allocator, plane: Plane) !Fire { | ||||||
|  |     const pos = Widget.Box.from(plane); | ||||||
|  |     const FIRE_H = @as(u16, @intCast(pos.h)) * 2; | ||||||
|  |     const FIRE_W = @as(u16, @intCast(pos.w)); | ||||||
|  |     var self: Fire = .{ | ||||||
|  |         .allocator = allocator, | ||||||
|  |         .plane = plane, | ||||||
|  |         .prng = std.Random.DefaultPrng.init(blk: { | ||||||
|  |             var seed: u64 = undefined; | ||||||
|  |             try std.posix.getrandom(std.mem.asBytes(&seed)); | ||||||
|  |             break :blk seed; | ||||||
|  |         }), | ||||||
|  |         .FIRE_H = FIRE_H, | ||||||
|  |         .FIRE_W = FIRE_W, | ||||||
|  |         .FIRE_SZ = @as(usize, @intCast(FIRE_H)) * FIRE_W, | ||||||
|  |         .FIRE_LAST_ROW = @as(usize, @intCast(FIRE_H - 1)) * FIRE_W, | ||||||
|  |         .screen_buf = try allocator.alloc(u8, @as(usize, @intCast(FIRE_H)) * FIRE_W), | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     var buf_idx: usize = 0; | ||||||
|  |     while (buf_idx < self.FIRE_SZ) : (buf_idx += 1) { | ||||||
|  |         self.screen_buf[buf_idx] = fire_black; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // last row is white...white is "fire source" | ||||||
|  |     buf_idx = 0; | ||||||
|  |     while (buf_idx < self.FIRE_W) : (buf_idx += 1) { | ||||||
|  |         self.screen_buf[self.FIRE_LAST_ROW + buf_idx] = fire_white; | ||||||
|  |     } | ||||||
|  |     return self; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub fn deinit(self: *Fire) void { | ||||||
|  |     self.allocator.free(self.screen_buf); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const fire_palette = [_]u8{ 0, 233, 234, 52, 53, 88, 89, 94, 95, 96, 130, 131, 132, 133, 172, 214, 215, 220, 220, 221, 3, 226, 227, 230, 195, 230 }; | ||||||
|  | const fire_black: u8 = 0; | ||||||
|  | const fire_white: u8 = fire_palette.len - 1; | ||||||
|  | 
 | ||||||
|  | pub fn render(self: *Fire) void { | ||||||
|  |     self.plane.home(); | ||||||
|  |     var rand = self.prng.random(); | ||||||
|  | 
 | ||||||
|  |     //update fire buf | ||||||
|  |     var doFire_x: u16 = 0; | ||||||
|  |     while (doFire_x < self.FIRE_W) : (doFire_x += 1) { | ||||||
|  |         var doFire_y: u16 = 0; | ||||||
|  |         while (doFire_y < self.FIRE_H) : (doFire_y += 1) { | ||||||
|  |             const doFire_idx = @as(usize, @intCast(doFire_y)) * self.FIRE_W + doFire_x; | ||||||
|  | 
 | ||||||
|  |             //spread fire | ||||||
|  |             self.spread_px = self.screen_buf[doFire_idx]; | ||||||
|  | 
 | ||||||
|  |             //bounds checking | ||||||
|  |             if ((self.spread_px == 0) and (doFire_idx >= self.FIRE_W)) { | ||||||
|  |                 self.screen_buf[doFire_idx - self.FIRE_W] = 0; | ||||||
|  |             } else { | ||||||
|  |                 self.spread_rnd_idx = rand.intRangeAtMost(u8, 0, 3); | ||||||
|  |                 if (doFire_idx >= (self.spread_rnd_idx + 1)) { | ||||||
|  |                     self.spread_dst = doFire_idx - self.spread_rnd_idx + 1; | ||||||
|  |                 } else { | ||||||
|  |                     self.spread_dst = doFire_idx; | ||||||
|  |                 } | ||||||
|  |                 if (self.spread_dst >= self.FIRE_W) { | ||||||
|  |                     if (self.spread_px > (self.spread_rnd_idx & 1)) { | ||||||
|  |                         self.screen_buf[self.spread_dst - self.FIRE_W] = self.spread_px - (self.spread_rnd_idx & 1); | ||||||
|  |                     } else { | ||||||
|  |                         self.screen_buf[self.spread_dst - self.FIRE_W] = 0; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     //scope cache - fire 2 screen buffer | ||||||
|  |     var frame_x: u16 = 0; | ||||||
|  |     var frame_y: u16 = 0; | ||||||
|  | 
 | ||||||
|  |     // for each row | ||||||
|  |     frame_y = 0; | ||||||
|  |     while (frame_y < self.FIRE_H) : (frame_y += 2) { // 'paint' two rows at a time because of half height char | ||||||
|  |         // for each col | ||||||
|  |         frame_x = 0; | ||||||
|  |         while (frame_x < self.FIRE_W) : (frame_x += 1) { | ||||||
|  |             //each character rendered is actually to rows of 'pixels' | ||||||
|  |             // - "hi" (current px row => fg char) | ||||||
|  |             // - "low" (next row => bg color) | ||||||
|  |             const px_hi = self.screen_buf[@as(usize, @intCast(frame_y)) * self.FIRE_W + frame_x]; | ||||||
|  |             const px_lo = self.screen_buf[@as(usize, @intCast(frame_y + 1)) * self.FIRE_W + frame_x]; | ||||||
|  | 
 | ||||||
|  |             self.plane.set_fg_palindex(fire_palette[px_hi]) catch {}; | ||||||
|  |             self.plane.set_bg_palindex(fire_palette[px_lo]) catch {}; | ||||||
|  |             _ = self.plane.putstr(px) catch {}; | ||||||
|  |         } | ||||||
|  |         self.plane.cursor_move_yx(-1, 0) catch {}; | ||||||
|  |         self.plane.cursor_move_rel(1, 0) catch {}; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										375
									
								
								src/tui/home.zig
									
										
									
									
									
								
							
							
						
						
									
										375
									
								
								src/tui/home.zig
									
										
									
									
									
								
							|  | @ -1,6 +1,8 @@ | ||||||
| const std = @import("std"); | const std = @import("std"); | ||||||
| const build_options = @import("build_options"); | const build_options = @import("build_options"); | ||||||
| const tp = @import("thespian"); | const tp = @import("thespian"); | ||||||
|  | const log = @import("log"); | ||||||
|  | const cbor = @import("cbor"); | ||||||
| 
 | 
 | ||||||
| const Plane = @import("renderer").Plane; | const Plane = @import("renderer").Plane; | ||||||
| const root = @import("root"); | const root = @import("root"); | ||||||
|  | @ -14,6 +16,52 @@ const keybind = @import("keybind"); | ||||||
| 
 | 
 | ||||||
| const fonts = @import("fonts.zig"); | const fonts = @import("fonts.zig"); | ||||||
| 
 | 
 | ||||||
|  | const style = struct { | ||||||
|  |     title: []const u8 = root.application_title, | ||||||
|  |     subtext: []const u8 = root.application_subtext, | ||||||
|  | 
 | ||||||
|  |     centered: bool = false, | ||||||
|  | 
 | ||||||
|  |     menu_commands: []const u8 = splice(if (build_options.gui) | ||||||
|  |         \\find_file | ||||||
|  |         \\create_new_file | ||||||
|  |         \\open_file | ||||||
|  |         \\open_recent_project | ||||||
|  |         \\find_in_files | ||||||
|  |         \\open_command_palette | ||||||
|  |         \\select_task | ||||||
|  |         \\add_task | ||||||
|  |         \\open_config | ||||||
|  |         \\open_gui_config | ||||||
|  |         \\change_fontface | ||||||
|  |         \\open_keybind_config | ||||||
|  |         \\toggle_input_mode | ||||||
|  |         \\change_theme | ||||||
|  |         \\open_help | ||||||
|  |         \\open_version_info | ||||||
|  |         \\quit | ||||||
|  |     else | ||||||
|  |         \\find_file | ||||||
|  |         \\create_new_file | ||||||
|  |         \\open_file | ||||||
|  |         \\open_recent_project | ||||||
|  |         \\find_in_files | ||||||
|  |         \\open_command_palette | ||||||
|  |         \\select_task | ||||||
|  |         \\add_task | ||||||
|  |         \\open_config | ||||||
|  |         \\open_keybind_config | ||||||
|  |         \\toggle_input_mode | ||||||
|  |         \\change_theme | ||||||
|  |         \\open_help | ||||||
|  |         \\open_version_info | ||||||
|  |         \\quit | ||||||
|  |     ), | ||||||
|  | 
 | ||||||
|  |     include_files: []const u8 = "", | ||||||
|  | }; | ||||||
|  | pub const Style = style; | ||||||
|  | 
 | ||||||
| allocator: std.mem.Allocator, | allocator: std.mem.Allocator, | ||||||
| plane: Plane, | plane: Plane, | ||||||
| parent: Plane, | parent: Plane, | ||||||
|  | @ -21,54 +69,24 @@ fire: ?Fire = null, | ||||||
| commands: Commands = undefined, | commands: Commands = undefined, | ||||||
| menu: *Menu.State(*Self), | menu: *Menu.State(*Self), | ||||||
| menu_w: usize = 0, | menu_w: usize = 0, | ||||||
|  | menu_len: usize = 0, | ||||||
| max_desc_len: usize = 0, | max_desc_len: usize = 0, | ||||||
| input_namespace: []const u8, | input_namespace: []const u8, | ||||||
| 
 | 
 | ||||||
|  | home_style: style, | ||||||
|  | home_style_bufs: [][]const u8, | ||||||
|  | 
 | ||||||
| const Self = @This(); | const Self = @This(); | ||||||
| 
 | 
 | ||||||
| const menu_commands = if (build_options.gui) &[_][]const u8{ |  | ||||||
|     "find_file", |  | ||||||
|     "create_new_file", |  | ||||||
|     "open_file", |  | ||||||
|     "open_recent_project", |  | ||||||
|     "find_in_files", |  | ||||||
|     "open_command_palette", |  | ||||||
|     "select_task", |  | ||||||
|     "add_task", |  | ||||||
|     "open_config", |  | ||||||
|     "open_gui_config", |  | ||||||
|     "change_fontface", |  | ||||||
|     "open_keybind_config", |  | ||||||
|     "toggle_input_mode", |  | ||||||
|     "change_theme", |  | ||||||
|     "open_help", |  | ||||||
|     "open_version_info", |  | ||||||
|     "quit", |  | ||||||
| } else &[_][]const u8{ |  | ||||||
|     "find_file", |  | ||||||
|     "create_new_file", |  | ||||||
|     "open_file", |  | ||||||
|     "open_recent_project", |  | ||||||
|     "find_in_files", |  | ||||||
|     "open_command_palette", |  | ||||||
|     "select_task", |  | ||||||
|     "add_task", |  | ||||||
|     "open_config", |  | ||||||
|     "open_keybind_config", |  | ||||||
|     "toggle_input_mode", |  | ||||||
|     "change_theme", |  | ||||||
|     "open_help", |  | ||||||
|     "open_version_info", |  | ||||||
|     "quit", |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| pub fn create(allocator: std.mem.Allocator, parent: Widget) !Widget { | pub fn create(allocator: std.mem.Allocator, parent: Widget) !Widget { | ||||||
|  |     const logger = log.logger("home"); | ||||||
|     const self: *Self = try allocator.create(Self); |     const self: *Self = try allocator.create(Self); | ||||||
|     var n = try Plane.init(&(Widget.Box{}).opts("editor"), parent.plane.*); |     var n = try Plane.init(&(Widget.Box{}).opts("editor"), parent.plane.*); | ||||||
|     errdefer n.deinit(); |     errdefer n.deinit(); | ||||||
| 
 | 
 | ||||||
|     command.executeName("enter_mode", command.Context.fmt(.{"home"})) catch {}; |     command.executeName("enter_mode", command.Context.fmt(.{"home"})) catch {}; | ||||||
|     const keybind_mode = tui.get_keybind_mode() orelse @panic("no active keybind mode"); |     const keybind_mode = tui.get_keybind_mode() orelse @panic("no active keybind mode"); | ||||||
|  |     const home_style, const home_style_bufs = root.read_config(style, allocator); | ||||||
| 
 | 
 | ||||||
|     const w = Widget.to(self); |     const w = Widget.to(self); | ||||||
|     self.* = .{ |     self.* = .{ | ||||||
|  | @ -77,15 +95,32 @@ pub fn create(allocator: std.mem.Allocator, parent: Widget) !Widget { | ||||||
|         .plane = n, |         .plane = n, | ||||||
|         .menu = try Menu.create(*Self, allocator, w.plane.*, .{ .ctx = self, .on_render = menu_on_render }), |         .menu = try Menu.create(*Self, allocator, w.plane.*, .{ .ctx = self, .on_render = menu_on_render }), | ||||||
|         .input_namespace = keybind.get_namespace(), |         .input_namespace = keybind.get_namespace(), | ||||||
|  |         .home_style = home_style, | ||||||
|  |         .home_style_bufs = home_style_bufs, | ||||||
|     }; |     }; | ||||||
|     try self.commands.init(self); |     try self.commands.init(self); | ||||||
|     self.get_max_desc_len(keybind_mode.keybind_hints); |     var it = std.mem.splitAny(u8, self.home_style.menu_commands, "\n "); | ||||||
|     inline for (menu_commands) |command_name| try self.add_menu_command(command_name, self.menu, keybind_mode.keybind_hints); |     while (it.next()) |command_name| { | ||||||
|  |         self.menu_len += 1; | ||||||
|  |         const id = command.get_id(command_name) orelse { | ||||||
|  |             logger.print("{s} is not defined", .{command_name}); | ||||||
|  |             continue; | ||||||
|  |         }; | ||||||
|  |         const description = command.get_description(id) orelse { | ||||||
|  |             logger.print("{s} has no description", .{command_name}); | ||||||
|  |             continue; | ||||||
|  |         }; | ||||||
|  |         var hints = std.mem.splitScalar(u8, keybind_mode.keybind_hints.get(command_name) orelse "", ','); | ||||||
|  |         const hint = hints.first(); | ||||||
|  |         self.max_desc_len = @max(self.max_desc_len, description.len + hint.len + 5); | ||||||
|  |         try self.add_menu_command(command_name, description, hint, self.menu); | ||||||
|  |     } | ||||||
|     self.position_menu(15, 9); |     self.position_menu(15, 9); | ||||||
|     return w; |     return w; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn deinit(self: *Self, allocator: std.mem.Allocator) void { | pub fn deinit(self: *Self, allocator: std.mem.Allocator) void { | ||||||
|  |     root.free_config(self.allocator, self.home_style_bufs); | ||||||
|     self.menu.deinit(allocator); |     self.menu.deinit(allocator); | ||||||
|     self.commands.deinit(); |     self.commands.deinit(); | ||||||
|     self.plane.deinit(); |     self.plane.deinit(); | ||||||
|  | @ -93,23 +128,10 @@ pub fn deinit(self: *Self, allocator: std.mem.Allocator) void { | ||||||
|     allocator.destroy(self); |     allocator.destroy(self); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn get_max_desc_len(self: *Self, hints_map: anytype) void { | fn add_menu_command(self: *Self, command_name: []const u8, description: []const u8, hint: []const u8, menu: anytype) !void { | ||||||
|     inline for (menu_commands) |command_name| { |  | ||||||
|         const id = command.get_id(command_name) orelse @panic(command_name ++ " is not defined"); |  | ||||||
|         const description = command.get_description(id) orelse @panic(command_name ++ " has no description"); |  | ||||||
|         var hints = std.mem.splitScalar(u8, hints_map.get(command_name) orelse "", ','); |  | ||||||
|         const hint = hints.first(); |  | ||||||
|         self.max_desc_len = @max(self.max_desc_len, description.len + hint.len + 5); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn add_menu_command(self: *Self, comptime command_name: []const u8, menu: anytype, hints_map: anytype) !void { |  | ||||||
|     const id = command.get_id(command_name) orelse @panic(command_name ++ " is not defined"); |  | ||||||
|     const description = command.get_description(id) orelse @panic(command_name ++ " has no description"); |  | ||||||
|     var hints = std.mem.splitScalar(u8, hints_map.get(command_name) orelse "", ','); |  | ||||||
|     const hint = hints.first(); |  | ||||||
|     const label_len = description.len + hint.len; |     const label_len = description.len + hint.len; | ||||||
|     var buf: [64]u8 = undefined; |     var buf: [64]u8 = undefined; | ||||||
|  |     { | ||||||
|         var fis = std.io.fixedBufferStream(&buf); |         var fis = std.io.fixedBufferStream(&buf); | ||||||
|         const writer = fis.writer(); |         const writer = fis.writer(); | ||||||
|         const leader = if (hint.len > 0) "." else " "; |         const leader = if (hint.len > 0) "." else " "; | ||||||
|  | @ -121,8 +143,17 @@ fn add_menu_command(self: *Self, comptime command_name: []const u8, menu: anytyp | ||||||
|             _ = try writer.write(leader); |             _ = try writer.write(leader); | ||||||
|         try writer.print(" :{s}", .{hint}); |         try writer.print(" :{s}", .{hint}); | ||||||
|         const label = fis.getWritten(); |         const label = fis.getWritten(); | ||||||
|     try menu.add_item_with_handler(label, menu_action(command_name)); |  | ||||||
|         self.menu_w = @max(self.menu_w, label.len + 1); |         self.menu_w = @max(self.menu_w, label.len + 1); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     var value = std.ArrayList(u8).init(self.allocator); | ||||||
|  |     defer value.deinit(); | ||||||
|  |     const writer = value.writer(); | ||||||
|  |     try cbor.writeValue(writer, description); | ||||||
|  |     try cbor.writeValue(writer, hint); | ||||||
|  |     try cbor.writeValue(writer, command_name); | ||||||
|  | 
 | ||||||
|  |     try menu.add_item_with_handler(value.items, menu_action); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn update(self: *Self) void { | pub fn update(self: *Self) void { | ||||||
|  | @ -143,7 +174,33 @@ pub fn receive(_: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!bool { | ||||||
|     return false; |     return false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn menu_on_render(_: *Self, button: *Button.State(*Menu.State(*Self)), theme: *const Widget.Theme, selected: bool) bool { | fn menu_on_render(self: *Self, button: *Button.State(*Menu.State(*Self)), theme: *const Widget.Theme, selected: bool) bool { | ||||||
|  |     var description: []const u8 = undefined; | ||||||
|  |     var hint: []const u8 = undefined; | ||||||
|  |     var command_name: []const u8 = undefined; | ||||||
|  |     var iter = button.opts.label; // label contains cbor | ||||||
|  |     if (!(cbor.matchString(&iter, &description) catch false)) | ||||||
|  |         description = "#ERROR#"; | ||||||
|  |     if (!(cbor.matchString(&iter, &hint) catch false)) | ||||||
|  |         hint = ""; | ||||||
|  |     if (!(cbor.matchString(&iter, &command_name) catch false)) | ||||||
|  |         command_name = ""; | ||||||
|  | 
 | ||||||
|  |     const label_len = description.len + hint.len; | ||||||
|  |     var buf: [64]u8 = undefined; | ||||||
|  |     const leader = blk: { | ||||||
|  |         var fis = std.io.fixedBufferStream(&buf); | ||||||
|  |         const writer = fis.writer(); | ||||||
|  |         const leader = if (hint.len > 0) "." else " "; | ||||||
|  |         _ = writer.write(" ") catch return false; | ||||||
|  |         _ = writer.write(leader) catch return false; | ||||||
|  |         _ = writer.write(leader) catch return false; | ||||||
|  |         for (0..(self.max_desc_len - label_len - 5)) |_| | ||||||
|  |             _ = writer.write(leader) catch return false; | ||||||
|  |         writer.print(" ", .{}) catch return false; | ||||||
|  |         break :blk fis.getWritten(); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|     const style_base = theme.editor; |     const style_base = theme.editor; | ||||||
|     const style_label = if (button.active) theme.editor_cursor else if (button.hover or selected) theme.editor_selection else style_base; |     const style_label = if (button.active) theme.editor_cursor else if (button.hover or selected) theme.editor_selection else style_base; | ||||||
|     if (button.active or button.hover or selected) { |     if (button.active or button.hover or selected) { | ||||||
|  | @ -159,8 +216,9 @@ fn menu_on_render(_: *Self, button: *Button.State(*Menu.State(*Self)), theme: *c | ||||||
|         button.plane.home(); |         button.plane.home(); | ||||||
|     } |     } | ||||||
|     const style_text = if (tui.find_scope_style(theme, "keyword")) |sty| sty.style else style_label; |     const style_text = if (tui.find_scope_style(theme, "keyword")) |sty| sty.style else style_label; | ||||||
|  |     const style_leader = if (tui.find_scope_style(theme, "comment")) |sty| sty.style else theme.editor; | ||||||
|     const style_keybind = if (tui.find_scope_style(theme, "entity.name")) |sty| sty.style else style_label; |     const style_keybind = if (tui.find_scope_style(theme, "entity.name")) |sty| sty.style else style_label; | ||||||
|     const sep = std.mem.indexOfScalar(u8, button.opts.label, ':') orelse button.opts.label.len; | 
 | ||||||
|     if (button.active) { |     if (button.active) { | ||||||
|         button.plane.set_style(style_label); |         button.plane.set_style(style_label); | ||||||
|     } else if (button.hover or selected) { |     } else if (button.hover or selected) { | ||||||
|  | @ -169,22 +227,35 @@ fn menu_on_render(_: *Self, button: *Button.State(*Menu.State(*Self)), theme: *c | ||||||
|         button.plane.set_style_bg_transparent(style_text); |         button.plane.set_style_bg_transparent(style_text); | ||||||
|     } |     } | ||||||
|     const pointer = if (selected) "⏵" else " "; |     const pointer = if (selected) "⏵" else " "; | ||||||
|     _ = button.plane.print("{s}{s}", .{ pointer, button.opts.label[0..sep] }) catch {}; |     _ = button.plane.print("{s}{s}", .{ pointer, description }) catch {}; | ||||||
|  |     if (button.active or button.hover or selected) { | ||||||
|  |         button.plane.set_style(style_leader); | ||||||
|  |     } else { | ||||||
|  |         button.plane.set_style_bg_transparent(style_leader); | ||||||
|  |     } | ||||||
|  |     _ = button.plane.print("{s}", .{leader}) catch {}; | ||||||
|     if (button.active or button.hover or selected) { |     if (button.active or button.hover or selected) { | ||||||
|         button.plane.set_style(style_keybind); |         button.plane.set_style(style_keybind); | ||||||
|     } else { |     } else { | ||||||
|         button.plane.set_style_bg_transparent(style_keybind); |         button.plane.set_style_bg_transparent(style_keybind); | ||||||
|     } |     } | ||||||
|     _ = button.plane.print("{s}", .{button.opts.label[sep + 1 ..]}) catch {}; |     _ = button.plane.print("{s}", .{hint}) catch {}; | ||||||
|     return false; |     return false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn menu_action(comptime command_name: []const u8) *const fn (_: **Menu.State(*Self), _: *Button.State(*Menu.State(*Self))) void { | fn menu_action(_: **Menu.State(*Self), button: *Button.State(*Menu.State(*Self))) void { | ||||||
|     return struct { |     var description: []const u8 = undefined; | ||||||
|         fn action(_: **Menu.State(*Self), _: *Button.State(*Menu.State(*Self))) void { |     var hint: []const u8 = undefined; | ||||||
|  |     var command_name: []const u8 = undefined; | ||||||
|  |     var iter = button.opts.label; // label contains cbor | ||||||
|  |     if (!(cbor.matchString(&iter, &description) catch false)) | ||||||
|  |         description = "#ERROR#"; | ||||||
|  |     if (!(cbor.matchString(&iter, &hint) catch false)) | ||||||
|  |         hint = ""; | ||||||
|  |     if (!(cbor.matchString(&iter, &command_name) catch false)) | ||||||
|  |         command_name = ""; | ||||||
|  | 
 | ||||||
|     command.executeName(command_name, .{}) catch {}; |     command.executeName(command_name, .{}) catch {}; | ||||||
|         } |  | ||||||
|     }.action; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn render(self: *Self, theme: *const Widget.Theme) bool { | pub fn render(self: *Self, theme: *const Widget.Theme) bool { | ||||||
|  | @ -199,35 +270,35 @@ pub fn render(self: *Self, theme: *const Widget.Theme) bool { | ||||||
|     const style_subtext = if (tui.find_scope_style(theme, "comment")) |sty| sty.style else theme.editor; |     const style_subtext = if (tui.find_scope_style(theme, "comment")) |sty| sty.style else theme.editor; | ||||||
| 
 | 
 | ||||||
|     if (self.plane.dim_x() > 120 and self.plane.dim_y() > 22) { |     if (self.plane.dim_x() > 120 and self.plane.dim_y() > 22) { | ||||||
|         self.plane.cursor_move_yx(2, 4) catch return false; |         self.plane.cursor_move_yx(2, self.centerI(4, self.home_style.title.len * 8)) catch return false; | ||||||
|         fonts.print_string_large(&self.plane, root.application_title, style_title) catch return false; |         fonts.print_string_large(&self.plane, self.home_style.title, style_title) catch return false; | ||||||
| 
 | 
 | ||||||
|         self.plane.cursor_move_yx(10, 8) catch return false; |         self.plane.cursor_move_yx(10, self.centerI(8, self.home_style.subtext.len * 4)) catch return false; | ||||||
|         fonts.print_string_medium(&self.plane, root.application_subtext, style_subtext) catch return false; |         fonts.print_string_medium(&self.plane, self.home_style.subtext, style_subtext) catch return false; | ||||||
| 
 | 
 | ||||||
|         self.position_menu(15, 10); |         self.position_menu(self.v_center(15, self.menu_len, 15), self.center(10, self.menu_w)); | ||||||
|     } else if (self.plane.dim_x() > 55 and self.plane.dim_y() > 16) { |     } else if (self.plane.dim_x() > 55 and self.plane.dim_y() > 16) { | ||||||
|         self.plane.cursor_move_yx(2, 4) catch return false; |         self.plane.cursor_move_yx(2, self.centerI(4, self.home_style.title.len * 4)) catch return false; | ||||||
|         fonts.print_string_medium(&self.plane, root.application_title, style_title) catch return false; |         fonts.print_string_medium(&self.plane, self.home_style.title, style_title) catch return false; | ||||||
| 
 | 
 | ||||||
|         self.plane.set_style_bg_transparent(style_subtext); |         self.plane.set_style_bg_transparent(style_subtext); | ||||||
|         self.plane.cursor_move_yx(7, 6) catch return false; |         self.plane.cursor_move_yx(7, self.centerI(6, self.home_style.subtext.len)) catch return false; | ||||||
|         _ = self.plane.print(root.application_subtext, .{}) catch {}; |         _ = self.plane.print("{s}", .{self.home_style.subtext}) catch {}; | ||||||
|         self.plane.set_style(theme.editor); |         self.plane.set_style(theme.editor); | ||||||
| 
 | 
 | ||||||
|         self.position_menu(9, 8); |         self.position_menu(self.v_center(9, self.menu_len, 9), self.center(8, self.menu_w)); | ||||||
|     } else { |     } else { | ||||||
|         self.plane.set_style_bg_transparent(style_title); |         self.plane.set_style_bg_transparent(style_title); | ||||||
|         self.plane.cursor_move_yx(1, 4) catch return false; |         self.plane.cursor_move_yx(1, self.centerI(4, self.home_style.title.len)) catch return false; | ||||||
|         _ = self.plane.print(root.application_title, .{}) catch return false; |         _ = self.plane.print("{s}", .{self.home_style.title}) catch return false; | ||||||
| 
 | 
 | ||||||
|         self.plane.set_style_bg_transparent(style_subtext); |         self.plane.set_style_bg_transparent(style_subtext); | ||||||
|         self.plane.cursor_move_yx(3, 6) catch return false; |         self.plane.cursor_move_yx(3, self.centerI(6, self.home_style.subtext.len)) catch return false; | ||||||
|         _ = self.plane.print(root.application_subtext, .{}) catch {}; |         _ = self.plane.print("{s}", .{self.home_style.subtext}) catch {}; | ||||||
|         self.plane.set_style(theme.editor); |         self.plane.set_style(theme.editor); | ||||||
| 
 | 
 | ||||||
|         const x = @min(self.plane.dim_x() -| 32, 8); |         const x = @min(self.plane.dim_x() -| 32, 8); | ||||||
|         self.position_menu(5, x); |         self.position_menu(self.v_center(5, self.menu_len, 5), self.center(x, self.menu_w)); | ||||||
|     } |     } | ||||||
|     const more = self.menu.render(theme); |     const more = self.menu.render(theme); | ||||||
| 
 | 
 | ||||||
|  | @ -239,6 +310,24 @@ fn position_menu(self: *Self, y: usize, x: usize) void { | ||||||
|     self.menu.resize(.{ .y = box.y + y, .x = box.x + x, .w = self.menu_w }); |     self.menu.resize(.{ .y = box.y + y, .x = box.x + x, .w = self.menu_w }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | fn center(self: *Self, non_centered: usize, w: usize) usize { | ||||||
|  |     if (!self.home_style.centered) return non_centered; | ||||||
|  |     const box = Widget.Box.from(self.plane); | ||||||
|  |     const x = if (box.w > w) (box.w - w) / 2 else 0; | ||||||
|  |     return box.x + x; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn centerI(self: *Self, non_centered: usize, w: usize) c_int { | ||||||
|  |     return @intCast(self.center(non_centered, w)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn v_center(self: *Self, non_centered: usize, h: usize, minoffset: usize) usize { | ||||||
|  |     if (!self.home_style.centered) return non_centered; | ||||||
|  |     const box = Widget.Box.from(self.plane); | ||||||
|  |     const y = if (box.h > h) (box.h - h) / 2 else 0; | ||||||
|  |     return box.y + @max(y, minoffset); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| pub fn handle_resize(self: *Self, pos: Widget.Box) void { | pub fn handle_resize(self: *Self, pos: Widget.Box) void { | ||||||
|     self.plane.move_yx(@intCast(pos.y), @intCast(pos.x)) catch return; |     self.plane.move_yx(@intCast(pos.y), @intCast(pos.x)) catch return; | ||||||
|     self.plane.resize_simple(@intCast(pos.h), @intCast(pos.w)) catch return; |     self.plane.resize_simple(@intCast(pos.h), @intCast(pos.w)) catch return; | ||||||
|  | @ -286,125 +375,19 @@ const cmds = struct { | ||||||
|     pub const home_sheeran_meta: Meta = .{}; |     pub const home_sheeran_meta: Meta = .{}; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const Fire = struct { | const Fire = @import("Fire.zig"); | ||||||
|     const px = "▀"; |  | ||||||
| 
 | 
 | ||||||
|     allocator: std.mem.Allocator, | fn splice(in: []const u8) []const u8 { | ||||||
|     plane: Plane, |     var out: []const u8 = ""; | ||||||
|     prng: std.Random.DefaultPrng, |     var it = std.mem.splitAny(u8, in, "\n "); | ||||||
| 
 |     var first = true; | ||||||
|     //scope cache - spread fire |     while (it.next()) |item| { | ||||||
|     spread_px: u8 = 0, |         if (first) { | ||||||
|     spread_rnd_idx: u8 = 0, |             first = false; | ||||||
|     spread_dst: usize = 0, |  | ||||||
| 
 |  | ||||||
|     FIRE_H: u16, |  | ||||||
|     FIRE_W: u16, |  | ||||||
|     FIRE_SZ: usize, |  | ||||||
|     FIRE_LAST_ROW: usize, |  | ||||||
| 
 |  | ||||||
|     screen_buf: []u8, |  | ||||||
| 
 |  | ||||||
|     const MAX_COLOR = 256; |  | ||||||
|     const LAST_COLOR = MAX_COLOR - 1; |  | ||||||
| 
 |  | ||||||
|     fn init(allocator: std.mem.Allocator, plane: Plane) !Fire { |  | ||||||
|         const pos = Widget.Box.from(plane); |  | ||||||
|         const FIRE_H = @as(u16, @intCast(pos.h)) * 2; |  | ||||||
|         const FIRE_W = @as(u16, @intCast(pos.w)); |  | ||||||
|         var self: Fire = .{ |  | ||||||
|             .allocator = allocator, |  | ||||||
|             .plane = plane, |  | ||||||
|             .prng = std.Random.DefaultPrng.init(blk: { |  | ||||||
|                 var seed: u64 = undefined; |  | ||||||
|                 try std.posix.getrandom(std.mem.asBytes(&seed)); |  | ||||||
|                 break :blk seed; |  | ||||||
|             }), |  | ||||||
|             .FIRE_H = FIRE_H, |  | ||||||
|             .FIRE_W = FIRE_W, |  | ||||||
|             .FIRE_SZ = @as(usize, @intCast(FIRE_H)) * FIRE_W, |  | ||||||
|             .FIRE_LAST_ROW = @as(usize, @intCast(FIRE_H - 1)) * FIRE_W, |  | ||||||
|             .screen_buf = try allocator.alloc(u8, @as(usize, @intCast(FIRE_H)) * FIRE_W), |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
|         var buf_idx: usize = 0; |  | ||||||
|         while (buf_idx < self.FIRE_SZ) : (buf_idx += 1) { |  | ||||||
|             self.screen_buf[buf_idx] = fire_black; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // last row is white...white is "fire source" |  | ||||||
|         buf_idx = 0; |  | ||||||
|         while (buf_idx < self.FIRE_W) : (buf_idx += 1) { |  | ||||||
|             self.screen_buf[self.FIRE_LAST_ROW + buf_idx] = fire_white; |  | ||||||
|         } |  | ||||||
|         return self; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     fn deinit(self: *Fire) void { |  | ||||||
|         self.allocator.free(self.screen_buf); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     const fire_palette = [_]u8{ 0, 233, 234, 52, 53, 88, 89, 94, 95, 96, 130, 131, 132, 133, 172, 214, 215, 220, 220, 221, 3, 226, 227, 230, 195, 230 }; |  | ||||||
|     const fire_black: u8 = 0; |  | ||||||
|     const fire_white: u8 = fire_palette.len - 1; |  | ||||||
| 
 |  | ||||||
|     fn render(self: *Fire) void { |  | ||||||
|         self.plane.home(); |  | ||||||
|         var rand = self.prng.random(); |  | ||||||
| 
 |  | ||||||
|         //update fire buf |  | ||||||
|         var doFire_x: u16 = 0; |  | ||||||
|         while (doFire_x < self.FIRE_W) : (doFire_x += 1) { |  | ||||||
|             var doFire_y: u16 = 0; |  | ||||||
|             while (doFire_y < self.FIRE_H) : (doFire_y += 1) { |  | ||||||
|                 const doFire_idx = @as(usize, @intCast(doFire_y)) * self.FIRE_W + doFire_x; |  | ||||||
| 
 |  | ||||||
|                 //spread fire |  | ||||||
|                 self.spread_px = self.screen_buf[doFire_idx]; |  | ||||||
| 
 |  | ||||||
|                 //bounds checking |  | ||||||
|                 if ((self.spread_px == 0) and (doFire_idx >= self.FIRE_W)) { |  | ||||||
|                     self.screen_buf[doFire_idx - self.FIRE_W] = 0; |  | ||||||
|         } else { |         } else { | ||||||
|                     self.spread_rnd_idx = rand.intRangeAtMost(u8, 0, 3); |             out = out ++ " "; | ||||||
|                     if (doFire_idx >= (self.spread_rnd_idx + 1)) { |  | ||||||
|                         self.spread_dst = doFire_idx - self.spread_rnd_idx + 1; |  | ||||||
|                     } else { |  | ||||||
|                         self.spread_dst = doFire_idx; |  | ||||||
|         } |         } | ||||||
|                     if (self.spread_dst >= self.FIRE_W) { |         out = out ++ item; | ||||||
|                         if (self.spread_px > (self.spread_rnd_idx & 1)) { |  | ||||||
|                             self.screen_buf[self.spread_dst - self.FIRE_W] = self.spread_px - (self.spread_rnd_idx & 1); |  | ||||||
|                         } else { |  | ||||||
|                             self.screen_buf[self.spread_dst - self.FIRE_W] = 0; |  | ||||||
|     } |     } | ||||||
|                     } |     return out; | ||||||
|                 } | } | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         //scope cache - fire 2 screen buffer |  | ||||||
|         var frame_x: u16 = 0; |  | ||||||
|         var frame_y: u16 = 0; |  | ||||||
| 
 |  | ||||||
|         // for each row |  | ||||||
|         frame_y = 0; |  | ||||||
|         while (frame_y < self.FIRE_H) : (frame_y += 2) { // 'paint' two rows at a time because of half height char |  | ||||||
|             // for each col |  | ||||||
|             frame_x = 0; |  | ||||||
|             while (frame_x < self.FIRE_W) : (frame_x += 1) { |  | ||||||
|                 //each character rendered is actually to rows of 'pixels' |  | ||||||
|                 // - "hi" (current px row => fg char) |  | ||||||
|                 // - "low" (next row => bg color) |  | ||||||
|                 const px_hi = self.screen_buf[@as(usize, @intCast(frame_y)) * self.FIRE_W + frame_x]; |  | ||||||
|                 const px_lo = self.screen_buf[@as(usize, @intCast(frame_y + 1)) * self.FIRE_W + frame_x]; |  | ||||||
| 
 |  | ||||||
|                 self.plane.set_fg_palindex(fire_palette[px_hi]) catch {}; |  | ||||||
|                 self.plane.set_bg_palindex(fire_palette[px_lo]) catch {}; |  | ||||||
|                 _ = self.plane.putstr(px) catch {}; |  | ||||||
|             } |  | ||||||
|             self.plane.cursor_move_yx(-1, 0) catch {}; |  | ||||||
|             self.plane.cursor_move_rel(1, 0) catch {}; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| }; |  | ||||||
|  |  | ||||||
|  | @ -230,6 +230,26 @@ fn check_all_not_dirty(self: *const Self) command.Result { | ||||||
|         return tp.exit("unsaved changes"); |         return tp.exit("unsaved changes"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | fn open_style_config(self: *Self, Style: type) command.Result { | ||||||
|  |     const file_name = try root.get_config_file_name(Style); | ||||||
|  |     const style, const style_bufs: [][]const u8 = if (root.exists_config(Style)) blk: { | ||||||
|  |         const style, const style_bufs = root.read_config(Style, self.allocator); | ||||||
|  |         break :blk .{ style, style_bufs }; | ||||||
|  |     } else .{ Style{}, &.{} }; | ||||||
|  |     defer root.free_config(self.allocator, style_bufs); | ||||||
|  |     var conf = std.ArrayList(u8).init(self.allocator); | ||||||
|  |     defer conf.deinit(); | ||||||
|  |     root.write_config_to_writer(Style, style, conf.writer()) catch {}; | ||||||
|  |     tui.reset_drag_context(); | ||||||
|  |     try self.create_editor(); | ||||||
|  |     try command.executeName("open_scratch_buffer", command.fmt(.{ | ||||||
|  |         file_name[0 .. file_name.len - ".json".len], | ||||||
|  |         conf.items, | ||||||
|  |         "conf", | ||||||
|  |     })); | ||||||
|  |     if (self.get_active_buffer()) |buffer| buffer.mark_not_ephemeral(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| const cmds = struct { | const cmds = struct { | ||||||
|     pub const Target = Self; |     pub const Target = Self; | ||||||
|     const Ctx = command.Context; |     const Ctx = command.Context; | ||||||
|  | @ -414,27 +434,15 @@ const cmds = struct { | ||||||
|     pub const open_gui_config_meta: Meta = .{ .description = "Edit gui configuration" }; |     pub const open_gui_config_meta: Meta = .{ .description = "Edit gui configuration" }; | ||||||
| 
 | 
 | ||||||
|     pub fn open_tabs_style_config(self: *Self, _: Ctx) Result { |     pub fn open_tabs_style_config(self: *Self, _: Ctx) Result { | ||||||
|         const Style = @import("status/tabs.zig").Style; |         try self.open_style_config(@import("status/tabs.zig").Style); | ||||||
|         const file_name = try root.get_config_file_name(Style); |  | ||||||
|         const tab_style, const tab_style_bufs: [][]const u8 = if (root.exists_config(Style)) blk: { |  | ||||||
|             const tab_style, const tab_style_bufs = root.read_config(Style, self.allocator); |  | ||||||
|             break :blk .{ tab_style, tab_style_bufs }; |  | ||||||
|         } else .{ Style{}, &.{} }; |  | ||||||
|         defer root.free_config(self.allocator, tab_style_bufs); |  | ||||||
|         var conf = std.ArrayList(u8).init(self.allocator); |  | ||||||
|         defer conf.deinit(); |  | ||||||
|         root.write_config_to_writer(Style, tab_style, conf.writer()) catch {}; |  | ||||||
|         tui.reset_drag_context(); |  | ||||||
|         try self.create_editor(); |  | ||||||
|         try command.executeName("open_scratch_buffer", command.fmt(.{ |  | ||||||
|             file_name[0 .. file_name.len - ".json".len], |  | ||||||
|             conf.items, |  | ||||||
|             "conf", |  | ||||||
|         })); |  | ||||||
|         if (self.get_active_buffer()) |buffer| buffer.mark_not_ephemeral(); |  | ||||||
|     } |     } | ||||||
|     pub const open_tabs_style_config_meta: Meta = .{ .description = "Edit tab style" }; |     pub const open_tabs_style_config_meta: Meta = .{ .description = "Edit tab style" }; | ||||||
| 
 | 
 | ||||||
|  |     pub fn open_home_style_config(self: *Self, _: Ctx) Result { | ||||||
|  |         try self.open_style_config(@import("home.zig").Style); | ||||||
|  |     } | ||||||
|  |     pub const open_home_style_config_meta: Meta = .{ .description = "Edit home screen" }; | ||||||
|  | 
 | ||||||
|     pub fn create_scratch_buffer(self: *Self, ctx: Ctx) Result { |     pub fn create_scratch_buffer(self: *Self, ctx: Ctx) Result { | ||||||
|         const args = try ctx.args.clone(self.allocator); |         const args = try ctx.args.clone(self.allocator); | ||||||
|         defer self.allocator.free(args.buf); |         defer self.allocator.free(args.buf); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue