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_title_font_size: f32,
|
||||||
item_subtitle_font_size: f32,
|
item_subtitle_font_size: f32,
|
||||||
|
|
||||||
|
column_icon_padding_top_curve: Curve,
|
||||||
column_item_spacing_curve: Curve,
|
column_item_spacing_curve: Curve,
|
||||||
|
column_selected_item_icon_scale_curve: Curve,
|
||||||
column_title_font_size: f32,
|
column_title_font_size: f32,
|
||||||
column_position_center: raylib.Vector2,
|
column_position_center: raylib.Vector2,
|
||||||
column_position_spacing: f32,
|
column_position_spacing: f32,
|
||||||
column_item_spacing: f32,
|
column_item_spacing: f32,
|
||||||
|
column_selected_item_icon_scale: f32,
|
||||||
|
column_icon_padding_top: f32,
|
||||||
column_item_after_start: f32,
|
column_item_after_start: f32,
|
||||||
column_item_before_start: f32,
|
column_item_before_start: f32,
|
||||||
|
|
||||||
|
@ -115,6 +119,7 @@ pub const Scales = struct {
|
||||||
|
|
||||||
self.font_size_curve = Curve{ .points = &[_]Curve.Point{
|
self.font_size_curve = Curve{ .points = &[_]Curve.Point{
|
||||||
.{ .x = 0, .y = 18 },
|
.{ .x = 0, .y = 18 },
|
||||||
|
.{ .x = 0.25, .y = 18 },
|
||||||
.{ .x = 1, .y = 26 },
|
.{ .x = 1, .y = 26 },
|
||||||
} };
|
} };
|
||||||
|
|
||||||
|
@ -123,12 +128,26 @@ pub const Scales = struct {
|
||||||
.{ .x = 1, .y = 80 },
|
.{ .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{
|
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 = 0.25, .y = 0 },
|
||||||
.{ .x = 1, .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();
|
self.recalculate();
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
@ -152,12 +171,13 @@ pub const Scales = struct {
|
||||||
};
|
};
|
||||||
self.column_position_spacing = 64;
|
self.column_position_spacing = 64;
|
||||||
self.column_item_spacing = self.column_item_spacing_curve.sample(height);
|
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_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 actions
|
||||||
// TODO item groups
|
// TODO item groups
|
||||||
// TODO item group sort
|
// TODO item group sort
|
||||||
|
@ -205,7 +225,6 @@ pub const Column = struct {
|
||||||
.align_h = .center,
|
.align_h = .center,
|
||||||
};
|
};
|
||||||
|
|
||||||
for (self.items.items) |item| item.update();
|
|
||||||
for (self.items.items) |item| item.draw();
|
for (self.items.items) |item| item.draw();
|
||||||
|
|
||||||
icon.draw();
|
icon.draw();
|
||||||
|
@ -239,22 +258,24 @@ pub const Column = struct {
|
||||||
fn refresh(self: *Column, comptime animate: bool) void {
|
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));
|
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| {
|
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.icon_height + scales.column_item_spacing;
|
||||||
}
|
}
|
||||||
y = scales.column_item_after_start;
|
y = scales.column_item_after_start;
|
||||||
for (self.items.items[self.selected..]) |item| {
|
for (self.items.items[self.selected..], self.selected..) |item, i| {
|
||||||
item.setPosition(animate, .{ .x = scales.column_position_center.x, .y = y });
|
const icon_scale = if (i == self.selected) scales.column_selected_item_icon_scale else 1.0;
|
||||||
y += scales.icon_height + scales.column_item_spacing;
|
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
|
// TODO animated text fade in/out
|
||||||
pub const Item = struct {
|
pub const Item = struct {
|
||||||
position: raylib.Vector2 = .{ .x = 0, .y = 0 },
|
position: Tweener(raylib.Vector2, .{}) = .{},
|
||||||
animator: Animator,
|
icon_scale: Tweener(f32, 1.0) = .{},
|
||||||
|
|
||||||
icon: raylib.Texture2D,
|
icon: raylib.Texture2D,
|
||||||
title: []const u8,
|
title: []const u8,
|
||||||
|
@ -266,21 +287,20 @@ pub const Item = struct {
|
||||||
.icon = texture,
|
.icon = texture,
|
||||||
.title = title,
|
.title = title,
|
||||||
.subtitle = subtitle,
|
.subtitle = subtitle,
|
||||||
.animator = .{
|
|
||||||
.start_position = .{},
|
|
||||||
.target_position = .{},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw(self: *Item) void {
|
pub fn draw(self: *Item) void {
|
||||||
|
const position = self.position.update();
|
||||||
|
const icon_scale = self.icon_scale.update();
|
||||||
|
|
||||||
var icon = Image{
|
var icon = Image{
|
||||||
.texture = self.icon,
|
.texture = self.icon,
|
||||||
.box = .{
|
.box = .{
|
||||||
.x = self.position.x - scales.icon_width / 2.0 + 67.0 / 2.0,
|
.x = position.x - scales.icon_width / 2.0 * (icon_scale - 1),
|
||||||
.y = self.position.y,
|
.y = position.y,
|
||||||
.w = scales.icon_width,
|
.w = scales.icon_width * icon_scale,
|
||||||
.h = scales.icon_height,
|
.h = scales.icon_height * icon_scale,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -314,38 +334,47 @@ pub const Item = struct {
|
||||||
title.draw();
|
title.draw();
|
||||||
subtitle.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.
|
/// Draws the dynamic gradient background.
|
||||||
// TODO shift based on time of day
|
// TODO shift based on time of day
|
||||||
// TODO image wallpaper
|
// TODO image wallpaper
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue