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 {}; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										373
									
								
								src/tui/home.zig
									
										
									
									
									
								
							
							
						
						
									
										373
									
								
								src/tui/home.zig
									
										
									
									
									
								
							|  | @ -1,6 +1,8 @@ | |||
| const std = @import("std"); | ||||
| const build_options = @import("build_options"); | ||||
| const tp = @import("thespian"); | ||||
| const log = @import("log"); | ||||
| const cbor = @import("cbor"); | ||||
| 
 | ||||
| const Plane = @import("renderer").Plane; | ||||
| const root = @import("root"); | ||||
|  | @ -14,6 +16,52 @@ const keybind = @import("keybind"); | |||
| 
 | ||||
| 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, | ||||
| plane: Plane, | ||||
| parent: Plane, | ||||
|  | @ -21,54 +69,24 @@ fire: ?Fire = null, | |||
| commands: Commands = undefined, | ||||
| menu: *Menu.State(*Self), | ||||
| menu_w: usize = 0, | ||||
| menu_len: usize = 0, | ||||
| max_desc_len: usize = 0, | ||||
| input_namespace: []const u8, | ||||
| 
 | ||||
| home_style: style, | ||||
| home_style_bufs: [][]const u8, | ||||
| 
 | ||||
| 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 { | ||||
|     const logger = log.logger("home"); | ||||
|     const self: *Self = try allocator.create(Self); | ||||
|     var n = try Plane.init(&(Widget.Box{}).opts("editor"), parent.plane.*); | ||||
|     errdefer n.deinit(); | ||||
| 
 | ||||
|     command.executeName("enter_mode", command.Context.fmt(.{"home"})) catch {}; | ||||
|     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); | ||||
|     self.* = .{ | ||||
|  | @ -77,15 +95,32 @@ pub fn create(allocator: std.mem.Allocator, parent: Widget) !Widget { | |||
|         .plane = n, | ||||
|         .menu = try Menu.create(*Self, allocator, w.plane.*, .{ .ctx = self, .on_render = menu_on_render }), | ||||
|         .input_namespace = keybind.get_namespace(), | ||||
|         .home_style = home_style, | ||||
|         .home_style_bufs = home_style_bufs, | ||||
|     }; | ||||
|     try self.commands.init(self); | ||||
|     self.get_max_desc_len(keybind_mode.keybind_hints); | ||||
|     inline for (menu_commands) |command_name| try self.add_menu_command(command_name, self.menu, keybind_mode.keybind_hints); | ||||
|     var it = std.mem.splitAny(u8, self.home_style.menu_commands, "\n "); | ||||
|     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); | ||||
|     return w; | ||||
| } | ||||
| 
 | ||||
