Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tabs widget #578

Closed
Kaiden42 opened this issue Oct 24, 2020 · 5 comments
Closed

Tabs widget #578

Kaiden42 opened this issue Oct 24, 2020 · 5 comments
Labels
feature New feature or request

Comments

@Kaiden42
Copy link
Contributor

I've experimented with a Tabs widget recently for structuring the UI using tabs. This widget was inspired by the tabs of the ionic and flutter framework.

tabs_example

It is also possible to define a message for handling the closing of a tab. In this case there will be a small close icon rendered on the right of each tab.

tabs_closeable

Anyone interested in such kind of widget? :)

However, there is still one problem I wasn't able to solve. This problem is about the lazy evaluation of the content of a tab. For me, the content of the tab should only be created when the tab is visible. I tried two approaches of handling this:

  • A closure: This works fine unless you are trying to take a reference to the application data. (The reference may not live long enough)

  • A trait: This could work, but hiding the specific rendering backend from the user would lead to massive code duplication.

For now it is only a TabBar wigdet and the user would need to implement the logic of the content.

A small working example currently looks like this:

use iced::{Column, Sandbox, Settings, TabBar, TabLabel, Text};

fn main() -> iced::Result {
    TabsExample::run(Settings::default())
}

#[derive(Debug)]
enum Message {
    TabSelected(usize),
}

struct TabsExample {
    selected_tab: usize,
}

impl Sandbox for TabsExample {
    type Message = Message;

    fn new() -> Self {
        TabsExample {
            selected_tab: 0,
        }
    }

    fn title(&self) -> String {
        String::from("Tabs example")
    }

    fn update(&mut self, message: Self::Message) {
        match message {
            Message::TabSelected(index) => {
                self.selected_tab = index
            }
        }
    }

    fn view(&mut self) -> iced::Element<'_, Self::Message> {
        Column::new()
            .push(
                TabBar::new(
                    self.selected_tab,
                    vec!(
                        TabLabel::Text(String::from("One")),
                        TabLabel::Text(String::from("Two")),
                        TabLabel::Text(String::from("Three")),
                    ),
                    Message::TabSelected,
                )
            )
            .push(
                match self.selected_tab {
                    0 => Text::new("One"),
                    1 => Text::new("Two"),
                    2 => Text::new("Three"),
                    _ => panic!()
                }
            )
            .into()
    }
}

This isn't ideal and I don't like this much.

Maybe someone else with a better knowledge about Rust has an idea of how to solve this problem. What would be the drawback of just creating the content even if the tab is not selected?

@twitchyliquid64
Copy link

Anyone interested in such kind of widget? :)

Yes! 🔥 😀 🎆 :DD

However, there is still one problem I wasn't able to solve. This problem is about the lazy evaluation of the content of a tab. For me, the content of the tab should only be created when the tab is visible. I tried two approaches of handling this:

The actual 'evaluation' of widgets (the costly/slow/expensive bits) are in two function calls to the widget:

  1. layout()
  2. draw()

If your TabBar code only call those methods on the widget for the currently-selected tab, I think you are good!

@hecrj
Copy link
Member

hecrj commented Oct 28, 2020

This isn't ideal and I don't like this much.

Could you elaborate? I like the idea of the TabBar being just a tab bar.

In other words, I don't think a TabBar should dictate much about the layout or position of its content. For instance, most web browsers show a (somewhat) static navbar between the tabs and their content.

Anyone interested in such kind of widget? :)

I am sure many would find this widget useful (me included!). Feel free to open-source it! Not every widget needs to make it into the main library right from the start.

@hecrj hecrj added the feature New feature or request label Oct 28, 2020
@ajax-crypto
Copy link

ajax-crypto commented Oct 28, 2020

This is wonderful!
I hope the close button is customisable w.r.t. the look (icon) and position (right or left of text)?
Also, would it be possible to do tab pinning, which implies that unpinned tabs can be rearranged?
(The other customization point is vertical vs. horizontal alignment of tabs)
(I dont know enough Rust to meaningfully contribute to this, I am learning it right now)

@Kaiden42
Copy link
Contributor Author

Yes! fire grinning fireworks :DD
...
If your TabBar code only call those methods on the widget for the currently-selected tab, I think you are good!

Thank you very much for your feedback! :) And I apologise for not responding until now.

Could you elaborate? I like the idea of the TabBar being just a tab bar.

Now that I've thought about it for a while, I think it's not that bad of an idea. Therefore I have decided to support both options. A TabBar Widget for a standalone TabBar and a Tabs Widget as a wrapper around the TabBar, which also handles the content (This makes the Tabs widget feel more familiar when coming from other UI frameworks).

Feel free to open-source it!

I definately will! :) And I have more good news. I have received permission from my professor to implement further widgets as part of my study project. Accordingly, more widgets will follow and will be published as well. I will talk about it in the upcomming week.

I hope the close button is customisable w.r.t. the look (icon) and position (right or left of text)?

Currently the close button will be on the right side (I've never seen the close icon on the left side before). As there are some users having problems with the SIL licence of the font/icon (#524) the user is able to set their own icon font.

Also, would it be possible to do tab pinning, which implies that unpinned tabs can be rearranged?

This is currently not implemented. I'm trying to keep it simple first.

(The other customization point is vertical vs. horizontal alignment of tabs)

I like to have vertical tabs on my browser too, but this is currently not supported as well.
Maybe I'll find some time after my project to implement some of the requested features.

(I dont know enough Rust to meaningfully contribute to this, I am learning it right now)

There is always a first time. I also learned a lot about Rust when I ventured into the TabBar. :)

@hecrj
Copy link
Member

hecrj commented Jan 19, 2022

Closing since this is available in iced_aw!

@hecrj hecrj closed this as completed Jan 19, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants