Первая версия тулбара
This commit is contained in:
0
assets/icons/.gitkeep
Normal file
0
assets/icons/.gitkeep
Normal file
@@ -9,11 +9,13 @@ const Size_i = basic_models.Size_i;
|
||||
const Point2_f = @import("models/basic_models.zig").Point2_f;
|
||||
const Color = dvui.Color;
|
||||
|
||||
const Toolbar = @import("Toolbar.zig");
|
||||
const Canvas = @This();
|
||||
|
||||
allocator: std.mem.Allocator,
|
||||
document: *Document,
|
||||
render_engine: RenderEngine,
|
||||
toolbar: Toolbar,
|
||||
texture: ?dvui.Texture = null,
|
||||
pos: dvui.Point = dvui.Point{ .x = 400, .y = 400 },
|
||||
scroll: dvui.ScrollInfo = .{
|
||||
@@ -30,15 +32,17 @@ cursor_document_point: ?Point2_f = null,
|
||||
/// true — рисовать документ (render), false — пример (gradient/squares).
|
||||
draw_document: bool = true,
|
||||
|
||||
pub fn init(allocator: std.mem.Allocator, document: *Document, engine: RenderEngine) Canvas {
|
||||
pub fn init(allocator: std.mem.Allocator, document: *Document, engine: RenderEngine, toolbar: Toolbar) Canvas {
|
||||
return .{
|
||||
.allocator = allocator,
|
||||
.document = document,
|
||||
.render_engine = engine,
|
||||
.toolbar = toolbar,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Canvas) void {
|
||||
self.toolbar.deinit();
|
||||
if (self.texture) |texture| {
|
||||
dvui.Texture.destroyLater(texture);
|
||||
self.texture = null;
|
||||
|
||||
36
src/Toolbar.zig
Normal file
36
src/Toolbar.zig
Normal file
@@ -0,0 +1,36 @@
|
||||
//! Структура тулбара инструментов. Жизненный цикл совпадает с Canvas.
|
||||
|
||||
const tool_interface = @import("tool_interface.zig");
|
||||
|
||||
const Toolbar = @This();
|
||||
|
||||
/// Описание одного инструмента для тулбара.
|
||||
pub const ToolDescriptor = struct {
|
||||
name: []const u8,
|
||||
/// Иконка в формате TVG (байты).
|
||||
icon_tvg: []const u8,
|
||||
/// Реализация интерфейса инструмента (своя для каждого инструмента в tools/).
|
||||
implementation: *const tool_interface.Tool,
|
||||
};
|
||||
|
||||
/// Вертикальный тулбар инструментов.
|
||||
tools: []const ToolDescriptor,
|
||||
selected_index: usize,
|
||||
|
||||
pub fn init(tools_list: []const ToolDescriptor) Toolbar {
|
||||
return .{
|
||||
.tools = tools_list,
|
||||
.selected_index = 0,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(_: *Toolbar) void {}
|
||||
|
||||
pub fn currentDescriptor(self: *const Toolbar) ?*const ToolDescriptor {
|
||||
if (self.tools.len == 0) return null;
|
||||
return &self.tools[self.selected_index];
|
||||
}
|
||||
|
||||
pub fn select(self: *Toolbar, index: usize) void {
|
||||
if (index < self.tools.len) self.selected_index = index;
|
||||
}
|
||||
@@ -5,6 +5,8 @@ const RenderEngine = @import("render/RenderEngine.zig").RenderEngine;
|
||||
const Document = @import("models/Document.zig");
|
||||
const random_document = @import("models/random_document.zig");
|
||||
const basic_models = @import("models/basic_models.zig");
|
||||
const tools = @import("tools.zig");
|
||||
const Toolbar = @import("Toolbar.zig");
|
||||
|
||||
const WindowContext = @This();
|
||||
|
||||
@@ -17,7 +19,12 @@ pub const OpenDocument = struct {
|
||||
const default_size = basic_models.Size_f{ .w = 800, .h = 600 };
|
||||
self.document = Document.init(allocator, default_size);
|
||||
self.cpu_render = CpuRenderEngine.init(allocator, .Squares);
|
||||
self.canvas = Canvas.init(allocator, &self.document, (&self.cpu_render).renderEngine());
|
||||
self.canvas = Canvas.init(
|
||||
allocator,
|
||||
&self.document,
|
||||
(&self.cpu_render).renderEngine(),
|
||||
Toolbar.init(&tools.default_tools),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn deinit(self: *OpenDocument) void {
|
||||
|
||||
3
src/icons.zig
Normal file
3
src/icons.zig
Normal file
@@ -0,0 +1,3 @@
|
||||
const dvui = @import("dvui");
|
||||
|
||||
pub const line = dvui.entypo.line_graph;
|
||||
14
src/tool_interface.zig
Normal file
14
src/tool_interface.zig
Normal file
@@ -0,0 +1,14 @@
|
||||
//! Общий интерфейс инструмента. Реализации живут в каталоге tools/.
|
||||
|
||||
const Point2_f = @import("models/basic_models.zig").Point2_f;
|
||||
|
||||
/// Контекст вызова: холст и точка в координатах документа.
|
||||
pub const ToolContext = struct {
|
||||
canvas: *anyopaque,
|
||||
document_point: Point2_f,
|
||||
};
|
||||
|
||||
/// Интерфейс инструмента: один метод — клик по холсту в позиции курсора.
|
||||
pub const Tool = struct {
|
||||
onClick: *const fn (*const ToolContext) void,
|
||||
};
|
||||
13
src/tools.zig
Normal file
13
src/tools.zig
Normal file
@@ -0,0 +1,13 @@
|
||||
//! Список инструментов по умолчанию для тулбара. Реализации — в каталоге tools/.
|
||||
|
||||
const Toolbar = @import("Toolbar.zig");
|
||||
const line = @import("tools/line.zig");
|
||||
const icons = @import("icons.zig");
|
||||
|
||||
pub const default_tools = [_]Toolbar.ToolDescriptor{
|
||||
.{
|
||||
.name = "Line",
|
||||
.icon_tvg = icons.line,
|
||||
.implementation = &line.tool,
|
||||
},
|
||||
};
|
||||
21
src/tools/line.zig
Normal file
21
src/tools/line.zig
Normal file
@@ -0,0 +1,21 @@
|
||||
//! Инструмент «Линия»: создаёт линию в позиции клика.
|
||||
|
||||
const Canvas = @import("../Canvas.zig");
|
||||
const tool_interface = @import("../tool_interface.zig");
|
||||
const shape = @import("../models/shape/shape.zig");
|
||||
|
||||
fn onClick(ctx: *const tool_interface.ToolContext) void {
|
||||
const canvas: *Canvas = @alignCast(@ptrCast(ctx.canvas));
|
||||
var obj = shape.createObject(canvas.document.allocator, .line) catch return;
|
||||
obj.setProperty(canvas.document.allocator, .{ .data = .{ .position = ctx.document_point } }) catch {
|
||||
obj.deinit(canvas.document.allocator);
|
||||
return;
|
||||
};
|
||||
canvas.document.addObject(obj) catch {
|
||||
obj.deinit(canvas.document.allocator);
|
||||
return;
|
||||
};
|
||||
canvas.requestRedraw();
|
||||
}
|
||||
|
||||
pub const tool = tool_interface.Tool{ .onClick = onClick };
|
||||
@@ -3,6 +3,7 @@ const dvui = @import("dvui");
|
||||
const dvui_ext = @import("dvui_ext.zig");
|
||||
const Canvas = @import("../Canvas.zig");
|
||||
const Rect_i = @import("../models/basic_models.zig").Rect_i;
|
||||
const tool_interface = @import("../tool_interface.zig");
|
||||
|
||||
pub fn canvasView(canvas: *Canvas, content_rect_scale: dvui.RectScale) void {
|
||||
var textured = dvui_ext.texturedBox(content_rect_scale, dvui.Rect.all(20));
|
||||
@@ -25,6 +26,7 @@ pub fn canvasView(canvas: *Canvas, content_rect_scale: dvui.RectScale) void {
|
||||
}
|
||||
scroll.deinit();
|
||||
|
||||
drawToolbar(canvas);
|
||||
dvui.label(@src(), "Canvas", .{}, .{ .gravity_x = 0.5, .gravity_y = 0.0 });
|
||||
}
|
||||
overlay.deinit();
|
||||
@@ -159,10 +161,49 @@ fn handleCanvasMouse(canvas: *Canvas, scroll: anytype) void {
|
||||
};
|
||||
const doc_pt = canvas.contentPointToDocument(content_pt, natural_scale);
|
||||
canvas.cursor_document_point = if (canvas.isContentPointOnDocument(content_pt, natural_scale)) doc_pt else null;
|
||||
if (canvas.cursor_document_point) |point|
|
||||
std.debug.print("cursor_document_point: {}\n", .{point});
|
||||
if (canvas.cursor_document_point) |point| {
|
||||
if (canvas.toolbar.currentDescriptor()) |desc| {
|
||||
var ctx = tool_interface.ToolContext{
|
||||
.canvas = canvas,
|
||||
.document_point = point,
|
||||
};
|
||||
desc.implementation.onClick(&ctx);
|
||||
}
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn drawToolbar(canvas: *Canvas) void {
|
||||
const tools_list = canvas.toolbar.tools;
|
||||
if (tools_list.len == 0) return;
|
||||
|
||||
var bar = dvui.box(
|
||||
@src(),
|
||||
.{ .dir = .vertical },
|
||||
.{
|
||||
.gravity_x = 0.0,
|
||||
.gravity_y = 0.0,
|
||||
.margin = dvui.Rect{ .x = 8, .y = 8 },
|
||||
.padding = dvui.Rect.all(6),
|
||||
.corner_radius = dvui.Rect.all(8),
|
||||
.background = true,
|
||||
.color_fill = dvui.Color.black.opacity(0.2),
|
||||
},
|
||||
);
|
||||
{
|
||||
for (tools_list, 0..) |*tool_desc, i| {
|
||||
const is_selected = (canvas.toolbar.selected_index == i);
|
||||
const opts: dvui.Options = .{
|
||||
.id_extra = i,
|
||||
.color_fill = if (is_selected) dvui.Color.transparent else undefined,
|
||||
};
|
||||
if (dvui.buttonIcon(@src(), tool_desc.name, tool_desc.icon_tvg, .{}, .{}, opts)) {
|
||||
canvas.toolbar.select(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
bar.deinit();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user