Skip to content

Commit

Permalink
Use unified modal
Browse files Browse the repository at this point in the history
  • Loading branch information
melody-rs committed Jun 25, 2024
1 parent 66cf00f commit 436ea1a
Show file tree
Hide file tree
Showing 9 changed files with 396 additions and 257 deletions.
51 changes: 51 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions crates/data/src/shared/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,8 @@ pub struct EventCondition {
#[serde(with = "id_serde")]
#[marshal(with = "id_alox")]
pub switch2_id: usize,
#[serde(with = "id_serde")]
#[marshal(with = "id_alox")]
pub variable_id: usize,
pub variable_value: i32,
pub self_switch_ch: SelfSwitch,
Expand Down
2 changes: 2 additions & 0 deletions crates/modals/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,5 @@ luminol-data.workspace = true
luminol-components.workspace = true

fuzzy-matcher = "0.3.7"

ouroboros = "0.18.4"
218 changes: 218 additions & 0 deletions crates/modals/src/database_modal/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
// Copyright (C) 2024 Lily Lyons
//
// This file is part of Luminol.
//
// Luminol is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Luminol is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Luminol. If not, see <http://www.gnu.org/licenses/>.
//
// Additional permission under GNU GPL version 3 section 7
//
// If you modify this Program, or any covered work, by linking or combining
// it with Steamworks API by Valve Corporation, containing parts covered by
// terms of the Steamworks API by Valve Corporation, the licensors of this
// Program grant you additional permission to convey the resulting work.

use std::marker::PhantomData;

use luminol_components::UiExt;

mod variable;
pub use variable::Variable;
mod switch;
pub use switch::Switch;

pub struct Modal<M> {
state: State,
id: egui::Id,
_phantom: PhantomData<M>, // so that M is constrained
}

enum State {
Closed,
Open {
search_text: String,
selected_id: usize,
new_size: Option<usize>,
},
}

#[allow(unused_variables)]
pub trait DatabaseModalHandler {
fn window_title() -> &'static str;

fn button_format(id: &mut usize, update_state: &mut luminol_core::UpdateState<'_>) -> String;

fn iter(
update_state: &mut luminol_core::UpdateState<'_>,
f: impl FnOnce(&mut dyn Iterator<Item = (usize, String)>), // can't figure out how to avoid the dyn
);

fn current_size(update_state: &luminol_core::UpdateState<'_>) -> Option<usize> {
None
}
fn resize(update_state: &mut luminol_core::UpdateState<'_>, new_size: usize) {}
}

impl<M> Modal<M>
where
M: DatabaseModalHandler,
{
pub fn new(id: egui::Id) -> Self {
Self {
state: State::Closed,
id,
_phantom: PhantomData,
}
}
}

impl<M> luminol_core::Modal for Modal<M>
where
M: DatabaseModalHandler,
{
type Data = usize;

fn button<'m>(
&'m mut self,
data: &'m mut Self::Data,
update_state: &'m mut luminol_core::UpdateState<'_>,
) -> impl egui::Widget + 'm {
move |ui: &mut egui::Ui| {
let button_text = if ui.is_enabled() {
M::button_format(data, update_state)
} else {
"...".to_string()
};
let button_response = ui.button(button_text);

if button_response.clicked() {
self.state = State::Open {
search_text: String::new(),
selected_id: *data,
new_size: M::current_size(update_state),
};
}
if ui.is_enabled() {
self.show_window(ui.ctx(), data, update_state);
}

button_response
}
}

fn reset(&mut self) {
self.state = State::Closed;
}
}

impl<M> Modal<M>
where
M: DatabaseModalHandler,
{
fn show_window(
&mut self,
ctx: &egui::Context,
data: &mut usize,
update_state: &mut luminol_core::UpdateState<'_>,
) {
let mut win_open = true;
let mut keep_open = true;
let mut needs_save = false;

let State::Open {
search_text,
selected_id,
new_size,
} = &mut self.state
else {
return;
};

egui::Window::new(M::window_title())
.resizable(true)
.open(&mut win_open)
.id(self.id)
.show(ctx, |ui| {
let matcher = fuzzy_matcher::skim::SkimMatcherV2::default();

ui.group(|ui| {
egui::ScrollArea::vertical()
.auto_shrink([false, false])
.max_height(384.)
.show(ui, |ui| {
M::iter(update_state, |iter| {
for (id, text) in iter {
if matcher.fuzzy(&text, search_text, false).is_none() {
continue;
}

ui.with_stripe(id % 2 == 0, |ui| {
ui.horizontal(|ui| {
let response =
ui.selectable_value(selected_id, id, text);
ui.add_space(ui.available_width());
if response.double_clicked() {
keep_open = false;
needs_save = true;
}
});
});
}
})
})
});

if M::current_size(update_state).is_some_and(|size| size <= 999) && new_size.is_some_and(|size| size > 999) {
egui::Frame::none().show(ui, |ui| {
ui.style_mut()
.visuals
.widgets
.noninteractive
.bg_stroke
.color = ui.style().visuals.warn_fg_color;
egui::Frame::group(ui.style())
.fill(ui.visuals().gray_out(ui.visuals().gray_out(
ui.visuals().gray_out(ui.style().visuals.warn_fg_color),
)))
.show(ui, |ui| {
ui.set_width(ui.available_width());
ui.label(egui::RichText::new("Setting the maximum above 999 may introduce performance issues and instability").color(ui.style().visuals.warn_fg_color));
});
});
}

ui.horizontal(|ui| {
luminol_components::close_options_ui(ui, &mut keep_open, &mut needs_save);

if let Some(size) = new_size {
ui.add(egui::DragValue::new(size).clamp_range(1..=usize::MAX));
if ui.button("Set Maximum").clicked() {
M::resize(update_state, *size);
}
}

egui::TextEdit::singleline(search_text)
.hint_text("Search 🔎")
.show(ui);
});
});

if needs_save {
*data = *selected_id;
}

if !win_open || !keep_open {
self.state = State::Closed;
}
}
}
59 changes: 59 additions & 0 deletions crates/modals/src/database_modal/switch.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright (C) 2024 Lily Lyons
//
// This file is part of Luminol.
//
// Luminol is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Luminol is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Luminol. If not, see <http://www.gnu.org/licenses/>.
//
// Additional permission under GNU GPL version 3 section 7
//
// If you modify this Program, or any covered work, by linking or combining
// it with Steamworks API by Valve Corporation, containing parts covered by
// terms of the Steamworks API by Valve Corporation, the licensors of this
// Program grant you additional permission to convey the resulting work.

pub struct Switch;

impl super::DatabaseModalHandler for Switch {
fn button_format(id: &mut usize, update_state: &mut luminol_core::UpdateState<'_>) -> String {
let system = update_state.data.system();
*id = system.switches.len().min(*id);
format!("{:0>3}: {}", *id + 1, system.switches[*id])
}

fn window_title() -> &'static str {
"Switches"
}

fn iter(
update_state: &mut luminol_core::UpdateState<'_>,
f: impl FnOnce(&mut dyn Iterator<Item = (usize, String)>),
) {
let system = update_state.data.system();
let mut iter = system
.switches
.iter()
.enumerate()
.map(|(id, name)| (id, format!("{:0>3}: {name}", id + 1)));
f(&mut iter);
}

fn current_size(update_state: &luminol_core::UpdateState<'_>) -> Option<usize> {
Some(update_state.data.system().variables.len())
}

fn resize(update_state: &mut luminol_core::UpdateState<'_>, new_size: usize) {
let system = &mut update_state.data.system();
system.variables.resize_with(new_size, String::new);
}
}
Loading

0 comments on commit 436ea1a

Please sign in to comment.