refactor(icon): Modularizar en carpeta (805→515 LOC hub, -36%)
This commit is contained in:
parent
50a6d3ca60
commit
1ae07812bd
7 changed files with 758 additions and 809 deletions
|
|
@ -9,7 +9,7 @@ const Command = @import("../core/command.zig");
|
|||
const Layout = @import("../core/layout.zig");
|
||||
const Style = @import("../core/style.zig");
|
||||
const Input = @import("../core/input.zig");
|
||||
const icon_module = @import("icon.zig");
|
||||
const icon_module = @import("icon/icon.zig");
|
||||
const iconbutton = @import("iconbutton.zig");
|
||||
|
||||
/// AppBar position
|
||||
|
|
|
|||
93
src/widgets/icon/drawing_helpers.zig
Normal file
93
src/widgets/icon/drawing_helpers.zig
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
//! Icon - Helpers de dibujo
|
||||
//!
|
||||
//! Funciones para dibujar líneas y círculos con grosor.
|
||||
|
||||
const Context = @import("../../core/context.zig").Context;
|
||||
const Command = @import("../../core/command.zig");
|
||||
const Style = @import("../../core/style.zig");
|
||||
|
||||
// =============================================================================
|
||||
// Drawing Helpers
|
||||
// =============================================================================
|
||||
|
||||
/// Draw a line with thickness
|
||||
pub fn drawLine(ctx: *Context, x1: i32, y1: i32, x2: i32, y2: i32, thickness: u32, color: Style.Color) void {
|
||||
if (thickness <= 1) {
|
||||
ctx.pushCommand(Command.line(x1, y1, x2, y2, color));
|
||||
} else {
|
||||
const dx = x2 - x1;
|
||||
const dy = y2 - y1;
|
||||
const len = @sqrt(@as(f32, @floatFromInt(dx * dx + dy * dy)));
|
||||
|
||||
if (len < 1) {
|
||||
ctx.pushCommand(Command.rect(x1, y1, thickness, thickness, color));
|
||||
return;
|
||||
}
|
||||
|
||||
const nx = -@as(f32, @floatFromInt(dy)) / len;
|
||||
const ny = @as(f32, @floatFromInt(dx)) / len;
|
||||
|
||||
const half = @as(f32, @floatFromInt(thickness)) / 2.0;
|
||||
var offset: f32 = -half;
|
||||
while (offset < half) : (offset += 1.0) {
|
||||
const ox = @as(i32, @intFromFloat(nx * offset));
|
||||
const oy = @as(i32, @intFromFloat(ny * offset));
|
||||
ctx.pushCommand(Command.line(x1 + ox, y1 + oy, x2 + ox, y2 + oy, color));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Fill a circle
|
||||
pub fn fillCircle(ctx: *Context, cx: i32, cy: i32, radius: u32, color: Style.Color) void {
|
||||
if (radius == 0) {
|
||||
ctx.pushCommand(Command.rect(cx, cy, 1, 1, color));
|
||||
return;
|
||||
}
|
||||
|
||||
const r = @as(i32, @intCast(radius));
|
||||
var dy: i32 = -r;
|
||||
while (dy <= r) : (dy += 1) {
|
||||
const dy_f = @as(f32, @floatFromInt(dy));
|
||||
const r_f = @as(f32, @floatFromInt(r));
|
||||
const dx = @as(i32, @intFromFloat(@sqrt(r_f * r_f - dy_f * dy_f)));
|
||||
ctx.pushCommand(Command.rect(cx - dx, cy + dy, @intCast(dx * 2 + 1), 1, color));
|
||||
}
|
||||
}
|
||||
|
||||
/// Stroke a circle
|
||||
pub fn strokeCircle(ctx: *Context, cx: i32, cy: i32, radius: u32, thickness: u32, color: Style.Color) void {
|
||||
if (radius == 0) return;
|
||||
|
||||
const r = @as(i32, @intCast(radius));
|
||||
var px: i32 = 0;
|
||||
var py: i32 = r;
|
||||
var d: i32 = 3 - 2 * r;
|
||||
|
||||
while (px <= py) {
|
||||
setPixelThick(ctx, cx + px, cy + py, thickness, color);
|
||||
setPixelThick(ctx, cx - px, cy + py, thickness, color);
|
||||
setPixelThick(ctx, cx + px, cy - py, thickness, color);
|
||||
setPixelThick(ctx, cx - px, cy - py, thickness, color);
|
||||
setPixelThick(ctx, cx + py, cy + px, thickness, color);
|
||||
setPixelThick(ctx, cx - py, cy + px, thickness, color);
|
||||
setPixelThick(ctx, cx + py, cy - px, thickness, color);
|
||||
setPixelThick(ctx, cx - py, cy - px, thickness, color);
|
||||
|
||||
if (d < 0) {
|
||||
d = d + 4 * px + 6;
|
||||
} else {
|
||||
d = d + 4 * (px - py) + 10;
|
||||
py -= 1;
|
||||
}
|
||||
px += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn setPixelThick(ctx: *Context, pixel_x: i32, pixel_y: i32, thickness: u32, color: Style.Color) void {
|
||||
if (thickness <= 1) {
|
||||
ctx.pushCommand(Command.rect(pixel_x, pixel_y, 1, 1, color));
|
||||
} else {
|
||||
const half = @as(i32, @intCast(thickness / 2));
|
||||
ctx.pushCommand(Command.rect(pixel_x - half, pixel_y - half, thickness, thickness, color));
|
||||
}
|
||||
}
|
||||
|
|
@ -2,137 +2,34 @@
|
|||
//!
|
||||
//! A lightweight icon system using simple vector drawing.
|
||||
//! Icons are defined as draw commands for resolution independence.
|
||||
//!
|
||||
//! ## Estructura modular
|
||||
//!
|
||||
//! - types.zig: Size, IconType, Config, Colors
|
||||
//! - drawing_helpers.zig: drawLine, fillCircle, strokeCircle
|
||||
//! - icon.zig: Hub principal (este archivo)
|
||||
|
||||
const std = @import("std");
|
||||
const Context = @import("../core/context.zig").Context;
|
||||
const Command = @import("../core/command.zig");
|
||||
const Layout = @import("../core/layout.zig");
|
||||
const Style = @import("../core/style.zig");
|
||||
const Context = @import("../../core/context.zig").Context;
|
||||
const Command = @import("../../core/command.zig");
|
||||
const Layout = @import("../../core/layout.zig");
|
||||
const Style = @import("../../core/style.zig");
|
||||
|
||||
/// Icon size presets
|
||||
pub const Size = enum {
|
||||
small, // 12x12
|
||||
medium, // 16x16
|
||||
large, // 24x24
|
||||
xlarge, // 32x32
|
||||
// Re-exports desde módulos
|
||||
pub const types = @import("types.zig");
|
||||
pub const Size = types.Size;
|
||||
pub const IconType = types.IconType;
|
||||
pub const Config = types.Config;
|
||||
pub const Colors = types.Colors;
|
||||
|
||||
pub fn pixels(self: Size) u32 {
|
||||
return switch (self) {
|
||||
.small => 12,
|
||||
.medium => 16,
|
||||
.large => 24,
|
||||
.xlarge => 32,
|
||||
};
|
||||
}
|
||||
};
|
||||
const helpers = @import("drawing_helpers.zig");
|
||||
const drawLine = helpers.drawLine;
|
||||
const fillCircle = helpers.fillCircle;
|
||||
const strokeCircle = helpers.strokeCircle;
|
||||
|
||||
/// Built-in icon types
|
||||
pub const IconType = enum {
|
||||
// Navigation
|
||||
arrow_up,
|
||||
arrow_down,
|
||||
arrow_left,
|
||||
arrow_right,
|
||||
chevron_up,
|
||||
chevron_down,
|
||||
chevron_left,
|
||||
chevron_right,
|
||||
home,
|
||||
menu,
|
||||
more_horizontal,
|
||||
more_vertical,
|
||||
|
||||
// Actions
|
||||
check,
|
||||
close,
|
||||
plus,
|
||||
minus,
|
||||
edit,
|
||||
delete,
|
||||
refresh,
|
||||
search,
|
||||
settings,
|
||||
filter,
|
||||
sort,
|
||||
copy,
|
||||
paste,
|
||||
cut,
|
||||
undo,
|
||||
redo,
|
||||
|
||||
// Files
|
||||
file,
|
||||
folder,
|
||||
folder_open,
|
||||
document,
|
||||
image_file,
|
||||
download,
|
||||
upload,
|
||||
save,
|
||||
|
||||
// Status
|
||||
info,
|
||||
warning,
|
||||
error_icon,
|
||||
success,
|
||||
question,
|
||||
star,
|
||||
star_filled,
|
||||
heart,
|
||||
heart_filled,
|
||||
|
||||
// UI elements
|
||||
eye,
|
||||
eye_off,
|
||||
lock,
|
||||
unlock,
|
||||
user,
|
||||
users,
|
||||
calendar,
|
||||
clock,
|
||||
bell,
|
||||
mail,
|
||||
|
||||
// Media
|
||||
play,
|
||||
pause,
|
||||
stop,
|
||||
volume,
|
||||
volume_off,
|
||||
|
||||
// Misc
|
||||
grip,
|
||||
drag,
|
||||
expand,
|
||||
collapse,
|
||||
maximize,
|
||||
minimize,
|
||||
external_link,
|
||||
};
|
||||
|
||||
/// Icon configuration
|
||||
pub const Config = struct {
|
||||
/// Icon size
|
||||
size: Size = .medium,
|
||||
/// Custom size (overrides size preset)
|
||||
custom_size: ?u32 = null,
|
||||
/// Stroke width
|
||||
stroke_width: u32 = 2,
|
||||
/// Fill icon
|
||||
filled: bool = false,
|
||||
};
|
||||
|
||||
/// Icon colors
|
||||
pub const Colors = struct {
|
||||
foreground: Style.Color = Style.Color.rgba(220, 220, 220, 255),
|
||||
background: ?Style.Color = null,
|
||||
|
||||
pub fn fromTheme(theme: Style.Theme) Colors {
|
||||
return .{
|
||||
.foreground = theme.foreground,
|
||||
};
|
||||
}
|
||||
};
|
||||
// =============================================================================
|
||||
// Public API
|
||||
// =============================================================================
|
||||
|
||||
/// Draw an icon
|
||||
pub fn icon(ctx: *Context, icon_type: IconType) void {
|
||||
|
|
@ -171,7 +68,7 @@ pub fn iconRect(
|
|||
const s: i32 = @intCast(size);
|
||||
const sw = config.stroke_width;
|
||||
|
||||
// Pre-calculated divisions to avoid runtime @divTrunc issues
|
||||
// Pre-calculated divisions
|
||||
const s2 = @divTrunc(s, 2);
|
||||
const s3 = @divTrunc(s, 3);
|
||||
const s4 = @divTrunc(s, 4);
|
||||
|
|
@ -184,7 +81,6 @@ pub fn iconRect(
|
|||
|
||||
// Draw icon based on type
|
||||
switch (icon_type) {
|
||||
// Arrows
|
||||
.arrow_up => {
|
||||
drawLine(ctx, x + s2, y + 2, x + 2, y + s - 4, sw, fg);
|
||||
drawLine(ctx, x + s2, y + 2, x + s - 2, y + s - 4, sw, fg);
|
||||
|
|
@ -205,8 +101,6 @@ pub fn iconRect(
|
|||
drawLine(ctx, x + s - 2, y + s2, x + 4, y + s - 2, sw, fg);
|
||||
drawLine(ctx, x + s - 2, y + s2, x + 2, y + s2, sw, fg);
|
||||
},
|
||||
|
||||
// Chevrons
|
||||
.chevron_up => {
|
||||
drawLine(ctx, x + 2, y + s23, x + s2, y + s3, sw, fg);
|
||||
drawLine(ctx, x + s2, y + s3, x + s - 2, y + s23, sw, fg);
|
||||
|
|
@ -223,8 +117,6 @@ pub fn iconRect(
|
|||
drawLine(ctx, x + s3, y + 2, x + s23, y + s2, sw, fg);
|
||||
drawLine(ctx, x + s23, y + s2, x + s3, y + s - 2, sw, fg);
|
||||
},
|
||||
|
||||
// Actions
|
||||
.check => {
|
||||
drawLine(ctx, x + 2, y + s2, x + s3, y + s - 4, sw, fg);
|
||||
drawLine(ctx, x + s3, y + s - 4, x + s - 2, y + 3, sw, fg);
|
||||
|
|
@ -240,8 +132,6 @@ pub fn iconRect(
|
|||
.minus => {
|
||||
drawLine(ctx, x + 3, y + s2, x + s - 3, y + s2, sw, fg);
|
||||
},
|
||||
|
||||
// Home
|
||||
.home => {
|
||||
drawLine(ctx, x + 2, y + s2, x + s2, y + 2, sw, fg);
|
||||
drawLine(ctx, x + s2, y + 2, x + s - 2, y + s2, sw, fg);
|
||||
|
|
@ -249,8 +139,6 @@ pub fn iconRect(
|
|||
drawLine(ctx, x + s - 3, y + s2, x + s - 3, y + s - 2, sw, fg);
|
||||
drawLine(ctx, x + 3, y + s - 2, x + s - 3, y + s - 2, sw, fg);
|
||||
},
|
||||
|
||||
// Menu
|
||||
.menu => {
|
||||
const bar_y1 = y + s4;
|
||||
const bar_y2 = y + s2;
|
||||
|
|
@ -259,8 +147,6 @@ pub fn iconRect(
|
|||
drawLine(ctx, x + 2, bar_y2, x + s - 2, bar_y2, sw, fg);
|
||||
drawLine(ctx, x + 2, bar_y3, x + s - 2, bar_y3, sw, fg);
|
||||
},
|
||||
|
||||
// More (dots)
|
||||
.more_horizontal => {
|
||||
const dot_r: u32 = @max(2, @as(u32, @intCast(s6)));
|
||||
fillCircle(ctx, x + s4, y + s2, dot_r, fg);
|
||||
|
|
@ -273,15 +159,11 @@ pub fn iconRect(
|
|||
fillCircle(ctx, x + s2, y + s2, dot_r, fg);
|
||||
fillCircle(ctx, x + s2, y + s34, dot_r, fg);
|
||||
},
|
||||
|
||||
// Search
|
||||
.search => {
|
||||
const r: u32 = @intCast(s3);
|
||||
strokeCircle(ctx, x + s3, y + s3, r, sw, fg);
|
||||
drawLine(ctx, x + s2, y + s2, x + s - 3, y + s - 3, sw, fg);
|
||||
},
|
||||
|
||||
// Settings (gear)
|
||||
.settings => {
|
||||
const r: u32 = @intCast(s4);
|
||||
strokeCircle(ctx, x + s2, y + s2, r, sw, fg);
|
||||
|
|
@ -290,44 +172,32 @@ pub fn iconRect(
|
|||
drawLine(ctx, x + 2, y + s2, x + s4, y + s2, sw, fg);
|
||||
drawLine(ctx, x + s - 2, y + s2, x + s34, y + s2, sw, fg);
|
||||
},
|
||||
|
||||
// File
|
||||
.file => {
|
||||
ctx.pushCommand(Command.rectOutline(x + 2, y + 2, @intCast(s - 4), @intCast(s - 4), fg));
|
||||
drawLine(ctx, x + s - 6, y + 2, x + s - 2, y + 6, sw, fg);
|
||||
},
|
||||
|
||||
// Folder
|
||||
.folder => {
|
||||
ctx.pushCommand(Command.rectOutline(x + 2, y + 4, @intCast(s - 4), @intCast(s - 6), fg));
|
||||
drawLine(ctx, x + 2, y + 4, x + s3, y + 4, sw, fg);
|
||||
drawLine(ctx, x + s3, y + 4, x + s3 + 2, y + 2, sw, fg);
|
||||
drawLine(ctx, x + s3 + 2, y + 2, x + s2, y + 2, sw, fg);
|
||||
},
|
||||
|
||||
// Document
|
||||
.document => {
|
||||
ctx.pushCommand(Command.rectOutline(x + 3, y + 2, @intCast(s - 6), @intCast(s - 4), fg));
|
||||
drawLine(ctx, x + 5, y + s3, x + s - 5, y + s3, 1, fg);
|
||||
drawLine(ctx, x + 5, y + s2, x + s - 5, y + s2, 1, fg);
|
||||
drawLine(ctx, x + 5, y + s23, x + s - 7, y + s23, 1, fg);
|
||||
},
|
||||
|
||||
// Save (floppy)
|
||||
.save => {
|
||||
ctx.pushCommand(Command.rectOutline(x + 2, y + 2, @intCast(s - 4), @intCast(s - 4), fg));
|
||||
ctx.pushCommand(Command.rect(x + 4, y + s2, @intCast(s - 8), @intCast(s3), fg));
|
||||
},
|
||||
|
||||
// Info
|
||||
.info => {
|
||||
const r: u32 = @intCast(s2 - 2);
|
||||
strokeCircle(ctx, x + s2, y + s2, r, sw, fg);
|
||||
fillCircle(ctx, x + s2, y + s3, 2, fg);
|
||||
drawLine(ctx, x + s2, y + s2 - 1, x + s2, y + s23 + 1, sw, fg);
|
||||
},
|
||||
|
||||
// Warning (triangle)
|
||||
.warning => {
|
||||
drawLine(ctx, x + s2, y + 2, x + 2, y + s - 2, sw, fg);
|
||||
drawLine(ctx, x + s2, y + 2, x + s - 2, y + s - 2, sw, fg);
|
||||
|
|
@ -335,31 +205,23 @@ pub fn iconRect(
|
|||
drawLine(ctx, x + s2, y + s3 + 1, x + s2, y + s2 + 1, sw, fg);
|
||||
fillCircle(ctx, x + s2, y + s23, 2, fg);
|
||||
},
|
||||
|
||||
// Error (X in circle)
|
||||
.error_icon => {
|
||||
const r: u32 = @intCast(s2 - 2);
|
||||
strokeCircle(ctx, x + s2, y + s2, r, sw, fg);
|
||||
drawLine(ctx, x + s3, y + s3, x + s23, y + s23, sw, fg);
|
||||
drawLine(ctx, x + s23, y + s3, x + s3, y + s23, sw, fg);
|
||||
},
|
||||
|
||||
// Success (checkmark in circle)
|
||||
.success => {
|
||||
const r: u32 = @intCast(s2 - 2);
|
||||
strokeCircle(ctx, x + s2, y + s2, r, sw, fg);
|
||||
drawLine(ctx, x + s4 + 1, y + s2, x + s2 - 1, y + s23, sw, fg);
|
||||
drawLine(ctx, x + s2 - 1, y + s23, x + s34 - 1, y + s3, sw, fg);
|
||||
},
|
||||
|
||||
// Question
|
||||
.question => {
|
||||
const r: u32 = @intCast(s2 - 2);
|
||||
strokeCircle(ctx, x + s2, y + s2, r, sw, fg);
|
||||
ctx.pushCommand(Command.text(x + s2 - 3, y + s3, "?", fg));
|
||||
},
|
||||
|
||||
// Star
|
||||
.star => {
|
||||
const s25 = @divTrunc(s * 2, 5);
|
||||
const s35 = @divTrunc(s * 3, 5);
|
||||
|
|
@ -377,8 +239,6 @@ pub fn iconRect(
|
|||
.star_filled => {
|
||||
fillCircle(ctx, x + s2, y + s2, @intCast(s3), fg);
|
||||
},
|
||||
|
||||
// Heart
|
||||
.heart => {
|
||||
drawLine(ctx, x + s2, y + s - 3, x + 3, y + s2, sw, fg);
|
||||
drawLine(ctx, x + s2, y + s - 3, x + s - 3, y + s2, sw, fg);
|
||||
|
|
@ -394,8 +254,6 @@ pub fn iconRect(
|
|||
ctx.pushCommand(Command.rect(x + s2 - hw, y + s2 + dy, @intCast(hw * 2), 1, fg));
|
||||
}
|
||||
},
|
||||
|
||||
// Eye
|
||||
.eye => {
|
||||
ctx.pushCommand(Command.rectOutline(x + 2, y + s3, @intCast(s - 4), @intCast(s3), fg));
|
||||
fillCircle(ctx, x + s2, y + s2, @intCast(s6), fg);
|
||||
|
|
@ -404,8 +262,6 @@ pub fn iconRect(
|
|||
ctx.pushCommand(Command.rectOutline(x + 2, y + s3, @intCast(s - 4), @intCast(s3), fg));
|
||||
drawLine(ctx, x + 2, y + s - 3, x + s - 2, y + 3, sw, fg);
|
||||
},
|
||||
|
||||
// Lock
|
||||
.lock => {
|
||||
ctx.pushCommand(Command.rectOutline(x + 3, y + s2, @intCast(s - 6), @intCast(s2 - 2), fg));
|
||||
drawLine(ctx, x + s3, y + s2, x + s3, y + s4, sw, fg);
|
||||
|
|
@ -417,8 +273,6 @@ pub fn iconRect(
|
|||
drawLine(ctx, x + s3, y + s2, x + s3, y + s4, sw, fg);
|
||||
drawLine(ctx, x + s3, y + s4, x + s2, y + s4, sw, fg);
|
||||
},
|
||||
|
||||
// User
|
||||
.user => {
|
||||
fillCircle(ctx, x + s2, y + s3, @intCast(s5), fg);
|
||||
drawLine(ctx, x + s4, y + s - 2, x + s4, y + s2 + 2, sw, fg);
|
||||
|
|
@ -429,24 +283,18 @@ pub fn iconRect(
|
|||
fillCircle(ctx, x + s3, y + s3 + 1, @intCast(s6), fg);
|
||||
fillCircle(ctx, x + s23, y + s4, @intCast(s6), fg);
|
||||
},
|
||||
|
||||
// Calendar
|
||||
.calendar => {
|
||||
ctx.pushCommand(Command.rectOutline(x + 2, y + 4, @intCast(s - 4), @intCast(s - 6), fg));
|
||||
drawLine(ctx, x + 2, y + s3, x + s - 2, y + s3, sw, fg);
|
||||
drawLine(ctx, x + s3, y + 2, x + s3, y + 5, sw, fg);
|
||||
drawLine(ctx, x + s23, y + 2, x + s23, y + 5, sw, fg);
|
||||
},
|
||||
|
||||
// Clock
|
||||
.clock => {
|
||||
const r: u32 = @intCast(s2 - 2);
|
||||
strokeCircle(ctx, x + s2, y + s2, r, sw, fg);
|
||||
drawLine(ctx, x + s2, y + s2, x + s2, y + s3, sw, fg);
|
||||
drawLine(ctx, x + s2, y + s2, x + s23, y + s2, sw, fg);
|
||||
},
|
||||
|
||||
// Bell
|
||||
.bell => {
|
||||
drawLine(ctx, x + s3, y + s23, x + s3, y + s3, sw, fg);
|
||||
drawLine(ctx, x + s23, y + s23, x + s23, y + s3, sw, fg);
|
||||
|
|
@ -454,33 +302,23 @@ pub fn iconRect(
|
|||
drawLine(ctx, x + 3, y + s23, x + s - 3, y + s23, sw, fg);
|
||||
fillCircle(ctx, x + s2, y + s - 3, 2, fg);
|
||||
},
|
||||
|
||||
// Mail
|
||||
.mail => {
|
||||
ctx.pushCommand(Command.rectOutline(x + 2, y + s4, @intCast(s - 4), @intCast(s2), fg));
|
||||
drawLine(ctx, x + 2, y + s4, x + s2, y + s2, sw, fg);
|
||||
drawLine(ctx, x + s - 2, y + s4, x + s2, y + s2, sw, fg);
|
||||
},
|
||||
|
||||
// Play
|
||||
.play => {
|
||||
drawLine(ctx, x + s3, y + 3, x + s3, y + s - 3, sw, fg);
|
||||
drawLine(ctx, x + s3, y + 3, x + s23 + 1, y + s2, sw, fg);
|
||||
drawLine(ctx, x + s3, y + s - 3, x + s23 + 1, y + s2, sw, fg);
|
||||
},
|
||||
|
||||
// Pause
|
||||
.pause => {
|
||||
ctx.pushCommand(Command.rect(x + s4, y + 3, @intCast(s5), @intCast(s - 6), fg));
|
||||
ctx.pushCommand(Command.rect(x + s - s4 - s5, y + 3, @intCast(s5), @intCast(s - 6), fg));
|
||||
},
|
||||
|
||||
// Stop
|
||||
.stop => {
|
||||
ctx.pushCommand(Command.rect(x + 3, y + 3, @intCast(s - 6), @intCast(s - 6), fg));
|
||||
},
|
||||
|
||||
// Volume
|
||||
.volume => {
|
||||
ctx.pushCommand(Command.rect(x + 2, y + s3, 4, @intCast(s3), fg));
|
||||
drawLine(ctx, x + 6, y + s3, x + s2, y + 3, sw, fg);
|
||||
|
|
@ -494,111 +332,81 @@ pub fn iconRect(
|
|||
drawLine(ctx, x + s23, y + s3, x + s - 3, y + s23, sw, fg);
|
||||
drawLine(ctx, x + s - 3, y + s3, x + s23, y + s23, sw, fg);
|
||||
},
|
||||
|
||||
// Edit
|
||||
.edit => {
|
||||
drawLine(ctx, x + 3, y + s - 5, x + s - 5, y + 3, sw, fg);
|
||||
drawLine(ctx, x + s - 5, y + 3, x + s - 3, y + 5, sw, fg);
|
||||
drawLine(ctx, x + s - 3, y + 5, x + 5, y + s - 3, sw, fg);
|
||||
},
|
||||
|
||||
// Delete (trash)
|
||||
.delete => {
|
||||
ctx.pushCommand(Command.rectOutline(x + 4, y + 4, @intCast(s - 8), @intCast(s - 6), fg));
|
||||
drawLine(ctx, x + 2, y + 4, x + s - 2, y + 4, sw, fg);
|
||||
drawLine(ctx, x + s3, y + 2, x + s23, y + 2, sw, fg);
|
||||
},
|
||||
|
||||
// Refresh
|
||||
.refresh => {
|
||||
const r: u32 = @intCast(s3);
|
||||
strokeCircle(ctx, x + s2, y + s2, r, sw, fg);
|
||||
drawLine(ctx, x + s2 + @as(i32, @intCast(r)), y + s2 - 3, x + s2 + @as(i32, @intCast(r)) + 3, y + s2, sw, fg);
|
||||
},
|
||||
|
||||
// Filter
|
||||
.filter => {
|
||||
drawLine(ctx, x + 2, y + 3, x + s - 2, y + 3, sw, fg);
|
||||
drawLine(ctx, x + 2, y + 3, x + s2, y + s2, sw, fg);
|
||||
drawLine(ctx, x + s - 2, y + 3, x + s2, y + s2, sw, fg);
|
||||
drawLine(ctx, x + s2, y + s2, x + s2, y + s - 3, sw, fg);
|
||||
},
|
||||
|
||||
// Sort
|
||||
.sort => {
|
||||
drawLine(ctx, x + 3, y + s4, x + s - 3, y + s4, sw, fg);
|
||||
drawLine(ctx, x + 5, y + s2, x + s - 5, y + s2, sw, fg);
|
||||
drawLine(ctx, x + 7, y + s34, x + s - 7, y + s34, sw, fg);
|
||||
},
|
||||
|
||||
// Copy
|
||||
.copy => {
|
||||
ctx.pushCommand(Command.rectOutline(x + 2, y + 4, @intCast(s - 6), @intCast(s - 6), fg));
|
||||
ctx.pushCommand(Command.rectOutline(x + 4, y + 2, @intCast(s - 6), @intCast(s - 6), fg));
|
||||
},
|
||||
|
||||
// Paste
|
||||
.paste => {
|
||||
ctx.pushCommand(Command.rectOutline(x + 3, y + 3, @intCast(s - 6), @intCast(s - 5), fg));
|
||||
ctx.pushCommand(Command.rect(x + s3, y + 2, @intCast(s3), 3, fg));
|
||||
},
|
||||
|
||||
// Cut
|
||||
.cut => {
|
||||
fillCircle(ctx, x + s3, y + s23, @intCast(s6), fg);
|
||||
fillCircle(ctx, x + s23, y + s23, @intCast(s6), fg);
|
||||
drawLine(ctx, x + s3, y + s2, x + s2, y + 3, sw, fg);
|
||||
drawLine(ctx, x + s23, y + s2, x + s2, y + 3, sw, fg);
|
||||
},
|
||||
|
||||
// Undo
|
||||
.undo => {
|
||||
drawLine(ctx, x + 3, y + s3, x + s3, y + 3, sw, fg);
|
||||
drawLine(ctx, x + 3, y + s3, x + s3, y + s2, sw, fg);
|
||||
drawLine(ctx, x + 3, y + s3, x + s - 3, y + s3, sw, fg);
|
||||
drawLine(ctx, x + s - 3, y + s3, x + s - 3, y + s23, sw, fg);
|
||||
},
|
||||
|
||||
// Redo
|
||||
.redo => {
|
||||
drawLine(ctx, x + s - 3, y + s3, x + s23, y + 3, sw, fg);
|
||||
drawLine(ctx, x + s - 3, y + s3, x + s23, y + s2, sw, fg);
|
||||
drawLine(ctx, x + s - 3, y + s3, x + 3, y + s3, sw, fg);
|
||||
drawLine(ctx, x + 3, y + s3, x + 3, y + s23, sw, fg);
|
||||
},
|
||||
|
||||
// Folder open
|
||||
.folder_open => {
|
||||
ctx.pushCommand(Command.rectOutline(x + 2, y + 4, @intCast(s - 4), @intCast(s - 6), fg));
|
||||
drawLine(ctx, x + 2, y + s2, x + s3, y + s2, sw, fg);
|
||||
drawLine(ctx, x + s3, y + s2, x + s2, y + s3, sw, fg);
|
||||
},
|
||||
|
||||
// Image file
|
||||
.image_file => {
|
||||
ctx.pushCommand(Command.rectOutline(x + 2, y + 2, @intCast(s - 4), @intCast(s - 4), fg));
|
||||
drawLine(ctx, x + 4, y + s23, x + s3, y + s2, sw, fg);
|
||||
drawLine(ctx, x + s3, y + s2, x + s23, y + s23, sw, fg);
|
||||
fillCircle(ctx, x + s23, y + s3, 2, fg);
|
||||
},
|
||||
|
||||
// Download
|
||||
.download => {
|
||||
drawLine(ctx, x + s2, y + 3, x + s2, y + s23, sw, fg);
|
||||
drawLine(ctx, x + s2, y + s23, x + s3, y + s2, sw, fg);
|
||||
drawLine(ctx, x + s2, y + s23, x + s23, y + s2, sw, fg);
|
||||
drawLine(ctx, x + 3, y + s - 3, x + s - 3, y + s - 3, sw, fg);
|
||||
},
|
||||
|
||||
// Upload
|
||||
.upload => {
|
||||
drawLine(ctx, x + s2, y + s23, x + s2, y + 3, sw, fg);
|
||||
drawLine(ctx, x + s2, y + 3, x + s3, y + s4 + 1, sw, fg);
|
||||
drawLine(ctx, x + s2, y + 3, x + s23, y + s4 + 1, sw, fg);
|
||||
drawLine(ctx, x + 3, y + s - 3, x + s - 3, y + s - 3, sw, fg);
|
||||
},
|
||||
|
||||
// Grip (drag handle)
|
||||
.grip => {
|
||||
const dot_r: u32 = 1;
|
||||
fillCircle(ctx, x + s3, y + s3, dot_r, fg);
|
||||
|
|
@ -608,16 +416,12 @@ pub fn iconRect(
|
|||
fillCircle(ctx, x + s3, y + s23, dot_r, fg);
|
||||
fillCircle(ctx, x + s23, y + s23, dot_r, fg);
|
||||
},
|
||||
|
||||
// Drag
|
||||
.drag => {
|
||||
drawLine(ctx, x + s2, y + 2, x + s2, y + s - 2, sw, fg);
|
||||
drawLine(ctx, x + 2, y + s2, x + s - 2, y + s2, sw, fg);
|
||||
drawLine(ctx, x + s2, y + 2, x + s3, y + s4, sw, fg);
|
||||
drawLine(ctx, x + s2, y + 2, x + s23, y + s4, sw, fg);
|
||||
},
|
||||
|
||||
// Expand
|
||||
.expand => {
|
||||
drawLine(ctx, x + 2, y + 2, x + s3, y + 2, sw, fg);
|
||||
drawLine(ctx, x + 2, y + 2, x + 2, y + s3, sw, fg);
|
||||
|
|
@ -628,8 +432,6 @@ pub fn iconRect(
|
|||
drawLine(ctx, x + s - 2, y + s - 2, x + s23, y + s - 2, sw, fg);
|
||||
drawLine(ctx, x + s - 2, y + s - 2, x + s - 2, y + s23, sw, fg);
|
||||
},
|
||||
|
||||
// Collapse
|
||||
.collapse => {
|
||||
drawLine(ctx, x + s3, y + s3, x + 2, y + s3, sw, fg);
|
||||
drawLine(ctx, x + s3, y + s3, x + s3, y + 2, sw, fg);
|
||||
|
|
@ -640,19 +442,13 @@ pub fn iconRect(
|
|||
drawLine(ctx, x + s23, y + s23, x + s - 2, y + s23, sw, fg);
|
||||
drawLine(ctx, x + s23, y + s23, x + s23, y + s - 2, sw, fg);
|
||||
},
|
||||
|
||||
// Maximize
|
||||
.maximize => {
|
||||
ctx.pushCommand(Command.rectOutline(x + 3, y + 3, @intCast(s - 6), @intCast(s - 6), fg));
|
||||
drawLine(ctx, x + 3, y + 5, x + s - 3, y + 5, sw, fg);
|
||||
},
|
||||
|
||||
// Minimize
|
||||
.minimize => {
|
||||
drawLine(ctx, x + 3, y + s - 4, x + s - 3, y + s - 4, sw, fg);
|
||||
},
|
||||
|
||||
// External link
|
||||
.external_link => {
|
||||
ctx.pushCommand(Command.rectOutline(x + 2, y + 4, @intCast(s - 6), @intCast(s - 6), fg));
|
||||
drawLine(ctx, x + s2, y + 2, x + s - 2, y + 2, sw, fg);
|
||||
|
|
@ -662,92 +458,6 @@ pub fn iconRect(
|
|||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Helper functions
|
||||
// =============================================================================
|
||||
|
||||
/// Draw a line with thickness
|
||||
fn drawLine(ctx: *Context, x1: i32, y1: i32, x2: i32, y2: i32, thickness: u32, color: Style.Color) void {
|
||||
if (thickness <= 1) {
|
||||
ctx.pushCommand(Command.line(x1, y1, x2, y2, color));
|
||||
} else {
|
||||
const dx = x2 - x1;
|
||||
const dy = y2 - y1;
|
||||
const len = @sqrt(@as(f32, @floatFromInt(dx * dx + dy * dy)));
|
||||
|
||||
if (len < 1) {
|
||||
ctx.pushCommand(Command.rect(x1, y1, thickness, thickness, color));
|
||||
return;
|
||||
}
|
||||
|
||||
const nx = -@as(f32, @floatFromInt(dy)) / len;
|
||||
const ny = @as(f32, @floatFromInt(dx)) / len;
|
||||
|
||||
const half = @as(f32, @floatFromInt(thickness)) / 2.0;
|
||||
var offset: f32 = -half;
|
||||
while (offset < half) : (offset += 1.0) {
|
||||
const ox = @as(i32, @intFromFloat(nx * offset));
|
||||
const oy = @as(i32, @intFromFloat(ny * offset));
|
||||
ctx.pushCommand(Command.line(x1 + ox, y1 + oy, x2 + ox, y2 + oy, color));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Fill a circle
|
||||
fn fillCircle(ctx: *Context, cx: i32, cy: i32, radius: u32, color: Style.Color) void {
|
||||
if (radius == 0) {
|
||||
ctx.pushCommand(Command.rect(cx, cy, 1, 1, color));
|
||||
return;
|
||||
}
|
||||
|
||||
const r = @as(i32, @intCast(radius));
|
||||
var dy: i32 = -r;
|
||||
while (dy <= r) : (dy += 1) {
|
||||
const dy_f = @as(f32, @floatFromInt(dy));
|
||||
const r_f = @as(f32, @floatFromInt(r));
|
||||
const dx = @as(i32, @intFromFloat(@sqrt(r_f * r_f - dy_f * dy_f)));
|
||||
ctx.pushCommand(Command.rect(cx - dx, cy + dy, @intCast(dx * 2 + 1), 1, color));
|
||||
}
|
||||
}
|
||||
|
||||
/// Stroke a circle
|
||||
fn strokeCircle(ctx: *Context, cx: i32, cy: i32, radius: u32, thickness: u32, color: Style.Color) void {
|
||||
if (radius == 0) return;
|
||||
|
||||
const r = @as(i32, @intCast(radius));
|
||||
var px: i32 = 0;
|
||||
var py: i32 = r;
|
||||
var d: i32 = 3 - 2 * r;
|
||||
|
||||
while (px <= py) {
|
||||
setPixelThick(ctx, cx + px, cy + py, thickness, color);
|
||||
setPixelThick(ctx, cx - px, cy + py, thickness, color);
|
||||
setPixelThick(ctx, cx + px, cy - py, thickness, color);
|
||||
setPixelThick(ctx, cx - px, cy - py, thickness, color);
|
||||
setPixelThick(ctx, cx + py, cy + px, thickness, color);
|
||||
setPixelThick(ctx, cx - py, cy + px, thickness, color);
|
||||
setPixelThick(ctx, cx + py, cy - px, thickness, color);
|
||||
setPixelThick(ctx, cx - py, cy - px, thickness, color);
|
||||
|
||||
if (d < 0) {
|
||||
d = d + 4 * px + 6;
|
||||
} else {
|
||||
d = d + 4 * (px - py) + 10;
|
||||
py -= 1;
|
||||
}
|
||||
px += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn setPixelThick(ctx: *Context, pixel_x: i32, pixel_y: i32, thickness: u32, color: Style.Color) void {
|
||||
if (thickness <= 1) {
|
||||
ctx.pushCommand(Command.rect(pixel_x, pixel_y, 1, 1, color));
|
||||
} else {
|
||||
const half = @as(i32, @intCast(thickness / 2));
|
||||
ctx.pushCommand(Command.rect(pixel_x - half, pixel_y - half, thickness, thickness, color));
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Tests
|
||||
// =============================================================================
|
||||
146
src/widgets/icon/types.zig
Normal file
146
src/widgets/icon/types.zig
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
//! Icon - Tipos y configuración
|
||||
//!
|
||||
//! Size, IconType, Config, Colors.
|
||||
|
||||
const Style = @import("../../core/style.zig");
|
||||
|
||||
// =============================================================================
|
||||
// Size
|
||||
// =============================================================================
|
||||
|
||||
/// Icon size presets
|
||||
pub const Size = enum {
|
||||
small, // 12x12
|
||||
medium, // 16x16
|
||||
large, // 24x24
|
||||
xlarge, // 32x32
|
||||
|
||||
pub fn pixels(self: Size) u32 {
|
||||
return switch (self) {
|
||||
.small => 12,
|
||||
.medium => 16,
|
||||
.large => 24,
|
||||
.xlarge => 32,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// =============================================================================
|
||||
// IconType
|
||||
// =============================================================================
|
||||
|
||||
/// Built-in icon types
|
||||
pub const IconType = enum {
|
||||
// Navigation
|
||||
arrow_up,
|
||||
arrow_down,
|
||||
arrow_left,
|
||||
arrow_right,
|
||||
chevron_up,
|
||||
chevron_down,
|
||||
chevron_left,
|
||||
chevron_right,
|
||||
home,
|
||||
menu,
|
||||
more_horizontal,
|
||||
more_vertical,
|
||||
|
||||
// Actions
|
||||
check,
|
||||
close,
|
||||
plus,
|
||||
minus,
|
||||
edit,
|
||||
delete,
|
||||
refresh,
|
||||
search,
|
||||
settings,
|
||||
filter,
|
||||
sort,
|
||||
copy,
|
||||
paste,
|
||||
cut,
|
||||
undo,
|
||||
redo,
|
||||
|
||||
// Files
|
||||
file,
|
||||
folder,
|
||||
folder_open,
|
||||
document,
|
||||
image_file,
|
||||
download,
|
||||
upload,
|
||||
save,
|
||||
|
||||
// Status
|
||||
info,
|
||||
warning,
|
||||
error_icon,
|
||||
success,
|
||||
question,
|
||||
star,
|
||||
star_filled,
|
||||
heart,
|
||||
heart_filled,
|
||||
|
||||
// UI elements
|
||||
eye,
|
||||
eye_off,
|
||||
lock,
|
||||
unlock,
|
||||
user,
|
||||
users,
|
||||
calendar,
|
||||
clock,
|
||||
bell,
|
||||
mail,
|
||||
|
||||
// Media
|
||||
play,
|
||||
pause,
|
||||
stop,
|
||||
volume,
|
||||
volume_off,
|
||||
|
||||
// Misc
|
||||
grip,
|
||||
drag,
|
||||
expand,
|
||||
collapse,
|
||||
maximize,
|
||||
minimize,
|
||||
external_link,
|
||||
};
|
||||
|
||||
// =============================================================================
|
||||
// Config
|
||||
// =============================================================================
|
||||
|
||||
/// Icon configuration
|
||||
pub const Config = struct {
|
||||
/// Icon size
|
||||
size: Size = .medium,
|
||||
/// Custom size (overrides size preset)
|
||||
custom_size: ?u32 = null,
|
||||
/// Stroke width
|
||||
stroke_width: u32 = 2,
|
||||
/// Fill icon
|
||||
filled: bool = false,
|
||||
};
|
||||
|
||||
// =============================================================================
|
||||
// Colors
|
||||
// =============================================================================
|
||||
|
||||
/// Icon colors
|
||||
pub const Colors = struct {
|
||||
foreground: Style.Color = Style.Color.rgba(220, 220, 220, 255),
|
||||
background: ?Style.Color = null,
|
||||
|
||||
pub fn fromTheme(theme: Style.Theme) Colors {
|
||||
return .{
|
||||
.foreground = theme.foreground,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
@ -9,7 +9,7 @@ const Command = @import("../core/command.zig");
|
|||
const Layout = @import("../core/layout.zig");
|
||||
const Style = @import("../core/style.zig");
|
||||
const Input = @import("../core/input.zig");
|
||||
const icon_module = @import("icon.zig");
|
||||
const icon_module = @import("icon/icon.zig");
|
||||
|
||||
/// IconButton style variants
|
||||
pub const ButtonStyle = enum {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ const Command = @import("../core/command.zig");
|
|||
const Layout = @import("../core/layout.zig");
|
||||
const Style = @import("../core/style.zig");
|
||||
const Input = @import("../core/input.zig");
|
||||
const icon_module = @import("icon.zig");
|
||||
const icon_module = @import("icon/icon.zig");
|
||||
|
||||
/// Navigation item
|
||||
pub const NavItem = struct {
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ pub const richtext = @import("richtext.zig");
|
|||
pub const breadcrumb = @import("breadcrumb.zig");
|
||||
pub const canvas = @import("canvas.zig");
|
||||
pub const chart = @import("chart.zig");
|
||||
pub const icon = @import("icon.zig");
|
||||
pub const icon = @import("icon/icon.zig");
|
||||
pub const virtual_scroll = @import("virtual_scroll.zig");
|
||||
pub const virtual_advanced_table = @import("virtual_advanced_table/virtual_advanced_table.zig");
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue