open-timeline-gui 0.1.0

OpenTimeline GUI
Documentation
// SPDX-License-Identifier: GPL-3.0-or-later

//!
//!The "order entities" game for egui
//!

use crate::config::SharedConfig;
use crate::games::{GameState, GameTimelineSearchAndFetch, draw_stats};
use eframe::egui::{self, Context, RichText, Ui, Vec2};
use open_timeline_core::HasIdAndName;
use open_timeline_games::GameManagement;
use open_timeline_games::order_entities::{GameVariant, OrderEntitiesGame};
use open_timeline_gui_core::{Draw, body_text_height};

// TODO: dragging is a pain
#[derive(Debug)]

pub struct OrderEntitiesGameGui {
    /// The game engine
    game: OrderEntitiesGame,

    /// The current state of the game
    state: GameState,

    /// Search and fetch the timeline used to play the game
    game_timeline_search_and_fetch: GameTimelineSearchAndFetch,
}

impl OrderEntitiesGameGui {
    /// Create new OrderEntitiesGameGui
    pub fn new(shared_config: SharedConfig) -> Self {
        Self {
            game: OrderEntitiesGame::new(),
            state: GameState::NotStarted,
            game_timeline_search_and_fetch: GameTimelineSearchAndFetch::new(shared_config),
        }
    }

    fn draw_question(&mut self, _ctx: &Context, ui: &mut Ui, enabled: bool) {
        // Show options
        if let Some(current_question) = self.game.current_question.as_mut()
            && !current_question.is_empty()
        {
            ui.add_enabled_ui(enabled, |ui| {
                let button_size =
                    Vec2::new(body_text_height(ui) * 2.0, body_text_height(ui) * 1.25);
                let mut up: Option<usize> = None;
                let mut down = None;
                for (index, item) in current_question.iter().enumerate() {
                    ui.horizontal(|ui| {
                        let up_button =
                            ui.add_sized(button_size, egui::Button::new(RichText::new("")));
                        let down_button =
                            ui.add_sized(button_size, egui::Button::new(RichText::new("")));
                        ui.add(egui::Label::new(item.name().as_str()));

                        if up_button.clicked() && index > 0 {
                            up = Some(index);
                        }
                        if down_button.clicked() && index < current_question.len() {
                            down = Some(index);
                        }
                    });
                }

                if let Some(index) = up {
                    if index != 0 {
                        current_question.swap(index, index - 1);
                    }
                }

                if let Some(index) = down {
                    if index != current_question.len() - 1 {
                        current_question.swap(index, index + 1);
                    }
                }
            });
        } else {
            open_timeline_gui_core::Label::weak(ui, "No question");
            self.draw_new_game_button(ui);
            return;
        }

        // Submit answer
        if enabled {
            if open_timeline_gui_core::Button::tall_full_width(ui, "Submit").clicked() {
                let answer = self.game.current_question.clone().unwrap();
                let _ = self.game.check_answer(answer);
                self.state = GameState::WaitingForNextRound;
            }
        }
    }

    fn draw_new_game_button(&mut self, ui: &mut Ui) {
        if open_timeline_gui_core::Button::tall_full_width(ui, "New Game").clicked() {
            self.game.new_game();
            self.state = GameState::NotStarted;
        }
    }
}

impl Draw for OrderEntitiesGameGui {
    fn draw(&mut self, ctx: &Context, ui: &mut Ui) {
        // Description
        open_timeline_gui_core::Label::description(ui, &self.game.description());
        ui.separator();

        // Search
        // Timeline search bar/label
        self.game_timeline_search_and_fetch
            .draw_timeline_search_bar(ctx, ui, self.state);
        ui.separator();

        // Radio button controls
        ui.horizontal(|ui| {
            ui.add_enabled_ui(self.state == GameState::NotStarted, |ui| {
                ui.radio_value(
                    &mut self.game.variant,
                    GameVariant::OrderByFirstStarted,
                    "Order by start date",
                );
                ui.radio_value(
                    &mut self.game.variant,
                    GameVariant::OrderByFirstEnded,
                    "Order by end date",
                );
            });
        });
        ui.separator();

        // Stats
        if self.state.has_started() {
            draw_stats(ctx, ui, self.game.stats);
            ui.separator();
        }

        // Controls
        match self.state {
            GameState::NotStarted => {
                ui.add_enabled_ui(
                    self.game_timeline_search_and_fetch
                        .timeline_playing_with()
                        .is_some(),
                    |ui| {
                        if open_timeline_gui_core::Button::tall_full_width(ui, "Start").clicked() {
                            self.game.new_game();
                            self.game_timeline_search_and_fetch.request_fetch_timeline();
                            self.state = GameState::StartedWaitingForTimeline;
                        }
                    },
                );
            }
            GameState::StartedWaitingForTimeline => {
                self.game_timeline_search_and_fetch
                    .check_for_fetch_response();
                if let Some(result) = self.game_timeline_search_and_fetch.timeline.as_ref() {
                    match result {
                        Ok(timeline) => {
                            if let Some(entities) = timeline.entities() {
                                self.game.set_entity_pool(entities.clone());
                            }
                            self.state = GameState::WaitingForAnswer;
                            let _ = self.game.setup_next_round();
                        }
                        Err(error) => {
                            // TODO
                            panic!("{error}");
                        }
                    }
                }
            }
            GameState::WaitingForAnswer => {
                self.draw_question(ctx, ui, true);
            }
            GameState::WaitingForNextRound => {
                self.draw_question(ctx, ui, false);
                ui.separator();
                if let Some(last_answer) = self.game.last_answer.as_ref() {
                    ui.horizontal(|ui| {
                        ui.label("Last Answer");
                        open_timeline_gui_core::Label::strong(ui, &format!("{last_answer:?}"));
                    });
                    ui.separator();
                }
                if open_timeline_gui_core::Button::tall_full_width(ui, "End").clicked() {
                    self.state = GameState::Finished;
                }
                if open_timeline_gui_core::Button::tall_full_width(ui, "Next Round").clicked() {
                    let _ = self.game.setup_next_round();
                    self.state = GameState::WaitingForAnswer;
                }
            }
            GameState::Finished => {
                self.draw_new_game_button(ui);
            }
        }
    }
}