mod color;
mod layer;
mod layout;
mod object;
mod timing;
pub use color::ColorSettings;
pub use layer::LayerSettings;
pub use layout::{BoxLayoutSettings, LayoutSettings, ViewLayoutSettings};
pub use object::ObjectSettings;
pub use timing::TimingSettings;
use color::{BoxColorParameter, ColorParameter, SelectableBoxColorParameter};
use layer::{
LayerAnchorParameter, LayerImageParameter, LayerLayoutParameter, LayerObjectLayoutParameter,
};
use layout::{BoxLayoutParameter, LayoutParameter, ViewLayoutParameter};
use object::{ObjectAnchorParameter, ObjectImageParameter, ObjectScaleParameter};
use timing::TimingParameter;
use dialogi::{DialogChange, DialogParameter};
use indexmap::IndexMap;
use simple_color::Color;
use std::collections::{HashMap, HashSet};
trait Settings<Parameter> {
type Value;
fn get_mut(&mut self, parameter: &Parameter) -> &mut Self::Value;
}
trait Resettable {
fn reset(&mut self) {}
fn reset_aspects(&mut self) {}
}
#[derive(Default)]
pub struct Override<T> {
default: T,
characters_default: HashMap<Box<str>, T>,
characters_aspect: HashMap<Box<str>, T>,
aspect: Option<T>,
characters_scene: HashMap<Box<str>, T>,
scene: Option<T>,
}
impl<T> Override<T> {
fn set_default(&mut self, name: Option<Box<str>>, value: T) {
if let Some(name) = name {
self.characters_default.insert(name, value);
} else {
self.default = value;
}
}
fn set_aspect(&mut self, name: Option<&str>, value: Option<T>) {
let Some(name) = name else {
self.aspect = value;
return;
};
if let Some(value) = value {
self.characters_aspect.insert(name.into(), value);
} else {
self.characters_aspect.remove(name);
}
}
fn set_scene(&mut self, name: Option<&str>, value: Option<T>) {
let Some(name) = name else {
self.scene = value;
return;
};
if let Some(value) = value {
self.characters_scene.insert(name.into(), value);
} else {
self.characters_scene.remove(name);
}
}
}
impl<T> Resettable for Override<T> {
fn reset(&mut self) {
self.scene = None;
}
fn reset_aspects(&mut self) {
self.aspect = None;
self.characters_aspect.clear();
}
}
impl<T> From<T> for Override<T> {
fn from(default: T) -> Self {
Self {
default,
characters_default: HashMap::new(),
characters_aspect: HashMap::new(),
aspect: None,
characters_scene: HashMap::new(),
scene: None,
}
}
}
impl<T> Override<T> {
pub fn get(&self, name: &str) -> T
where
T: Copy,
{
*self.get_ref(name)
}
pub fn get_ref(&self, name: &str) -> &T {
if let Some(scene) = &self.scene {
scene
} else if name.is_empty() {
if let Some(aspect) = &self.aspect {
aspect
} else {
&self.default
}
} else if let Some(character_scene) = self.characters_scene.get(name) {
character_scene
} else if let Some(aspect) = &self.aspect {
aspect
} else if let Some(character_aspect) = self.characters_aspect.get(name) {
character_aspect
} else if let Some(character_default) = self.characters_default.get(name) {
character_default
} else {
&self.default
}
}
}
#[derive(Default)]
pub struct Names {
pub default: HashMap<Box<str>, Box<str>>,
pub aspect: HashMap<Box<str>, Box<str>>,
pub scene: HashMap<Box<str>, Box<str>>,
}
impl Names {
pub fn new() -> Self {
Self::default()
}
pub fn reset(&mut self) {
self.scene.clear();
}
pub fn reset_aspects(&mut self) {
self.aspect.clear();
}
pub fn get<'a>(&'a self, name: &'a str) -> &'a str {
self.scene
.get(name)
.or_else(|| self.aspect.get(name))
.or_else(|| self.default.get(name))
.map_or(name, |v| v)
}
}
type OvrrideColorSettings = ColorSettings<Override<Color>>;
type OverrideTimingSettings = TimingSettings<Override<f32>>;
type OverrideObjectSettings =
ObjectSettings<Override<Option<Box<str>>>, Override<[f32; 2]>, Override<f32>>;
type OverrideLayerSettings =
LayerSettings<Override<Option<usize>>, Override<f32>, Override<Option<usize>>>;
type OverrideLayoutSettings = LayoutSettings<Override<f32>>;
pub struct PlayerSettings {
pub colors: OvrrideColorSettings,
pub timing: OverrideTimingSettings,
pub objects: OverrideObjectSettings,
pub layers: OverrideLayerSettings,
pub layout: OverrideLayoutSettings,
pub names: Names,
pub custom_colors: HashMap<Box<str>, Override<Color>>,
pub custom_floats: HashMap<Box<str>, Override<f32>>,
}
impl PlayerSettings {
pub fn common() -> Self {
Self {
colors: ColorSettings::common(),
timing: TimingSettings::common(),
objects: ObjectSettings::common(),
layers: LayerSettings::common(),
layout: LayoutSettings::common(),
names: Names::new(),
custom_colors: HashMap::new(),
custom_floats: HashMap::new(),
}
}
pub fn apply_setting(&mut self, context: &mut SettingsContext, key: &str, value: &str) {
if let Some(parameter) = Parameter::create(key, context) {
let setter = parameter.value_setter(value, context);
self.set_character_default(setter);
}
}
pub fn extract_settings(
&mut self,
context: &mut SettingsContext,
config_map: &mut IndexMap<Box<str>, Box<str>>,
) {
for (key, value) in config_map.drain(..) {
self.apply_setting(context, &key, &value);
}
}
pub fn reset(&mut self) {
self.colors.reset();
self.timing.reset();
self.layers.reset();
self.layout.reset();
self.names.reset();
for override_value in self.custom_colors.values_mut() {
override_value.reset();
}
for override_value in self.custom_floats.values_mut() {
override_value.reset();
}
}
pub fn set_aspect(&mut self, setter: Setter) {
use Setter::*;
match setter {
Color(parameter, value) => self
.colors
.get_mut(¶meter.parameter)
.set_aspect(parameter.name.as_deref(), Some(value)),
Timing(parameter, value) => self
.timing
.get_mut(¶meter.parameter)
.set_aspect(parameter.name.as_deref(), Some(value)),
ObjectImage(parameter, value) => self
.objects
.get_mut(¶meter.parameter)
.set_aspect(parameter.name.as_deref(), Some(value)),
ObjectAnchor(parameter, value) => self
.objects
.get_mut(¶meter.parameter)
.set_aspect(parameter.name.as_deref(), Some(value)),
ObjectScale(parameter, value) => self
.objects
.get_mut(¶meter.parameter)
.set_aspect(parameter.name.as_deref(), Some(value)),
LayerImage(parameter, value) => self
.layers
.get_mut(¶meter.parameter)
.set_aspect(parameter.name.as_deref(), Some(value)),
LayerLayout(parameter, value) => self
.layers
.get_mut(¶meter.parameter)
.set_aspect(parameter.name.as_deref(), Some(value)),
LayerAnchor(parameter, value) => self
.layers
.get_mut(¶meter.parameter)
.set_aspect(parameter.name.as_deref(), Some(value)),
Layout(parameter, value) => self
.layout
.get_mut(¶meter.parameter)
.set_aspect(parameter.name.as_deref(), Some(value)),
Name(parameter, value) => {
self.names.aspect.insert(parameter, value);
}
CustomColor(parameter, value) => self
.custom_colors
.entry(parameter.parameter.clone())
.or_default()
.set_aspect(parameter.name.as_deref(), Some(value)),
CustomFloat(parameter, value) => self
.custom_floats
.entry(parameter.parameter.clone())
.or_default()
.set_aspect(parameter.name.as_deref(), Some(value)),
}
}
pub fn reset_aspects(&mut self) {
self.colors.reset_aspects();
self.timing.reset_aspects();
self.objects.reset_aspects();
self.layers.reset_aspects();
self.layout.reset_aspects();
self.names.reset_aspects();
for override_value in self.custom_colors.values_mut() {
override_value.reset_aspects();
}
for override_value in self.custom_floats.values_mut() {
override_value.reset_aspects();
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct NamedParameter<T> {
name: Option<Box<str>>,
parameter: T,
}
trait ParameterNamer: Sized {
fn named(self, name: Option<Box<str>>) -> NamedParameter<Self> {
NamedParameter {
name,
parameter: self,
}
}
}
impl<T> ParameterNamer for T {}
type NamedColorParameter = NamedParameter<ColorParameter>;
type NamedTimingParameter = NamedParameter<TimingParameter>;
type NamedObjectImageParameter = NamedParameter<ObjectImageParameter>;
type NamedObjectAnchorParameter = NamedParameter<ObjectAnchorParameter>;
type NamedObjectScaleParameter = NamedParameter<ObjectScaleParameter>;
type NamedLayerImageParameter = NamedParameter<LayerImageParameter>;
type NamedLayerLayoutParameter = NamedParameter<LayerLayoutParameter>;
type NamedLayerAnchorParameter = NamedParameter<LayerAnchorParameter>;
type NamedLayoutParameter = NamedParameter<LayoutParameter>;
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum Parameter {
Color(NamedColorParameter),
Timing(NamedTimingParameter),
ObjectImage(NamedObjectImageParameter),
ObjectAnchor(NamedObjectAnchorParameter),
ObjectScale(NamedObjectScaleParameter),
LayerImage(NamedLayerImageParameter),
LayerLayout(NamedLayerLayoutParameter),
LayerAnchor(NamedLayerAnchorParameter),
Layout(NamedLayoutParameter),
Name(Box<str>),
CustomColor(NamedParameter<Box<str>>),
CustomFloat(NamedParameter<Box<str>>),
}
pub struct Object {
index: usize,
images: HashMap<Box<str>, usize>,
}
impl Object {
fn new(index: usize) -> Self {
Self {
index,
images: HashMap::new(),
}
}
}
pub struct LayerInfo {
pub name: Box<str>,
pub path: Box<str>,
}
pub fn extract_layers(layers: &mut Vec<LayerInfo>, config_map: &mut IndexMap<Box<str>, Box<str>>) {
let keys: Vec<_> = config_map.keys().cloned().collect();
for key in keys {
let Some(("Layer", name)) = key.split_once(':') else {
continue;
};
let path = config_map.shift_remove(&key).expect("Invalid layer");
layers.push(LayerInfo {
name: name.into(),
path,
});
}
if layers.is_empty() {
layers.push(LayerInfo {
name: "Background".into(),
path: Box::default(),
});
layers.push(LayerInfo {
name: "Character".into(),
path: Box::default(),
});
}
}
#[derive(Default)]
pub struct SettingsContext {
pub object_cache: HashMap<Box<str>, Object>,
pub layers: Vec<LayerInfo>,
pub anchors: HashMap<Box<str>, usize>,
pub custom_color_names: HashSet<Box<str>>,
pub custom_float_names: HashSet<Box<str>>,
}
impl SettingsContext {
pub fn new() -> Self {
Self::default()
}
}
impl Parameter {
fn create_character(name: &str, context: &mut SettingsContext) -> Option<Self> {
let (main, sub) = name.split_once(':')?;
if main != "Character" {
return None;
}
let (character_name, option) = sub.split_once(':')?;
let character_name = character_name.into();
if option == "name" {
Some(Self::Name(character_name))
} else {
create_parameter(option, Some(character_name), context)
}
}
pub fn value_setter(self, value: &str, context: &mut SettingsContext) -> Setter {
fn color(repr: &str) -> Color {
match repr {
"black" => Color::BLACK,
"white" => Color::WHITE,
"red" => Color::RED,
"yellow" => Color::YELLOW,
"green" => Color::GREEN,
"cyan" => Color::CYAN,
"blue" => Color::BLUE,
"magenta" => Color::MAGENTA,
_ => repr
.parse::<Color>()
.unwrap_or_else(|_| panic!("Color '{repr}' does not exist")),
}
}
match self {
Self::Color(parameter) => Setter::Color(parameter, color(value)),
Self::Timing(parameter) => Setter::Timing(
parameter,
value.parse().expect("Parsing timing parameter failed"),
),
Self::ObjectImage(parameter) => Setter::ObjectImage(parameter, Some(value.into())),
Self::ObjectAnchor(parameter) => Setter::ObjectAnchor(parameter, {
let (x, y) = value
.split_once(char::is_whitespace)
.expect("Parsing object anchor parameter failed");
let x = x.parse().expect("Parsing object anchor parameter failed");
let y = y.parse().expect("Parsing object anchor parameter failed");
[x, y]
}),
Self::ObjectScale(parameter) => Setter::ObjectScale(
parameter,
value.parse().expect("Parsing image scale parameter failed"),
),
Self::LayerImage(parameter) => {
let index = if value.is_empty() {
None
} else {
let path = &context.layers[parameter.parameter.0].path;
let path_holder;
let full_path = if path.is_empty() {
value
} else {
path_holder = format!("{path}:{value}");
&path_holder
};
if let Some(Object { index, .. }) = context.object_cache.get(full_path) {
Some(*index)
} else {
eprintln!("Undefined image object {value:?}");
None
}
};
Setter::LayerImage(parameter, index)
}
Self::LayerLayout(parameter) => Setter::LayerLayout(
parameter,
value
.parse()
.expect("Parsing object layout parameter failed"),
),
Self::LayerAnchor(parameter) => {
let index = if value.is_empty() {
None
} else {
let anchor_index = context.anchors.len();
Some(*context.anchors.entry(value.into()).or_insert(anchor_index))
};
Setter::LayerAnchor(parameter, index)
}
Self::Layout(parameter) => Setter::Layout(
parameter,
value.parse().expect("Parsing layout parameter failed"),
),
Self::Name(parameter) => Setter::Name(parameter, value.into()),
Self::CustomColor(parameter) => Setter::CustomColor(parameter, color(value)),
Self::CustomFloat(parameter) => Setter::CustomFloat(
parameter,
value
.parse()
.unwrap_or_else(|_| panic!("Parsing custom float parameter failed: {value:?}")),
),
}
}
}
fn create_parameter(
parameter_name: &str,
character_name: Option<Box<str>>,
context: &mut SettingsContext,
) -> Option<Parameter> {
let (path, parameter_name) = parameter_name.split_once(':')?;
Some(match path {
"Color" => Parameter::Color(
match parameter_name {
"background" => ColorParameter::Background,
"foreground" => ColorParameter::Foreground,
"dialog-text-fill" => ColorParameter::Dialog(BoxColorParameter::TextFill),
"dialog-text-line" => ColorParameter::Dialog(BoxColorParameter::TextLine),
"dialog-name-fill" => ColorParameter::Dialog(BoxColorParameter::NameFill),
"dialog-name-line" => ColorParameter::Dialog(BoxColorParameter::NameLine),
"choice-default-text-fill" => ColorParameter::Choice(SelectableBoxColorParameter {
selected: false,
parameter: BoxColorParameter::TextFill,
}),
"choice-default-text-line" => ColorParameter::Choice(SelectableBoxColorParameter {
selected: false,
parameter: BoxColorParameter::TextLine,
}),
"choice-default-name-fill" => ColorParameter::Choice(SelectableBoxColorParameter {
selected: false,
parameter: BoxColorParameter::NameFill,
}),
"choice-default-name-line" => ColorParameter::Choice(SelectableBoxColorParameter {
selected: false,
parameter: BoxColorParameter::NameLine,
}),
"choice-select-text-fill" => ColorParameter::Choice(SelectableBoxColorParameter {
selected: true,
parameter: BoxColorParameter::TextFill,
}),
"choice-select-text-line" => ColorParameter::Choice(SelectableBoxColorParameter {
selected: true,
parameter: BoxColorParameter::TextLine,
}),
"choice-select-name-fill" => ColorParameter::Choice(SelectableBoxColorParameter {
selected: true,
parameter: BoxColorParameter::NameFill,
}),
"choice-select-name-line" => ColorParameter::Choice(SelectableBoxColorParameter {
selected: true,
parameter: BoxColorParameter::NameLine,
}),
"revert-default-text-fill" => ColorParameter::Revert(SelectableBoxColorParameter {
selected: false,
parameter: BoxColorParameter::TextFill,
}),
"revert-default-text-line" => ColorParameter::Revert(SelectableBoxColorParameter {
selected: false,
parameter: BoxColorParameter::TextLine,
}),
"revert-default-name-fill" => ColorParameter::Revert(SelectableBoxColorParameter {
selected: false,
parameter: BoxColorParameter::NameFill,
}),
"revert-default-name-line" => ColorParameter::Revert(SelectableBoxColorParameter {
selected: false,
parameter: BoxColorParameter::NameLine,
}),
"revert-select-text-fill" => ColorParameter::Revert(SelectableBoxColorParameter {
selected: true,
parameter: BoxColorParameter::TextFill,
}),
"revert-select-text-line" => ColorParameter::Revert(SelectableBoxColorParameter {
selected: true,
parameter: BoxColorParameter::TextLine,
}),
"revert-select-name-fill" => ColorParameter::Revert(SelectableBoxColorParameter {
selected: true,
parameter: BoxColorParameter::NameFill,
}),
"revert-select-name-line" => ColorParameter::Revert(SelectableBoxColorParameter {
selected: true,
parameter: BoxColorParameter::NameLine,
}),
_ => return None,
}
.named(character_name),
),
"Timing" => Parameter::Timing(
match parameter_name {
"auto-next" => TimingParameter::AutoNext,
"letter" => TimingParameter::Letter,
"line" => TimingParameter::Line,
"select" => TimingParameter::Select,
"view" => TimingParameter::View,
_ => return None,
}
.named(character_name),
),
"Image" => {
let (object_name, parameter_name) = parameter_name.rsplit_once(':')?;
let entry_count = context.object_cache.len();
let Object { index, images } = context
.object_cache
.entry(object_name.into())
.or_insert_with(|| Object::new(entry_count));
let image_index = images.len();
let parameter_index = *images.entry(parameter_name.into()).or_insert(image_index);
Parameter::ObjectImage(
ObjectImageParameter(*index, parameter_index).named(character_name),
)
}
"Anchor" => {
let (object_name, parameter_name) = parameter_name.rsplit_once(':')?;
let entry_count = context.object_cache.len();
let Object { index, .. } = context
.object_cache
.entry(object_name.into())
.or_insert_with(|| Object::new(entry_count));
let anchor_index = context.anchors.len();
let parameter_index = *context
.anchors
.entry(parameter_name.into())
.or_insert(anchor_index);
Parameter::ObjectAnchor(
ObjectAnchorParameter(*index, parameter_index).named(character_name),
)
}
"Transform" => {
let (object_name, parameter_name) = parameter_name.rsplit_once(':')?;
if parameter_name != "scale" {
return None;
}
let entry_count = context.object_cache.len();
let Object { index, .. } = context
.object_cache
.entry(object_name.into())
.or_insert_with(|| Object::new(entry_count));
Parameter::ObjectScale(ObjectScaleParameter(*index).named(character_name))
}
"Object" => {
let (layer_name, parameter_name) = parameter_name.split_once(':')?;
let layer = context
.layers
.iter()
.position(|layer| &*layer.name == layer_name)?;
match parameter_name {
"image" => Parameter::LayerImage(LayerImageParameter(layer).named(character_name)),
"hor" => Parameter::LayerLayout(
LayerLayoutParameter {
layer,
layout: LayerObjectLayoutParameter::Hor,
}
.named(character_name),
),
"ver" => Parameter::LayerLayout(
LayerLayoutParameter {
layer,
layout: LayerObjectLayoutParameter::Ver,
}
.named(character_name),
),
"scale" => Parameter::LayerLayout(
LayerLayoutParameter {
layer,
layout: LayerObjectLayoutParameter::Scale,
}
.named(character_name),
),
"anchor" => {
Parameter::LayerAnchor(LayerAnchorParameter(layer).named(character_name))
}
_ => return None,
}
}
"Layout" => Parameter::Layout(
{
let (subpath, parameter_name) = parameter_name.split_once(':')?;
let box_layout_parameter = || {
Some(match parameter_name {
"hor" => BoxLayoutParameter::Hor,
"ver" => BoxLayoutParameter::Ver,
"width" => BoxLayoutParameter::Width,
"height" => BoxLayoutParameter::Height,
"corner" => BoxLayoutParameter::Corner,
"line" => BoxLayoutParameter::Line,
"text-size" => BoxLayoutParameter::TextSize,
"name-size" => BoxLayoutParameter::NameSize,
_ => return None,
})
};
let view_layout_parameter = || {
Some(match parameter_name {
"hor" => ViewLayoutParameter::Hor,
"ver" => ViewLayoutParameter::Ver,
"zoom" => ViewLayoutParameter::Zoom,
_ => return None,
})
};
match subpath {
"Main" => box_layout_parameter()?.main(),
"List" => box_layout_parameter()?.list(),
"View" => LayoutParameter::View(view_layout_parameter()?),
_ => return None,
}
}
.named(character_name),
),
"Parameter" => {
let (type_name, param_name) = parameter_name.split_once(':')?;
let param_name: Box<str> = param_name.into();
match type_name {
"Color" => {
context.custom_color_names.insert(param_name.clone());
Parameter::CustomColor(param_name.named(character_name))
}
"Number" => {
context.custom_float_names.insert(param_name.clone());
Parameter::CustomFloat(param_name.named(character_name))
}
_ => return None,
}
}
_ => return None,
})
}
impl Parameter {
pub fn create_setter(key: &str, value: &str, context: &mut SettingsContext) -> Option<Setter> {
let parameter = if let Some(p) = create_parameter(key, None, context) {
p
} else {
Self::create_character(key, context)?
};
Some(parameter.value_setter(value, context))
}
}
impl DialogParameter for Parameter {
type Context = SettingsContext;
fn create(name: &str, context: &mut SettingsContext) -> Option<Self> {
if name == "-" {
None
} else if let Some(parameter) = create_parameter(name, None, context) {
Some(parameter)
} else {
let result = Self::create_character(name, context);
if result.is_none() {
eprintln!("Setting not availabe: {name}");
}
result
}
}
}
#[derive(Clone)]
pub enum Setter {
Color(NamedColorParameter, Color),
Timing(NamedTimingParameter, f32),
ObjectImage(NamedObjectImageParameter, Option<Box<str>>),
ObjectAnchor(NamedObjectAnchorParameter, [f32; 2]),
ObjectScale(NamedObjectScaleParameter, f32),
LayerImage(NamedLayerImageParameter, Option<usize>),
LayerLayout(NamedLayerLayoutParameter, f32),
LayerAnchor(NamedLayerAnchorParameter, Option<usize>),
Layout(NamedLayoutParameter, f32),
Name(Box<str>, Box<str>),
CustomColor(NamedParameter<Box<str>>, Color),
CustomFloat(NamedParameter<Box<str>>, f32),
}
impl Setter {
pub fn change(self) -> Change {
match self {
Self::Color(parameter, value) => Change::Color(parameter, Some(value)),
Self::Timing(parameter, value) => Change::Timing(parameter, Some(value)),
Self::ObjectImage(parameter, value) => Change::ObjectImage(parameter, Some(value)),
Self::ObjectAnchor(parameter, value) => Change::ObjectAnchor(parameter, Some(value)),
Self::ObjectScale(parameter, value) => Change::ObjectScale(parameter, Some(value)),
Self::LayerImage(parameter, value) => Change::LayerImage(parameter, Some(value)),
Self::LayerLayout(parameter, value) => Change::LayerLayout(parameter, Some(value)),
Self::LayerAnchor(parameter, value) => Change::LayerAnchor(parameter, Some(value)),
Self::Layout(parameter, value) => Change::Layout(parameter, Some(value)),
Self::Name(parameter, value) => Change::Name(parameter, Some(value)),
Self::CustomColor(parameter, value) => Change::CustomColor(parameter, Some(value)),
Self::CustomFloat(parameter, value) => Change::CustomFloat(parameter, Some(value)),
}
}
}
pub enum Change {
Color(NamedColorParameter, Option<Color>),
Timing(NamedTimingParameter, Option<f32>),
ObjectImage(NamedObjectImageParameter, Option<Option<Box<str>>>),
ObjectAnchor(NamedObjectAnchorParameter, Option<[f32; 2]>),
ObjectScale(NamedObjectScaleParameter, Option<f32>),
LayerImage(NamedLayerImageParameter, Option<Option<usize>>),
LayerLayout(NamedLayerLayoutParameter, Option<f32>),
LayerAnchor(NamedLayerAnchorParameter, Option<Option<usize>>),
Layout(NamedLayoutParameter, Option<f32>),
Name(Box<str>, Option<Box<str>>),
CustomColor(NamedParameter<Box<str>>, Option<Color>),
CustomFloat(NamedParameter<Box<str>>, Option<f32>),
}
impl Change {
pub fn parameter(&self) -> Parameter {
match self {
Self::Color(parameter, _) => Parameter::Color(parameter.clone()),
Self::Timing(parameter, _) => Parameter::Timing(parameter.clone()),
Self::ObjectImage(parameter, _) => Parameter::ObjectImage(parameter.clone()),
Self::ObjectAnchor(parameter, _) => Parameter::ObjectAnchor(parameter.clone()),
Self::ObjectScale(parameter, _) => Parameter::ObjectScale(parameter.clone()),
Self::LayerImage(parameter, _) => Parameter::LayerImage(parameter.clone()),
Self::LayerLayout(parameter, _) => Parameter::LayerLayout(parameter.clone()),
Self::LayerAnchor(parameter, _) => Parameter::LayerAnchor(parameter.clone()),
Self::Layout(parameter, _) => Parameter::Layout(parameter.clone()),
Self::Name(parameter, _) => Parameter::Name(parameter.clone()),
Self::CustomColor(parameter, _) => Parameter::CustomColor(parameter.clone()),
Self::CustomFloat(parameter, _) => Parameter::CustomFloat(parameter.clone()),
}
}
}
impl DialogChange for Change {
type Parameter = Parameter;
fn default_change(parameter: Parameter) -> Self {
match parameter {
Parameter::Color(parameter) => Self::Color(parameter, None),
Parameter::Timing(parameter) => Self::Timing(parameter, None),
Parameter::ObjectImage(parameter) => Self::ObjectImage(parameter, None),
Parameter::ObjectAnchor(parameter) => Self::ObjectAnchor(parameter, None),
Parameter::ObjectScale(parameter) => Self::ObjectScale(parameter, None),
Parameter::LayerImage(parameter) => Self::LayerImage(parameter, None),
Parameter::LayerLayout(parameter) => Self::LayerLayout(parameter, None),
Parameter::LayerAnchor(parameter) => Self::LayerAnchor(parameter, None),
Parameter::Layout(parameter) => Self::Layout(parameter, None),
Parameter::Name(parameter) => Self::Name(parameter, None),
Parameter::CustomColor(parameter) => Self::CustomColor(parameter, None),
Parameter::CustomFloat(parameter) => Self::CustomFloat(parameter, None),
}
}
fn value_change(parameter: Parameter, value: &str, context: &mut SettingsContext) -> Self {
parameter.value_setter(value, context).change()
}
}
impl PlayerSettings {
pub fn revert(&mut self, parameter: &Parameter) {
use Parameter::*;
match parameter {
Color(parameter) => self
.colors
.get_mut(¶meter.parameter)
.set_scene(parameter.name.as_deref(), None),
Timing(parameter) => self
.timing
.get_mut(¶meter.parameter)
.set_scene(parameter.name.as_deref(), None),
ObjectImage(parameter) => self
.objects
.get_mut(¶meter.parameter)
.set_scene(parameter.name.as_deref(), None),
ObjectAnchor(parameter) => self
.objects
.get_mut(¶meter.parameter)
.set_scene(parameter.name.as_deref(), None),
ObjectScale(parameter) => self
.objects
.get_mut(¶meter.parameter)
.set_scene(parameter.name.as_deref(), None),
LayerImage(parameter) => self
.layers
.get_mut(¶meter.parameter)
.set_scene(parameter.name.as_deref(), None),
LayerLayout(parameter) => self
.layers
.get_mut(¶meter.parameter)
.set_scene(parameter.name.as_deref(), None),
LayerAnchor(parameter) => self
.layers
.get_mut(¶meter.parameter)
.set_scene(parameter.name.as_deref(), None),
Layout(parameter) => self
.layout
.get_mut(¶meter.parameter)
.set_scene(parameter.name.as_deref(), None),
Name(parameter) => {
self.names.scene.remove(parameter);
}
CustomColor(parameter) => {
if let Some(override_value) = self.custom_colors.get_mut(¶meter.parameter) {
override_value.set_scene(parameter.name.as_deref(), None);
}
}
CustomFloat(parameter) => {
if let Some(override_value) = self.custom_floats.get_mut(¶meter.parameter) {
override_value.set_scene(parameter.name.as_deref(), None);
}
}
}
}
pub fn change(&mut self, change: &Change) {
use Change::*;
match change {
Color(parameter, value) => self
.colors
.get_mut(¶meter.parameter)
.set_scene(parameter.name.as_deref(), *value),
Timing(parameter, value) => self
.timing
.get_mut(¶meter.parameter)
.set_scene(parameter.name.as_deref(), *value),
ObjectImage(parameter, value) => self
.objects
.get_mut(¶meter.parameter)
.set_scene(parameter.name.as_deref(), value.clone()),
ObjectScale(parameter, value) => self
.objects
.get_mut(¶meter.parameter)
.set_scene(parameter.name.as_deref(), *value),
ObjectAnchor(parameter, value) => self
.objects
.get_mut(¶meter.parameter)
.set_scene(parameter.name.as_deref(), *value),
LayerImage(parameter, value) => self
.layers
.get_mut(¶meter.parameter)
.set_scene(parameter.name.as_deref(), *value),
LayerLayout(parameter, value) => self
.layers
.get_mut(¶meter.parameter)
.set_scene(parameter.name.as_deref(), *value),
LayerAnchor(parameter, value) => self
.layers
.get_mut(¶meter.parameter)
.set_scene(parameter.name.as_deref(), *value),
Layout(parameter, value) => self
.layout
.get_mut(¶meter.parameter)
.set_scene(parameter.name.as_deref(), *value),
Name(parameter, value) => {
if let Some(value) = value {
self.names.scene.insert(parameter.clone(), value.clone());
} else {
self.names.scene.remove(parameter);
}
}
CustomColor(parameter, value) => self
.custom_colors
.entry(parameter.parameter.clone())
.or_default()
.set_scene(parameter.name.as_deref(), *value),
CustomFloat(parameter, value) => self
.custom_floats
.entry(parameter.parameter.clone())
.or_default()
.set_scene(parameter.name.as_deref(), *value),
}
}
pub fn set_character_default(&mut self, change: Setter) {
use Setter::*;
match change {
Color(parameter, value) => self
.colors
.get_mut(¶meter.parameter)
.set_default(parameter.name, value),
Timing(parameter, value) => self
.timing
.get_mut(¶meter.parameter)
.set_default(parameter.name, value),
ObjectImage(parameter, value) => self
.objects
.get_mut(¶meter.parameter)
.set_default(parameter.name, value),
ObjectAnchor(parameter, value) => self
.objects
.get_mut(¶meter.parameter)
.set_default(parameter.name, value),
ObjectScale(parameter, value) => self
.objects
.get_mut(¶meter.parameter)
.set_default(parameter.name, value),
LayerImage(parameter, value) => self
.layers
.get_mut(¶meter.parameter)
.set_default(parameter.name, value),
LayerLayout(parameter, value) => self
.layers
.get_mut(¶meter.parameter)
.set_default(parameter.name, value),
LayerAnchor(parameter, value) => self
.layers
.get_mut(¶meter.parameter)
.set_default(parameter.name, value),
Layout(parameter, value) => self
.layout
.get_mut(¶meter.parameter)
.set_default(parameter.name, value),
Name(parameter, value) => {
self.names.default.insert(parameter, value);
}
CustomColor(parameter, value) => self
.custom_colors
.entry(parameter.parameter.clone())
.or_default()
.set_default(parameter.name, value),
CustomFloat(parameter, value) => self
.custom_floats
.entry(parameter.parameter.clone())
.or_default()
.set_default(parameter.name, value),
}
}
pub fn custom_color(&self, name: &str, character: &str) -> Option<Color> {
self.custom_colors.get(name).map(|o| o.get(character))
}
pub fn custom_float(&self, name: &str, character: &str) -> Option<f32> {
self.custom_floats.get(name).map(|o| o.get(character))
}
}