From 50821c8046eeee50e29cab1927bdd4df24d5a68e Mon Sep 17 00:00:00 2001 From: Roman Pytkov Date: Fri, 27 Feb 2026 01:07:00 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9A=D0=BB=D0=B0=D1=81=D0=BD=D1=8B=D0=B5=20?= =?UTF-8?q?=D1=82=D0=B0=D0=B1=D0=B1=D0=B0=D1=80=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/icons.zig | 2 + src/ui/left_panel.zig | 2 +- src/ui/tab_bar.zig | 102 +++++++++++++++++++++++++++++++++++++++--- 3 files changed, 99 insertions(+), 7 deletions(-) diff --git a/src/icons.zig b/src/icons.zig index 1f0f5e9..144b35c 100644 --- a/src/icons.zig +++ b/src/icons.zig @@ -5,3 +5,5 @@ pub const ellipse = dvui.entypo.circle; pub const arc = dvui.entypo.loop; pub const broken = dvui.entypo.flow_line; pub const trash = dvui.entypo.trash; +pub const cross = dvui.entypo.cross; +pub const plus = dvui.entypo.plus; diff --git a/src/ui/left_panel.zig b/src/ui/left_panel.zig index 50569b5..f941b31 100644 --- a/src/ui/left_panel.zig +++ b/src/ui/left_panel.zig @@ -77,7 +77,7 @@ fn objectTreeRow(open_doc: *WindowContext.OpenDocument, obj: *Object, depth: u32 if (hovered) { const delete_opts: dvui.Options = .{ .id_extra = row_id +% 1, - .margin = dvui.Rect{ .x = 4 }, + .margin = dvui.Rect{ .x = 4, .w = 6 }, .padding = dvui.Rect.all(2), .gravity_y = 0.5, .gravity_x = 1.0, diff --git a/src/ui/tab_bar.zig b/src/ui/tab_bar.zig index 59c5501..9d45bf4 100644 --- a/src/ui/tab_bar.zig +++ b/src/ui/tab_bar.zig @@ -1,22 +1,112 @@ const std = @import("std"); const dvui = @import("dvui"); +const icons = @import("../icons.zig"); const WindowContext = @import("../WindowContext.zig"); +const DocCallback = union(enum) { + select: usize, + close: usize, +}; + +fn documentTab(ctx: *WindowContext, index: usize, callback: *?DocCallback) void { + const row_id: usize = index; + const is_selected = if (ctx.active_document_index) |active| active == index else false; + const focus_color = dvui.themeGet().focus; + + var row = dvui.box( + @src(), + .{ .dir = .horizontal }, + .{ + .id_extra = row_id, + .expand = .none, + .gravity_y = 0.5, + }, + ); + { + var hovered: bool = false; + var select_row: bool = false; + const row_data = row.data(); + + // Ручная обработка hover/click по строке без пометки события как handled, + // чтобы кнопка закрытия могла нормально получать свои события. + for (dvui.events()) |*e| { + switch (e.evt) { + .mouse => |*mouse| { + if (!dvui.eventMatchSimple(e, row_data)) continue; + hovered = true; + if (mouse.action == .press and mouse.button == .left) { + select_row = true; + } + }, + else => {}, + } + } + + var overlay = dvui.overlay(@src(), .{ + .margin = dvui.Rect{ .x = 4, .w = 4 }, + .padding = dvui.Rect{ .x = 12, .y = 0, .w = 0, .h = 0 }, + .background = is_selected or hovered, + .color_fill = if (is_selected) focus_color.opacity(0.35) else if (hovered) focus_color.opacity(0.18) else null, + .corner_radius = dvui.Rect.all(4), + }); + { + var buf: [32]u8 = undefined; + const label = std.fmt.bufPrint(&buf, "Doc {d}", .{index + 1}) catch "Doc"; + dvui.labelNoFmt(@src(), label, .{}, .{ + .gravity_x = 0.5, + .gravity_y = 0.5, + .margin = .{ .w = 24 }, + }); + + if (hovered) { + if (dvui.buttonIcon(@src(), "Close", icons.cross, .{}, .{}, .{ + .id_extra = row_id +% 1, + .margin = dvui.Rect{ .x = 8, .w = 6 }, + .padding = dvui.Rect.all(2), + .gravity_x = 1, + .gravity_y = 0.5, + })) { + callback.* = .{ .close = index }; + } + } + } + overlay.deinit(); + + if (select_row) { + callback.* = .{ .select = index }; + } + } + row.deinit(); +} + pub fn tabBar(ctx: *WindowContext) void { var bar = dvui.box( @src(), .{ .dir = .horizontal }, - .{ .expand = .horizontal, .min_size_content = .{ .h = 32 }, .background = true, .padding = dvui.Rect.all(4) }, + .{ + .expand = .horizontal, + .background = true, + .padding = .{ + .x = 12, + .w = 12, + }, + }, ); { + var callback: ?DocCallback = null; for (ctx.documents.items, 0..) |_, i| { - var buf: [32]u8 = undefined; - const label = std.fmt.bufPrint(&buf, "Doc {d}", .{i + 1}) catch "Doc"; - if (dvui.button(@src(), label, .{}, .{ .id_extra = i })) { - ctx.setActiveDocument(i); + documentTab(ctx, i, &callback); + } + if (callback) |action| { + switch (action) { + .select => |index| ctx.setActiveDocument(index), + .close => |index| ctx.closeDocument(index), } } - if (dvui.button(@src(), "+", .{}, .{})) { + + if (dvui.buttonIcon(@src(), "Create", icons.plus, .{}, .{}, .{ + .gravity_y = 0, + })) { ctx.addNewDocument() catch |err| { std.debug.print("addNewDocument error: {}\n", .{err}); };