Skip to content

Commit

Permalink
Give the StateButton a proper TrackedState
Browse files Browse the repository at this point in the history
  • Loading branch information
vE5li committed Apr 15, 2024
1 parent 3c25046 commit b61efa4
Show file tree
Hide file tree
Showing 9 changed files with 198 additions and 132 deletions.
12 changes: 10 additions & 2 deletions korangar/src/debug/profiling/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ mod ring_buffer;
mod statistics;

use std::mem::MaybeUninit;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::{AtomicBool, AtomicUsize};
use std::sync::{LazyLock, Mutex, MutexGuard};
use std::time::Instant;

Expand All @@ -22,15 +22,23 @@ static mut SHADOW_THREAD_PROFILER: LazyLock<Mutex<Profiler>> = LazyLock::new(||
static mut DEFERRED_THREAD_PROFILER: LazyLock<Mutex<Profiler>> = LazyLock::new(|| Mutex::new(Profiler::default()));

static mut PROFILER_HALTED: AtomicBool = AtomicBool::new(false);
static mut PROFILER_HALTED_VERSION: AtomicUsize = AtomicUsize::new(0);

pub fn set_profiler_halted(running: bool) {
unsafe { PROFILER_HALTED.store(running, std::sync::atomic::Ordering::Relaxed) };
unsafe {
PROFILER_HALTED.store(running, std::sync::atomic::Ordering::Relaxed);
PROFILER_HALTED_VERSION.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
};
}

pub fn is_profiler_halted() -> bool {
unsafe { PROFILER_HALTED.load(std::sync::atomic::Ordering::Relaxed) }
}

pub fn get_profiler_halted_version() -> usize {
unsafe { PROFILER_HALTED_VERSION.load(std::sync::atomic::Ordering::Relaxed) }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ProfilerThread {
Main,
Expand Down
106 changes: 31 additions & 75 deletions korangar/src/interface/windows/account/login.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
use std::cell::RefCell;
use std::ops::Not;
use std::rc::Rc;

use derive_new::new;
use korangar_interface::elements::{
ButtonBuilder, Container, ElementWrap, FocusMode, InputFieldBuilder, PickList, StateButtonBuilder, Text,
};
use korangar_interface::event::ClickAction;
use korangar_interface::state::{RawTrackedState, TrackedState, TrackedStateClone, TrackedStateExt};
use korangar_interface::state::{RawTrackedState, TrackedState, TrackedStateBinary, TrackedStateClone, TrackedStateExt};
use korangar_interface::windows::{PrototypeWindow, Window, WindowBuilder};
use korangar_procedural::size_bound;

Expand Down Expand Up @@ -62,7 +60,7 @@ impl<'a> PrototypeWindow<Adapter> for LoginWindow<'a> {
let password = RawTrackedState::new(saved_settings.password.clone());

let selected_service = RawTrackedState::new(selected_service);
let login_settings = Rc::new(RefCell::new(login_settings));
let login_settings = RawTrackedState::new(login_settings);

let selector = {
let username = username.clone();
Expand All @@ -73,19 +71,19 @@ impl<'a> PrototypeWindow<Adapter> for LoginWindow<'a> {
let service_changed = {
let mut username = username.clone();
let mut password = password.clone();
let login_settings = login_settings.clone();
let mut login_settings = login_settings.clone();
let selected_service = selected_service.clone();

Box::new(move || {
let service_id = selected_service.cloned();
let mut login_settings = login_settings.borrow_mut();
let saved_settings = login_settings.service_settings.entry(service_id).or_default();
let saved_settings =
login_settings.mutate(|login_settings| login_settings.service_settings.entry(service_id).or_default().clone());

username.mutate(|username| {
*username = saved_settings.username.clone();
*username = saved_settings.username;
});
password.mutate(|password| {
*password = saved_settings.password.clone();
*password = saved_settings.password;
});

Vec::new()
Expand All @@ -95,19 +93,20 @@ impl<'a> PrototypeWindow<Adapter> for LoginWindow<'a> {
let login_action = {
let username = username.clone();
let password = password.clone();
let login_settings = login_settings.clone();
let mut login_settings = login_settings.clone();
let selected_service = selected_service.clone();

move || {
// TODO: Deduplicate code
let service_id = selected_service.cloned();

let mut login_settings = login_settings.borrow_mut();
login_settings.recent_service_id = Some(service_id);
login_settings.mutate(|login_settings| {
login_settings.recent_service_id = Some(service_id);

let saved_settings = login_settings.service_settings.entry(service_id).or_default();
saved_settings.username = username.cloned();
saved_settings.password = password.cloned();
let saved_settings = login_settings.service_settings.entry(service_id).or_default();
saved_settings.username = username.cloned();
saved_settings.password = password.cloned();
});

vec![ClickAction::Custom(UserEvent::LogIn {
service_id: selected_service.cloned(),
Expand All @@ -132,7 +131,7 @@ impl<'a> PrototypeWindow<Adapter> for LoginWindow<'a> {
let password_action = {
let username = username.clone();
let password = password.clone();
let login_settings = login_settings.clone();
let mut login_settings = login_settings.clone();
let selected_service = selected_service.clone();

Box::new(move || match password.get().is_empty() {
Expand All @@ -142,12 +141,13 @@ impl<'a> PrototypeWindow<Adapter> for LoginWindow<'a> {
// TODO: Deduplicate code
let service_id = selected_service.cloned();

let mut login_settings = login_settings.borrow_mut();
login_settings.recent_service_id = Some(service_id);
login_settings.mutate(|login_settings| {
login_settings.recent_service_id = Some(service_id);

let saved_settings = login_settings.service_settings.entry(service_id).or_default();
saved_settings.username = username.cloned();
saved_settings.password = password.cloned();
let saved_settings = login_settings.service_settings.entry(service_id).or_default();
saved_settings.username = username.cloned();
saved_settings.password = password.cloned();
});

vec![ClickAction::Custom(UserEvent::LogIn {
service_id: selected_service.cloned(),
Expand All @@ -158,60 +158,16 @@ impl<'a> PrototypeWindow<Adapter> for LoginWindow<'a> {
})
};

let remember_username_selector = {
let login_settings = login_settings.clone();
let selected_service = selected_service.clone();

move || {
let service_id = selected_service.cloned();
let mut login_settings = login_settings.borrow_mut();
let saved_settings = login_settings.service_settings.entry(service_id).or_default();
let remember_username = {
let service_id = selected_service.clone();

saved_settings.remember_username
}
login_settings.mapped(move |login_settings| &login_settings.service_settings.get(&service_id.get()).unwrap().remember_username)
};

let remember_password_selector = {
let login_settings = login_settings.clone();
let selected_service = selected_service.clone();

move || {
let service_id = selected_service.cloned();
let mut login_settings = login_settings.borrow_mut();
let saved_settings = login_settings.service_settings.entry(service_id).or_default();
let remember_password = {
let service_id = selected_service.clone();

saved_settings.remember_password
}
};

let remember_username_action = {
let login_settings = login_settings.clone();
let selected_service = selected_service.clone();

Box::new(move || {
let service_id = selected_service.cloned();
let mut login_settings = login_settings.borrow_mut();
let saved_settings = login_settings.service_settings.entry(service_id).or_default();

saved_settings.remember_username = !saved_settings.remember_username;

Vec::new()
})
};

let remember_password_action = {
let login_settings = login_settings.clone();
let selected_service = selected_service.clone();

Box::new(move || {
let service_id = selected_service.cloned();
let mut login_settings = login_settings.borrow_mut();
let saved_settings = login_settings.service_settings.entry(service_id).or_default();

saved_settings.remember_password = !saved_settings.remember_password;

Vec::new()
})
login_settings.mapped(move |login_settings| &login_settings.service_settings.get(&service_id.get()).unwrap().remember_password)
};

let elements = vec![
Expand Down Expand Up @@ -241,15 +197,15 @@ impl<'a> PrototypeWindow<Adapter> for LoginWindow<'a> {
vec![
StateButtonBuilder::new()
.with_text("Remember username")
.with_selector(remember_username_selector)
.with_event(remember_username_action)
.with_remote(remember_username.new_remote())
.with_event(remember_username.toggle_action())
.with_transparent_background()
.build()
.wrap(),
StateButtonBuilder::new()
.with_text("Remember password")
.with_selector(remember_password_selector)
.with_event(remember_password_action)
.with_remote(remember_password.new_remote())
.with_event(remember_password.toggle_action())
.with_transparent_background()
.build()
.wrap(),
Expand Down
4 changes: 2 additions & 2 deletions korangar/src/interface/windows/debug/packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,14 @@ impl<const N: usize> PrototypeWindow<Adapter> for PacketWindow<N> {
.wrap(),
StateButtonBuilder::new()
.with_text("Show pings")
.with_selector(self.show_pings.selector())
.with_remote(self.show_pings.new_remote())
.with_event(self.show_pings.toggle_action())
.with_width_bound(dimension_bound!(33.33%))
.build()
.wrap(),
StateButtonBuilder::new()
.with_text("Update")
.with_selector(self.update.selector())
.with_remote(self.update.new_remote())
.with_event(self.update.toggle_action())
.with_width_bound(dimension_bound!(!))
.build()
Expand Down
94 changes: 84 additions & 10 deletions korangar/src/interface/windows/debug/profiler.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,92 @@
use korangar_interface::elements::{ElementWrap, PickList, StateButtonBuilder};
use korangar_interface::state::{RawTrackedState, TrackedState, TrackedStateBinary};
use korangar_interface::state::{RawTrackedState, Remote, TrackedState, TrackedStateBinary, ValueState, Version};
use korangar_interface::windows::{PrototypeWindow, Window, WindowBuilder};
use korangar_procedural::{dimension_bound, size_bound};

use crate::debug::{is_profiler_halted, set_profiler_halted, ProfilerThread};
use crate::debug::{get_profiler_halted_version, is_profiler_halted, set_profiler_halted, ProfilerThread};
use crate::interface::application::Adapter;
use crate::interface::elements::FrameView;
use crate::interface::layout::ScreenSize;
use crate::interface::windows::WindowCache;

/// Wrapper struct that exposes an implementation of [`TrackedState`] for the
/// halted state of the profiler.
#[derive(Default, Clone)]
struct TrackedProfilerHaltedState {
dummy_state: std::rc::Rc<std::cell::RefCell<bool>>,
}

impl TrackedState<bool> for TrackedProfilerHaltedState {
type RemoteType = ProfilerHaltedRemote;

fn set(&mut self, value: bool) {
set_profiler_halted(value);
}

fn get(&self) -> std::cell::Ref<'_, bool> {
*self.dummy_state.borrow_mut() = is_profiler_halted();
self.dummy_state.borrow()
}

fn get_version(&self) -> korangar_interface::state::Version {
Version::from_raw(get_profiler_halted_version())
}

fn with_mut<Closure, Return>(&mut self, closure: Closure) -> Return
where
Closure: FnOnce(&mut bool) -> korangar_interface::state::ValueState<Return>,
{
let mut temporary_state = *self.dummy_state.borrow();

match closure(&mut temporary_state) {
ValueState::Mutated(return_value) => {
set_profiler_halted(temporary_state);
return_value
}
ValueState::Unchanged(return_value) => return_value,
}
}

fn update(&mut self) {
let state = is_profiler_halted();
set_profiler_halted(state);
}

fn new_remote(&self) -> Self::RemoteType {
ProfilerHaltedRemote {
state: self.clone(),
version: Version::from_raw(get_profiler_halted_version()),
}
}
}

/// Wrapper struct that exposes an implementation of [`Remote`] for the halted
/// state of the profiler.
struct ProfilerHaltedRemote {
state: TrackedProfilerHaltedState,
version: Version,
}

impl Remote<bool> for ProfilerHaltedRemote {
type State = TrackedProfilerHaltedState;

fn clone_state(&self) -> Self::State {
self.state.clone()
}

fn get(&self) -> std::cell::Ref<'_, bool> {
self.state.get()
}

fn consume_changed(&mut self) -> bool {
let version = Version::from_raw(get_profiler_halted_version());
let changed = self.version != version;
self.version = version;

changed
}
}

pub struct ProfilerWindow {
always_update: RawTrackedState<bool>,
visible_thread: RawTrackedState<ProfilerThread>,
Expand All @@ -31,11 +109,7 @@ impl PrototypeWindow<Adapter> for ProfilerWindow {
}

fn to_window(&self, window_cache: &WindowCache, application: &Adapter, available_space: ScreenSize) -> Window<Adapter> {
let toggle_halting = || {
let is_profiler_halted = is_profiler_halted();
set_profiler_halted(!is_profiler_halted);
Vec::new()
};
let profiler_halted_state = TrackedProfilerHaltedState::default();

let elements = vec![
PickList::default()
Expand All @@ -51,15 +125,15 @@ impl PrototypeWindow<Adapter> for ProfilerWindow {
.wrap(),
StateButtonBuilder::new()
.with_text("Always update")
.with_selector(self.always_update.selector())
.with_event(self.always_update.toggle_action())
.with_remote(self.always_update.new_remote())
.with_width_bound(dimension_bound!(150))
.build()
.wrap(),
StateButtonBuilder::new()
.with_text("Halt")
.with_selector(|| is_profiler_halted())
.with_event(Box::new(toggle_halting))
.with_remote(profiler_halted_state.new_remote())
.with_event(profiler_halted_state.toggle_action())
.with_width_bound(dimension_bound!(150))
.build()
.wrap(),
Expand Down
2 changes: 1 addition & 1 deletion korangar/src/interface/windows/settings/graphics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ where
0,
StateButtonBuilder::new()
.with_text("Framerate limit")
.with_selector(self.framerate_limit.selector())
.with_event(self.framerate_limit.toggle_action())
.with_remote(self.framerate_limit.new_remote())
.build()
.wrap(),
);
Expand Down
2 changes: 1 addition & 1 deletion korangar/src/interface/windows/settings/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ use crate::interface::windows::WindowCache;
fn render_state_button(text: &'static str, state: impl TrackedStateBinary<bool>) -> ElementCell<Adapter> {
StateButtonBuilder::new()
.with_text(text)
.with_selector(state.selector())
.with_event(state.toggle_action())
.with_remote(state.new_remote())
.build()
.wrap()
}
Expand Down
Loading

0 comments on commit b61efa4

Please sign in to comment.