david-vanderson / dvui

Other
431 stars 36 forks source link

Tabbed Widget #130

Open VisenDev opened 2 months ago

VisenDev commented 2 months ago

Tabs seem like a fairly common ui construct. It might be worth adding a widget to support this in dvui.}

Proposed api

{
  const TabNames = enum{home, edit, help};
  const tabs = try dvui.tabbed(@src(), TabNames, TabbedOptions(TabNames){
    .tab_render_fn = &default_tab_render_fn,
    .location = .top,
   }, .{});
  defer tabs.deinit();

  switch(tabs.getActiveTab()) {
     .home => {
        //render home menu
     },
     .edit => {
       //render edit menu
     },
     .help => {
        //render help menu
     }
  }
}

The usage of a tab_render_fn lets tabs support more complex widgets like icons - rather than being limited to just text.

david-vanderson commented 2 months ago

Good idea. I remember @JosephABudd made a tabbed interface. Is that still available? I think it used MenuItems as the tabs, and looked something like this (ignore the red borders): https://github.com/david-vanderson/dvui/discussions/67

Instead of a callback, I'd rather the api be that the code renders each tab directly. There's not that much functionality, but likely a lot of visual details to get right. Which corners of the tabs to round, how to show the active one differently, what happens if there are too many to fit in a single row/col.

JosephABudd commented 2 months ago

The widget is in the widget/zip folder. widget.zip

Below is the tab-bar being initeilaized:

        self.tabs = try Tabs.init(startup, self_as_container, tabs_options);
        errdefer self.deinit();

        // Create 1 of each type of tab.

        try self.AddNewAddTab(true);

Blow is the AddNewAddTab fn.

    pub fn AddNewAddTab(
        self: *Screen,
        selected: bool,
    ) !void {
        // The Add tab uses this screen's Add panel for content.
        const panel: *AddPanel = try AddPanel.init(
            self.allocator,
            self.window,
            self.main_view,
            self.messenger.?,
            self.exit,
            self.state.?.*,
        );
        const panel_as_content: *Content = try panel.asContent();
        errdefer panel.deinit();
        const tab: *Tab = try Tab.init(
            self.tabs.?,
            self.main_view,
            panel_as_content,
            .{
                // KICKZIG TODO:
                // You can override the options for the Add tab.
                //.closable = true,
                //.movable = true,
            },
        );
        errdefer {
            panel_as_content.deinit();
        }
        try self.tabs.?.appendTab(tab, selected);
        errdefer {
            self.allocator.destroy(tab);
            panel_as_content.deinit();
        }
    }
JosephABudd commented 2 months ago

The screen shots are at https://github.com/JosephABudd/kickzig

david-vanderson commented 2 months ago

Thanks - that helps a lot!

JosephABudd commented 2 months ago

I've been refactoring pretty much everything in kickzig. Here is my final working version of the widget folder. I worked on it today and fixed a couple of bigs that were in the version I uploaded previously. The edits were in api.zig and TabBarWidget.zig. tabbar.zip