Skip to content

Commit

Permalink
wasm: split into multiple files and implement setEnabled
Browse files Browse the repository at this point in the history
  • Loading branch information
zenith391 committed Oct 27, 2024
1 parent fcdb2ad commit 4de0b92
Show file tree
Hide file tree
Showing 15 changed files with 677 additions and 602 deletions.
51 changes: 51 additions & 0 deletions src/backends/wasm/Button.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
const common = @import("common.zig");
const js = @import("js.zig");
const lib = @import("../../capy.zig");
const GuiWidget = common.GuiWidget;
const Events = common.Events;

const Button = @This();

peer: *GuiWidget,
/// The label returned by getLabel(), it's invalidated everytime setLabel is called
temp_label: ?[:0]const u8 = null,

pub usingnamespace Events(Button);

pub fn create() !Button {
return Button{ .peer = try GuiWidget.init(
Button,
lib.lasting_allocator,
"button",
"button",
) };
}

pub fn setLabel(self: *Button, label: [:0]const u8) void {
js.setText(self.peer.element, label.ptr, label.len);
if (self.temp_label) |slice| {
lib.lasting_allocator.free(slice);
self.temp_label = null;
}
}

pub fn getLabel(self: *const Button) [:0]const u8 {
if (self.temp_label) |text| {
return text;
} else {
const len = js.getTextLen(self.peer.element);
const text = lib.lasting_allocator.allocSentinel(u8, len, 0) catch unreachable;
js.getText(self.peer.element, text.ptr);
self.temp_label = text;

return text;
}
}

pub fn setEnabled(self: *const Button, enable: bool) void {
if (enable) {
js.removeAttribute(self.peer.element, "disabled");
} else {
js.setAttribute(self.peer.element, "disabled", "disabled");
}
}
128 changes: 128 additions & 0 deletions src/backends/wasm/Canvas.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
const std = @import("std");
const common = @import("common.zig");
const js = @import("js.zig");
const lib = @import("../../capy.zig");
const GuiWidget = common.GuiWidget;
const Events = common.Events;

const Canvas = @This();

peer: *GuiWidget,

pub usingnamespace Events(Canvas);

pub const DrawContextImpl = struct {
ctx: js.CanvasContextId,

pub const Font = struct {
face: [:0]const u8,
size: f64,
};

pub const TextSize = struct { width: u32, height: u32 };

pub const TextLayout = struct {
wrap: ?f64 = null,

pub fn setFont(self: *TextLayout, font: Font) void {
// TODO
_ = self;
_ = font;
}

pub fn deinit(self: *TextLayout) void {
// TODO
_ = self;
}

pub fn getTextSize(self: *TextLayout, str: []const u8) TextSize {
// TODO
_ = self;
_ = str;
return TextSize{ .width = 0, .height = 0 };
}

pub fn init() TextLayout {
return TextLayout{};
}
};

pub fn setColorRGBA(self: *DrawContextImpl, r: f32, g: f32, b: f32, a: f32) void {
const color = lib.Color{
.red = @as(u8, @intFromFloat(std.math.clamp(r, 0, 1) * 255)),
.green = @as(u8, @intFromFloat(std.math.clamp(g, 0, 1) * 255)),
.blue = @as(u8, @intFromFloat(std.math.clamp(b, 0, 1) * 255)),
.alpha = @as(u8, @intFromFloat(std.math.clamp(a, 0, 1) * 255)),
};
js.setColor(self.ctx, color.red, color.green, color.blue, color.alpha);
}

pub fn rectangle(self: *DrawContextImpl, x: i32, y: i32, w: u32, h: u32) void {
js.rectPath(self.ctx, x, y, w, h);
}

pub fn roundedRectangleEx(self: *DrawContextImpl, x: i32, y: i32, w: u32, h: u32, corner_radiuses: [4]f32) void {
_ = corner_radiuses;
js.rectPath(self.ctx, x, y, w, h);
}

pub fn text(self: *DrawContextImpl, x: i32, y: i32, layout: TextLayout, str: []const u8) void {
// TODO: layout
_ = layout;
js.fillText(self.ctx, str.ptr, str.len, x, y);
}

pub fn image(self: *DrawContextImpl, x: i32, y: i32, w: u32, h: u32, data: lib.ImageData) void {
_ = w;
_ = h; // TODO: scaling
js.fillImage(self.ctx, data.peer.id, x, y);
}

pub fn line(self: *DrawContextImpl, x1: i32, y1: i32, x2: i32, y2: i32) void {
js.moveTo(self.ctx, x1, y1);
js.lineTo(self.ctx, x2, y2);
js.stroke(self.ctx);
}

pub fn ellipse(self: *DrawContextImpl, x: i32, y: i32, w: u32, h: u32) void {
js.ellipse(self.ctx, x, y, w, h);
}

pub fn clear(self: *DrawContextImpl, x: u32, y: u32, w: u32, h: u32) void {
// TODO
_ = self;
_ = x;
_ = y;
_ = w;
_ = h;
}

pub fn stroke(self: *DrawContextImpl) void {
js.stroke(self.ctx);
}

pub fn fill(self: *DrawContextImpl) void {
js.fill(self.ctx);
}
};

pub fn create() !Canvas {
return Canvas{ .peer = try GuiWidget.init(
Canvas,
lib.lasting_allocator,
"canvas",
"canvas",
) };
}

pub fn _requestDraw(self: *Canvas) !void {
const ctxId = js.openContext(self.peer.element);
const impl = DrawContextImpl{ .ctx = ctxId };
var ctx = @import("../../backend.zig").DrawContext{ .impl = impl };
if (self.peer.class.drawHandler) |handler| {
handler(&ctx, self.peer.classUserdata);
}
if (self.peer.user.drawHandler) |handler| {
handler(&ctx, self.peer.userdata);
}
}
50 changes: 50 additions & 0 deletions src/backends/wasm/Container.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
const common = @import("common.zig");
const js = @import("js.zig");
const lib = @import("../../capy.zig");
const GuiWidget = common.GuiWidget;
const Events = common.Events;

