implement hovering over elements

dev
LeRoyce Pearson 2024-02-26 19:50:26 -07:00
parent 54d04f4a2b
commit 91f896c5ef
1 changed files with 195 additions and 10 deletions

View File

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