SimpleExample/
demo.rs

1use rust_page_system::{
2    Button, Renderer,
3    misc::{center_elements::get_center, vec::GetOrCreate},
4    system::{
5        input_handler::InputHandler,
6        page_system::{Page, PageData, PersistentElements},
7        renderer::RendererConfig,
8        state::AppState,
9        window::{WindowConfig, create_window, get_monitor_refresh_rate}
10    }
11};
12use sdl3::{pixels::Color, rect::Rect, sys::render::SDL_LOGICAL_PRESENTATION_STRETCH};
13use std::{env, rc::Rc, time::Duration};
14
15// To Be Ignored, Just An Setup To Configure The Build
16use crate::build::setup_build;
17mod build;
18
19//==========================================================================================================================================================================
20//=======================================================================# main function recommended setup #===============================================================
21//==========================================================================================================================================================================
22fn main()
23{
24    // To Be Ignored, Just An Setup To Configure The Build
25    setup_build();
26    let window_config = WindowConfig 
27    {
28        window_title: "SimpleExample".to_string(),
29        icon: (None, None),
30        // Recommended to start with 16:9 aspect ratio
31        start_window_size: (800, 450),
32        // Recommended to have minimum size with 16:9 aspect ratio
33        window_minimum_size: (800, 450),
34        resizable: true,
35        centered: true,
36        // By Default SDL_LOGICAL_PRESENTATION_STRETCH Is Set, Only Setting It Here For Demonstration Purpose
37        different_sdl_presentation_mode: Some(SDL_LOGICAL_PRESENTATION_STRETCH),
38        font: ("JetBrainsMono".to_string(), Some("Bold".to_string()))
39    };
40
41    let mut window_modules = create_window(window_config);
42    let mut input_handler = InputHandler::new(true);
43    let mut app_state = AppState::new(PageId::Page1, window_modules.canvas.window().size(), window_modules.stretch_mode_status);
44    let mut page_data = PageData::new(&app_state);
45    let renderer_config = RendererConfig { canvas: window_modules.canvas, texture_creator: &window_modules.texture_creator, ttf_context: &window_modules.ttf_context, font_path: &window_modules.font_path, decrease_color_when_selected: Some((25, 25, 25)), selection_color: Some((0, 0, 200, 125)), assets_dir: None };
46    let mut renderer = Renderer::new(renderer_config);
47
48    populate_page_data(&mut page_data);
49
50    // Wrap the button_action function in a mutable closure so it can capture
51    // additional context if needed. Passing a closure here allows the
52    // button handler API to accept additional arguments beyond the default.
53    let mut button_action_closure = |app_state: &mut AppState<PageId, ButtonId>, button_id: &ButtonId, page_data: &mut PageData<PageId, ButtonId>| button_action(app_state, button_id, page_data);
54
55    loop
56    {
57        println!("{:?}", page_data.persistent_elements_to_render.is_some());
58        //using 900 / your_refresh_rate to a very crispy experience
59        std::thread::sleep(Duration::from_millis(900 / get_monitor_refresh_rate()));
60        app_state.update_window_size(renderer.canvas.window().size().0, renderer.canvas.window().size().1);
61        input_handler.handle_input(&mut window_modules.event_pump, &mut window_modules.clipboard_system, &mut page_data, &mut app_state, &mut button_action_closure);
62        page_data.create_current_page(&mut app_state);
63        renderer.render(&page_data, &mut app_state, &input_handler);
64    }
65}
66
67//==========================================================================================================================================================================
68//===============================================================# can be a different file, like: buttons_actions.rs #======================================================
69//==========================================================================================================================================================================
70pub fn button_action(app_state: &mut AppState<PageId, ButtonId>, button_id: &ButtonId, app_data: &mut PageData<PageId, ButtonId>)
71{
72    if !app_state.capturing_input.0
73    {
74        if &ButtonId::ButtonPage1 == button_id
75        {
76            app_state.change_current_page(app_data, PageId::Page1, button_id);
77            return;
78        };
79        if &ButtonId::ButtonSubPage == button_id
80        {
81            app_state.change_current_page(app_data, PageId::Page1SubPage, button_id);
82            return;
83        };
84        if &ButtonId::ButtonBack == button_id
85        {
86            println!("button back clicked");
87            app_state.change_current_page(app_data, PageId::Page1, button_id);
88            return;
89        };
90        // Non Handle Buttons Will Be Considered User Input Buttons
91        app_state.capturing_input = (true, Some(*button_id));
92    }
93}
94
95//==========================================================================================================================================================================
96//===============================================================# can be a different file, like: setup_page_data.rs #======================================================
97//==========================================================================================================================================================================
98pub fn populate_page_data(page_data: &mut PageData<PageId, ButtonId>)
99{
100    page_data.push_page_link(Some(vec![(PageId::Page1SubPage, Rc::new(subpage_page1))]), Some(vec![(PageId::Page1, Rc::new(|input: &mut Vec<String>| page_1(input, 13)))]));
101}
102
103//==========================================================================================================================================================================
104//====================================================================# can be a different file, like: style.rs (or not even exist) #=======================================
105//==========================================================================================================================================================================
106pub const BACKGROUND_COLOR: Color = Color::RGB(30, 30, 46);
107pub const TEXT_COLOR: Color = Color::RGB(255, 255, 255);
108pub const SUBTEXT_COLOR: Color = Color::RGB(186, 194, 222);
109pub const PURPLE_COLOR: Color = Color::RGB(203, 166, 247);
110pub const PINK_COLOR: Color = Color::RGB(243, 139, 168);
111pub const ORANGE_COLOR: Color = Color::RGB(250, 179, 135);
112pub const BLACK_COLOR: Color = Color::RGB(17, 17, 27);
113pub const RED_COLOR: Color = Color::RGB(255, 0, 0);
114
115//==========================================================================================================================================================================
116//===============================================================# can be a different file, like: pages.rs #================================================================
117//==========================================================================================================================================================================
118#[derive(Debug, Clone, Copy, PartialEq, Eq)]
119/// Defines The ID for your Pages
120pub enum PageId
121{
122    Persistent,
123    Page1,
124    Page1SubPage
125}
126#[derive(Eq, PartialEq, Clone, Copy, Debug)]
127#[repr(usize)]
128/// Defines The ID for your Buttons
129pub enum ButtonId
130{
131    ButtonPage1,
132    ButtonPurpleInputStartPage1,
133    ButtonSubPage,
134    ButtonBack
135}
136
137// Define Your Pages Here:
138pub fn persistent_elements(_string: String) -> PersistentElements<PageId, ButtonId>
139{
140    //"persistent_elements now can also receive extra args without affecting the functionality of the app"
141    // like the parsed = _string
142    //===================== rects =========================
143    let all_rects = vec![(BLACK_COLOR, (Rect::new(0, 0, 1920, 100), 0))];
144
145    //===================== texts =========================
146    let all_text = vec![(17.0, (825, 34), "This Is A Persistent Element".to_string(), TEXT_COLOR)];
147
148    //===================== images =========================
149    let all_images = vec![((10, 10), (50, 50), format!("{}/.cache/page_system/example_1.jpg", env::home_dir().unwrap().display()))];
150
151    //===================== page creation =========================
152    PersistentElements { id: PageId::Persistent, background_color: None, rects: Some(all_rects), buttons: None, texts: Some(all_text), images: Some(all_images) }
153}
154
155pub fn page_1(user_input: &mut Vec<String>, _int: i32) -> Page<PageId, ButtonId>
156{
157    //"pages now can also receive extra args without affecting the functionality of the app"
158    // like the parsed = _int
159    //===================== variables =========================
160    let purple_button_data = get_center((600, 100), (1920, 1080));
161    let subpage_button_data = get_center((235, 40), (1920, 1080));
162
163    //===================== buttons =========================
164    let all_buttons = vec![Button { enabled: true, color: PURPLE_COLOR, rect: Rect::new(subpage_button_data.pos_x, 150, subpage_button_data.w, subpage_button_data.h), radius: 20, id: ButtonId::ButtonSubPage, has_transition: None }, Button { enabled: true, color: PURPLE_COLOR, rect: Rect::new(purple_button_data.pos_x, purple_button_data.pos_y, purple_button_data.w, purple_button_data.h), radius: 5, id: ButtonId::ButtonPurpleInputStartPage1, has_transition: None }];
165
166    //===================== texts =========================
167    let all_text = vec![(18.0, (all_buttons[0].rect.x + 10, all_buttons[0].rect.y + 7), "Go To subpage_page1".to_string(), TEXT_COLOR), (18.0, (all_buttons[1].rect.x + 75, all_buttons[1].rect.y - 25), "Click the Button To Start Getting Input".to_string(), SUBTEXT_COLOR), (25.0, (all_buttons[1].rect.x + 15, all_buttons[1].rect.y + 35), user_input.get_or_create(0), BLACK_COLOR)];
168
169    //===================== page creation =========================
170    Page { has_userinput: Some(vec![(PageId::Page1, ButtonId::ButtonPurpleInputStartPage1)]), has_persistent_elements: Some(vec![(PageId::Persistent, Rc::new(|| persistent_elements("a".to_string())))]), id: PageId::Page1, background_color: Some(BACKGROUND_COLOR), rects: None, buttons: Some(all_buttons), texts: Some(all_text), images: None }
171}
172
173pub fn subpage_page1() -> Page<PageId, ButtonId>
174{
175    //===================== buttons =========================
176    let all_buttons = vec![Button { enabled: true, color: PINK_COLOR, rect: Rect::new(200, 0, 50, 150), radius: 0, id: ButtonId::ButtonBack, has_transition: None }];
177
178    //===================== texts =========================
179    let all_text = vec![(18.0, (all_buttons[0].rect.x + 10, all_buttons[0].rect.y + 7), "<-".to_string(), TEXT_COLOR)];
180
181    //===================== page creation =========================
182    Page { has_userinput: None, has_persistent_elements: None, id: PageId::Page1SubPage, background_color: Some(BACKGROUND_COLOR), rects: None, buttons: Some(all_buttons), texts: Some(all_text), images: None }
183}