Skip to content

Commit

Permalink
ui & desktop: Add a basic “Quit” button.
Browse files Browse the repository at this point in the history
  • Loading branch information
kpreid committed Oct 27, 2023
1 parent a6d7982 commit bc8db71
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 18 deletions.
10 changes: 9 additions & 1 deletion all-is-cubes-desktop/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,15 @@ fn main() -> Result<(), anyhow::Error> {
));

let start_session_time = Instant::now();
let session = runtime.block_on(Session::builder().ui(viewport_cell.as_source()).build());
let session = runtime.block_on(
Session::builder()
.ui(viewport_cell.as_source())
.quit(Arc::new(|| {
// TODO: command the event loop to exit instead
std::process::exit(0)
}))
.build(),
);
session.graphics_options_mut().set(graphics_options);
let session_done_time = Instant::now();
log::debug!(
Expand Down
28 changes: 28 additions & 0 deletions all-is-cubes-ui/src/apps/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,8 @@ pub struct SessionBuilder<I> {
fullscreen_state: ListenableSource<FullscreenState>,
set_fullscreen: FullscreenSetter,

quit: Option<QuitFn>,

_instant: PhantomData<I>,
}

Expand All @@ -540,6 +542,7 @@ impl<I> Default for SessionBuilder<I> {
viewport_for_ui: None,
fullscreen_state: ListenableSource::constant(None),
set_fullscreen: None,
quit: None,
_instant: PhantomData,
}
}
Expand All @@ -556,6 +559,7 @@ impl<I: time::Instant> SessionBuilder<I> {
viewport_for_ui,
fullscreen_state,
set_fullscreen,
quit,
_instant: _,
} = self;
let game_universe = Universe::new();
Expand All @@ -579,6 +583,7 @@ impl<I: time::Instant> SessionBuilder<I> {
viewport,
fullscreen_state,
set_fullscreen,
quit,
)
.await,
),
Expand Down Expand Up @@ -627,6 +632,15 @@ impl<I: time::Instant> SessionBuilder<I> {
self.set_fullscreen = setter;
self
}

/// Enable a “quit”/“exit” command in the session's user interface.
///
/// This does not cause the session to self-destruct; rather, the provided callback
/// function should cause the session’s owner to stop presenting it to the user.
pub fn quit(mut self, quit_fn: QuitFn) -> Self {
self.quit = Some(quit_fn);
self
}
}

// TODO: these should be in one struct or something.
Expand Down Expand Up @@ -758,6 +772,20 @@ pub enum CursorIcon {
PointingHand,
}

/// TODO: this should be an async fn
pub(crate) type QuitFn = Arc<dyn Fn() -> Result<QuitSucceeded, QuitCancelled> + Send + Sync>;

/// Return type of a [`SessionBuilder::quit()`] callback on successful quit.
/// This is uninhabited (cannot happen) since the callback should never be observed to
/// finish if it successfully quits.
pub type QuitSucceeded = std::convert::Infallible;

/// Return type of a [`SessionBuilder::quit()`] callback if other considerations cancelled
/// the quit operation. In this case, the session will return to normal operation.
#[derive(Clone, Copy, Debug, PartialEq)]
#[allow(clippy::exhaustive_structs)]
pub struct QuitCancelled;