| pub fn deinit(self: *Self, allocator: std.mem.Allocator) void { | ||||
|     root.free_config(self.allocator, self.home_style_bufs); | ||||
|     self.menu.deinit(allocator); | ||||
|     self.commands.deinit(); | ||||
|     self.plane.deinit(); | ||||
|  | @ -93,23 +128,10 @@ pub fn deinit(self: *Self, allocator: std.mem.Allocator) void { | |||
|     allocator.destroy(self); | ||||
| } | ||||
| 
 | ||||
| fn get_max_desc_len(self: *Self, hints_map: 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(); | ||||
| fn add_menu_command(self: *Self, command_name: []const u8, description: []const u8, hint: []const u8, menu: anytype) !void { | ||||
|     const label_len = description.len + hint.len; | ||||
|     var buf: [64]u8 = undefined; | ||||
|     { | ||||
|         var fis = std.io.fixedBufferStream(&buf); | ||||
|         const writer = fis.writer(); | ||||
|         const leader = if (hint.len > 0) "." else " "; | ||||
|  | @ -121,10 +143,19 @@ fn add_menu_command(self: *Self, comptime command_name: []const u8, menu: anytyp | |||
|             _ = try writer.write(leader); | ||||
|         try writer.print(" :{s}", .{hint}); | ||||
|         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); | ||||
|     } | ||||
| 
 | ||||
|     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 { | ||||
|     self.menu.update(); | ||||
| } | ||||
|  | @ -143,7 +174,33 @@ pub fn receive(_: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!bool { | |||
|     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_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) { | ||||
|  | @ -159,8 +216,9 @@ fn menu_on_render(_: *Self, button: *Button.State(*Menu.State(*Self)), theme: *c | |||
|         button.plane.home(); | ||||
|     } | ||||
|     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 sep = std.mem.indexOfScalar(u8, button.opts.label, ':') orelse button.opts.label.len; | ||||
| 
 | ||||
|     if (button.active) { | ||||
|         button.plane.set_style(style_label); | ||||
|     } else if (button.hover or selected) { | ||||
|  | @ -169,23 +227,36 @@ fn menu_on_render(_: *Self, button: *Button.State(*Menu.State(*Self)), theme: *c | |||
|         button.plane.set_style_bg_transparent(style_text); | ||||
|     } | ||||
|     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) { | ||||
|         button.plane.set_style(style_keybind); | ||||
|     } else { | ||||
|         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; | ||||
| } | ||||
| 
 | ||||
| fn menu_action(comptime command_name: []const u8) *const fn (_: **Menu.State(*Self), _: *Button.State(*Menu.State(*Self))) void { | ||||
|     return struct { | ||||
|         fn action(_: **Menu.State(*Self), _: *Button.State(*Menu.State(*Self))) void { | ||||
| fn menu_action(_: **Menu.State(*Self), button: *Button.State(*Menu.State(*Self))) void { | ||||
|     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 = ""; | ||||
| 
 | ||||
|     command.executeName(command_name, .{}) catch {}; | ||||
| } | ||||
|     }.action; | ||||
| } | ||||
| 
 | ||||
| pub fn render(self: *Self, theme: *const Widget.Theme) bool { | ||||
|     if (!std.mem.eql(u8, self.input_namespace, keybind.get_namespace())) | ||||
|  | @ -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; | ||||
| 
 | ||||
|     if (self.plane.dim_x() > 120 and self.plane.dim_y() > 22) { | ||||
|         self.plane.cursor_move_yx(2, 4) catch return false; | ||||
|         fonts.print_string_large(&self.plane, root.application_title, style_title) 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, self.home_style.title, style_title) catch return false; | ||||
| 
 | ||||
|         self.plane.cursor_move_yx(10, 8) catch return false; | ||||
|         fonts.print_string_medium(&self.plane, root.application_subtext, style_subtext) 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, 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) { | ||||
|         self.plane.cursor_move_yx(2, 4) catch return false; | ||||
|         fonts.print_string_medium(&self.plane, root.application_title, style_title) 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, self.home_style.title, style_title) catch return false; | ||||
| 
 | ||||
|         self.plane.set_style_bg_transparent(style_subtext); | ||||
|         self.plane.cursor_move_yx(7, 6) catch return false; | ||||
|         _ = self.plane.print(root.application_subtext, .{}) catch {}; | ||||
|         self.plane.cursor_move_yx(7, self.centerI(6, self.home_style.subtext.len)) catch return false; | ||||
|         _ = self.plane.print("{s}", .{self.home_style.subtext}) catch {}; | ||||
|         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 { | ||||
|         self.plane.set_style_bg_transparent(style_title); | ||||
|         self.plane.cursor_move_yx(1, 4) catch return false; | ||||
|         _ = self.plane.print(root.application_title, .{}) catch return false; | ||||
|         self.plane.cursor_move_yx(1, self.centerI(4, self.home_style.title.len)) catch return false; | ||||
|         _ = self.plane.print("{s}", .{self.home_style.title}) catch return false; | ||||
| 
 | ||||
|         self.plane.set_style_bg_transparent(style_subtext); | ||||
|         self.plane.cursor_move_yx(3, 6) catch return false; | ||||
|         _ = self.plane.print(root.application_subtext, .{}) catch {}; | ||||
|         self.plane.cursor_move_yx(3, self.centerI(6, self.home_style.subtext.len)) catch return false; | ||||
|         _ = self.plane.print("{s}", .{self.home_style.subtext}) catch {}; | ||||
|         self.plane.set_style(theme.editor); | ||||
| 
 | ||||
|         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); | ||||
| 
 | ||||
|  | @ -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 }); | ||||
| } | ||||
| 
 | ||||
| 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 { | ||||
|     self.plane.move_yx(@intCast(pos.y), @intCast(pos.x)) 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 = .{}; | ||||
| }; | ||||
| 
 | ||||
| const Fire = struct { | ||||
|     const px = "▀"; | ||||
| const Fire = @import("Fire.zig"); | ||||
| 
 | ||||
|     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; | ||||
| 
 | ||||
|     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; | ||||
| fn splice(in: []const u8) []const u8 { | ||||
|     var out: []const u8 = ""; | ||||
|     var it = std.mem.splitAny(u8, in, "\n "); | ||||
|     var first = true; | ||||
|     while (it.next()) |item| { | ||||
|         if (first) { | ||||
|             first = false; | ||||
|         } 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; | ||||
|             out = out ++ " "; | ||||
|         } | ||||
|                     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; | ||||
|         out = out ++ item; | ||||
|     } | ||||
|     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"); | ||||
| } | ||||
| 
 | ||||
| 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 { | ||||
|     pub const Target = Self; | ||||
|     const Ctx = command.Context; | ||||
|  | @ -414,27 +434,15 @@ const cmds = struct { | |||
|     pub const open_gui_config_meta: Meta = .{ .description = "Edit gui configuration" }; | ||||
| 
 | ||||
|     pub fn open_tabs_style_config(self: *Self, _: Ctx) Result { | ||||
|         const Style = @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(); | ||||
|         try self.open_style_config(@import("status/tabs.zig").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 { | ||||
|         const args = try ctx.args.clone(self.allocator); | ||||
|         defer self.allocator.free(args.buf); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue