--> retained mode ui
This commit is contained in:
+249
-15
@@ -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
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
@@ -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(¶ms, &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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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 {}
|
|
||||||
@@ -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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user