Skip to content

Commit

Permalink
Merge pull request #440 from Relm4/list-view-wrapper
Browse files Browse the repository at this point in the history
core: Add TypedListView type
  • Loading branch information
AaronErhardt committed May 8, 2023
2 parents 4ee5c24 + a3a8b51 commit 2c83e12
Show file tree
Hide file tree
Showing 10 changed files with 892 additions and 10 deletions.
8 changes: 5 additions & 3 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,25 @@

## Unreleased

### Added

+ core: Add `TypedListView` as idiomatic wrapper over `gtk::ListView`

### Fixed

+ macros: Improve error messages for non-identifier parameter patterns

## 0.6.0-beta.1 - 2023-4-19

### Added

+ core: Introduce setting and action safeties
+ examples: Introduce setting and action safeties
+ core: Implement `RelmSetChildExt` for `gtk::AspectFrame`
+ core: Add `FactoryHashMap` as alternative to `FactoryVecDeque`
+ core: Add gnome_44 feature flag for GNOME 44
+ core: Documentation and better support for data bindings
+ core: Add `set_tooltip` method to `RelmWidgetExt`
+ core: Add `main_adw_application` method to retrieve the `adw::Application` when the libadwaita feature is enabled
+ macros: Add `skip_macro` option for watch and track attributes to skip their initialization
+ examples: Introduce setting and action safeties
+ examples: Example for using relm4-icons

### Changed
Expand Down
186 changes: 186 additions & 0 deletions examples/typed_list_view.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
use gtk::prelude::*;
use relm4::{
binding::{Binding, U8Binding},
prelude::*,
typed_list_view::{RelmListItem, TypedListView},
RelmObjectExt,
};

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
struct MyListItem {
value: u8,
binding: U8Binding,
}

impl MyListItem {
fn new(value: u8) -> Self {
Self {
value,
binding: U8Binding::new(0),
}
}
}

struct Widgets {
label: gtk::Label,
label2: gtk::Label,
button: gtk::CheckButton,
}

impl Drop for Widgets {
fn drop(&mut self) {
dbg!(self.label.label());
}
}

impl RelmListItem for MyListItem {
type Root = gtk::Box;
type Widgets = Widgets;

fn setup(_item: &gtk::ListItem) -> (gtk::Box, Widgets) {
relm4::view! {
my_box = gtk::Box {
#[name = "label"]
gtk::Label,

#[name = "label2"]
gtk::Label,

#[name = "button"]
gtk::CheckButton,
}
}

let widgets = Widgets {
label,
label2,
button,
};

(my_box, widgets)
}

fn bind(&mut self, widgets: &mut Self::Widgets, _root: &mut Self::Root) {
let Widgets {
label,
label2,
button,
} = widgets;

label.set_label(&format!("Value: {} ", self.value));
label2.add_write_only_binding(&self.binding, "label");
button.set_active(self.value % 2 == 0);
}
}

struct App {
counter: u8,
list_view_wrapper: TypedListView<MyListItem, gtk::SingleSelection>,
}

#[derive(Debug)]
enum Msg {
Append,
Remove,
OnlyShowEven(bool),
}

#[relm4::component]
impl SimpleComponent for App {
type Init = u8;
type Input = Msg;
type Output = ();

view! {
gtk::Window {
set_title: Some("Actually idiomatic list view possible?"),
set_default_size: (300, 100),

gtk::Box {
set_orientation: gtk::Orientation::Vertical,
set_spacing: 5,
set_margin_all: 5,

gtk::Button {
set_label: "Append 10 items",
connect_clicked => Msg::Append,
},

gtk::Button {
set_label: "Remove second item",
connect_clicked => Msg::Remove,
},

gtk::ToggleButton {
set_label: "Only show even numbers",
connect_clicked[sender] => move |btn| {
sender.input(Msg::OnlyShowEven(btn.is_active()));
}
},

gtk::ScrolledWindow {
set_vexpand: true,

#[local_ref]
my_view -> gtk::ListView {}
}
}
}
}

fn init(
counter: Self::Init,
root: &Self::Root,
sender: ComponentSender<Self>,
) -> ComponentParts<Self> {
// Initialize the ListView wrapper
let mut list_view_wrapper: TypedListView<MyListItem, gtk::SingleSelection> =
TypedListView::with_sorting();

// Add a filter and disable it
list_view_wrapper.add_filter(|item| item.value % 2 == 0);
list_view_wrapper.set_filter_status(0, false);

let model = App {
counter,
list_view_wrapper,
};

let my_view = &model.list_view_wrapper.view;

let widgets = view_output!();

ComponentParts { model, widgets }
}

fn update(&mut self, msg: Self::Input, _sender: ComponentSender<Self>) {
match msg {
Msg::Append => {
// Add 10 items
for _ in 0..10 {
self.counter = self.counter.wrapping_add(1);
self.list_view_wrapper.append(MyListItem::new(self.counter));
}

// Count up the first item
let first_item = self.list_view_wrapper.get(0).unwrap();
let first_binding = &mut first_item.borrow_mut().binding;
let mut guard = first_binding.guard();
*guard += 1;
}
Msg::Remove => {
// Remove the second item
self.list_view_wrapper.remove(1);
}
Msg::OnlyShowEven(show_only_even) => {
// Disable or enable the first filter
self.list_view_wrapper.set_filter_status(0, show_only_even);
}
}
}
}

fn main() {
let app = RelmApp::new("relm4.example.typed-list-view");
app.run::<App>(0);
}
Loading

0 comments on commit 2c83e12

Please sign in to comment.