const Container = @This();

peer: *GuiWidget,

pub usingnamespace Events(Container);

pub fn create() !Container {
return Container{
.peer = try GuiWidget.init(
Container,
lib.lasting_allocator,
"div",
"container",
),
};
}

pub fn add(self: *Container, peer: *GuiWidget) void {
js.appendElement(self.peer.element, peer.element);
self.peer.children.append(peer) catch unreachable;
}

pub fn remove(self: *const Container, peer: *GuiWidget) void {
_ = peer;
_ = self;
}

pub fn setTabOrder(self: *Container, peers: []const *GuiWidget) void {
_ = peers;
_ = self;
}

pub fn move(self: *const Container, peer: *GuiWidget, x: u32, y: u32) void {
_ = self;
js.setPos(peer.element, x, y);
}

pub fn resize(self: *const Container, peer: *GuiWidget, w: u32, h: u32) void {
_ = self;
js.setSize(peer.element, w, h);
if (peer.user.resizeHandler) |handler| {
handler(w, h, peer.userdata);
}
}
20 changes: 20 additions & 0 deletions src/backends/wasm/Dropdown.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const common = @import("common.zig");
const js = @import("js.zig");
const lib = @import("../../capy.zig");
const GuiWidget = common.GuiWidget;
const Events = common.Events;

const Dropdown = @This();

peer: js.ElementId,

pub usingnamespace Events(Dropdown);

pub fn create() !Dropdown {
return Dropdown{ .peer = try GuiWidget.init(
Dropdown,
lib.lasting_allocator,
"select",
"select",
) };
}
22 changes: 22 additions & 0 deletions src/backends/wasm/ImageData.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const common = @import("common.zig");
const js = @import("js.zig");
const lib = @import("../../capy.zig");
const GuiWidget = common.GuiWidget;
const Events = common.Events;

const ImageData = @This();

// TODO
id: js.ResourceId,

pub fn from(width: usize, height: usize, stride: usize, cs: lib.Colorspace, bytes: []const u8) !ImageData {
return ImageData{
.id = js.uploadImage(
width,
height,
stride,
cs == .RGB,
bytes.ptr,
),
};
}
45 changes: 45 additions & 0 deletions src/backends/wasm/Label.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
const common = @import("common.zig");
const js = @import("js.zig");
const lib = @import("../../capy.zig");
const GuiWidget = common.GuiWidget;
const Events = common.Events;

const Label = @This();

peer: *GuiWidget,
/// The text returned by getText(), it's invalidated everytime setText is called
temp_text: ?[]const u8 = null,

pub usingnamespace Events(Label);

pub fn create() !Label {
return Label{ .peer = try GuiWidget.init(
Label,
lib.lasting_allocator,
"span",
"label",
) };
}

pub fn setAlignment(_: *Label, _: f32) void {}

pub fn setText(self: *Label, text: []const u8) void {
js.setText(self.peer.element, text.ptr, text.len);
if (self.temp_text) |slice| {
lib.lasting_allocator.free(slice);
self.temp_text = null;
}
}

pub fn getText(self: *Label) []const u8 {
if (self.temp_text) |text| {
return text;
} else {
const len = js.getTextLen(self.peer.element);
const text = lib.lasting_allocator.allocSentinel(u8, len, 0) catch unreachable;
js.getText(self.peer.element, text.ptr);
self.temp_text = text;

return text;
}
}
64 changes: 64 additions & 0 deletions src/backends/wasm/Slider.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
const std = @import("std");
const common = @import("common.zig");
const js = @import("js.zig");
const lib = @import("../../capy.zig");
const GuiWidget = common.GuiWidget;
const Events = common.Events;

const Slider = @This();

peer: *GuiWidget,

pub usingnamespace Events(Slider);

pub fn create() !Slider {
return Slider{
.peer = try GuiWidget.init(
Slider,
lib.lasting_allocator,
"input",
"slider",
),
};
}

pub fn getValue(self: *const Slider) f32 {
return js.getValue(self.peer.element);
}

pub fn setValue(self: *Slider, value: f32) void {
var buf: [100]u8 = undefined;
const slice = std.fmt.bufPrint(&buf, "{}", .{value}) catch unreachable;
js.setAttribute(self.peer.element, "value", slice);
}

pub fn setMinimum(self: *Slider, minimum: f32) void {
var buf: [100]u8 = undefined;
const slice = std.fmt.bufPrint(&buf, "{}", .{minimum}) catch unreachable;
js.setAttribute(self.peer.element, "min", slice);
}

pub fn setMaximum(self: *Slider, maximum: f32) void {
var buf: [100]u8 = undefined;
const slice = std.fmt.bufPrint(&buf, "{}", .{maximum}) catch unreachable;
js.setAttribute(self.peer.element, "max", slice);
}

pub fn setStepSize(self: *Slider, stepSize: f32) void {
var buf: [100]u8 = undefined;
const slice = std.fmt.bufPrint(&buf, "{}", .{stepSize}) catch unreachable;
js.setAttribute(self.peer.element, "step", slice);
}

pub fn setEnabled(self: *Slider, enable: bool) void {
if (enable) {
js.removeAttribute(self.peer.element, "disabled");
} else {
js.setAttribute(self.peer.element, "disabled", "disabled");
}
}

pub fn setOrientation(self: *Slider, orientation: lib.Orientation) void {
_ = orientation;
_ = self;
}
Loading

0 comments on commit 4de0b92

Please sign in to comment.