#[cfg(test)]
mod tests {
use super::*;
Expand Down
1 change: 1 addition & 0 deletions all-is-cubes-ui/src/ui_content/hud.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ pub(crate) struct HudInputs {
pub mouselook_mode: ListenableSource<bool>,
pub fullscreen_mode: ListenableSource<FullscreenState>,
pub set_fullscreen: FullscreenSetter,
pub(crate) quit: Option<crate::apps::QuitFn>,
}

impl fmt::Debug for HudInputs {
Expand Down
48 changes: 32 additions & 16 deletions all-is-cubes-ui/src/ui_content/pages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,40 @@ pub(super) fn new_paused_widget_tree(
) -> Result<WidgetTree, InstallVuiError> {
use parts::{heading, shrink};

let mut children = vec![
// TODO: establish standard resolutions for logo etc
LayoutTree::leaf(shrink(u, R16, LayoutTree::leaf(logo_text()))?),
LayoutTree::leaf(shrink(u, R32, heading("Paused"))?),
LayoutTree::leaf(open_page_button(
hud_inputs,
VuiPageState::AboutText,
hud_inputs.hud_blocks.blocks[UiBlocks::AboutButtonLabel].clone(),
)),
LayoutTree::leaf(open_page_button(
hud_inputs,
VuiPageState::Options,
hud_inputs.hud_blocks.blocks[UiBlocks::OptionsButtonLabel].clone(),
)),
LayoutTree::leaf(pause_toggle_button(hud_inputs)),
];
if let Some(quit_fn) = hud_inputs.quit.as_ref().cloned() {
children.push(LayoutTree::leaf(widgets::ActionButton::new(
hud_inputs.hud_blocks.blocks[UiBlocks::QuitButtonLabel].clone(),
&hud_inputs.hud_blocks.blocks,
// TODO: quit_fn should be an async function, but we don't have a way to
// kick off a “Quitting...” task yet.
move || match quit_fn() {
Ok(s) => match s {},
Err(crate::apps::QuitCancelled) => {

// TODO: display message indicating failure
}
},
)))
}
let contents = Arc::new(LayoutTree::Stack {
direction: Face6::NY,
children: vec![
// TODO: establish standard resolutions for logo etc
LayoutTree::leaf(shrink(u, R16, LayoutTree::leaf(logo_text()))?),
LayoutTree::leaf(shrink(u, R32, heading("Paused"))?),
LayoutTree::leaf(open_page_button(
hud_inputs,
VuiPageState::AboutText,
hud_inputs.hud_blocks.blocks[UiBlocks::AboutButtonLabel].clone(),
)),
LayoutTree::leaf(open_page_button(
hud_inputs,
VuiPageState::Options,
hud_inputs.hud_blocks.blocks[UiBlocks::OptionsButtonLabel].clone(),
)),
LayoutTree::leaf(pause_toggle_button(hud_inputs)),
],
children,
});
Ok(page_modal_backdrop(Arc::new(LayoutTree::Shrink(
hud_inputs
Expand Down
5 changes: 4 additions & 1 deletion all-is-cubes-ui/src/ui_content/vui_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use all_is_cubes::time;
use all_is_cubes::transaction::{self, Transaction};
use all_is_cubes::universe::{URef, Universe, UniverseStepInfo};

use crate::apps::{ControlMessage, FullscreenSetter, FullscreenState, InputProcessor};
use crate::apps::{ControlMessage, FullscreenSetter, FullscreenState, InputProcessor, QuitFn};
use crate::ui_content::hud::{HudBlocks, HudInputs};
use crate::ui_content::pages;
use crate::vui::widgets::TooltipState;
Expand Down Expand Up @@ -80,6 +80,7 @@ impl Vui {
viewport_source: ListenableSource<Viewport>,
fullscreen_source: ListenableSource<FullscreenState>,
set_fullscreen: FullscreenSetter,
quit: Option<QuitFn>,
) -> Self {
let mut universe = Universe::new();
// TODO: take YieldProgress as a parameter
Expand Down Expand Up @@ -111,6 +112,7 @@ impl Vui {
mouselook_mode: input_processor.mouselook_mode(),
fullscreen_mode: fullscreen_source,
set_fullscreen,
quit,
};
let hud_widget_tree = super::hud::new_hud_widget_tree(
character_source.clone(),
Expand Down Expand Up @@ -471,6 +473,7 @@ mod tests {
ListenableSource::constant(Viewport::ARBITRARY),
ListenableSource::constant(None),
None,
None,
)
.await;
(vui, ccrx)
Expand Down
9 changes: 9 additions & 0 deletions all-is-cubes-ui/src/vui/blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ pub enum UiBlocks {
AboutButtonLabel,
PauseButtonLabel,
SaveButtonLabel,
QuitButtonLabel,
OptionsButtonLabel,
MouselookButtonLabel,
FullscreenButtonLabel,
Expand Down Expand Up @@ -86,6 +87,7 @@ impl fmt::Display for UiBlocks {
UiBlocks::AboutButtonLabel => write!(f, "about-button"),
UiBlocks::PauseButtonLabel => write!(f, "pause-button"),
UiBlocks::SaveButtonLabel => write!(f, "save-button"),
UiBlocks::QuitButtonLabel => write!(f, "quit-button"),
UiBlocks::OptionsButtonLabel => write!(f, "options-button"),
UiBlocks::MouselookButtonLabel => write!(f, "mouselook-button"),
UiBlocks::FullscreenButtonLabel => write!(f, "fullscreen-button"),
Expand Down Expand Up @@ -203,6 +205,13 @@ impl UiBlocks {
)?
.build(),

UiBlocks::QuitButtonLabel => make_button_label_block(
universe,
"Quit",
ButtonIcon::Text(&font::FONT_7X13, "Quit"),
)?
.build(),

UiBlocks::OptionsButtonLabel => make_button_label_block(
universe,
"Options",
Expand Down

0 comments on commit bc8db71

Please sign in to comment.