Compare commits
4 Commits
fc303ba553
...
89f41c9d78
Author | SHA1 | Date | |
---|---|---|---|
89f41c9d78 | |||
8d53a185a4 | |||
ca3d26a18d | |||
a339d2a392 |
@ -1,7 +1,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
/// A data type to store connections of nodes in directional-graph.
|
/// A data type to store connections of nodes in directional-graph.
|
||||||
pub fn Digraph(comptime T: type, comptime lessThanFn: LessThanFunc(T)) type {
|
pub fn Container(comptime T: type, comptime lessThanFn: LessThanFunc(T)) type {
|
||||||
return struct {
|
return struct {
|
||||||
///
|
///
|
||||||
pub const Node = T;
|
pub const Node = T;
|
||||||
@ -108,16 +108,16 @@ pub fn Digraph(comptime T: type, comptime lessThanFn: LessThanFunc(T)) type {
|
|||||||
|
|
||||||
var begin: usize = undefined;
|
var begin: usize = undefined;
|
||||||
var end : usize = undefined;
|
var end : usize = undefined;
|
||||||
if (baseFrom < from) {
|
if (lessThanFn(baseFrom, from)) {
|
||||||
begin = baseIdx;
|
begin = baseIdx;
|
||||||
while ((begin < n) and (self.map.items[begin].from < from)) { begin += 1; }
|
while ((begin < n) and lessThanFn(self.map.items[begin].from, from)) { begin += 1; }
|
||||||
|
|
||||||
end = begin;
|
end = begin;
|
||||||
while ((end < n) and (self.map.items[end].from == from)) { end += 1; }
|
while ((end < n) and (self.map.items[end].from == from)) { end += 1; }
|
||||||
|
|
||||||
} else if (baseFrom > from) {
|
} else if (lessThanFn(from, baseFrom)) {
|
||||||
end = baseIdx;
|
end = baseIdx;
|
||||||
while ((end > 0) and (self.map.items[end-1].from > from)) { end -= 1; }
|
while ((end > 0) and lessThanFn(from, self.map.items[end-1].from)) { end -= 1; }
|
||||||
|
|
||||||
begin = end;
|
begin = end;
|
||||||
while ((begin > 0) and (self.map.items[begin-1].from == from)) { begin -= 1; }
|
while ((begin > 0) and (self.map.items[begin-1].from == from)) { begin -= 1; }
|
||||||
@ -144,9 +144,9 @@ pub fn Digraph(comptime T: type, comptime lessThanFn: LessThanFunc(T)) type {
|
|||||||
idx = (left + right) / 2;
|
idx = (left + right) / 2;
|
||||||
|
|
||||||
const target = self.map.items[idx].from;
|
const target = self.map.items[idx].from;
|
||||||
if (target < from) {
|
if (lessThanFn(target, from)) {
|
||||||
left = idx + 1;
|
left = idx + 1;
|
||||||
} else if (target > from) {
|
} else if (lessThanFn(from, target)) {
|
||||||
right = idx -| 1;
|
right = idx -| 1;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
@ -160,7 +160,7 @@ pub fn Digraph(comptime T: type, comptime lessThanFn: LessThanFunc(T)) type {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A type of comparator function for the type T, which is to be passed as an argument of `Digraph()`.
|
/// A type of comparator function for the type T, which is to be passed as an argument of `Container()`.
|
||||||
pub fn LessThanFunc(comptime T: type) type {
|
pub fn LessThanFunc(comptime T: type) type {
|
||||||
return fn (lhs: T, rhs: T) bool;
|
return fn (lhs: T, rhs: T) bool;
|
||||||
}
|
}
|
||||||
@ -179,15 +179,15 @@ pub fn lessThanFuncFor(comptime T: type) LessThanFunc(T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "compile check for various types" {
|
test "compile check for various types" {
|
||||||
_ = Digraph(u8, lessThanFuncFor(u8));
|
_ = Container(u8, lessThanFuncFor(u8));
|
||||||
_ = Digraph(u16, lessThanFuncFor(u16));
|
_ = Container(u16, lessThanFuncFor(u16));
|
||||||
_ = Digraph(i8, lessThanFuncFor(i8));
|
_ = Container(i8, lessThanFuncFor(i8));
|
||||||
_ = Digraph(i16, lessThanFuncFor(i16));
|
_ = Container(i16, lessThanFuncFor(i16));
|
||||||
_ = Digraph(*i8, lessThanFuncFor(*i8));
|
_ = Container(*i8, lessThanFuncFor(*i8));
|
||||||
_ = Digraph(*anyopaque, lessThanFuncFor(*anyopaque));
|
_ = Container(*anyopaque, lessThanFuncFor(*anyopaque));
|
||||||
}
|
}
|
||||||
test "check if connected" {
|
test "check if connected" {
|
||||||
const Sut = Digraph(u8, lessThanFuncFor(u8));
|
const Sut = Container(u8, lessThanFuncFor(u8));
|
||||||
|
|
||||||
const map = [_]Sut.Conn {
|
const map = [_]Sut.Conn {
|
||||||
.{ .from = 3, .to = 0, },
|
.{ .from = 3, .to = 0, },
|
||||||
@ -214,7 +214,7 @@ test "check if connected" {
|
|||||||
try std.testing.expect(!sut.isConnected(2, 1));
|
try std.testing.expect(!sut.isConnected(2, 1));
|
||||||
}
|
}
|
||||||
test "make new connection" {
|
test "make new connection" {
|
||||||
const Sut = Digraph(u8, lessThanFuncFor(u8));
|
const Sut = Container(u8, lessThanFuncFor(u8));
|
||||||
|
|
||||||
var sut = try Sut.init(std.testing.allocator, &.{});
|
var sut = try Sut.init(std.testing.allocator, &.{});
|
||||||
defer sut.deinit();
|
defer sut.deinit();
|
||||||
@ -230,7 +230,7 @@ test "make new connection" {
|
|||||||
try std.testing.expect(!sut.isConnected(1, 3));
|
try std.testing.expect(!sut.isConnected(1, 3));
|
||||||
}
|
}
|
||||||
test "making an existing connection fails" {
|
test "making an existing connection fails" {
|
||||||
const Sut = Digraph(u8, lessThanFuncFor(u8));
|
const Sut = Container(u8, lessThanFuncFor(u8));
|
||||||
|
|
||||||
const map = [_]Sut.Conn {
|
const map = [_]Sut.Conn {
|
||||||
.{ .from = 0, .to = 1, },
|
.{ .from = 0, .to = 1, },
|
||||||
@ -242,7 +242,7 @@ test "making an existing connection fails" {
|
|||||||
try std.testing.expectError(Sut.Error.AlreadyConnected, sut.connect(0, 1));
|
try std.testing.expectError(Sut.Error.AlreadyConnected, sut.connect(0, 1));
|
||||||
}
|
}
|
||||||
test "disconnect an existing connection" {
|
test "disconnect an existing connection" {
|
||||||
const Sut = Digraph(u8, lessThanFuncFor(u8));
|
const Sut = Container(u8, lessThanFuncFor(u8));
|
||||||
|
|
||||||
const map = [_]Sut.Conn {
|
const map = [_]Sut.Conn {
|
||||||
.{ .from = 0, .to = 1, },
|
.{ .from = 0, .to = 1, },
|
||||||
@ -258,7 +258,7 @@ test "disconnect an existing connection" {
|
|||||||
try std.testing.expect(!sut.isConnected(2, 3));
|
try std.testing.expect(!sut.isConnected(2, 3));
|
||||||
}
|
}
|
||||||
test "disconnecting a missing connection fails" {
|
test "disconnecting a missing connection fails" {
|
||||||
const Sut = Digraph(u8, lessThanFuncFor(u8));
|
const Sut = Container(u8, lessThanFuncFor(u8));
|
||||||
|
|
||||||
var sut = try Sut.init(std.testing.allocator, &.{});
|
var sut = try Sut.init(std.testing.allocator, &.{});
|
||||||
defer sut.deinit();
|
defer sut.deinit();
|
||||||
@ -267,7 +267,7 @@ test "disconnecting a missing connection fails" {
|
|||||||
try std.testing.expectError(Sut.Error.NotConnected, sut.disconnect(1, 0));
|
try std.testing.expectError(Sut.Error.NotConnected, sut.disconnect(1, 0));
|
||||||
}
|
}
|
||||||
test "chaotic operation" {
|
test "chaotic operation" {
|
||||||
const Sut = Digraph(u16, lessThanFuncFor(u16));
|
const Sut = Container(u16, lessThanFuncFor(u16));
|
||||||
|
|
||||||
var sut = try Sut.init(std.testing.allocator, &.{});
|
var sut = try Sut.init(std.testing.allocator, &.{});
|
||||||
defer sut.deinit();
|
defer sut.deinit();
|
||||||
|
71
src/hncore/Merged.zig
Normal file
71
src/hncore/Merged.zig
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
/// Returns a type having fields that type A and type B have.
|
||||||
|
/// Fields from B are more preferred than from A in case that field names are duplicated.
|
||||||
|
pub fn Merged(comptime A: type, comptime B: type) type {
|
||||||
|
const at = @typeInfo(A).@"struct";
|
||||||
|
const bt = @typeInfo(B).@"struct";
|
||||||
|
|
||||||
|
return @Type(.{
|
||||||
|
.@"struct" = .{
|
||||||
|
.layout = .auto,
|
||||||
|
.fields = mergeFields(at.fields, bt.fields),
|
||||||
|
.is_tuple = false,
|
||||||
|
.decls = &.{},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
fn mergeFields(
|
||||||
|
comptime a: []const std.builtin.Type.StructField,
|
||||||
|
comptime b: []const std.builtin.Type.StructField) []std.builtin.Type.StructField {
|
||||||
|
var ret: [a.len+b.len]std.builtin.Type.StructField = undefined;
|
||||||
|
var len: usize = 0;
|
||||||
|
|
||||||
|
inline for (b) |f| {
|
||||||
|
ret[len] = f;
|
||||||
|
ret[len].is_comptime = false;
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
inline for (a) |f| {
|
||||||
|
inline for (b) |fb| {
|
||||||
|
if (std.mem.eql(u8, f.name, fb.name)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret[len] = f;
|
||||||
|
ret[len].is_comptime = false;
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret[0..len];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Same to `Merged(@TypeOf(a), @TypeOf(b))` but returns a merged value, not type.
|
||||||
|
pub fn merge(a: anytype, b: anytype) Merged(@TypeOf(a), @TypeOf(b)) {
|
||||||
|
var ret: Merged(@TypeOf(a), @TypeOf(b)) = undefined;
|
||||||
|
|
||||||
|
const af = @typeInfo(@TypeOf(a)).@"struct".fields;
|
||||||
|
const bf = @typeInfo(@TypeOf(b)).@"struct".fields;
|
||||||
|
|
||||||
|
inline for (bf) |f| {
|
||||||
|
@field(ret, f.name) = @field(b, f.name);
|
||||||
|
}
|
||||||
|
inline for (af) |f| {
|
||||||
|
inline for (bf) |fb| {
|
||||||
|
if (std.mem.eql(u8, f.name, fb.name)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
@field(ret, f.name) = @field(a, f.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
test "merging 2 structs" {
|
||||||
|
const merged = merge(.{.a = 0, .b = 1, .c = 2,}, .{.b = 44, .d = 53,});
|
||||||
|
try std.testing.expect(merged.a == 0);
|
||||||
|
try std.testing.expect(merged.b == 44);
|
||||||
|
try std.testing.expect(merged.c == 2);
|
||||||
|
try std.testing.expect(merged.d == 53);
|
||||||
|
}
|
76
src/hncore/Mindmap.zig
Normal file
76
src/hncore/Mindmap.zig
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const Digraph = @import("./Digraph.zig");
|
||||||
|
|
||||||
|
pub const Node = @import("./Node.zig");
|
||||||
|
pub const NodeList = std.ArrayList(*Node);
|
||||||
|
pub const NodeDigraph = Digraph.Container(*const Node, Digraph.lessThanFuncFor(*const Node));
|
||||||
|
|
||||||
|
///
|
||||||
|
alloc: std.mem.Allocator,
|
||||||
|
|
||||||
|
///
|
||||||
|
nodes: NodeList,
|
||||||
|
|
||||||
|
///
|
||||||
|
digraph: NodeDigraph,
|
||||||
|
|
||||||
|
///
|
||||||
|
root: *Node,
|
||||||
|
|
||||||
|
///
|
||||||
|
pub fn init(alloc: std.mem.Allocator) !@This() {
|
||||||
|
var nodes = NodeList.init(alloc);
|
||||||
|
errdefer nodes.deinit();
|
||||||
|
|
||||||
|
var digraph = try NodeDigraph.init(alloc, &.{});
|
||||||
|
errdefer digraph.deinit();
|
||||||
|
|
||||||
|
var root = try alloc.create(Node);
|
||||||
|
errdefer alloc.destroy(root);
|
||||||
|
|
||||||
|
root.* = try Node.init(alloc, 0, "helloworld");
|
||||||
|
errdefer root.deinit(alloc);
|
||||||
|
|
||||||
|
try nodes.append(root);
|
||||||
|
|
||||||
|
var node1 = try alloc.create(Node);
|
||||||
|
errdefer alloc.destroy(node1);
|
||||||
|
node1.* = try Node.init(alloc, 1, "node1");
|
||||||
|
errdefer node1.deinit(alloc);
|
||||||
|
try nodes.append(node1);
|
||||||
|
try digraph.connect(root, node1);
|
||||||
|
|
||||||
|
var node2 = try alloc.create(Node);
|
||||||
|
errdefer alloc.destroy(node2);
|
||||||
|
node2.* = try Node.init(alloc, 2, "node1");
|
||||||
|
errdefer node2.deinit(alloc);
|
||||||
|
try nodes.append(node2);
|
||||||
|
try digraph.connect(root, node2);
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.alloc = alloc,
|
||||||
|
.nodes = nodes,
|
||||||
|
.digraph = digraph,
|
||||||
|
.root = root,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
///
|
||||||
|
pub fn deinit(self: *@This()) void {
|
||||||
|
for (self.nodes.items) |node| {
|
||||||
|
node.deinit(self.alloc);
|
||||||
|
self.alloc.destroy(node);
|
||||||
|
}
|
||||||
|
self.digraph.deinit();
|
||||||
|
self.nodes.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
pub fn serialize(self: *const @This(), writer: anytype) !void {
|
||||||
|
_ = self;
|
||||||
|
_ = writer;
|
||||||
|
}
|
||||||
|
///
|
||||||
|
pub fn deserialize(reader: anytype) !@This() {
|
||||||
|
_ = reader;
|
||||||
|
}
|
@ -1,29 +1,27 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
///
|
///
|
||||||
pub const Node = struct {
|
/// unique and immutable integer
|
||||||
/// unique and immutable integer
|
id: usize,
|
||||||
id: usize,
|
|
||||||
|
|
||||||
/// summary text of this node
|
/// summary text of this node
|
||||||
summary: []const u8,
|
summary: []const u8,
|
||||||
|
|
||||||
///
|
///
|
||||||
pub fn init(alloc: std.mem.Allocator, id: usize, summary: []const u8) !Node {
|
pub fn init(alloc: std.mem.Allocator, id: usize, summary: []const u8) !@This() {
|
||||||
return .{
|
return .{
|
||||||
.id = id,
|
.id = id,
|
||||||
.summary = try alloc.dupe(u8, summary),
|
.summary = try alloc.dupe(u8, summary),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
/// pass the same allocator as init() call
|
/// pass the same allocator as init() call
|
||||||
pub fn deinit(self: *@This(), alloc: std.mem.Allocator) void {
|
pub fn deinit(self: *@This(), alloc: std.mem.Allocator) void {
|
||||||
alloc.free(self.summary);
|
alloc.free(self.summary);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
test "serialize" {
|
test "serialize" {
|
||||||
const alloc = std.testing.allocator;
|
const alloc = std.testing.allocator;
|
||||||
var node = try Node.init(alloc, 0, "helloworld");
|
var node = try init(alloc, 0, "helloworld");
|
||||||
defer node.deinit(alloc);
|
defer node.deinit(alloc);
|
||||||
|
|
||||||
var json = std.ArrayList(u8).init(alloc);
|
var json = std.ArrayList(u8).init(alloc);
|
||||||
|
16
src/hncore/Project.zig
Normal file
16
src/hncore/Project.zig
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const Mindmap = @import("./Mindmap.zig");
|
||||||
|
|
||||||
|
///
|
||||||
|
mindmap: Mindmap,
|
||||||
|
|
||||||
|
///
|
||||||
|
pub fn init(alloc: std.mem.Allocator) !@This() {
|
||||||
|
return .{
|
||||||
|
.mindmap = try .init(alloc),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
pub fn deinit(self: *@This()) void {
|
||||||
|
self.mindmap.deinit();
|
||||||
|
}
|
@ -1,6 +1,8 @@
|
|||||||
pub const Digraph = @import("./Digraph.zig").Digraph;
|
pub const Mindmap = @import("./Mindmap.zig");
|
||||||
pub const Node = @import("./Node.zig").Node;
|
pub const Node = @import("./Node.zig");
|
||||||
pub const Store = @import("./Store.zig").Store;
|
pub const Project = @import("./Project.zig");
|
||||||
|
|
||||||
|
pub const merge = @import("./Merged.zig").merge;
|
||||||
|
|
||||||
test {
|
test {
|
||||||
@import("std").testing.refAllDecls(@This());
|
@import("std").testing.refAllDecls(@This());
|
||||||
|
@ -2,23 +2,32 @@ const std = @import("std");
|
|||||||
const dvui = @import("dvui");
|
const dvui = @import("dvui");
|
||||||
const hncore = @import("hncore");
|
const hncore = @import("hncore");
|
||||||
|
|
||||||
|
const ui = @import("./ui.zig");
|
||||||
|
|
||||||
|
///
|
||||||
pub const App = struct {
|
pub const App = struct {
|
||||||
|
///
|
||||||
|
project: hncore.Project,
|
||||||
|
|
||||||
|
///
|
||||||
pub fn init(alloc: std.mem.Allocator) !App {
|
pub fn init(alloc: std.mem.Allocator) !App {
|
||||||
_ = alloc;
|
|
||||||
return App {
|
return App {
|
||||||
|
.project = try .init(alloc),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
///
|
||||||
pub fn deinit(self: *App) void {
|
pub fn deinit(self: *App) void {
|
||||||
_ = self;
|
self.project.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
pub fn gui(self: *App) !void {
|
pub fn gui(self: *App) !void {
|
||||||
|
try self.guiMenu();
|
||||||
|
try self.guiMain();
|
||||||
|
}
|
||||||
|
fn guiMenu(self: *@This()) !void {
|
||||||
_ = self;
|
_ = self;
|
||||||
|
|
||||||
try gui_menu();
|
|
||||||
try gui_main();
|
|
||||||
}
|
|
||||||
fn gui_menu() !void {
|
|
||||||
var root = try dvui.menu(@src(), .horizontal, .{ .background = true, .expand = .horizontal });
|
var root = try dvui.menu(@src(), .horizontal, .{ .background = true, .expand = .horizontal });
|
||||||
defer root.deinit();
|
defer root.deinit();
|
||||||
|
|
||||||
@ -31,17 +40,15 @@ pub const App = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn gui_main() !void {
|
fn guiMain(self: *@This()) !void {
|
||||||
var box = try dvui.scrollArea(@src(), .{}, .{
|
var overlay = try dvui.overlay(@src(), .{
|
||||||
.expand = .both,
|
.expand = .both,
|
||||||
.color_fill = .{ .name = .fill_window },
|
|
||||||
.padding = dvui.Rect.all(8),
|
.padding = dvui.Rect.all(8),
|
||||||
|
.color_fill = .{ .name = .fill_window },
|
||||||
|
.background = true,
|
||||||
});
|
});
|
||||||
defer box.deinit();
|
defer overlay.deinit();
|
||||||
|
|
||||||
if (try dvui.button(@src(), "Zoom In", .{}, .{})) {
|
try ui.manipulator(self.project.mindmap.root, &self.project.mindmap.digraph);
|
||||||
}
|
|
||||||
if (try dvui.button(@src(), "Zoom In", .{}, .{})) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -23,6 +23,7 @@ pub fn main() !void {
|
|||||||
defer win.deinit();
|
defer win.deinit();
|
||||||
|
|
||||||
var app = try App.init(gpa.allocator());
|
var app = try App.init(gpa.allocator());
|
||||||
|
defer app.deinit();
|
||||||
while (true) {
|
while (true) {
|
||||||
try win.begin(
|
try win.begin(
|
||||||
win.beginWait(backend.hasEvent()),
|
win.beginWait(backend.hasEvent()),
|
||||||
|
53
src/hnet/ui.zig
Normal file
53
src/hnet/ui.zig
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const dvui = @import("dvui");
|
||||||
|
const hncore = @import("hncore");
|
||||||
|
|
||||||
|
///
|
||||||
|
pub fn manipulator(root: *const hncore.Mindmap.Node, digraph: *const hncore.Mindmap.NodeDigraph) !void {
|
||||||
|
var overlay = try dvui.overlay(@src(), .{
|
||||||
|
.expand = .both,
|
||||||
|
});
|
||||||
|
defer overlay.deinit();
|
||||||
|
|
||||||
|
_ = try nodeTreeInManipulator(.{ .x = 100, .y = 100, }, root, digraph);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
pub fn nodeTreeInManipulator(base: dvui.Point, node: *const hncore.Mindmap.Node, digraph: *const hncore.Mindmap.NodeDigraph) !dvui.Rect {
|
||||||
|
const size = try nodeInManipulator(base, node);
|
||||||
|
const childrenRect = nodeChildrenInManipulator(
|
||||||
|
.{ .x = base.x + size.x, .y = base.y, }, node, digraph);
|
||||||
|
return .{
|
||||||
|
.x = base.x,
|
||||||
|
.y = base.y,
|
||||||
|
.w = childrenRect.w + size.w,
|
||||||
|
.h = @max(childrenRect.h, size.h),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
pub fn nodeInManipulator(base: dvui.Point, node: *const hncore.Mindmap.Node) !dvui.Rect {
|
||||||
|
var box = try dvui.box(@src(), .vertical, .{
|
||||||
|
.id_extra = node.id,
|
||||||
|
.border = .all(1),
|
||||||
|
.rect = .{ .x = base.x, .y = base.y, .w = 100, .h = 20, },
|
||||||
|
});
|
||||||
|
defer box.deinit();
|
||||||
|
return box.wd.borderRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
pub fn nodeChildrenInManipulator(base: dvui.Point, node: *const hncore.Mindmap.Node, digraph: *const hncore.Mindmap.NodeDigraph) dvui.Rect {
|
||||||
|
const parentMargin = 16;
|
||||||
|
const siblingMargin = 8;
|
||||||
|
|
||||||
|
var childDepth : f32 = 0;
|
||||||
|
var childOffset: f32 = 0;
|
||||||
|
for (digraph.getChildrenOf(node)) |conn| {
|
||||||
|
const childRect = nodeTreeInManipulator(
|
||||||
|
.{ .x = base.x + parentMargin, .y = base.y + childOffset, }, conn.to, digraph) catch unreachable;
|
||||||
|
childOffset += childRect.h + siblingMargin;
|
||||||
|
childDepth = @max(childRect.w, childDepth);
|
||||||
|
}
|
||||||
|
return .{ .x = base.x, .y = base.y, .w = childDepth, .h = childOffset, };
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user