Skip to content

Commit

Permalink
Merge branch 'main' into barebones
Browse files Browse the repository at this point in the history
  • Loading branch information
CaspianA1 committed Oct 3, 2024
2 parents a7e2470 + bcdb1b7 commit 4979d2b
Show file tree
Hide file tree
Showing 16 changed files with 202 additions and 186 deletions.
2 changes: 1 addition & 1 deletion src/dashboard_defs/credit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ pub fn make_credit_window(top_left: Vec2f, size: Vec2f,
(Cow::Owned(italicized_font_info), "")
}

fn extract_text(&self) -> Cow<str> {
fn extract_text(&self, _: &SharedWindowState) -> Cow<str> {
Cow::Borrowed(self)
}

Expand Down
64 changes: 14 additions & 50 deletions src/dashboard_defs/dashboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,13 @@ use crate::{
window_tree::{
ColorSDL,
Window,
WindowContents,
PossibleSharedWindowStateUpdater
WindowContents
},

dashboard_defs::{
error::make_error_window,
credit::make_credit_window,
weather::make_weather_window,
error::{make_error_window, ErrorState},
shared_window_state::SharedWindowState,
twilio::{make_twilio_window, TwilioState},
surprise::{make_surprise_window, SurpriseCreationInfo},
Expand Down Expand Up @@ -92,11 +91,11 @@ struct ApiKeys {

//////////

// This returns a top-level window, shared window state, and a shared window state updater
// This returns a top-level window, and shared window state
pub async fn make_dashboard(
texture_pool: &mut TexturePool<'_>,
update_rate_creator: UpdateRateCreator)
-> GenericResult<(Window, DynamicOptional, PossibleSharedWindowStateUpdater)> {
-> GenericResult<(Window, DynamicOptional)> {

////////// Defining some shared global variables

Expand Down Expand Up @@ -229,17 +228,15 @@ pub async fn make_dashboard(

let twilio_window = make_twilio_window(
&twilio_state,

// This is how often the history windows check for new messages (this is low so that it'll be fast in the beginning)
update_rate_creator.new_instance(0.25),
shared_update_rate,

Vec2f::new(0.58, 0.40),
Vec2f::new(0.4, 0.55),

0.025,
WindowContents::Color(ColorSDL::RGB(23, 23, 23)),
Vec2f::new(0.0, 0.45),
theme_color_1,
Some(theme_color_1),
ColorSDL::RGB(238, 238, 238),
WindowContents::Nothing
);
Expand All @@ -249,7 +246,7 @@ pub async fn make_dashboard(
let error_window = make_error_window(
Vec2f::new(0.0, 0.95),
Vec2f::new(0.15, 0.05),
update_rate_creator.new_instance(2.0),
update_rate_creator.new_instance(1.0),
WindowContents::Color(ColorSDL::RGBA(255, 0, 0, 190)),
ColorSDL::GREEN
);
Expand Down Expand Up @@ -331,10 +328,14 @@ pub async fn make_dashboard(
}))
};

let mut all_main_windows = vec![twilio_window, error_window, weather_window, credit_window];
let mut all_main_windows = vec![twilio_window, weather_window, credit_window];
all_main_windows.extend(spinitron_windows);
add_static_texture_set(&mut all_main_windows, &main_static_texture_info, texture_pool);

/* The error window goes last (so that it can manage
errors in one shared update iteration properly) */
all_main_windows.push(error_window);

////////// Making all of the main windows

// Modify the calculation of the main window's position and size
Expand Down Expand Up @@ -450,55 +451,18 @@ pub async fn make_dashboard(
SharedWindowState {
clock_hands,
spinitron_state,
error_state: ErrorState::new(),
twilio_state,
font_info: &FONT_INFO,
get_fallback_texture_creation_info,
curr_dashboard_error: None,
rand_generator: rand::thread_rng()
}
);

/* TODO:
- Allow for error reporting via the individual window updaters (make a new updater there, an invisible window)
- At some point, maybe figure out how to make this function async (no task spawn needed then)
*/
fn shared_window_state_updater(state: &mut DynamicOptional, texture_pool: &mut TexturePool<'_>) -> MaybeError {
let state = state.get_mut::<SharedWindowState>();

let mut error = None;

// More continual updaters can be added here
let success_states_and_names = [
(state.spinitron_state.update()?, "Spinitron"),
(state.twilio_state.update(texture_pool)?, "Twilio (messaging)")
];

for (succeeded, name) in success_states_and_names {
if !succeeded {
if let Some(already_error) = &mut error {
*already_error += ", and ";
*already_error += name;
}
else {
error = Some(format!("Internal dashboard error from {name}"))
}
}
}

if let Some(inner_error) = &mut error {
*inner_error += "!";
}

state.curr_dashboard_error = error;

Ok(())
}

//////////

Ok((
all_windows_window,
boxed_shared_state,
Some((shared_window_state_updater, shared_update_rate))
boxed_shared_state
))
}
113 changes: 94 additions & 19 deletions src/dashboard_defs/error.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
use std::borrow::Cow;
use std::{
borrow::Cow,
collections::BTreeSet,
hash::{Hash, Hasher}
};

use crate::{
utility_types::{
Expand All @@ -19,43 +23,114 @@ use crate::{
}
};

//////////

#[derive(Hash)]
pub struct ErrorState {
source_list: BTreeSet<&'static str>
}

impl ErrorState {
pub fn new() -> Self {
Self {source_list: BTreeSet::new()}
}

pub fn report(&mut self, source: &'static str, err: &str) {
self.source_list.insert(source);
log::error!("Error from '{source}': '{err}'");
}

pub fn unreport(&mut self, source: &'static str) {
self.source_list.remove(source);
}

// This should only ever be called if the number of sources is greater than zero.
pub fn make_message(&self) -> String {
let mut message = String::new();

let num_sources = self.source_list.len();
assert!(num_sources > 0);

let last_source_index = num_sources - 1;
let plural_suffix = if num_sources == 1 {""} else {"s"};

for (i, source) in self.source_list.iter().enumerate() {
let (is_first_source, is_last_source) = (i == 0, i == last_source_index);
let (subsection_ending, maybe_and) = if is_last_source {(".", "and ")} else {("", "")};

let subsection = if is_first_source {
format!("Internal dashboard error{plural_suffix} from '{source}'{subsection_ending}")
}
else {
format!(", {maybe_and}'{source}'{subsection_ending}")
};

message.push_str(subsection.as_str());
}

message
}
}

//////////

// TODO: maybe replace this with the SDL message box?
pub fn make_error_window(top_left: Vec2f, size: Vec2f, update_rate: UpdateRate,
background_contents: WindowContents, text_color: ColorSDL) -> Window {

type ErrorWindowState = Option<String>; // This is the previous error
type ErrorWindowState = Option<u64>; // This is the current hash of the error state (if `None`, not initialized yet)

impl updatable_text_pattern::UpdatableTextWindowMethods for ErrorWindowState {
fn should_skip_update(updater_params: &mut WindowUpdaterParams) -> bool {
let inner_shared_state = updater_params.shared_window_state.get::<SharedWindowState>();
let inner_shared_state = updater_params.shared_window_state.get_mut::<SharedWindowState>();

let wrapped_individual_state = updater_params.window.get_state_mut
::<updatable_text_pattern::UpdatableTextWindowFields<ErrorWindowState>>();

let prev_error = &wrapped_individual_state.inner;

let (curr_error, cached_error) = (
&inner_shared_state.curr_dashboard_error, prev_error
);
//////////

// This means that the error changed (or disappeared)!
if curr_error != cached_error {
let skip_update = curr_error.is_none();
wrapped_individual_state.inner.clone_from(curr_error);
updater_params.window.set_draw_skipping(skip_update);
skip_update
}
else {
true
fn hash_obj<T: Hash>(obj: &T) -> u64 {
let mut hasher = std::hash::DefaultHasher::new();
obj.hash(&mut hasher);
hasher.finish()
}

let no_errors_to_display = inner_shared_state.error_state.source_list.is_empty();

let skip_update = match &mut wrapped_individual_state.inner {
Some(prev_hash) => {
let curr_hash = hash_obj(&inner_shared_state.error_state);

if curr_hash == *prev_hash {
// Nothing changed, so keep things the same. Skipping update.
true
}
else {
// Update the hash, and only skip updating if there's no errors to display.
*prev_hash = curr_hash;
no_errors_to_display
}
}

None => {
let hash = hash_obj(&inner_shared_state.error_state);
wrapped_individual_state.inner = Some(hash);
no_errors_to_display // Skipping update if not displaying any errors the first time.
}
};

// Skipping drawing if not displaying any errors.
updater_params.window.set_draw_skipping(no_errors_to_display);

skip_update
}

fn compute_within_updater<'a>(inner_shared_state: &'a SharedWindowState) -> updatable_text_pattern::ComputedInTextUpdater<'a> {
(Cow::Borrowed(inner_shared_state.font_info), " ")
}

fn extract_text(&self) -> Cow<str> {
Cow::Borrowed(self.as_ref().unwrap())
fn extract_text(&self, inner_shared_state: &SharedWindowState) -> Cow<str> {
Cow::Owned(inner_shared_state.error_state.make_message())
}

fn extract_texture_contents(window_contents: &mut WindowContents) -> &mut WindowContents {
Expand Down
3 changes: 2 additions & 1 deletion src/dashboard_defs/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
mod clock;
mod error;
mod credit;
mod twilio;
mod weather;
mod surprise;
mod spinitron;
mod shared_window_state;
mod updatable_text_pattern;

pub mod error;
pub mod dashboard;
7 changes: 3 additions & 4 deletions src/dashboard_defs/shared_window_state.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
use crate::{
spinitron::state::SpinitronState,
texture::{FontInfo, TextureCreationInfo},
dashboard_defs::{twilio::TwilioState, clock::ClockHands}
dashboard_defs::{twilio::TwilioState, clock::ClockHands, error::ErrorState}
};

pub struct SharedWindowState<'a> {
pub clock_hands: ClockHands,
pub spinitron_state: SpinitronState,
pub twilio_state: TwilioState<'a>,
pub twilio_state: TwilioState,
pub error_state: ErrorState,

pub font_info: &'a FontInfo,

// This is used whenever a texture can't be loaded
pub get_fallback_texture_creation_info: fn() -> TextureCreationInfo<'a>,

pub curr_dashboard_error: Option<String>,

pub rand_generator: rand::rngs::ThreadRng

/* TODO: can I keep the texture pool here, instead of passing it in to
Expand Down
24 changes: 14 additions & 10 deletions src/dashboard_defs/spinitron.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,24 @@ pub fn make_spinitron_windows(
of `area_drawn_to_screen`. */
fn spinitron_model_window_updater_fn(params: WindowUpdaterParams) -> MaybeError {
let inner_shared_state = params.shared_window_state.get_mut::<SharedWindowState>();
let spinitron_state = &mut inner_shared_state.spinitron_state;

let individual_window_state = params.window.get_state::<SpinitronModelWindowState>();
let model_name = individual_window_state.model_name;
let window_size_pixels = params.area_drawn_to_screen;

////////// The spin texture window is the window designated for updating the Spinitron state

let is_text_window = individual_window_state.maybe_text_color.is_some();

if model_name == SpinitronModelName::Spin && !is_text_window {
let spin_texture_window_size = window_size_pixels.0.min(window_size_pixels.1);
let size_2d = (spin_texture_window_size, spin_texture_window_size);
inner_shared_state.spinitron_state.update(size_2d, &mut inner_shared_state.error_state)?;
}

//////////

let spinitron_state = &mut inner_shared_state.spinitron_state;

let should_update_texture =
spinitron_state.model_was_updated(model_name) ||
matches!(params.window.get_contents(), WindowContents::Nothing);
Expand All @@ -74,15 +84,15 @@ pub fn make_spinitron_windows(

//////////

let texture_creation_info = if let Some(text_color) = individual_window_state.maybe_text_color {
let texture_creation_info = if is_text_window {
let model_text = spinitron_state.model_to_string(model_name);

TextureCreationInfo::Text((
Cow::Borrowed(inner_shared_state.font_info),

TextDisplayInfo {
text: DisplayText::new(&model_text),
color: text_color,
color: individual_window_state.maybe_text_color.unwrap(),
pixel_area: window_size_pixels, // TODO: why does cutting the max pixel width in half still work?

/* TODO:
Expand All @@ -96,12 +106,6 @@ pub fn make_spinitron_windows(
))
}
else {
// Registering the aspect-ratio-corrected spin window size
if matches!(model_name, SpinitronModelName::Spin) {
let size = window_size_pixels.0.min(window_size_pixels.1);
spinitron_state.register_spin_window_size((size, size));
}

spinitron_state.get_cached_texture_creation_info(model_name)
};

Expand Down
Loading

0 comments on commit 4979d2b

Please sign in to comment.