implement hovering over elements
parent
54d04f4a2b
commit
91f896c5ef
205
src/main.zig
205
src/main.zig
|
@ -132,7 +132,10 @@ pub fn main() !void {
|
||||||
|
|
||||||
const handler = &drawCardHandler;
|
const handler = &drawCardHandler;
|
||||||
|
|
||||||
var selection: usize = 0;
|
var actions = std.ArrayList(Action).init(gpa.allocator());
|
||||||
|
defer actions.deinit();
|
||||||
|
|
||||||
|
var hovered_action: ?Action = null;
|
||||||
|
|
||||||
while (seizer.backend.glfw.c.glfwWindowShouldClose(window) != seizer.backend.glfw.c.GLFW_TRUE) {
|
while (seizer.backend.glfw.c.glfwWindowShouldClose(window) != seizer.backend.glfw.c.GLFW_TRUE) {
|
||||||
input_state = .{
|
input_state = .{
|
||||||
|
@ -143,11 +146,40 @@ pub fn main() !void {
|
||||||
};
|
};
|
||||||
seizer.backend.glfw.c.glfwPollEvents();
|
seizer.backend.glfw.c.glfwPollEvents();
|
||||||
|
|
||||||
if (input_state.left) {
|
if (hovered_action == null and actions.items.len > 0) {
|
||||||
if (selection == 0) selection = game_state.hands[0].items.len;
|
hovered_action = actions.items[0];
|
||||||
selection = selection - 1;
|
}
|
||||||
} else if (input_state.right) {
|
|
||||||
selection = (selection + 1) % game_state.hands[0].items.len;
|
if (hovered_action) |hovered| {
|
||||||
|
if (input_state.left) {
|
||||||
|
for (actions.items) |action| {
|
||||||
|
if (action.element.pointer == hovered.element.pointer) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (action.center[0] < hovered.center[0]) {
|
||||||
|
hovered_action = Action{
|
||||||
|
.center = .{ action.center[0], hovered.center[1] },
|
||||||
|
.command = action.command,
|
||||||
|
.element = action.element,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (input_state.right) {
|
||||||
|
for (actions.items) |action| {
|
||||||
|
if (action.element.pointer == hovered.element.pointer) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (action.center[0] > hovered.center[0]) {
|
||||||
|
hovered_action = Action{
|
||||||
|
.center = .{ action.center[0], hovered.center[1] },
|
||||||
|
.command = action.command,
|
||||||
|
.element = action.element,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root_element == null) {
|
if (root_element == null) {
|
||||||
|
@ -206,6 +238,7 @@ pub fn main() !void {
|
||||||
root.pointer,
|
root.pointer,
|
||||||
&canvas,
|
&canvas,
|
||||||
.{
|
.{
|
||||||
|
.hovered = if (hovered_action) |ha| ha.element else null,
|
||||||
.deck = deck_sprites,
|
.deck = deck_sprites,
|
||||||
},
|
},
|
||||||
.{ 0, 0 },
|
.{ 0, 0 },
|
||||||
|
@ -219,10 +252,35 @@ pub fn main() !void {
|
||||||
canvas.end();
|
canvas.end();
|
||||||
|
|
||||||
seizer.backend.glfw.c.glfwSwapBuffers(window);
|
seizer.backend.glfw.c.glfwSwapBuffers(window);
|
||||||
|
|
||||||
|
if (root_element) |root| {
|
||||||
|
actions.clearRetainingCapacity();
|
||||||
|
try root.interface.get_actions(
|
||||||
|
root.pointer,
|
||||||
|
&actions,
|
||||||
|
.{
|
||||||
|
.hovered = if (hovered_action) |ha| ha.element else null,
|
||||||
|
.deck = deck_sprites,
|
||||||
|
},
|
||||||
|
.{ 0, 0 },
|
||||||
|
.{
|
||||||
|
@floatFromInt(window_size[0]),
|
||||||
|
@floatFromInt(window_size[1]),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Action = struct {
|
||||||
|
center: [2]f32,
|
||||||
|
/// A string representing what should occur if this action is taken
|
||||||
|
command: []const u8,
|
||||||
|
element: Element,
|
||||||
|
};
|
||||||
|
|
||||||
const RenderResources = struct {
|
const RenderResources = struct {
|
||||||
|
hovered: ?Element,
|
||||||
deck: DeckSprites,
|
deck: DeckSprites,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -240,9 +298,14 @@ pub const Element = struct {
|
||||||
pointer: ?*anyopaque,
|
pointer: ?*anyopaque,
|
||||||
interface: *const Interface,
|
interface: *const Interface,
|
||||||
|
|
||||||
|
pub const Error = error{
|
||||||
|
OutOfMemory,
|
||||||
|
};
|
||||||
|
|
||||||
pub const Interface = struct {
|
pub const Interface = struct {
|
||||||
minimum_size: *const fn (?*anyopaque, RenderResources) [2]f32,
|
minimum_size: *const fn (?*anyopaque, RenderResources) [2]f32,
|
||||||
render: *const fn (?*anyopaque, *seizer.Canvas, RenderResources, [2]f32, [2]f32) void,
|
render: *const fn (?*anyopaque, *seizer.Canvas, RenderResources, [2]f32, [2]f32) void,
|
||||||
|
get_actions: *const fn (?*anyopaque, *std.ArrayList(Action), RenderResources, [2]f32, [2]f32) Error!void,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -292,6 +355,7 @@ pub const Page = struct {
|
||||||
.interface = &Element.Interface{
|
.interface = &Element.Interface{
|
||||||
.minimum_size = &element_minimum_size,
|
.minimum_size = &element_minimum_size,
|
||||||
.render = &element_render,
|
.render = &element_render,
|
||||||
|
.get_actions = &element_get_actions,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -345,6 +409,40 @@ pub const Page = struct {
|
||||||
child.element.interface.render(child.element.pointer, canvas, render_resources, child_min, child_max);
|
child.element.interface.render(child.element.pointer, canvas, render_resources, child_min, child_max);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn element_get_actions(pointer: ?*anyopaque, actions: *std.ArrayList(Action), render_resources: RenderResources, min: [2]f32, max: [2]f32) Element.Error!void {
|
||||||
|
const this: *@This() = @ptrCast(@alignCast(pointer));
|
||||||
|
|
||||||
|
const parent_size = [2]f32{
|
||||||
|
max[0] - min[0],
|
||||||
|
max[1] - min[1],
|
||||||
|
};
|
||||||
|
|
||||||
|
for (this.children.items) |child| {
|
||||||
|
const pos_in_parent = [2]f32{
|
||||||
|
child.anchor_in_parent[0] * parent_size[0],
|
||||||
|
child.anchor_in_parent[1] * parent_size[1],
|
||||||
|
};
|
||||||
|
|
||||||
|
const child_size = child.element.interface.minimum_size(child.element.pointer, render_resources);
|
||||||
|
|
||||||
|
const pos_in_child = [2]f32{
|
||||||
|
child.anchor_in_child[0] * child_size[0],
|
||||||
|
child.anchor_in_child[1] * child_size[1],
|
||||||
|
};
|
||||||
|
|
||||||
|
const child_min = [2]f32{
|
||||||
|
pos_in_parent[0] - pos_in_child[0],
|
||||||
|
pos_in_parent[1] - pos_in_child[1],
|
||||||
|
};
|
||||||
|
const child_max = [2]f32{
|
||||||
|
pos_in_parent[0] + (child_size[0] - pos_in_child[0]),
|
||||||
|
pos_in_parent[1] + (child_size[1] - pos_in_child[1]),
|
||||||
|
};
|
||||||
|
|
||||||
|
try child.element.interface.get_actions(child.element.pointer, actions, render_resources, child_min, child_max);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HBox = struct {
|
pub const HBox = struct {
|
||||||
|
@ -371,6 +469,7 @@ pub const HBox = struct {
|
||||||
.interface = &Element.Interface{
|
.interface = &Element.Interface{
|
||||||
.minimum_size = &element_minimum_size,
|
.minimum_size = &element_minimum_size,
|
||||||
.render = &element_render,
|
.render = &element_render,
|
||||||
|
.get_actions = &element_get_actions,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -424,6 +523,40 @@ pub const HBox = struct {
|
||||||
x += child_size[0] + space_around;
|
x += child_size[0] + space_around;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn element_get_actions(pointer: ?*anyopaque, actions: *std.ArrayList(Action), render_resources: RenderResources, min: [2]f32, max: [2]f32) Element.Error!void {
|
||||||
|
const this: *@This() = @ptrCast(@alignCast(pointer));
|
||||||
|
|
||||||
|
if (this.children.items.len == 0) return;
|
||||||
|
|
||||||
|
const parent_size = [2]f32{
|
||||||
|
max[0] - min[0],
|
||||||
|
max[1] - min[1],
|
||||||
|
};
|
||||||
|
|
||||||
|
var filled_space: f32 = 0;
|
||||||
|
for (this.children.items) |child| {
|
||||||
|
const child_size = child.interface.minimum_size(child.pointer, render_resources);
|
||||||
|
|
||||||
|
filled_space += child_size[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
const empty_space = parent_size[0] - filled_space;
|
||||||
|
|
||||||
|
const space_around = empty_space / @as(f32, @floatFromInt((this.children.items.len + 1)));
|
||||||
|
|
||||||
|
var x: f32 = min[0] + space_around;
|
||||||
|
for (this.children.items) |child| {
|
||||||
|
const child_size = child.interface.minimum_size(child.pointer, render_resources);
|
||||||
|
|
||||||
|
const child_min = [2]f32{ x, min[1] };
|
||||||
|
const child_max = [2]f32{ x + child_size[0], max[1] };
|
||||||
|
|
||||||
|
try child.interface.get_actions(child.pointer, actions, render_resources, child_min, child_max);
|
||||||
|
|
||||||
|
x += child_size[0] + space_around;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Pile = struct {
|
pub const Pile = struct {
|
||||||
|
@ -451,6 +584,7 @@ pub const Pile = struct {
|
||||||
.interface = &Element.Interface{
|
.interface = &Element.Interface{
|
||||||
.minimum_size = &element_minimum_size,
|
.minimum_size = &element_minimum_size,
|
||||||
.render = &element_render,
|
.render = &element_render,
|
||||||
|
.get_actions = &element_get_actions,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -483,6 +617,30 @@ pub const Pile = struct {
|
||||||
}, .{});
|
}, .{});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (render_resources.hovered != null and render_resources.hovered.?.pointer == @as(?*anyopaque, this)) {
|
||||||
|
const oy = -@as(f32, @floatFromInt(this.cards.len)) * (@as(f32, @floatFromInt(render_resources.deck.tilesheet.tile_size[1])) / (52.0 * 4));
|
||||||
|
canvas.rect(
|
||||||
|
.{ min[0], start_y + oy },
|
||||||
|
.{ @floatFromInt(render_resources.deck.tilesheet.tile_size[0]), @floatFromInt(render_resources.deck.tilesheet.tile_size[1]) },
|
||||||
|
.{ .color = .{ 0xAA, 0xFF, 0xAA, 0x60 } },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn element_get_actions(pointer: ?*anyopaque, actions: *std.ArrayList(Action), render_resources: RenderResources, min: [2]f32, max: [2]f32) Element.Error!void {
|
||||||
|
const this: *@This() = @ptrCast(@alignCast(pointer));
|
||||||
|
|
||||||
|
const center = [2]f32{
|
||||||
|
min[0] + @as(f32, @floatFromInt(render_resources.deck.tilesheet.tile_size[0])) / 2,
|
||||||
|
max[1] - @as(f32, @floatFromInt(render_resources.deck.tilesheet.tile_size[1])) * (2.0 - @as(f32, @floatFromInt(this.cards.len)) / (52.0 * 4)),
|
||||||
|
};
|
||||||
|
|
||||||
|
try actions.append(.{
|
||||||
|
.center = center,
|
||||||
|
.command = "take",
|
||||||
|
.element = this.element(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -511,6 +669,7 @@ pub const Spread = struct {
|
||||||
.interface = &Element.Interface{
|
.interface = &Element.Interface{
|
||||||
.minimum_size = &element_minimum_size,
|
.minimum_size = &element_minimum_size,
|
||||||
.render = &element_render,
|
.render = &element_render,
|
||||||
|
.get_actions = &element_get_actions,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -527,22 +686,48 @@ pub const Spread = struct {
|
||||||
pub fn element_render(pointer: ?*anyopaque, canvas: *seizer.Canvas, render_resources: RenderResources, min: [2]f32, max: [2]f32) void {
|
pub fn element_render(pointer: ?*anyopaque, canvas: *seizer.Canvas, render_resources: RenderResources, min: [2]f32, max: [2]f32) void {
|
||||||
const this: *@This() = @ptrCast(@alignCast(pointer));
|
const this: *@This() = @ptrCast(@alignCast(pointer));
|
||||||
|
|
||||||
const start_y = max[1] - @as(f32, @floatFromInt(render_resources.deck.tilesheet.tile_size[1]));
|
|
||||||
|
|
||||||
for (this.cards, 0..) |card, i| {
|
for (this.cards, 0..) |card, i| {
|
||||||
const ox = @as(f32, @floatFromInt(i)) * @as(f32, @floatFromInt(render_resources.deck.tilesheet.tile_size[0]));
|
const ox = @as(f32, @floatFromInt(i)) * @as(f32, @floatFromInt(render_resources.deck.tilesheet.tile_size[0]));
|
||||||
if (this.hidden) {
|
if (this.hidden) {
|
||||||
render_resources.deck.tilesheet.renderTile(canvas, render_resources.deck.back, .{
|
render_resources.deck.tilesheet.renderTile(canvas, render_resources.deck.back, .{
|
||||||
min[0] + ox,
|
min[0] + ox,
|
||||||
start_y,
|
min[1],
|
||||||
}, .{});
|
}, .{});
|
||||||
} else {
|
} else {
|
||||||
render_resources.deck.tilesheet.renderTile(canvas, render_resources.deck.getTileForCard(card), .{
|
render_resources.deck.tilesheet.renderTile(canvas, render_resources.deck.getTileForCard(card), .{
|
||||||
min[0] + ox,
|
min[0] + ox,
|
||||||
start_y,
|
min[1],
|
||||||
}, .{});
|
}, .{});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (render_resources.hovered != null and render_resources.hovered.?.pointer == @as(?*anyopaque, this)) {
|
||||||
|
canvas.rect(
|
||||||
|
min,
|
||||||
|
.{ max[0] - min[0], max[1] - min[1] },
|
||||||
|
.{ .color = .{ 0xAA, 0xFF, 0xAA, 0x60 } },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn element_get_actions(pointer: ?*anyopaque, actions: *std.ArrayList(Action), render_resources: RenderResources, min: [2]f32, max: [2]f32) Element.Error!void {
|
||||||
|
const this: *@This() = @ptrCast(@alignCast(pointer));
|
||||||
|
|
||||||
|
_ = max;
|
||||||
|
|
||||||
|
for (this.cards, 0..) |card, i| {
|
||||||
|
const ox = @as(f32, @floatFromInt(i)) * @as(f32, @floatFromInt(render_resources.deck.tilesheet.tile_size[0]));
|
||||||
|
|
||||||
|
_ = card;
|
||||||
|
try actions.append(.{
|
||||||
|
.center = [2]f32{
|
||||||
|
min[0] + ox,
|
||||||
|
min[1],
|
||||||
|
},
|
||||||
|
.command = "mark",
|
||||||
|
.element = this.element(),
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue