--> retained mode ui

This commit is contained in:
cool-mist
2026-03-15 12:04:48 +05:30
parent 3cb08bf08e
commit 194136dfc7
12 changed files with 590 additions and 484 deletions
+249 -15
View File
@@ -4,32 +4,33 @@ mod logic;
use std::collections::HashMap; use std::collections::HashMap;
use crate::{resources::Resources, widgets::*}; use crate::{
game,
resources::{self, Resources, SoundKind},
widgets::*,
};
use macroquad::prelude::*; use macroquad::prelude::*;
use sol_lib::generator::Puzzle; use sol_lib::{board::BoardState, generator::Puzzle};
#[derive(Default)] #[derive(Default)]
pub struct Game { pub struct Game {
resources: Resources,
// Game state // Game state
settings: GameSettings, settings: Settings,
puzzle: Puzzle, puzzle: Puzzle,
show_rules: bool, show_rules: bool,
game_mode: GameMode, game_mode: GameMode,
game_mode_btns: HashMap<GameMode, WidgetId>,
// Render state // Render state
resources: Resources,
window_height: f32, window_height: f32,
window_width: f32, window_width: f32,
rules_font_size: f32, // TODO: remove
generate_btn: ButtonWidget,
board: BoardWidget,
game_mode_btns: HashMap<GameMode, ButtonWidget>,
widgets: HashMap<WidgetId, Widget>, widgets: HashMap<WidgetId, Widget>,
board: WidgetId,
counter_pieces: WidgetId, counter_pieces: WidgetId,
counter_moves: WidgetId, counter_moves: WidgetId,
@@ -40,6 +41,7 @@ pub struct Game {
btn_rules: WidgetId, btn_rules: WidgetId,
btn_reset: WidgetId, btn_reset: WidgetId,
btn_next: WidgetId, btn_next: WidgetId,
btn_generate: WidgetId,
} }
#[derive(Eq, PartialEq, Copy, Clone, Hash, Default)] #[derive(Eq, PartialEq, Copy, Clone, Hash, Default)]
@@ -49,16 +51,65 @@ pub enum Widget {
Label(LabelWidget), Label(LabelWidget),
Counter(CounterWidget), Counter(CounterWidget),
Button(ButtonWidget), Button(ButtonWidget),
Board(BoardWidget),
} }
impl Widget { impl Widget {
fn draw(&mut self, resources: &Resources) { fn draw(&mut self, resources: &Resources, settings: &Settings) {
match self { match self {
Widget::Label(label) => label.draw(&resources), Widget::Label(label) => label.draw(&resources),
Widget::Counter(counter) => counter.draw(&resources), Widget::Counter(counter) => counter.draw(&resources),
Widget::Button(btn) => btn.draw(&resources), Widget::Button(btn) => btn.draw(&resources),
Widget::Board(board) => board.draw(&resources, &settings),
} }
} }
fn update(
&mut self,
interaction: &Interaction,
resources: &Resources,
settings: &Settings,
) -> Command {
match self {
Widget::Label(_) => Command::NoInteraction,
Widget::Counter(c) => handle_counter_input(interaction, c, resources, settings),
Widget::Button(b) => handle_button_input(interaction, b, resources, settings),
Widget::Board(_) => Command::NoInteraction,
}
}
}
fn handle_counter_input(
interaction: &Interaction,
counter: &mut CounterWidget,
resources: &Resources,
settings: &Settings,
) -> Command {
let counter_interaction = counter.handle_input(interaction, resources, settings);
let Some(interaction_type) = counter_interaction.interaction_type else {
return Command::NoInteraction;
};
match interaction_type {
CounterInteractionType::Increment => (counter.on_increment)(counter_interaction),
CounterInteractionType::Decrement => (counter.on_decrement)(counter_interaction),
}
}
fn handle_button_input(
interaction: &Interaction,
button: &mut ButtonWidget,
resources: &Resources,
settings: &Settings,
) -> Command {
let clicked = button
.handle_input(interaction, resources, settings)
.clicked;
if clicked {
return (button.on_click)(button);
}
Command::NoInteraction
} }
macro_rules! get_widget_fn { macro_rules! get_widget_fn {
@@ -78,6 +129,7 @@ macro_rules! get_widget_fn {
get_widget_fn!(label, LabelWidget, Widget::Label); get_widget_fn!(label, LabelWidget, Widget::Label);
get_widget_fn!(button, ButtonWidget, Widget::Button); get_widget_fn!(button, ButtonWidget, Widget::Button);
get_widget_fn!(counter, CounterWidget, Widget::Counter); get_widget_fn!(counter, CounterWidget, Widget::Counter);
get_widget_fn!(board, BoardWidget, Widget::Board);
macro_rules! widget_accessor { macro_rules! widget_accessor {
($name:ident, $fn:ident) => { ($name:ident, $fn:ident) => {
@@ -93,13 +145,14 @@ macro_rules! widget_accessor {
widget_accessor!(w_button, button); widget_accessor!(w_button, button);
widget_accessor!(w_label, label); widget_accessor!(w_label, label);
widget_accessor!(w_counter, counter); widget_accessor!(w_counter, counter);
widget_accessor!(w_board, board);
#[derive(Default)] #[derive(Default)]
pub struct GameSettings { pub struct Settings {
pub volume: f32, pub volume: f32,
pub max_moves_per_piece: u32,
pub debug: bool, pub debug: bool,
pub num_pieces: u32, pub max_pieces: u32,
pub max_age: u32,
} }
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
@@ -115,3 +168,184 @@ impl Default for GameMode {
GameMode::Medium GameMode::Medium
} }
} }
pub enum Command {
NoInteraction,
ResetBoard,
NextPuzzle,
ToggleRules,
UpdateBoard(BoardState),
SwitchGameMode(GameMode),
UpdateMaxPieceCount(u32),
UpdateMaxAge(u32),
NewCustomPuzzle,
ToggleDebug,
HideRules,
Quit,
}
pub async fn new_game() -> Game {
let resources = resources::init().await;
let game_mode = GameMode::Medium;
let settings = Settings {
volume: constants::VOLUME,
max_age: 3,
max_pieces: 2,
..Default::default()
};
let puzzle = logic::generate_new_puzzle(game_mode, &settings);
let game_mode = GameMode::Medium;
let label_heading = LabelWidget::initialize_state(constants::HEADING_TEXT);
let label_pieces = LabelWidget::initialize_state(constants::PIECES_LABEL_TEXT);
let label_max_age = LabelWidget::initialize_state(constants::AGE_LABEL_TEXT);
let show_rules = false;
let mut widgets = HashMap::new();
let label_pieces = add_widget(&mut widgets, Widget::Label(label_pieces));
let label_max_age = add_widget(&mut widgets, Widget::Label(label_max_age));
let label_heading = add_widget(&mut widgets, Widget::Label(label_heading));
let mut w_counter_pieces =
CounterWidget::new(2, 7, settings.max_pieces, false, UiColor::Yellow);
w_counter_pieces.on_increment = |c| Command::UpdateMaxPieceCount(c.current);
w_counter_pieces.on_decrement = |c| Command::UpdateMaxPieceCount(c.current);
let counter_pieces = add_widget(&mut widgets, Widget::Counter(w_counter_pieces));
let mut w_counter_moves = CounterWidget::new(1, 7, settings.max_age, false, UiColor::Yellow);
w_counter_moves.on_increment = |c| Command::UpdateMaxAge(c.current);
w_counter_moves.on_decrement = |c| Command::UpdateMaxAge(c.current);
let counter_moves = add_widget(&mut widgets, Widget::Counter(w_counter_moves));
let btn_reset = add_widget(
&mut widgets,
Widget::Button(ButtonWidget::new(
true,
UiColor::Yellow,
constants::RESET_BUTTON_TEXT,
SoundKind::Button,
)),
);
let btn_next = add_widget(
&mut widgets,
Widget::Button(ButtonWidget::new(
false,
UiColor::Green,
constants::NEXT_BUTTON_TEXT,
SoundKind::Button,
)),
);
let btn_rules = add_widget(
&mut widgets,
Widget::Button(ButtonWidget::new(
true,
UiColor::Brown,
constants::RULES_BUTTON_TEXT,
SoundKind::Button,
)),
);
let btn_generate = add_widget(
&mut widgets,
Widget::Button(ButtonWidget::new(
false,
UiColor::Pink,
constants::GENERATE_BUTTON_TEXT,
SoundKind::Button,
)),
);
let mut game_mode_btns = HashMap::new();
game_mode_btns.insert(
GameMode::Easy,
add_widget(
&mut widgets,
Widget::Button(ButtonWidget::new(
true,
UiColor::Yellow,
constants::EASY_BUTTON_TEXT,
SoundKind::Mode,
)),
),
);
game_mode_btns.insert(
GameMode::Medium,
add_widget(
&mut widgets,
Widget::Button(ButtonWidget::new(
true,
UiColor::Yellow,
constants::MEDIUM_BUTTON_TEXT,
SoundKind::Mode,
)),
),
);
game_mode_btns.insert(
GameMode::Hard,
add_widget(
&mut widgets,
Widget::Button(ButtonWidget::new(
true,
UiColor::Yellow,
constants::HARD_BUTTON_TEXT,
SoundKind::Mode,
)),
),
);
game_mode_btns.insert(
GameMode::Custom,
add_widget(
&mut widgets,
Widget::Button(ButtonWidget::new(
true,
UiColor::Blue,
constants::CUSTOM_BUTTON_TEXT,
SoundKind::Mode,
)),
),
);
let active_game_mode_btn = game_mode_btns.get(&game_mode).unwrap();
game::button(&mut widgets, *active_game_mode_btn).is_active = false;
let board = add_widget(
&mut widgets,
Widget::Board(BoardWidget::initialize_state(
puzzle.board.size,
puzzle.board.clone(),
)),
);
Game {
puzzle,
board,
resources,
settings,
game_mode,
game_mode_btns,
btn_reset,
btn_next,
btn_rules,
show_rules,
widgets,
counter_pieces,
counter_moves,
btn_generate,
label_pieces,
label_max_age,
label_heading,
..Default::default()
}
}
fn add_widget(widgets: &mut HashMap<WidgetId, Widget>, w: Widget) -> WidgetId {
let id = rand::rand() as u64;
let widget_id = WidgetId(id);
widgets.insert(widget_id, w);
widget_id
}
-1
View File
@@ -42,4 +42,3 @@ pub const CUSTOM_BUTTON_TEXT: &str = "CUSTOM";
pub const GENERATE_BUTTON_TEXT: &str = "GENERATE"; pub const GENERATE_BUTTON_TEXT: &str = "GENERATE";
pub const PIECES_LABEL_TEXT: &str = "Pieces"; pub const PIECES_LABEL_TEXT: &str = "Pieces";
pub const AGE_LABEL_TEXT: &str = " Age"; pub const AGE_LABEL_TEXT: &str = " Age";
+14 -26
View File
@@ -1,6 +1,6 @@
use super::{Game, constants}; use super::{Game, constants};
use crate::{ use crate::{
game::{self, GameMode, w_button, w_counter, w_label}, game::{self, GameMode, w_board, w_button, w_counter, w_label},
widgets::*, widgets::*,
}; };
use macroquad::{math, prelude::*}; use macroquad::{math, prelude::*};
@@ -12,12 +12,10 @@ impl Game {
let min_dimension = f32::min(self.window_height, self.window_width); let min_dimension = f32::min(self.window_height, self.window_width);
let square_width = constants::BOARD_SQUARE_WIDTH_MULTIPLIER * min_dimension; let square_width = constants::BOARD_SQUARE_WIDTH_MULTIPLIER * min_dimension;
let num_squares = self.board.num_squares; let num_squares = w_board!(self, board).num_squares;
let board_width = square_width * num_squares as f32; let board_width = square_width * num_squares as f32;
let board_x = (self.window_width * 0.6 - board_width) / 2.0; let board_x = (self.window_width * 0.6 - board_width) / 2.0;
let board_y = (self.window_height - board_width) / 2.0; let board_y = (self.window_height - board_width) / 2.0;
let board_rect = Rect::new(board_x, board_y, board_width, board_width);
self.board.initialize_drawables(square_width, board_rect);
let heading_font_size = constants::HEADING_FONT_SIZE_MULTIPLIER * min_dimension; let heading_font_size = constants::HEADING_FONT_SIZE_MULTIPLIER * min_dimension;
let f = heading_font_size.floor() as u16; let f = heading_font_size.floor() as u16;
@@ -41,6 +39,13 @@ impl Game {
&self.resources, &self.resources,
); );
let board_rect = Rect::new(board_x, board_y, board_width, board_width);
w_board!(self, board).initialize_drawables(
square_width,
board_rect,
heading_font_size * 0.4,
);
// Buttons // Buttons
let btn_h = constants::BUTTON_HEIGHT_MULTIPLIER * min_dimension; let btn_h = constants::BUTTON_HEIGHT_MULTIPLIER * min_dimension;
let btn_w = constants::BUTTON_WIDTH_MULTIPLIER * board_width; let btn_w = constants::BUTTON_WIDTH_MULTIPLIER * board_width;
@@ -63,15 +68,13 @@ impl Game {
)); ));
let btn_next_x_offset = (board_width - square_width) + (square_width - btn_w) / 2.; let btn_next_x_offset = (board_width - square_width) + (square_width - btn_w) / 2.;
w_button!(self, btn_reset).place(Rect::new( w_button!(self, btn_next).place(Rect::new(
board_x + btn_next_x_offset, board_x + btn_next_x_offset,
bottom_row_y, bottom_row_y,
btn_w, btn_w,
btn_h, btn_h,
)); ));
self.rules_font_size = heading_font_size;
// Right column // Right column
let right_column_x = let right_column_x =
board_x + board_width + constants::RIGHT_COLUMN_OFFSET_MULTIPLIER * square_width; board_x + board_width + constants::RIGHT_COLUMN_OFFSET_MULTIPLIER * square_width;
@@ -108,7 +111,7 @@ impl Game {
// Right column 2 // Right column 2
let right_column_2_x = let right_column_2_x =
right_column_x + btn_w + constants::RIGHT_COLUMN_OFFSET_MULTIPLIER * square_width; right_column_x + btn_w + constants::RIGHT_COLUMN_OFFSET_MULTIPLIER * square_width;
self.generate_btn.place(Rect::new( w_button!(self, btn_generate).place(Rect::new(
right_column_2_x, right_column_2_x,
board_y + board_width - square_width + (square_width - btn_h) / 2., board_y + board_width - square_width + (square_width - btn_h) / 2.,
2. * btn_w, 2. * btn_w,
@@ -164,31 +167,16 @@ impl Game {
pub fn draw(&mut self) { pub fn draw(&mut self) {
self.update_window_size(); self.update_window_size();
self.draw_board();
self.generate_btn.draw(&self.resources);
for (_, btn) in &self.game_mode_btns {
btn.draw(&self.resources);
}
for (_, widget) in &mut self.widgets { for (_, widget) in &mut self.widgets {
widget.draw(&self.resources); widget.draw(&self.resources, &self.settings);
} }
self.draw_fps(); self.draw_fps();
} }
fn draw_board(&mut self) {
let params = BoardDrawParams {
show_rules: self.show_rules,
rules_font_size: self.rules_font_size,
};
self.board.draw(&params, &self.resources, &self.settings);
}
fn get_game_mode_button<'a>(&'a mut self, mode: &GameMode) -> &'a mut ButtonWidget { fn get_game_mode_button<'a>(&'a mut self, mode: &GameMode) -> &'a mut ButtonWidget {
self.game_mode_btns.get_mut(mode).unwrap() let id = self.game_mode_btns.get(mode).unwrap();
game::button(&mut self.widgets, *id)
} }
fn draw_fps(&self) { fn draw_fps(&self) {
+125 -252
View File
@@ -1,9 +1,7 @@
use std::collections::HashMap; use super::{Game, GameMode, Settings, constants};
use super::{Game, GameMode, GameSettings, constants};
use crate::{ use crate::{
game::{self, Widget, WidgetId, w_button, w_counter}, game::{self, Command, w_board, w_button, w_counter},
resources::{self, *}, resources::*,
widgets::*, widgets::*,
}; };
use macroquad::prelude::*; use macroquad::prelude::*;
@@ -13,266 +11,149 @@ use sol_lib::{
}; };
impl Game { impl Game {
pub async fn new() -> Self { pub fn update(&mut self, interaction: Interaction) {
let resources = resources::init().await; let command = self.get_command(interaction);
let game_mode = GameMode::Medium; self.update_state(command);
let settings = GameSettings { }
volume: constants::VOLUME,
max_moves_per_piece: 3, fn get_command(&mut self, interaction: Interaction) -> Command {
num_pieces: 2,
..Default::default() for (_, widget) in &mut self.widgets {
let cmd = widget.update(&interaction, &self.resources, &self.settings);
let ret_cmd = match cmd {
Command::NoInteraction => false,
_ => true,
}; };
let puzzle = Game::generate_puzzle(game_mode, &settings);
let board = BoardWidget::initialize_state(puzzle.board.size, puzzle.board.clone());
let mut game_mode_btns = HashMap::new();
let game_mode = GameMode::Medium;
game_mode_btns.insert(
GameMode::Easy,
ButtonWidget::new(true, UiColor::Yellow, constants::EASY_BUTTON_TEXT),
);
game_mode_btns.insert(
GameMode::Medium,
ButtonWidget::new(true, UiColor::Yellow, constants::MEDIUM_BUTTON_TEXT),
);
game_mode_btns.insert(
GameMode::Hard,
ButtonWidget::new(true, UiColor::Yellow, constants::HARD_BUTTON_TEXT),
);
game_mode_btns.insert(
GameMode::Custom,
ButtonWidget::new(true, UiColor::Blue, constants::CUSTOM_BUTTON_TEXT),
);
let generate_btn = ButtonWidget::new(false, UiColor::Pink, constants::GENERATE_BUTTON_TEXT);
let heading = LabelWidget::initialize_state(constants::HEADING_TEXT);
let pieces_label = LabelWidget::initialize_state(constants::PIECES_LABEL_TEXT);
let max_age_label = LabelWidget::initialize_state(constants::AGE_LABEL_TEXT);
let show_rules = false;
game_mode_btns.get_mut(&game_mode).unwrap().is_active = false;
let mut widgets = HashMap::new(); if ret_cmd {
let label_pieces = add_widget(&mut widgets, Widget::Label(pieces_label)); return cmd;
let label_max_age = add_widget(&mut widgets, Widget::Label(max_age_label));
let label_heading = add_widget(&mut widgets, Widget::Label(heading));
let counter_pieces = add_widget(
&mut widgets,
Widget::Counter(CounterWidget::new(
2,
7,
settings.num_pieces,
false,
UiColor::Yellow,
)),
);
let counter_moves = add_widget(
&mut widgets,
Widget::Counter(CounterWidget::new(
1,
7,
settings.max_moves_per_piece,
false,
UiColor::Yellow,
)),
);
let btn_reset = add_widget(
&mut widgets,
Widget::Button(ButtonWidget::new(
true,
UiColor::Yellow,
constants::RESET_BUTTON_TEXT,
)),
);
let btn_next = add_widget(
&mut widgets,
Widget::Button(ButtonWidget::new(
false,
UiColor::Green,
constants::NEXT_BUTTON_TEXT,
)),
);
let btn_rules = add_widget(
&mut widgets,
Widget::Button(ButtonWidget::new(
true,
UiColor::Brown,
constants::RULES_BUTTON_TEXT,
)),
);
Self {
puzzle,
board,
resources,
settings,
game_mode,
game_mode_btns,
btn_reset,
btn_next,
btn_rules,
show_rules,
widgets,
counter_pieces,
counter_moves,
generate_btn,
label_pieces,
label_max_age,
label_heading,
..Default::default()
} }
} }
pub fn handle_interaction(&mut self, interaction: GameInteraction) { let board_interaction =
match interaction { w_board!(self, board).handle_input(&interaction, &self.resources, &self.settings);
GameInteraction::NoInteraction => {} if let Some(new_board_state) = board_interaction.new_board_state {
GameInteraction::Board(new_board_state) => match new_board_state { return Command::UpdateBoard(new_board_state);
BoardState::Won => {
w_button!(self, btn_next).is_active = true;
} }
_ => {}
}, if w_button!(self, btn_reset)
GameInteraction::ButtonRelease(button_name) => match button_name { .handle_input(&interaction, &self.resources, &self.settings)
ButtonName::Reset => self.reset(), .clicked
ButtonName::Next => self.next_puzzle(), {
ButtonName::Rules => { return Command::ResetBoard;
}
if w_button!(self, btn_next)
.handle_input(&interaction, &self.resources, &self.settings)
.clicked
{
return Command::NextPuzzle;
}
for (mode, btn) in &mut self.game_mode_btns {
if game::button(&mut self.widgets, *btn)
.handle_input(&interaction, &self.resources, &self.settings)
.clicked
{
return Command::SwitchGameMode(*mode);
}
}
if w_button!(self, btn_rules)
.handle_input(&interaction, &self.resources, &self.settings)
.clicked
{
return Command::ToggleRules;
}
if w_button!(self, btn_generate)
.handle_input(&interaction, &self.resources, &self.settings)
.clicked
{
return Command::NewCustomPuzzle;
}
if interaction.keys_released.contains(&KeyCode::Escape) {
return Command::HideRules;
}
if interaction.keys_released.contains(&KeyCode::D) {
return Command::ToggleDebug;
}
if interaction.keys_released.contains(&KeyCode::Q) {
return Command::Quit;
}
return Command::NoInteraction;
}
fn update_state(&mut self, command: Command) {
match command {
Command::NoInteraction => (),
Command::UpdateBoard(new_board_state) => self.update_board(new_board_state),
Command::SwitchGameMode(mode) => self.switch_game_mode(mode),
Command::ToggleDebug => self.settings.debug = !self.settings.debug,
Command::HideRules => self.hide_rules(),
Command::ResetBoard => self.reset(),
Command::NextPuzzle => self.next_puzzle(),
Command::ToggleRules => self.toggle_rules(),
Command::UpdateMaxPieceCount(new_value) => self.settings.max_pieces = new_value,
Command::UpdateMaxAge(new_value) => self.settings.max_age = new_value,
Command::NewCustomPuzzle => self.new_custom_puzzle(),
Command::Quit => std::process::exit(0),
}
}
fn new_custom_puzzle(&mut self) {
if self.game_mode == GameMode::Custom {
self.next_puzzle();
}
}
fn toggle_rules(&mut self) {
self.show_rules = !self.show_rules; self.show_rules = !self.show_rules;
w_board!(self, board).show_rules = self.show_rules;
w_button!(self, btn_rules).text = match self.show_rules { w_button!(self, btn_rules).text = match self.show_rules {
true => constants::RULES_BUTTON_ALT_TEXT.to_string(), true => constants::RULES_BUTTON_ALT_TEXT.to_string(),
false => constants::RULES_BUTTON_TEXT.to_string(), false => constants::RULES_BUTTON_TEXT.to_string(),
}; };
} }
ButtonName::Generate => {
if self.game_mode == GameMode::Custom {
self.next_puzzle();
}
}
},
GameInteraction::GameMode(mode) => {
self.game_mode = mode;
for (mode, btn) in &mut self.game_mode_btns {
if *mode == self.game_mode {
btn.is_active = false;
} else {
btn.is_active = true;
}
}
let is_custom_game_mode = self.game_mode == GameMode::Custom; fn hide_rules(&mut self) {
self.generate_btn.is_active = is_custom_game_mode;
w_counter!(self, counter_pieces).set_active(is_custom_game_mode);
w_counter!(self, counter_moves).set_active(is_custom_game_mode);
// A change in game mode, immediately generate new puzzle
if !is_custom_game_mode {
self.next_puzzle();
}
}
GameInteraction::Counter(counter_name, new_value) => match counter_name {
CounterName::Pieces => {
self.settings.num_pieces = new_value;
}
CounterName::Age => {
self.settings.max_moves_per_piece = new_value;
}
},
GameInteraction::ToggleDebug => self.settings.debug = !self.settings.debug,
GameInteraction::HideRules => {
if self.show_rules { if self.show_rules {
play_sound_once( play_sound_once(
&self.resources.sound(&SoundKind::Button), &self.resources.sound(&SoundKind::Button),
self.settings.volume, self.settings.volume,
); );
self.show_rules = false; self.show_rules = false;
w_board!(self, board).show_rules = false;
w_button!(self, btn_rules).text = constants::RULES_BUTTON_TEXT.to_string(); w_button!(self, btn_rules).text = constants::RULES_BUTTON_TEXT.to_string();
} }
} }
GameInteraction::Quit => std::process::exit(0),
} fn switch_game_mode(&mut self, mode: GameMode) {
self.game_mode = mode;
for (mode, btn_id) in &mut self.game_mode_btns {
// The active mode button is 'disabled' to indicate it is active
let is_active = !(*mode == self.game_mode);
game::button(&mut self.widgets, *btn_id).is_active = is_active;
} }
pub fn handle_user_input(&mut self) -> GameInteraction { let is_custom_game_mode = self.game_mode == GameMode::Custom;
let (mx, my) = mouse_position(); w_button!(self, btn_generate).is_active = is_custom_game_mode;
let winput = UserInteraction { w_counter!(self, counter_pieces).set_active(is_custom_game_mode);
mouse_pos: Circle::new(mx, my, 0.0), w_counter!(self, counter_moves).set_active(is_custom_game_mode);
}; self.next_puzzle();
// WIDGETS
let board_interaction = self
.board
.handle_input(&winput, &self.resources, &self.settings);
if let Some(new_board_state) = board_interaction.new_board_state {
return GameInteraction::Board(new_board_state);
} }
if w_button!(self, btn_reset).handle_input( fn update_board(&mut self, new_board_state: BoardState) {
&self.resources.sound(&SoundKind::Button), match new_board_state {
self.settings.volume, BoardState::Won => {
) { w_button!(self, btn_next).is_active = true;
return GameInteraction::ButtonRelease(ButtonName::Reset);
} }
_ => {}
if w_button!(self, btn_next).handle_input(
&self.resources.sound(&SoundKind::Button),
self.settings.volume,
) {
return GameInteraction::ButtonRelease(ButtonName::Next);
} }
for (mode, btn) in &mut self.game_mode_btns {
if btn.handle_input(
&self.resources.sound(&SoundKind::Mode),
self.settings.volume,
) {
return GameInteraction::GameMode(*mode);
}
}
if w_button!(self, btn_rules).handle_input(
&self.resources.sound(&SoundKind::Button),
self.settings.volume,
) {
return GameInteraction::ButtonRelease(ButtonName::Rules);
}
let pieces_counter_interaction =
w_counter!(self, counter_pieces).handle_input(&winput, &self.resources, &self.settings);
if pieces_counter_interaction.interacted {
return GameInteraction::Counter(
CounterName::Pieces,
pieces_counter_interaction.current,
);
}
let age_counter_interaction =
w_counter!(self, counter_moves).handle_input(&winput, &self.resources, &self.settings);
if age_counter_interaction.interacted {
return GameInteraction::Counter(CounterName::Age, age_counter_interaction.current);
}
if self.generate_btn.handle_input(
&self.resources.sound(&SoundKind::Button),
self.settings.volume,
) {
return GameInteraction::ButtonRelease(ButtonName::Generate);
}
// KEY INPUTS
if is_key_released(KeyCode::Escape) {
return GameInteraction::HideRules;
}
if is_key_released(KeyCode::D) {
return GameInteraction::ToggleDebug;
}
if is_key_released(KeyCode::Q) {
return GameInteraction::Quit;
}
return GameInteraction::NoInteraction;
} }
fn reset(&mut self) { fn reset(&mut self) {
@@ -281,11 +162,11 @@ impl Game {
fn reset_game(&mut self, options: ResetOptions) { fn reset_game(&mut self, options: ResetOptions) {
if options.create_new_puzzle { if options.create_new_puzzle {
self.puzzle = Game::generate_puzzle(self.game_mode, &self.settings); self.puzzle = generate_new_puzzle(self.game_mode, &self.settings);
} }
w_button!(self, btn_next).is_active = false; w_button!(self, btn_next).is_active = false;
self.board.reset(&self.puzzle); w_board!(self, board).reset(&self.puzzle);
} }
fn next_puzzle(&mut self) { fn next_puzzle(&mut self) {
@@ -294,20 +175,21 @@ impl Game {
..Default::default() ..Default::default()
}); });
} }
}
fn generate_puzzle(mode: GameMode, settings: &GameSettings) -> Puzzle { pub fn generate_new_puzzle(mode: GameMode, settings: &Settings) -> Puzzle {
let piece_count = match mode { let piece_count = match mode {
GameMode::Easy => 3, GameMode::Easy => 3,
GameMode::Medium => 5, GameMode::Medium => 5,
GameMode::Hard => 7, GameMode::Hard => 7,
GameMode::Custom => settings.num_pieces, GameMode::Custom => settings.max_pieces,
}; };
let max_moves_per_piece = match mode { let max_moves_per_piece = match mode {
GameMode::Easy => 2, GameMode::Easy => 2,
GameMode::Medium => 2, GameMode::Medium => 2,
GameMode::Hard => 2, GameMode::Hard => 2,
GameMode::Custom => settings.max_moves_per_piece, GameMode::Custom => settings.max_age,
}; };
let generated = generator::generate_weighted_random( let generated = generator::generate_weighted_random(
@@ -318,15 +200,6 @@ impl Game {
); );
let puzzle = generated.puzzle(); let puzzle = generated.puzzle();
puzzle.expect("No puzzle was generated") puzzle.expect("No puzzle was generated")
}
}
fn add_widget(widgets: &mut HashMap<WidgetId, Widget>, w: Widget) -> WidgetId {
let id = rand::rand() as u64;
let widget_id = WidgetId(id);
widgets.insert(widget_id, w);
widget_id
} }
#[derive(Default)] #[derive(Default)]
@@ -334,7 +207,7 @@ struct ResetOptions {
create_new_puzzle: bool, create_new_puzzle: bool,
} }
struct MacroquadRandAdapter; pub struct MacroquadRandAdapter;
impl RandomRange for MacroquadRandAdapter { impl RandomRange for MacroquadRandAdapter {
fn gen_range(&self, min: usize, max: usize) -> usize { fn gen_range(&self, min: usize, max: usize) -> usize {
rand::gen_range(min, max) rand::gen_range(min, max)
+30 -6
View File
@@ -2,12 +2,15 @@ mod game;
mod resources; mod resources;
mod widgets; mod widgets;
use game::Game; use std::collections::HashSet;
use macroquad::prelude::*; use macroquad::prelude::*;
use miniquad::date; use miniquad::date;
use game::constants; use game::constants;
use crate::widgets::Interaction;
fn window_conf() -> Conf { fn window_conf() -> Conf {
let window_title = { let window_title = {
if cfg!(debug_assertions) { if cfg!(debug_assertions) {
@@ -28,15 +31,36 @@ fn window_conf() -> Conf {
async fn main() { async fn main() {
rand::srand(date::now() as u64); rand::srand(date::now() as u64);
let background_color = Color::from_rgba(196, 195, 208, 255); let background_color = Color::from_rgba(196, 195, 208, 255);
let mut game = Game::new().await; let mut game = game::new_game().await;
loop { loop {
clear_background(background_color); clear_background(background_color);
let interaction = game.handle_user_input(); game.update(get_interaction());
game.handle_interaction(interaction);
game.draw(); game.draw();
next_frame().await
next_frame().await;
} }
} }
fn get_interaction() -> Interaction {
let mut mouse_pressed = HashSet::new();
let mut mouse_released = HashSet::new();
let buttons = vec![MouseButton::Left, MouseButton::Right];
for btn in buttons {
if is_mouse_button_pressed(btn) {
mouse_pressed.insert(btn);
}
if is_mouse_button_released(btn) {
mouse_released.insert(btn);
}
}
let (mx, my) = mouse_position();
Interaction {
mouse_pos: Circle::new(mx, my, 0.),
keys_released: get_keys_released(),
mouse_pressed,
mouse_released,
}
}
+13 -4
View File
@@ -68,10 +68,19 @@ pub async fn init() -> Resources {
fn generate_texture_rects_pieces(active: bool) -> HashMap<PieceKind, Rect> { fn generate_texture_rects_pieces(active: bool) -> HashMap<PieceKind, Rect> {
let mut texture_rects_pieces = HashMap::new(); let mut texture_rects_pieces = HashMap::new();
texture_rects_pieces.insert(PieceKind::Pawn, piece_texture_rect(PieceKind::Pawn, active)); texture_rects_pieces.insert(PieceKind::Pawn, piece_texture_rect(PieceKind::Pawn, active));
texture_rects_pieces.insert(PieceKind::Knight, piece_texture_rect(PieceKind::Knight, active)); texture_rects_pieces.insert(
texture_rects_pieces.insert(PieceKind::Bishop, piece_texture_rect(PieceKind::Bishop, active)); PieceKind::Knight,
piece_texture_rect(PieceKind::Knight, active),
);
texture_rects_pieces.insert(
PieceKind::Bishop,
piece_texture_rect(PieceKind::Bishop, active),
);
texture_rects_pieces.insert(PieceKind::Rook, piece_texture_rect(PieceKind::Rook, active)); texture_rects_pieces.insert(PieceKind::Rook, piece_texture_rect(PieceKind::Rook, active));
texture_rects_pieces.insert(PieceKind::Queen, piece_texture_rect(PieceKind::Queen, active)); texture_rects_pieces.insert(
PieceKind::Queen,
piece_texture_rect(PieceKind::Queen, active),
);
texture_rects_pieces.insert(PieceKind::King, piece_texture_rect(PieceKind::King, active)); texture_rects_pieces.insert(PieceKind::King, piece_texture_rect(PieceKind::King, active));
texture_rects_pieces texture_rects_pieces
@@ -93,7 +102,7 @@ fn piece_texture_rect(piece: PieceKind, active: bool) -> Rect {
Rect::new(index as f32 * 128.0, color as f32 * 128.0, 128.0, 128.0) Rect::new(index as f32 * 128.0, color as f32 * 128.0, 128.0, 128.0)
} }
#[derive(Eq, PartialEq, Hash)] #[derive(Eq, Copy, Clone, PartialEq, Hash)]
pub enum SoundKind { pub enum SoundKind {
Click, Click,
Win, Win,
+6 -7
View File
@@ -1,11 +1,11 @@
mod board; mod board;
use std::collections::HashSet;
pub use board::*; pub use board::*;
mod button; mod button;
pub use button::*; pub use button::*;
mod id_text_input;
mod label; mod label;
pub use label::*; pub use label::*;
@@ -18,8 +18,11 @@ use macroquad::{
}; };
use quad_snd::PlaySoundParams; use quad_snd::PlaySoundParams;
pub struct UserInteraction { pub struct Interaction {
pub mouse_pos: Circle, pub mouse_pos: Circle,
pub keys_released: HashSet<KeyCode>,
pub mouse_pressed: HashSet<MouseButton>,
pub mouse_released: HashSet<MouseButton>,
} }
#[allow(unused)] #[allow(unused)]
@@ -67,10 +70,6 @@ impl UiColor {
} }
} }
pub fn draw_rect(rect: &Rect, color: UiColor) {
draw_rectangle(rect.x, rect.y, rect.w, rect.h, color.to_bg_color());
}
pub fn draw_shadow(rect: &Rect, shadow_width: f32) { pub fn draw_shadow(rect: &Rect, shadow_width: f32) {
let shadow_color = Color::new(0., 0., 0., 0.8); let shadow_color = Color::new(0., 0., 0., 0.8);
draw_rectangle( draw_rectangle(
+22 -40
View File
@@ -2,11 +2,10 @@ use core::fmt;
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
use crate::{ use crate::{
game::{GameMode, GameSettings, constants}, game::{Settings, constants},
resources::{Resources, SoundKind}, resources::{Resources, SoundKind},
widgets::*, widgets::*,
}; };
use macroquad::prelude::*;
use sol_lib::{ use sol_lib::{
board::{Board, BoardState, piece::Piece}, board::{Board, BoardState, piece::Piece},
generator::Puzzle, generator::Puzzle,
@@ -17,35 +16,13 @@ pub struct BoardWidget {
current_board: Board, current_board: Board,
square_width: f32, square_width: f32,
pub num_squares: usize, // this is a constant = 4 for now. pub num_squares: usize, // this is a constant = 4 for now.
pub show_rules: bool,
rules_font_size: f32,
board_rect: Rect, board_rect: Rect,
squares: Vec<GameSquare>, squares: Vec<GameSquare>,
state: GameState, state: GameState,
} }
#[derive(Copy, Clone)]
pub enum ButtonName {
Reset,
Next,
Rules,
Generate,
}
pub enum CounterName {
Pieces,
Age,
}
pub enum GameInteraction {
NoInteraction,
Board(BoardState),
ButtonRelease(ButtonName),
GameMode(GameMode),
Counter(CounterName, u32),
ToggleDebug,
HideRules,
Quit,
}
pub struct BoardInteraction { pub struct BoardInteraction {
pub new_board_state: Option<BoardState>, pub new_board_state: Option<BoardState>,
} }
@@ -58,9 +35,15 @@ impl BoardWidget {
board board
} }
pub fn initialize_drawables(&mut self, square_width: f32, board_rect: Rect) { pub fn initialize_drawables(
&mut self,
square_width: f32,
board_rect: Rect,
rules_font_size: f32,
) {
self.square_width = square_width; self.square_width = square_width;
self.board_rect = board_rect; self.board_rect = board_rect;
self.rules_font_size = rules_font_size;
let dark = UiColor::Brown.to_bg_color(); let dark = UiColor::Brown.to_bg_color();
let light = UiColor::Yellow.to_bg_color(); let light = UiColor::Yellow.to_bg_color();
@@ -90,11 +73,11 @@ impl BoardWidget {
self.squares = rects; self.squares = rects;
} }
pub fn draw(&self, params: &BoardDrawParams, resources: &Resources, settings: &GameSettings) { pub fn draw(&self, resources: &Resources, settings: &Settings) {
let board_shadow_width = constants::BOARD_SHADOW_MULTIPLIER * self.square_width; let board_shadow_width = constants::BOARD_SHADOW_MULTIPLIER * self.square_width;
draw_shadow(&self.board_rect, board_shadow_width); draw_shadow(&self.board_rect, board_shadow_width);
if params.show_rules { if self.show_rules {
draw_rectangle( draw_rectangle(
self.board_rect.x, self.board_rect.x,
self.board_rect.y, self.board_rect.y,
@@ -103,16 +86,20 @@ impl BoardWidget {
UiColor::Yellow.to_bg_color(), UiColor::Yellow.to_bg_color(),
); );
let font_size = params.rules_font_size * 0.4;
let rules = "\ let rules = "\
Every move should be a \n\ Every move should be a \n\
capture. Win when only \n\ capture. Win when only \n\
one piece is left.\n\ one piece is left.\n\
Age: Each piece can only \n\ Age: Each piece can only \n\
move 'age' times"; move 'age' times";
let measurement = measure_text(rules, Some(resources.font()), font_size as u16, 1.0); let measurement = measure_text(
rules,
Some(resources.font()),
self.rules_font_size as u16,
1.0,
);
let draw_text_params = TextParams { let draw_text_params = TextParams {
font_size: font_size as u16, font_size: self.rules_font_size as u16,
font: Some(resources.font()), font: Some(resources.font()),
color: UiColor::Brown.to_bg_color(), color: UiColor::Brown.to_bg_color(),
..Default::default() ..Default::default()
@@ -214,9 +201,9 @@ impl BoardWidget {
pub fn handle_input( pub fn handle_input(
&mut self, &mut self,
interaction: &UserInteraction, interaction: &Interaction,
resources: &Resources, resources: &Resources,
settings: &GameSettings, settings: &Settings,
) -> BoardInteraction { ) -> BoardInteraction {
let mouse_pos = interaction.mouse_pos; let mouse_pos = interaction.mouse_pos;
if mouse_pos.overlaps_rect(&self.board_rect) == false { if mouse_pos.overlaps_rect(&self.board_rect) == false {
@@ -315,7 +302,7 @@ impl BoardWidget {
mouse_pos: Circle, mouse_pos: Circle,
source: (usize, usize), source: (usize, usize),
resources: &Resources, resources: &Resources,
settings: &GameSettings, settings: &Settings,
) -> GameState { ) -> GameState {
let mut selected = None; let mut selected = None;
for square in &mut self.squares { for square in &mut self.squares {
@@ -444,8 +431,3 @@ struct PieceDrawTextureParams<'a> {
texture: &'a Texture2D, texture: &'a Texture2D,
draw_text_params: DrawTextureParams, draw_text_params: DrawTextureParams,
} }
pub struct BoardDrawParams {
pub show_rules: bool,
pub rules_font_size: f32,
}
+42 -15
View File
@@ -1,5 +1,8 @@
use crate::{resources::Resources, widgets::*}; use crate::{
use macroquad::{audio::Sound, prelude::*}; game::{Command, Settings},
resources::{Resources, SoundKind},
widgets::*,
};
pub struct ButtonWidget { pub struct ButtonWidget {
pub is_active: bool, pub is_active: bool,
@@ -8,15 +11,32 @@ pub struct ButtonWidget {
is_down: bool, is_down: bool,
rect: Rect, rect: Rect,
shadow_width: f32, shadow_width: f32,
sound: SoundKind,
pub on_click: fn(&mut ButtonWidget) -> Command,
}
pub struct ButtonInteraction {
pub clicked: bool,
}
impl ButtonInteraction {
fn not_clicked() -> Self {
Self { clicked: false }
}
fn clicked() -> Self {
Self { clicked: true }
}
} }
impl ButtonWidget { impl ButtonWidget {
pub fn new(is_active: bool, color: UiColor, text: impl Into<String>) -> Self { pub fn new(is_active: bool, color: UiColor, text: impl Into<String>, sound: SoundKind) -> Self {
Self { Self {
is_active, is_active,
text: text.into(), text: text.into(),
color, color,
shadow_width: 5.0, shadow_width: 5.0,
sound,
..Default::default() ..Default::default()
} }
} }
@@ -105,33 +125,38 @@ impl ButtonWidget {
button_pressed_correction button_pressed_correction
} }
pub fn handle_input(&mut self, click_sound: &Sound, volume: f32) -> bool { pub fn handle_input(
&mut self,
interaction: &Interaction,
resources: &Resources,
settings: &Settings,
) -> ButtonInteraction {
if !self.is_active { if !self.is_active {
self.is_down = false; self.is_down = false;
return false; return ButtonInteraction::not_clicked();
} }
let (mx, my) = mouse_position(); let mouse = interaction.mouse_pos;
let c = Circle::new(mx, my, 0.0); if interaction.mouse_pressed.contains(&MouseButton::Left) {
if mouse.overlaps_rect(&self.rect) {
if is_mouse_button_pressed(MouseButton::Left) {
if c.overlaps_rect(&self.rect) {
self.is_down = true; self.is_down = true;
return false; return ButtonInteraction::not_clicked();
} }
} }
if is_mouse_button_released(MouseButton::Left) { if interaction.mouse_released.contains(&MouseButton::Left) {
if c.overlaps_rect(&self.rect) { if mouse.overlaps_rect(&self.rect) {
let click_sound = resources.sound(&self.sound);
let volume = settings.volume;
play_sound_once(&click_sound, volume); play_sound_once(&click_sound, volume);
self.is_down = false; self.is_down = false;
return true; return ButtonInteraction::clicked();
} }
self.is_down = false; self.is_down = false;
} }
false ButtonInteraction::not_clicked()
} }
} }
@@ -144,6 +169,8 @@ impl Default for ButtonWidget {
shadow_width: Default::default(), shadow_width: Default::default(),
color: UiColor::Grey, color: UiColor::Grey,
text: String::new(), text: String::new(),
sound: SoundKind::Click,
on_click: |_| Command::NoInteraction,
} }
} }
} }
+66 -23
View File
@@ -1,15 +1,16 @@
use crate::{ use crate::{
game::GameSettings, game::{Command, Settings},
resources::{Resources, SoundKind}, resources::{Resources, SoundKind},
widgets::*, widgets::*,
}; };
use macroquad::prelude::*; use macroquad::prelude::*;
#[derive(Default)]
pub struct CounterWidget { pub struct CounterWidget {
visual_rect: Rect, visual_rect: Rect,
increment: ButtonWidget, increment: ButtonWidget,
decrement: ButtonWidget, decrement: ButtonWidget,
pub on_increment: fn(CounterWidgetInteraction) -> Command,
pub on_decrement: fn(CounterWidgetInteraction) -> Command,
min: u32, min: u32,
max: u32, max: u32,
current: u32, current: u32,
@@ -22,19 +23,43 @@ pub struct CounterWidget {
pub struct CounterWidgetInteraction { pub struct CounterWidgetInteraction {
pub current: u32, pub current: u32,
pub interacted: bool, pub interaction_type: Option<CounterInteractionType>,
}
#[derive(Copy, Clone)]
pub enum CounterInteractionType {
Increment,
Decrement,
}
impl CounterWidgetInteraction {
fn decrement(current: u32) -> Self {
Self {
current,
interaction_type: Some(CounterInteractionType::Decrement),
}
}
fn increment(current: u32) -> Self {
Self {
current,
interaction_type: Some(CounterInteractionType::Increment),
}
}
fn not_interacted(current: u32) -> Self {
Self {
current,
interaction_type: None,
}
}
} }
impl CounterWidget { impl CounterWidget {
pub fn new( pub fn new(min: u32, max: u32, current: u32, is_active: bool, color: UiColor) -> Self {
min: u32, let increment = ButtonWidget::new(is_active, color, "+", SoundKind::Click);
max: u32, let decrement = ButtonWidget::new(is_active, color, "-", SoundKind::Click);
current: u32,
is_active: bool,
color: UiColor,
) -> Self {
let increment = ButtonWidget::new(is_active, color, "+");
let decrement = ButtonWidget::new(is_active, color, "-");
Self { Self {
min, min,
max, max,
@@ -83,35 +108,33 @@ impl CounterWidget {
pub fn handle_input( pub fn handle_input(
&mut self, &mut self,
_: &UserInteraction, interaction: &Interaction,
resources: &Resources, resources: &Resources,
settings: &GameSettings, settings: &Settings,
) -> CounterWidgetInteraction { ) -> CounterWidgetInteraction {
let mut interacted = false;
if self if self
.increment .increment
.handle_input(resources.sound(&SoundKind::Click), settings.volume) .handle_input(&interaction, &resources, &settings)
.clicked
{ {
if self.current < self.max { if self.current < self.max {
self.current += 1; self.current += 1;
interacted = true; return CounterWidgetInteraction::increment(self.current);
} }
} }
if self if self
.decrement .decrement
.handle_input(resources.sound(&SoundKind::Click), settings.volume) .handle_input(&interaction, &resources, &settings)
.clicked
{ {
if self.current > self.min { if self.current > self.min {
self.current -= 1; self.current -= 1;
interacted = true; return CounterWidgetInteraction::decrement(self.current);
} }
} }
return CounterWidgetInteraction { return CounterWidgetInteraction::not_interacted(self.current);
current: self.current,
interacted,
};
} }
pub fn draw(&mut self, resources: &Resources) { pub fn draw(&mut self, resources: &Resources) {
@@ -149,3 +172,23 @@ impl CounterWidget {
); );
} }
} }
impl Default for CounterWidget {
fn default() -> Self {
Self {
on_increment: |_| Command::NoInteraction,
on_decrement: |_| Command::NoInteraction,
visual_rect: Default::default(),
increment: Default::default(),
decrement: Default::default(),
min: Default::default(),
max: Default::default(),
current: Default::default(),
font_size: Default::default(),
visual_dims: Default::default(),
increment_dims: Default::default(),
decrement_dims: Default::default(),
is_active: Default::default(),
}
}
}
-73
View File
@@ -1,73 +0,0 @@
#[allow(dead_code)]
use crate::{resources::Resources, widgets::*};
use macroquad::prelude::*;
#[derive(Default)]
pub struct IdTextInput {
rect: Rect,
text_rect: Rect,
copy_box_rect: Rect,
paste_box_rect: Rect,
}
pub struct IdTextInputDrawParams<'a> {
pub text: &'a str,
pub color: UiColor,
pub copy_color: UiColor,
pub paste_color: UiColor,
pub shadow_width: f32,
}
impl IdTextInput {
pub fn initialize_state() -> Self {
Default::default()
}
pub fn initialize_drawables(&mut self, rect: Rect) {
let copy_button_w = 0.25 * rect.w;
let paste_button_h = 0.5 * rect.h;
self.rect = rect;
self.text_rect = Rect::new(rect.x, rect.y, rect.w - copy_button_w, rect.h);
self.copy_box_rect = Rect::new(
rect.x + (rect.w - copy_button_w),
rect.y,
copy_button_w,
paste_button_h,
);
self.paste_box_rect = Rect::new(
rect.x + (rect.w - copy_button_w),
rect.y + paste_button_h,
copy_button_w,
paste_button_h,
);
}
pub fn draw(&self, params: &IdTextInputDrawParams, resources: &Resources) {
draw_rect(&self.text_rect, params.color);
draw_rect(&self.copy_box_rect, params.copy_color);
draw_rect(&self.paste_box_rect, params.paste_color);
draw_shadow(&self.rect, params.shadow_width);
let font = resources.font();
let font_size = (0.15 * self.text_rect.w) as u16;
let text_dims = measure_text(params.text, Some(font), font_size, 1.0);
draw_text_ex(
params.text,
self.rect.x + (self.text_rect.w - text_dims.width) / 2.,
self.rect.y + (self.text_rect.h - text_dims.height) / 2. + text_dims.offset_y,
TextParams {
font: Some(font),
font_size: font_size,
color: params.color.to_fg_color(),
..Default::default()
},
);
}
pub fn handle_input(&self, _: &UserInteraction) -> IdTextInputInteraction {
IdTextInputInteraction {}
}
}
pub struct IdTextInputInteraction {}
+2 -1
View File
@@ -21,7 +21,8 @@ impl LabelWidget {
pub fn initialize_drawables(&mut self, rect: Rect, font_size: f32, resources: &Resources) { pub fn initialize_drawables(&mut self, rect: Rect, font_size: f32, resources: &Resources) {
self.rect = rect; self.rect = rect;
self.font_size = font_size; self.font_size = font_size;
self.text_dimensions = measure_text(&self.text, Some(resources.font()), font_size as u16, 1.0); self.text_dimensions =
measure_text(&self.text, Some(resources.font()), font_size as u16, 1.0);
} }
pub fn draw(&self, resources: &Resources) { pub fn draw(&self, resources: &Resources) {