improve layout and scaling
This commit is contained in:
parent
52a4b4ee59
commit
984b70a39d
1 changed files with 78 additions and 49 deletions
127
src/main.zig
127
src/main.zig
|
@ -102,11 +102,15 @@ pub const Scales = struct {
|
|||
item_title_font_size: f32,
|
||||
item_subtitle_font_size: f32,
|
||||
|
||||
column_icon_padding_top_curve: Curve,
|
||||
column_item_spacing_curve: Curve,
|
||||
column_selected_item_icon_scale_curve: Curve,
|
||||
column_title_font_size: f32,
|
||||
column_position_center: raylib.Vector2,
|
||||
column_position_spacing: f32,
|
||||
column_item_spacing: f32,
|
||||
column_selected_item_icon_scale: f32,
|
||||
column_icon_padding_top: f32,
|
||||
column_item_after_start: f32,
|
||||
column_item_before_start: f32,
|
||||
|
||||
|
@ -115,6 +119,7 @@ pub const Scales = struct {
|
|||
|
||||
self.font_size_curve = Curve{ .points = &[_]Curve.Point{
|
||||
.{ .x = 0, .y = 18 },
|
||||
.{ .x = 0.25, .y = 18 },
|
||||
.{ .x = 1, .y = 26 },
|
||||
} };
|
||||
|
||||
|
@ -123,12 +128,26 @@ pub const Scales = struct {
|
|||
.{ .x = 1, .y = 80 },
|
||||
} };
|
||||
|
||||
self.column_icon_padding_top_curve = Curve{ .points = &[_]Curve.Point{
|
||||
.{ .x = 0, .y = 0 },
|
||||
.{ .x = 0.25, .y = 0 },
|
||||
.{ .x = 1, .y = 16 },
|
||||
} };
|
||||
|
||||
self.column_item_spacing_curve = Curve{ .points = &[_]Curve.Point{
|
||||
.{ .x = 0, .y = 16, .right_tangent = -90 },
|
||||
.{ .x = 0, .y = 10, .right_tangent = -90 },
|
||||
.{ .x = 0.25, .y = 0 },
|
||||
.{ .x = 1, .y = 0 },
|
||||
} };
|
||||
|
||||
self.column_selected_item_icon_scale_curve = Curve{
|
||||
.points = &[_]Curve.Point{
|
||||
.{ .x = 0, .y = 1 },
|
||||
.{ .x = 0.25, .y = 1.5 },
|
||||
.{ .x = 1, .y = 2 },
|
||||
},
|
||||
};
|
||||
|
||||
self.recalculate();
|
||||
return self;
|
||||
}
|
||||
|
@ -152,12 +171,13 @@ pub const Scales = struct {
|
|||
};
|
||||
self.column_position_spacing = 64;
|
||||
self.column_item_spacing = self.column_item_spacing_curve.sample(height);
|
||||
self.column_selected_item_icon_scale = self.column_selected_item_icon_scale_curve.sample(height);
|
||||
self.column_icon_padding_top = self.column_icon_padding_top_curve.sample(height);
|
||||
self.column_item_after_start = self.column_position_center.y + self.icon_height + self.column_title_font_size + 12;
|
||||
self.column_item_before_start = self.column_position_center.y;
|
||||
self.column_item_before_start = self.column_position_center.y - self.column_icon_padding_top;
|
||||
}
|
||||
};
|
||||
|
||||
// TODO selected item scale up
|
||||
// TODO item actions
|
||||
// TODO item groups
|
||||
// TODO item group sort
|
||||
|
@ -205,7 +225,6 @@ pub const Column = struct {
|
|||
.align_h = .center,
|
||||
};
|
||||
|
||||
for (self.items.items) |item| item.update();
|
||||
for (self.items.items) |item| item.draw();
|
||||
|
||||
icon.draw();
|
||||
|
@ -239,22 +258,24 @@ pub const Column = struct {
|
|||
fn refresh(self: *Column, comptime animate: bool) void {
|
||||
var y = scales.column_item_before_start - (scales.icon_height + scales.column_item_spacing) * @as(f32, @floatFromInt(self.selected));
|
||||
for (self.items.items[0..self.selected]) |item| {
|
||||
item.setPosition(animate, .{ .x = scales.column_position_center.x, .y = y });
|
||||
item.position.set(animate, .{ .x = scales.column_position_center.x, .y = y });
|
||||
item.icon_scale.set(animate, 1.0);
|
||||
y += scales.icon_height + scales.column_item_spacing;
|
||||
}
|
||||
y = scales.column_item_after_start;
|
||||
for (self.items.items[self.selected..]) |item| {
|
||||
item.setPosition(animate, .{ .x = scales.column_position_center.x, .y = y });
|
||||
y += scales.icon_height + scales.column_item_spacing;
|
||||
for (self.items.items[self.selected..], self.selected..) |item, i| {
|
||||
const icon_scale = if (i == self.selected) scales.column_selected_item_icon_scale else 1.0;
|
||||
item.position.set(animate, .{ .x = scales.column_position_center.x, .y = y });
|
||||
item.icon_scale.set(animate, icon_scale);
|
||||
y += scales.icon_height * icon_scale + scales.column_item_spacing + (std.math.pow(f32, 4.0, icon_scale) - 4.0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// TODO animated item icon scale
|
||||
// TODO animated text fade in/out
|
||||
pub const Item = struct {
|
||||
position: raylib.Vector2 = .{ .x = 0, .y = 0 },
|
||||
animator: Animator,
|
||||
position: Tweener(raylib.Vector2, .{}) = .{},
|
||||
icon_scale: Tweener(f32, 1.0) = .{},
|
||||
|
||||
icon: raylib.Texture2D,
|
||||
title: []const u8,
|
||||
|
@ -266,21 +287,20 @@ pub const Item = struct {
|
|||
.icon = texture,
|
||||
.title = title,
|
||||
.subtitle = subtitle,
|
||||
.animator = .{
|
||||
.start_position = .{},
|
||||
.target_position = .{},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
pub fn draw(self: *Item) void {
|
||||
const position = self.position.update();
|
||||
const icon_scale = self.icon_scale.update();
|
||||
|
||||
var icon = Image{
|
||||
.texture = self.icon,
|
||||
.box = .{
|
||||
.x = self.position.x - scales.icon_width / 2.0 + 67.0 / 2.0,
|
||||
.y = self.position.y,
|
||||
.w = scales.icon_width,
|
||||
.h = scales.icon_height,
|
||||
.x = position.x - scales.icon_width / 2.0 * (icon_scale - 1),
|
||||
.y = position.y,
|
||||
.w = scales.icon_width * icon_scale,
|
||||
.h = scales.icon_height * icon_scale,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -314,38 +334,47 @@ pub const Item = struct {
|
|||
title.draw();
|
||||
subtitle.draw();
|
||||
}
|
||||
|
||||
pub const Animator = struct {
|
||||
time: f32 = 0,
|
||||
start_position: raylib.Vector2,
|
||||
target_position: raylib.Vector2,
|
||||
|
||||
fn easeOutExpo(self: Animator, length: f32) f32 {
|
||||
return 1.0 - std.math.pow(f32, 2, -10 * std.math.clamp(self.time / length, 0.0, 1.0));
|
||||
}
|
||||
};
|
||||
|
||||
fn update(self: *Item) void {
|
||||
self.animator.time += raylib.GetFrameTime();
|
||||
self.position = raylib.Vector2Lerp(
|
||||
self.animator.start_position,
|
||||
self.animator.target_position,
|
||||
self.animator.easeOutExpo(0.333),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn setPosition(self: *Item, comptime animate: bool, position: raylib.Vector2) void {
|
||||
if (animate) {
|
||||
self.animator.time = 0;
|
||||
self.animator.start_position = self.position;
|
||||
self.animator.target_position = position;
|
||||
} else {
|
||||
self.animator.start_position = position;
|
||||
self.animator.target_position = position;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
pub fn Tweener(comptime T: type, comptime default: T) type {
|
||||
return struct {
|
||||
time: f32 = 0.0,
|
||||
length: f32 = 0.333,
|
||||
|
||||
start: T = default,
|
||||
target: T = default,
|
||||
current: T = default,
|
||||
|
||||
fn set(self: *Self, comptime animate: bool, value: T) void {
|
||||
if (animate) {
|
||||
self.time = 0;
|
||||
self.start = self.current;
|
||||
self.target = value;
|
||||
} else {
|
||||
self.start = value;
|
||||
self.target = value;
|
||||
self.current = value;
|
||||
}
|
||||
}
|
||||
|
||||
fn update(self: *Self) T {
|
||||
self.time += raylib.GetFrameTime();
|
||||
self.current = switch (T) {
|
||||
f32 => std.math.lerp(self.start, self.target, self.easeOutExpo()),
|
||||
raylib.Vector2 => raylib.Vector2Lerp(self.start, self.target, self.easeOutExpo()),
|
||||
else => @compileError("no lerp function for type " ++ @typeName(T)),
|
||||
};
|
||||
return self.current;
|
||||
}
|
||||
|
||||
fn easeOutExpo(self: Self) f32 {
|
||||
return 1.0 - std.math.pow(f32, 2, -10 * std.math.clamp(self.time / self.length, 0.0, 1.0));
|
||||
}
|
||||
|
||||
const Self = @This();
|
||||
};
|
||||
}
|
||||
|
||||
/// Draws the dynamic gradient background.
|
||||
// TODO shift based on time of day
|
||||
// TODO image wallpaper
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue