Класные таббары

This commit is contained in:
2026-02-27 01:07:00 +03:00
parent 98c93a3780
commit 50821c8046
3 changed files with 99 additions and 7 deletions

View File

@@ -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;

View File

@@ -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,

View File

@@ -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});
};