Initial Commit
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
**/*/target
|
||||
1110
relm4_example/Cargo.lock
generated
Normal file
1110
relm4_example/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
9
relm4_example/Cargo.toml
Normal file
9
relm4_example/Cargo.toml
Normal file
@@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "relm4_example"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
relm4 = { version = "0.7.0-beta.2" }
|
||||
1110
relm4_example/examples/components/Cargo.lock
generated
Normal file
1110
relm4_example/examples/components/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
7
relm4_example/examples/components/Cargo.toml
Normal file
7
relm4_example/examples/components/Cargo.toml
Normal file
@@ -0,0 +1,7 @@
|
||||
[package]
|
||||
name = "components"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
relm4 = { version = "0.7.0-beta.2" }
|
||||
61
relm4_example/examples/components/src/close_dialog.rs
Normal file
61
relm4_example/examples/components/src/close_dialog.rs
Normal file
@@ -0,0 +1,61 @@
|
||||
use gtk::prelude::{GtkWindowExt, WidgetExt, DialogExt};
|
||||
use relm4::{gtk, SimpleComponent, ComponentSender, ComponentParts};
|
||||
|
||||
pub struct DialogModel {
|
||||
hidden: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum DialogInput {
|
||||
Show,
|
||||
Accept,
|
||||
Cancel,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum DialogOutput {
|
||||
Close,
|
||||
}
|
||||
|
||||
#[relm4::component(pub)]
|
||||
impl SimpleComponent for DialogModel {
|
||||
type Init = bool;
|
||||
type Input = DialogInput;
|
||||
type Output = DialogOutput;
|
||||
|
||||
view! {
|
||||
gtk::MessageDialog {
|
||||
set_modal: true,
|
||||
#[watch]
|
||||
set_visible: !model.hidden,
|
||||
set_text: Some("Do you want to close before saving?"),
|
||||
set_secondary_text: Some("All unsaved changes will be lost!"),
|
||||
add_button: ("Close", gtk::ResponseType::Accept),
|
||||
add_button: ("Cancel", gtk::ResponseType::Cancel),
|
||||
connect_response[sender] => move |_, resp| {
|
||||
sender.input(if resp == gtk::ResponseType::Accept {
|
||||
DialogInput::Accept
|
||||
} else {
|
||||
DialogInput::Cancel
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn init(params: Self::Init, root: &Self::Root, sender: ComponentSender<Self>) -> ComponentParts<Self> {
|
||||
let model = DialogModel { hidden: params };
|
||||
let widgets = view_output!();
|
||||
ComponentParts { model, widgets }
|
||||
}
|
||||
|
||||
fn update(&mut self, msg: Self::Input, sender: ComponentSender<Self>) {
|
||||
match msg {
|
||||
DialogInput::Show => self.hidden = false,
|
||||
DialogInput::Accept => {
|
||||
self.hidden = true;
|
||||
sender.output(DialogOutput::Close).unwrap();
|
||||
}
|
||||
DialogInput::Cancel => self.hidden = true,
|
||||
}
|
||||
}
|
||||
}
|
||||
65
relm4_example/examples/components/src/header.rs
Normal file
65
relm4_example/examples/components/src/header.rs
Normal file
@@ -0,0 +1,65 @@
|
||||
use gtk::prelude::{ButtonExt, ToggleButtonExt, WidgetExt};
|
||||
use relm4::{gtk, SimpleComponent, ComponentSender, ComponentParts};
|
||||
|
||||
pub struct HeaderModel;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum HeaderOutput {
|
||||
View,
|
||||
Edit,
|
||||
Export,
|
||||
}
|
||||
|
||||
#[relm4::component(pub)]
|
||||
impl SimpleComponent for HeaderModel {
|
||||
type Init = ();
|
||||
type Input = ();
|
||||
type Output = HeaderOutput;
|
||||
|
||||
view! {
|
||||
#[root]
|
||||
gtk::HeaderBar {
|
||||
#[wrap(Some)]
|
||||
set_title_widget = >k::Box {
|
||||
add_css_class: "linked",
|
||||
|
||||
#[name = "group"]
|
||||
gtk::ToggleButton {
|
||||
set_label: "View",
|
||||
set_active: true,
|
||||
connect_toggled[sender] => move |btn| {
|
||||
if btn.is_active() {
|
||||
sender.output(HeaderOutput::View).unwrap()
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
gtk::ToggleButton {
|
||||
set_label: "Edit",
|
||||
set_group: Some(&group),
|
||||
connect_toggled[sender] => move |btn| {
|
||||
if btn.is_active() {
|
||||
sender.output(HeaderOutput::Edit).unwrap()
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
gtk::ToggleButton {
|
||||
set_label: "Export",
|
||||
set_group: Some(&group),
|
||||
connect_toggled[sender] => move |btn| {
|
||||
if btn.is_active() {
|
||||
sender.output(HeaderOutput::Export).unwrap()
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn init(_params: Self::Init, root: &Self::Root, sender: ComponentSender<Self>) -> ComponentParts<Self> {
|
||||
let model = HeaderModel;
|
||||
let widgets = view_output!();
|
||||
ComponentParts { model, widgets }
|
||||
}
|
||||
}
|
||||
97
relm4_example/examples/components/src/main.rs
Normal file
97
relm4_example/examples/components/src/main.rs
Normal file
@@ -0,0 +1,97 @@
|
||||
mod header;
|
||||
mod close_dialog;
|
||||
|
||||
use gtk::prelude::{GtkWindowExt, ApplicationExt};
|
||||
use relm4::{gtk::{self, glib}, SimpleComponent, ComponentSender, ComponentParts, Controller, ComponentController, Component, RelmApp};
|
||||
use header::{HeaderModel, HeaderOutput};
|
||||
use close_dialog::{DialogModel, DialogInput, DialogOutput};
|
||||
|
||||
#[derive(Debug)]
|
||||
enum AppMode {
|
||||
View,
|
||||
Edit,
|
||||
Export,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum AppMsg {
|
||||
SetMode(AppMode),
|
||||
CloseRequest,
|
||||
Close,
|
||||
}
|
||||
|
||||
struct AppModel {
|
||||
mode: AppMode,
|
||||
header: Controller<HeaderModel>,
|
||||
dialog: Controller<DialogModel>,
|
||||
}
|
||||
|
||||
#[relm4::component]
|
||||
impl SimpleComponent for AppModel {
|
||||
type Init = AppMode;
|
||||
type Input = AppMsg;
|
||||
type Output = ();
|
||||
|
||||
view! {
|
||||
main_window = gtk::Window {
|
||||
set_default_width: 500,
|
||||
set_default_height: 250,
|
||||
set_titlebar: Some(model.header.widget()),
|
||||
|
||||
gtk::Label {
|
||||
#[watch]
|
||||
set_label: &format!("Placeholder for {:?}", model.mode),
|
||||
},
|
||||
|
||||
connect_close_request[sender] => move |_| {
|
||||
sender.input(AppMsg::CloseRequest);
|
||||
glib::Propagation::Proceed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn init(params: Self::Init, root: &Self::Root, sender: ComponentSender<Self>) -> ComponentParts<Self> {
|
||||
let header: Controller<HeaderModel> = HeaderModel::builder()
|
||||
.launch(())
|
||||
.forward(sender.input_sender(), |msg| match msg {
|
||||
HeaderOutput::View => AppMsg::SetMode(AppMode::View),
|
||||
HeaderOutput::Edit => AppMsg::SetMode(AppMode::Edit),
|
||||
HeaderOutput::Export => AppMsg::SetMode(AppMode::Export),
|
||||
});
|
||||
|
||||
let dialog = DialogModel::builder()
|
||||
.transient_for(root)
|
||||
.launch(true)
|
||||
.forward(sender.input_sender(), |msg| match msg {
|
||||
DialogOutput::Close => AppMsg::Close,
|
||||
});
|
||||
|
||||
let model = AppModel {
|
||||
mode: params,
|
||||
header,
|
||||
dialog,
|
||||
};
|
||||
|
||||
let widgets = view_output!();
|
||||
ComponentParts { model, widgets }
|
||||
}
|
||||
|
||||
fn update(&mut self, msg: Self::Input, _sender: ComponentSender<Self>) {
|
||||
match msg {
|
||||
AppMsg::SetMode(mode) => {
|
||||
self.mode = mode;
|
||||
}
|
||||
AppMsg::CloseRequest => {
|
||||
self.dialog.sender().send(DialogInput::Show).unwrap();
|
||||
}
|
||||
AppMsg::Close => {
|
||||
relm4::main_application().quit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let relm = RelmApp::new("relm4.test.components");
|
||||
relm.run::<AppModel>(AppMode::Edit);
|
||||
}
|
||||
89
relm4_example/examples/counter_basic.rs
Normal file
89
relm4_example/examples/counter_basic.rs
Normal file
@@ -0,0 +1,89 @@
|
||||
use gtk::glib::clone;
|
||||
use gtk::prelude::{BoxExt, ButtonExt, GtkWindowExt};
|
||||
use relm4::{gtk, ComponentParts, ComponentSender, RelmApp, RelmWidgetExt, SimpleComponent};
|
||||
|
||||
#[derive(Debug)]
|
||||
enum AppInput {
|
||||
Increment,
|
||||
Decrement,
|
||||
}
|
||||
|
||||
struct AppModel {
|
||||
counter: u8,
|
||||
}
|
||||
|
||||
struct AppWidgets {
|
||||
label: gtk::Label,
|
||||
}
|
||||
|
||||
impl SimpleComponent for AppModel {
|
||||
type Input = AppInput;
|
||||
type Output = ();
|
||||
type Init = u8;
|
||||
type Root = gtk::Window;
|
||||
type Widgets = AppWidgets;
|
||||
|
||||
fn init_root() -> Self::Root {
|
||||
gtk::Window::builder()
|
||||
.title("Simple App")
|
||||
.default_width(300)
|
||||
.default_height(100)
|
||||
.build()
|
||||
}
|
||||
|
||||
fn init(
|
||||
counter: Self::Init,
|
||||
window: &Self::Root,
|
||||
sender: ComponentSender<Self>,
|
||||
) -> relm4::ComponentParts<Self> {
|
||||
let model = AppModel { counter };
|
||||
|
||||
let vbox = gtk::Box::builder()
|
||||
.orientation(gtk::Orientation::Vertical)
|
||||
.spacing(5)
|
||||
.build();
|
||||
|
||||
let inc_button = gtk::Button::with_label("Increment");
|
||||
let dec_button = gtk::Button::with_label("Decrement");
|
||||
|
||||
let label = gtk::Label::new(Some(&format!("Counter: {}", model.counter)));
|
||||
label.set_margin_all(5);
|
||||
|
||||
window.set_child(Some(&vbox));
|
||||
vbox.set_margin_all(5);
|
||||
vbox.append(&inc_button);
|
||||
vbox.append(&dec_button);
|
||||
vbox.append(&label);
|
||||
|
||||
inc_button.connect_clicked(clone!(@strong sender => move |_| {
|
||||
sender.input(AppInput::Increment);
|
||||
}));
|
||||
dec_button.connect_clicked(clone!(@strong sender => move |_| {
|
||||
sender.input(AppInput::Decrement);
|
||||
}));
|
||||
|
||||
let widgets = AppWidgets { label };
|
||||
|
||||
ComponentParts { model, widgets }
|
||||
}
|
||||
|
||||
fn update(&mut self, message: Self::Input, _sender: ComponentSender<Self>) {
|
||||
match message {
|
||||
AppInput::Increment => {
|
||||
self.counter = self.counter.wrapping_add(1);
|
||||
}
|
||||
AppInput::Decrement => {
|
||||
self.counter = self.counter.wrapping_sub(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn update_view(&self, widgets: &mut Self::Widgets, _sender: ComponentSender<Self>) {
|
||||
widgets.label.set_label(&format!("Counter: {}", self.counter));
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let app = RelmApp::new("relm4.test.simple_manual");
|
||||
app.run::<AppModel>(0);
|
||||
}
|
||||
1110
relm4_example/examples/counter_factory/Cargo.lock
generated
Normal file
1110
relm4_example/examples/counter_factory/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
7
relm4_example/examples/counter_factory/Cargo.toml
Normal file
7
relm4_example/examples/counter_factory/Cargo.toml
Normal file
@@ -0,0 +1,7 @@
|
||||
[package]
|
||||
name = "counter_factory"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
relm4 = { version = "0.7.0-beta.2" }
|
||||
91
relm4_example/examples/counter_factory/src/counter.rs
Normal file
91
relm4_example/examples/counter_factory/src/counter.rs
Normal file
@@ -0,0 +1,91 @@
|
||||
use gtk::prelude::{BoxExt, ButtonExt, OrientableExt};
|
||||
use relm4::factory::{DynamicIndex, FactoryComponent, FactorySender};
|
||||
use relm4::gtk;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Counter {
|
||||
value: u8,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CounterMsg {
|
||||
Increment,
|
||||
Decrement,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CounterOutput {
|
||||
SendFront(DynamicIndex),
|
||||
MoveUp(DynamicIndex),
|
||||
MoveDown(DynamicIndex),
|
||||
}
|
||||
|
||||
#[relm4::factory(pub)]
|
||||
impl FactoryComponent for Counter {
|
||||
type Init = u8;
|
||||
type Input = CounterMsg;
|
||||
type Output = CounterOutput;
|
||||
type CommandOutput = ();
|
||||
type ParentWidget = gtk::Box;
|
||||
|
||||
view! {
|
||||
root = gtk::Box {
|
||||
set_orientation: gtk::Orientation::Horizontal,
|
||||
set_spacing: 10,
|
||||
|
||||
#[name(label)]
|
||||
gtk::Label {
|
||||
#[watch]
|
||||
set_label: &self.value.to_string(),
|
||||
set_width_chars: 3,
|
||||
},
|
||||
|
||||
#[name(add_button)]
|
||||
gtk::Button {
|
||||
set_label: "+",
|
||||
connect_clicked => CounterMsg::Increment,
|
||||
},
|
||||
|
||||
#[name(remove_button)]
|
||||
gtk::Button {
|
||||
set_label: "-",
|
||||
connect_clicked => CounterMsg::Decrement,
|
||||
},
|
||||
|
||||
#[name(move_up_button)]
|
||||
gtk::Button {
|
||||
set_label: "Up",
|
||||
connect_clicked[sender, index] => move |_| {
|
||||
sender.output(CounterOutput::MoveUp(index.clone())).unwrap();
|
||||
}
|
||||
},
|
||||
|
||||
#[name(move_down_button)]
|
||||
gtk::Button {
|
||||
set_label: "Down",
|
||||
connect_clicked[sender, index] => move |_| {
|
||||
sender.output(CounterOutput::MoveDown(index.clone())).unwrap();
|
||||
}
|
||||
},
|
||||
|
||||
#[name(to_front_button)]
|
||||
gtk::Button {
|
||||
set_label: "To Start",
|
||||
connect_clicked[sender, index] => move |_| {
|
||||
sender.output(CounterOutput::SendFront(index.clone())).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn init_model(value: Self::Init, _index: &DynamicIndex, _sender: FactorySender<Self>) -> Self {
|
||||
Self { value }
|
||||
}
|
||||
|
||||
fn update(&mut self, msg: Self::Input, _sender: FactorySender<Self>) {
|
||||
match msg {
|
||||
CounterMsg::Increment => self.value = self.value.wrapping_add(1),
|
||||
CounterMsg::Decrement => self.value = self.value.wrapping_sub(1),
|
||||
}
|
||||
}
|
||||
}
|
||||
107
relm4_example/examples/counter_factory/src/main.rs
Normal file
107
relm4_example/examples/counter_factory/src/main.rs
Normal file
@@ -0,0 +1,107 @@
|
||||
mod counter;
|
||||
use counter::{Counter, CounterOutput};
|
||||
|
||||
use gtk::prelude::{BoxExt, ButtonExt, GtkWindowExt, OrientableExt};
|
||||
use relm4::{gtk, factory::{FactoryVecDeque, DynamicIndex}, RelmApp, ComponentParts, ComponentSender, SimpleComponent};
|
||||
|
||||
struct App {
|
||||
created_widgets: u8,
|
||||
counters: FactoryVecDeque<Counter>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum AppMsg {
|
||||
AddCounter,
|
||||
RemoveCounter,
|
||||
SendFront(DynamicIndex),
|
||||
MoveUp(DynamicIndex),
|
||||
MoveDown(DynamicIndex),
|
||||
}
|
||||
|
||||
#[relm4::component]
|
||||
impl SimpleComponent for App {
|
||||
type Init = u8;
|
||||
type Input = AppMsg;
|
||||
type Output = ();
|
||||
|
||||
view! {
|
||||
gtk::Window {
|
||||
set_title: Some("Factory Example"),
|
||||
set_default_size: (300, 100),
|
||||
|
||||
gtk::Box {
|
||||
set_orientation: gtk::Orientation::Vertical,
|
||||
set_spacing: 5,
|
||||
|
||||
gtk::Button {
|
||||
set_label: "Add Counter",
|
||||
connect_clicked => AppMsg::AddCounter,
|
||||
},
|
||||
|
||||
gtk::Button {
|
||||
set_label: "Remove Counter",
|
||||
connect_clicked => AppMsg::RemoveCounter,
|
||||
},
|
||||
|
||||
#[local_ref]
|
||||
counter_box -> gtk::Box {
|
||||
set_orientation: gtk::Orientation::Vertical,
|
||||
set_spacing: 5,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn init(counter: Self::Init, root: &Self::Root, sender: ComponentSender<Self>) -> ComponentParts<Self> {
|
||||
let counters = FactoryVecDeque::builder()
|
||||
.launch_default()
|
||||
.forward(sender.input_sender(), |msg| match msg {
|
||||
CounterOutput::SendFront(index) => AppMsg::SendFront(index),
|
||||
CounterOutput::MoveUp(index) => AppMsg::MoveUp(index),
|
||||
CounterOutput::MoveDown(index) => AppMsg::MoveDown(index),
|
||||
});
|
||||
let model = App {
|
||||
created_widgets: counter,
|
||||
counters,
|
||||
};
|
||||
|
||||
let counter_box = model.counters.widget();
|
||||
let widgets = view_output!();
|
||||
|
||||
ComponentParts { model, widgets }
|
||||
}
|
||||
|
||||
fn update(&mut self, msg: Self::Input, _sender: ComponentSender<Self>) {
|
||||
let mut counters_guard = self.counters.guard();
|
||||
match msg {
|
||||
AppMsg::AddCounter => {
|
||||
counters_guard.push_back(self.created_widgets);
|
||||
self.created_widgets = self.created_widgets.wrapping_add(1);
|
||||
}
|
||||
AppMsg::RemoveCounter => {
|
||||
counters_guard.pop_back();
|
||||
}
|
||||
AppMsg::SendFront(index) => {
|
||||
counters_guard.move_front(index.current_index());
|
||||
}
|
||||
AppMsg::MoveDown(index) => {
|
||||
let index = index.current_index();
|
||||
let new_index = index + 1;
|
||||
if new_index < counters_guard.len() {
|
||||
counters_guard.move_to(index, new_index);
|
||||
}
|
||||
}
|
||||
AppMsg::MoveUp(index) => {
|
||||
let index = index.current_index();
|
||||
if index != 0 {
|
||||
counters_guard.move_to(index, index - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let app = RelmApp::new("relm4.example.factory");
|
||||
app.run::<App>(0);
|
||||
}
|
||||
81
relm4_example/examples/counter_macro.rs
Normal file
81
relm4_example/examples/counter_macro.rs
Normal file
@@ -0,0 +1,81 @@
|
||||
use gtk::prelude::{BoxExt, ButtonExt, GtkWindowExt, OrientableExt};
|
||||
use relm4::{gtk, ComponentParts, ComponentSender, RelmApp, RelmWidgetExt, SimpleComponent};
|
||||
|
||||
struct CounterModel {
|
||||
counter: u8,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum CounterMessage {
|
||||
Increment,
|
||||
Decrement,
|
||||
}
|
||||
|
||||
#[relm4::component]
|
||||
impl SimpleComponent for CounterModel {
|
||||
type Init = u8;
|
||||
|
||||
type Input = CounterMessage;
|
||||
type Output = ();
|
||||
|
||||
view! {
|
||||
gtk::Window {
|
||||
set_title: Some("Counter"),
|
||||
set_default_width: 300,
|
||||
set_default_height: 100,
|
||||
|
||||
gtk::Box {
|
||||
set_orientation: gtk::Orientation::Vertical,
|
||||
set_spacing: 5,
|
||||
set_margin_all: 5,
|
||||
|
||||
gtk::Button {
|
||||
set_label: "Increment",
|
||||
connect_clicked[sender] => move |_| {
|
||||
sender.input(CounterMessage::Increment);
|
||||
}
|
||||
},
|
||||
|
||||
gtk::Button::with_label("Decrement") {
|
||||
connect_clicked[sender] => move |_| {
|
||||
sender.input(CounterMessage::Decrement);
|
||||
}
|
||||
},
|
||||
|
||||
gtk::Label {
|
||||
#[watch]
|
||||
set_label: &format!("Counter: {}", model.counter),
|
||||
set_margin_all: 5,
|
||||
},
|
||||
|
||||
if model.counter % 2 == 0 {
|
||||
gtk::Label {
|
||||
set_label: "The value is even",
|
||||
}
|
||||
} else {
|
||||
gtk::Label {
|
||||
set_label: "The value is odd",
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn init(counter: Self::Init, root: &Self::Root, sender: ComponentSender<Self>) -> ComponentParts<Self> {
|
||||
let model = CounterModel { counter };
|
||||
let widgets = view_output!();
|
||||
ComponentParts { model, widgets }
|
||||
}
|
||||
|
||||
fn update(&mut self, msg: Self::Input, _sender: ComponentSender<Self>) {
|
||||
match msg {
|
||||
CounterMessage::Increment => self.counter = self.counter.wrapping_add(1),
|
||||
CounterMessage::Decrement => self.counter = self.counter.wrapping_sub(1),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let app = RelmApp::new("relm4.test.simple");
|
||||
app.run::<CounterModel>(0);
|
||||
}
|
||||
55
relm4_example/examples/paned.rs
Normal file
55
relm4_example/examples/paned.rs
Normal file
@@ -0,0 +1,55 @@
|
||||
use gtk::prelude::*;
|
||||
use relm4::{gtk, ComponentParts, ComponentSender, RelmApp, SimpleComponent};
|
||||
|
||||
struct PanedModel {}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum PanedMessage {}
|
||||
|
||||
#[relm4::component]
|
||||
impl SimpleComponent for PanedModel {
|
||||
type Init = ();
|
||||
type Input = PanedMessage;
|
||||
type Output = ();
|
||||
|
||||
view! {
|
||||
gtk::Window {
|
||||
set_title: Some("Paned Example"),
|
||||
set_default_width: 300,
|
||||
set_default_height: 200,
|
||||
|
||||
gtk::Paned {
|
||||
set_orientation: gtk::Orientation::Horizontal,
|
||||
set_resize_start_child: false,
|
||||
set_shrink_start_child: false,
|
||||
set_resize_end_child: true,
|
||||
|
||||
#[wrap(Some)]
|
||||
set_start_child = >k::Label {
|
||||
set_label: "Left Side",
|
||||
set_size_request: (100, -1)
|
||||
},
|
||||
|
||||
#[wrap(Some)]
|
||||
set_end_child = >k::Label {
|
||||
set_label: "Right Side"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn init(_: Self::Init, root: &Self::Root, _sender: ComponentSender<Self>) -> ComponentParts<Self> {
|
||||
let model = PanedModel {};
|
||||
let widgets = view_output!();
|
||||
ComponentParts { model, widgets }
|
||||
}
|
||||
|
||||
fn update(&mut self, _msg: Self::Input, _sender: ComponentSender<Self>) {
|
||||
// No update logic needed for this static UI
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let app = RelmApp::new("relm4.test.paned");
|
||||
app.run::<PanedModel>(());
|
||||
}
|
||||
22
relm4_example/src/main.rs
Normal file
22
relm4_example/src/main.rs
Normal file
@@ -0,0 +1,22 @@
|
||||
use relm4::gtk::{Application, ApplicationWindow, prelude::{ApplicationExt, GtkWindowExt, ButtonExt, WidgetExt, ApplicationExtManual}};
|
||||
use tgbutton::CustomButton;
|
||||
|
||||
mod tgbutton;
|
||||
|
||||
fn main() {
|
||||
let application = Application::new(Some("com.example.custombutton"), Default::default());
|
||||
|
||||
application.connect_activate(|app| {
|
||||
let window = ApplicationWindow::new(app);
|
||||
window.set_title(Some("Custom Button Example"));
|
||||
window.set_default_size(300, 100);
|
||||
|
||||
let custom_button = CustomButton::new();
|
||||
custom_button.set_label("Custom Button");
|
||||
|
||||
window.set_child(Some(&custom_button));
|
||||
window.show();
|
||||
});
|
||||
|
||||
application.run();
|
||||
}
|
||||
61
relm4_example/src/tgbutton.rs
Normal file
61
relm4_example/src/tgbutton.rs
Normal file
@@ -0,0 +1,61 @@
|
||||
use relm4::gtk;
|
||||
use gtk::glib;
|
||||
use gtk::prelude::*;
|
||||
use gtk::subclass::prelude::*;
|
||||
use gtk::Button;
|
||||
|
||||
mod imp {
|
||||
use super::*;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct CustomButton;
|
||||
|
||||
#[glib::object_subclass]
|
||||
impl ObjectSubclass for CustomButton {
|
||||
const NAME: &'static str = "CustomButton";
|
||||
type Type = super::CustomButton;
|
||||
type ParentType = Button;
|
||||
}
|
||||
|
||||
impl ObjectImpl for CustomButton {}
|
||||
impl WidgetImpl for CustomButton {
|
||||
fn snapshot(&self, widget: &Self::Type, snapshot: >k::Snapshot) {
|
||||
self.parent_snapshot(widget, snapshot);
|
||||
|
||||
let rect = widget.allocation();
|
||||
let surface = cairo::ImageSurface::create(cairo::Format::ARgb32, rect.width(), rect.height())
|
||||
.expect("Can't create surface");
|
||||
let cr = cairo::Context::new(&surface).expect("Can't create context");
|
||||
|
||||
// Draw the hollow circle
|
||||
cr.set_source_rgb(1.0, 0.0, 0.0); // Red color
|
||||
cr.set_line_width(5.0); // Line width for the circle
|
||||
cr.arc(
|
||||
(rect.width() / 2) as f64,
|
||||
(rect.height() / 2) as f64,
|
||||
22.5, // Radius
|
||||
0.0,
|
||||
2.0 * std::f64::consts::PI,
|
||||
);
|
||||
cr.stroke();
|
||||
|
||||
// Draw on the widget
|
||||
let snapshot_rect = gtk::gdk::Rectangle::new(rect.x(), rect.y(), rect.width(), rect.height());
|
||||
snapshot.append_cairo(&snapshot_rect, &surface);
|
||||
}
|
||||
}
|
||||
|
||||
impl ButtonImpl for CustomButton {}
|
||||
}
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct CustomButton(ObjectSubclass<imp::CustomButton>)
|
||||
@extends Button, gtk::Widget;
|
||||
}
|
||||
|
||||
impl CustomButton {
|
||||
pub fn new() -> Self {
|
||||
glib::Object::new(&[]).expect("Failed to create CustomButton")
|
||||
}
|
||||
}
|
||||
pub use imp::CustomButton;
|
||||
Reference in New Issue
Block a user