intermediate #1

Merged
yves-biener merged 31 commits from intermediate into main 2025-02-16 16:02:59 +01:00
4 changed files with 93 additions and 27 deletions
Showing only changes of commit d951906b2b - Show all commits

View File

@@ -73,16 +73,12 @@ the primary use-case for myself to create this library in the first place.
## Roadmap ## Roadmap
- [ ] Container rendering - [ ] Container rendering
- [ ] Layout - [x] Layout
- [x] direction - [x] direction
- [x] vertical - [x] vertical
- [x] horizontal - [x] horizontal
- [x] padding - [x] padding
- [x] gap - [x] gap
- [x] alignment (removed - for now at least)
- center
- left
- right
- [x] sizing (removed - for now at least) - [x] sizing (removed - for now at least)
- width - width
- height - height
@@ -96,10 +92,23 @@ the primary use-case for myself to create this library in the first place.
- [x] corners - [x] corners
- [x] separators - [x] separators
- [x] Rectangle - [x] Rectangle
- [ ] Scroll - [ ] User control
- [x] event handling
- [x] user content
- [ ] Default `Element` implementations
- [ ] Scrollable
- [ ] user input handling
- [ ] vertical - [ ] vertical
- [ ] horizontal - [ ] horizontal
- [ ] scroll bar(s) - [ ] scroll bar(s) rendering
- [ ] vertical
- [ ] horizontal
- [ ] Content alignment (i.e. standard calculations done with the provided `Size`)
- [ ] Text display
- [ ] User input
- [ ] single line
- [ ] multi line
- [ ] min size? (I don't have access to the `.resize` `Event`..)
Decorations should respect the layout and the viewport accordingly. This means Decorations should respect the layout and the viewport accordingly. This means
that scrollbars are always visible (except there is no need to have a scrollbar) that scrollbars are always visible (except there is no need to have a scrollbar)
@@ -119,6 +128,30 @@ This still has one issue: Layout of child elements that are already too large
scrollbar given the right parameters however. The scrolling input action would scrollbar given the right parameters however. The scrolling input action would
then also be implemented by the user. then also be implemented by the user.
Open questions are regarding the sizing options (i.e. how is the size of a
`Container` actually controlled?, how should it be controlled?, etc.). There
should be support for the child elements to provide some kind of 'list'
functionality built-in.
**REMINDER**: (mostly for myself) The library should be and remain simple. This
means that some code for using the library may be duplicated, but this is not
the main goal. Others may provide more re-usable code snippets that build on top
of this library instead.
### User specific event handling and content rendering
For interactions controlled by the user each container can use an `Element`
interface which contains functions which are called by the `Container`
during event handling (i.e. `fn handle(..)`) and during rendering (i.e. `fn
content(..)`) to provide user specific content and user interaction. The
`Element` may be stateful, but may also be stateless and then be re-used in
multiple different `Container`s.
Composing multiple `Element`s currently requires the implementation of a wrapper
which contains the `Element`s that need to be handled (should work pretty well
for stateless `Element`s). Such *stateless* `Element`s may be provided by this
library.
### Input ### Input
How is the user input handled in the containers? Should there be active How is the user input handled in the containers? Should there be active

View File

@@ -6,7 +6,7 @@ const Key = zterm.Key;
const log = std.log.scoped(.example); const log = std.log.scoped(.example);
pub const ExampleElement = struct { pub const ExampleElement = packed struct {
pub fn element(this: *@This()) App.Element { pub fn element(this: *@This()) App.Element {
return .{ return .{
.ptr = this, .ptr = this,

View File

@@ -185,17 +185,6 @@ pub const Rectangle = packed struct {
} }
}; };
/// Scroll configuration struct
pub const Scroll = packed struct {
/// Enable horizontal scrolling for this element
horizontal: bool = false,
/// Enable vertical scrolling for this element
vertical: bool = false,
// TODO: rendering enhancements:
// - render corresponding scroll-bars?
};
/// Layout configuration struct /// Layout configuration struct
pub const Layout = packed struct { pub const Layout = packed struct {
/// control the direction in which child elements are laid out /// control the direction in which child elements are laid out
@@ -244,7 +233,6 @@ pub fn Container(comptime Event: type) type {
pub const Properties = packed struct { pub const Properties = packed struct {
border: Border = .{}, border: Border = .{},
rectangle: Rectangle = .{}, rectangle: Rectangle = .{},
scroll: Scroll = .{},
layout: Layout = .{}, layout: Layout = .{},
}; };
@@ -328,9 +316,7 @@ pub fn Container(comptime Event: type) type {
break :blk rows - element_rows * len; break :blk rows - element_rows * len;
}, },
}; };
// TODO: make sure that items cannot underflow in size!
// - make their size and position still according (even if outside of the visible space!)
// - don't render them then accordingly -> avoid index out of bounce accesses!
for (this.elements.items) |*element| { for (this.elements.items) |*element| {
var element_size: Size = undefined; var element_size: Size = undefined;
switch (layout.direction) { switch (layout.direction) {

View File

@@ -1,4 +1,6 @@
//! Interface for Element's which describe the contents of a `Container`. //! Interface for Element's which describe the contents of a `Container`.
const std = @import("std");
const Cell = @import("cell.zig"); const Cell = @import("cell.zig");
const Size = @import("size.zig").Size; const Size = @import("size.zig").Size;
@@ -12,12 +14,57 @@ pub fn Element(Event: type) type {
content: ?*const fn (ctx: *anyopaque, cells: []Cell, size: Size) anyerror!void = null, content: ?*const fn (ctx: *anyopaque, cells: []Cell, size: Size) anyerror!void = null,
}; };
/// Handle the received event. The event is one of the user provided
/// events or a system event, with the exception of the `.resize`
/// `Event` as every `Container` already handles that event.
///
/// In case of user errors this function should return an error. This
/// error may then be used by the application to display information
/// about the user error.
pub inline fn handle(this: @This(), event: Event) !void { pub inline fn handle(this: @This(), event: Event) !void {
if (this.vtable.handle) |handle_fn| try handle_fn(this.ptr, event); if (this.vtable.handle) |handle_fn|
try handle_fn(this.ptr, event);
} }
/// Write content into the `cells` of the `Container`. The associated
/// `cells` slice has the size of (`size.cols * size.rows`). The
/// renderer will know where to place the contents on the screen.
///
/// This function should only fail with an error if the error is
/// non-recoverable (i.e. an allocation error, system error, etc.).
/// Otherwise user specific errors should be caught using the `handle`
/// function before the rendering of the `Container` happens.
pub inline fn content(this: @This(), cells: []Cell, size: Size) !void { pub inline fn content(this: @This(), cells: []Cell, size: Size) !void {
if (this.vtable.content) |content_fn| try content_fn(this.ptr, cells, size); if (this.vtable.content) |content_fn|
try content_fn(this.ptr, cells, size);
}
};
}
/// This is an empty template implementation for an Element type which `zterm` may provide.
///
/// TODO: Should elements need to be composible with each other, such that they may build complexer outputs?
/// - the goal would rather be to have re-usable parts of handlers and/or content functions which serve similar functionalities.
pub fn Template(Event: type) type {
return packed struct {
pub fn element(this: *@This()) Element(Event) {
return .{
.ptr = this,
.vtable = &.{
.handle = handle,
.content = content,
},
};
}
fn handle(ctx: *anyopaque, event: Event) !void {
_ = ctx;
_ = event;
}
fn content(ctx: *anyopaque, cells: []Cell, size: Size) !void {
_ = ctx;
std.debug.assert(cells.len == @as(usize, size.cols) * @as(usize, size.rows));
} }
}; };
} }