A Basic Counter App
The easiest way to learn about Maycoon is to start studying some examples. In this Tutorial we will find out how to create a basic counter App with increase and decrease buttons, as well as a text widget to display the count.
Setup
For creating a new project, see the Installation Guide.
The App
First we need to import the necessary items from the maycoon
crate:
use maycoon::core::app::context::AppContext; use maycoon::core::app::update::Update; use maycoon::core::app::Application; use maycoon::core::config::MayConfig; use maycoon::core::layout::{AlignItems, Dimension, FlexDirection, LayoutStyle}; use maycoon::core::reference::Ref; use maycoon::core::signal::eval::EvalSignal; use maycoon::core::signal::state::StateSignal; use maycoon::core::signal::{MaybeSignal, Signal}; use maycoon::core::widget::{Widget, WidgetLayoutExt}; use maycoon::math::Vector2; use maycoon::theme::theme::celeste::CelesteTheme; use maycoon::widgets::button::Button; use maycoon::widgets::container::Container; use maycoon::widgets::text::Text; // Our application structure struct MyApp; impl Application for MyApp { // The theme we want to use type Theme = CelesteTheme; // The root widget fn build(context: AppContext) -> impl Widget { let counter = context.use_signal(StateSignal::new(0)); Container::new(vec![ { let counter = counter.clone(); Box::new( Button::new(Text::new("Increase".to_string())).with_on_pressed( MaybeSignal::signal(context.use_signal(EvalSignal::new(move || { counter.set(*counter.get() + 1); Update::DRAW }))), ), ) }, { let counter = counter.clone(); Box::new( Button::new(Text::new("Decrease".to_string())).with_on_pressed( MaybeSignal::signal(context.use_signal(EvalSignal::new(move || { counter.set(*counter.get() - 1); Update::DRAW }))), ), ) }, { let counter = counter.clone(); Box::new(Text::new(counter.map(|i| Ref::Owned(i.to_string())))) }, ]) .with_layout_style(LayoutStyle { size: Vector2::<Dimension>::new(Dimension::percent(1.0), Dimension::percent(1.0)), flex_direction: FlexDirection::Column, align_items: Some(AlignItems::Center), ..Default::default() }) } // The configuration fn config(&self) -> MayConfig<Self::Theme> { MayConfig::default() } } fn main() { MyApp.run() }
A Container
widget draws and handles a collection of widgets specified as a Vector of Box
ed Widgets. In our case, we need two buttons: Increase and decrease to manipulate our counter value, as well as a text widget for displaying the counter value.
We use the MaybeSignal::signal
function to pass the signals to the buttons and pass fixed strings to the "Increase" and "Decrease" buttons.
For the two buttons, we need to define Update
s to apply updates to the App.
The Update::DRAW
constant tells the App to only re-draw and not re-layout the application when pressing the buttons.
The with_layout_style
function applies a custom layout which centers the widgets in our case.
NOTE: You need to clone
signals before using them inside move
closures to use them inside multiple closures.
Running the App
To launch the App, you can run cargo run
.
You should see a window with "Increase" and "Decrease" buttons along with a text.