1mod color;
2mod image;
3mod layout;
4mod object;
5mod timing;
6
7pub use color::ColorSettings;
8pub use image::ImageSettings;
9use indexmap::IndexMap;
10pub use layout::{BoxLayoutSettings, LayoutSettings, ViewLayoutSettings};
11pub use object::ObjectSettings;
12pub use timing::TimingSettings;
13
14use color::{BoxColorParameter, ColorParameter, SelectableBoxColorParameter};
15use image::ImageParameter;
16use layout::{BoxLayoutParameter, LayoutParameter, ViewLayoutParameter};
17use object::{ObjectImageParameter, ObjectLayerLayoutParameter, ObjectLayoutParameter};
18use timing::TimingParameter;
19
20use dialogi::{DialogChange, DialogParameter};
21use simple_color::Color;
22
23use std::collections::HashMap;
24
25trait Settings<Parameter> {
26 type Value;
27
28 fn get_mut(&mut self, parameter: &Parameter) -> &mut Self::Value;
29}
30
31trait Resettable {
32 fn reset(&mut self) {}
33}
34
35#[derive(Default)]
36pub struct Override<T> {
37 default: T,
38 characters_default: HashMap<Box<str>, T>,
39 characters_scene: HashMap<Box<str>, T>,
40 scene: Option<T>,
41}
42
43impl<T> Override<T> {
44 fn set_default(&mut self, name: Option<Box<str>>, value: T) {
45 if let Some(name) = name {
46 self.characters_default.insert(name, value);
47 } else {
48 self.default = value;
49 }
50 }
51
52 fn set_scene(&mut self, name: Option<&str>, value: Option<T>) {
53 let Some(name) = name else {
54 self.scene = value;
55 return;
56 };
57
58 if let Some(value) = value {
59 self.characters_scene.insert(name.into(), value);
60 } else {
61 self.characters_scene.remove(name);
62 }
63 }
64}
65
66impl<T> Resettable for Override<T> {
67 fn reset(&mut self) {
68 self.scene = None;
69 }
70}
71
72impl<T> From<T> for Override<T> {
73 fn from(default: T) -> Self {
74 Self {
75 default,
76 characters_default: HashMap::new(),
77 characters_scene: HashMap::new(),
78 scene: None,
79 }
80 }
81}
82
83impl<T> Override<T> {
84 pub fn get(&self, name: &str) -> T
85 where
86 T: Copy,
87 {
88 *self.get_ref(name)
89 }
90
91 pub fn get_ref(&self, name: &str) -> &T {
92 if let Some(scene) = &self.scene {
93 scene
94 } else if name.is_empty() {
95 &self.default
96 } else if let Some(character_scene) = self.characters_scene.get(name) {
97 character_scene
98 } else if let Some(character_default) = self.characters_default.get(name) {
99 character_default
100 } else {
101 &self.default
102 }
103 }
104}
105
106#[derive(Default)]
107pub struct Names {
108 pub default: HashMap<Box<str>, Box<str>>,
109 pub scene: HashMap<Box<str>, Box<str>>,
110}
111
112impl Names {
113 pub fn new() -> Self {
114 Self::default()
115 }
116
117 pub fn reset(&mut self) {
118 self.scene.clear();
119 }
120
121 pub fn get<'a>(&'a self, name: &'a str) -> &'a str {
122 self.scene
123 .get(name)
124 .or_else(|| self.default.get(name))
125 .map_or(name, |v| v)
126 }
127}
128
129pub struct PlayerSettings {
130 pub colors: ColorSettings<Override<Color>>,
131 pub timing: TimingSettings<Override<f32>>,
132 pub images: ImageSettings<Override<Option<Box<str>>>>,
133 pub objects: ObjectSettings<Override<Option<usize>>, Override<f32>>,
134 pub layout: LayoutSettings<Override<f32>>,
135 pub names: Names,
136}
137
138impl PlayerSettings {
139 pub fn common() -> Self {
140 Self {
141 colors: ColorSettings::common(),
142 timing: TimingSettings::common(),
143 images: ImageSettings::common(),
144 objects: ObjectSettings::common(),
145 layout: LayoutSettings::common(),
146 names: Names::new(),
147 }
148 }
149
150 pub fn apply_setting(&mut self, context: &mut SettingsContext, key: &str, value: &str) {
151 if let Some(parameter) = Parameter::create(key, context) {
152 let setter = parameter.value_setter(value, context);
153 self.set_character_default(setter);
154 }
155 }
156
157 pub fn extract_settings(
158 &mut self,
159 context: &mut SettingsContext,
160 config_map: &mut IndexMap<Box<str>, Box<str>>,
161 ) {
162 for (key, value) in config_map.drain(..) {
163 self.apply_setting(context, &key, &value);
164 }
165 }
166
167 pub fn reset(&mut self) {
168 self.colors.reset();
169 self.timing.reset();
170 self.objects.reset();
171 self.layout.reset();
172 self.names.reset();
173 }
174}
175
176#[derive(Clone, Debug, PartialEq, Eq, Hash)]
177pub struct NamedParameter<T> {
178 name: Option<Box<str>>,
179 parameter: T,
180}
181
182trait ParameterNamer: Sized {
183 fn named(self, name: Option<Box<str>>) -> NamedParameter<Self> {
184 NamedParameter {
185 name,
186 parameter: self,
187 }
188 }
189}
190
191impl<T> ParameterNamer for T {}
192
193type NamedColorParameter = NamedParameter<ColorParameter>;
194type NamedTimingParameter = NamedParameter<TimingParameter>;
195type NamedImageParameter = NamedParameter<ImageParameter>;
196type NamedObjectImageParameter = NamedParameter<ObjectImageParameter>;
197type NamedObjectLayoutParameter = NamedParameter<ObjectLayoutParameter>;
198type NamedLayoutParameter = NamedParameter<LayoutParameter>;
199
200#[derive(Clone, Debug, PartialEq, Eq, Hash)]
201pub enum Parameter {
202 Color(NamedColorParameter),
203 Timing(NamedTimingParameter),
204 Image(NamedImageParameter),
205 ObjectImage(NamedObjectImageParameter),
206 ObjectLayout(NamedObjectLayoutParameter),
207 Layout(NamedLayoutParameter),
208 Name(Box<str>),
209}
210
211pub struct ImageObject {
212 index: usize,
213 order: HashMap<Box<str>, usize>,
214}
215
216impl ImageObject {
217 fn new(index: usize) -> Self {
218 Self {
219 index,
220 order: HashMap::new(),
221 }
222 }
223}
224
225pub struct LayerInfo {
226 pub name: Box<str>,
227 pub path: Box<str>,
228}
229
230pub fn extract_layers(layers: &mut Vec<LayerInfo>, config_map: &mut IndexMap<Box<str>, Box<str>>) {
231 let keys: Vec<_> = config_map.keys().cloned().collect();
232 for key in keys {
233 let Some(("Layer", name)) = key.split_once(':') else {
234 continue;
235 };
236
237 let path = config_map.shift_remove(&key).expect("Invalid layer");
238 layers.push(LayerInfo {
239 name: name.into(),
240 path,
241 });
242 }
243
244 if layers.is_empty() {
245 layers.push(LayerInfo {
246 name: "Background".into(),
247 path: Box::default(),
248 });
249 layers.push(LayerInfo {
250 name: "Character".into(),
251 path: Box::default(),
252 });
253 }
254}
255
256#[derive(Default)]
257pub struct SettingsContext {
258 pub object_cache: HashMap<Box<str>, ImageObject>,
259 pub layers: Vec<LayerInfo>,
260}
261
262impl SettingsContext {
263 pub fn new() -> Self {
264 Self::default()
265 }
266}
267
268impl Parameter {
269 fn create_character(name: &str, context: &mut SettingsContext) -> Option<Self> {
270 let (main, sub) = name.split_once(':')?;
271
272 if main != "Character" {
273 return None;
274 }
275
276 let (character_name, option) = sub.split_once(':')?;
277
278 let character_name = character_name.into();
279 if option == "name" {
280 Some(Self::Name(character_name))
281 } else {
282 create_parameter(option, Some(character_name), context)
283 }
284 }
285
286 pub fn value_setter(self, value: &str, context: &SettingsContext) -> Setter {
287 fn color(repr: &str) -> Color {
288 match repr {
289 "black" => Color::BLACK,
290 "white" => Color::WHITE,
291
292 "red" => Color::RED,
293 "yellow" => Color::YELLOW,
294 "green" => Color::GREEN,
295 "cyan" => Color::CYAN,
296 "blue" => Color::BLUE,
297 "magenta" => Color::MAGENTA,
298
299 _ => repr
300 .parse::<Color>()
301 .unwrap_or_else(|_| panic!("Color '{repr}' does not exist")),
302 }
303 }
304
305 match self {
306 Self::Color(parameter) => Setter::Color(parameter, color(value)),
307 Self::Timing(parameter) => Setter::Timing(
308 parameter,
309 value.parse().expect("Parsing timing parameter failed"),
310 ),
311 Self::Image(parameter) => Setter::Image(parameter, Some(value.into())),
312 Self::ObjectImage(parameter) => {
313 let index = if value.is_empty() {
314 None
315 } else {
316 let path = &context.layers[parameter.parameter].path;
317 let path_holder;
318 let full_path = if path.is_empty() {
319 value
320 } else {
321 path_holder = format!("{path}:{value}");
322 &path_holder
323 };
324 if let Some(ImageObject { index, .. }) = context.object_cache.get(full_path) {
325 Some(*index)
326 } else {
327 eprintln!("Undefined image object {value:?}");
328 None
329 }
330 };
331 Setter::ObjectImage(parameter, index)
332 }
333 Self::ObjectLayout(parameter) => Setter::ObjectLayout(
334 parameter,
335 value
336 .parse()
337 .expect("Parsing object layout parameter failed"),
338 ),
339 Self::Layout(parameter) => Setter::Layout(
340 parameter,
341 value.parse().expect("Parsing layout parameter failed"),
342 ),
343 Self::Name(parameter) => Setter::Name(parameter, value.into()),
344 }
345 }
346}
347
348fn create_parameter(
349 parameter_name: &str,
350 character_name: Option<Box<str>>,
351 context: &mut SettingsContext,
352) -> Option<Parameter> {
353 let (path, parameter_name) = parameter_name.split_once(':')?;
354 Some(match path {
355 "Color" => Parameter::Color(
356 match parameter_name {
357 "background" => ColorParameter::Background,
358 "foreground" => ColorParameter::Foreground,
359 "dialog-text-fill" => ColorParameter::Dialog(BoxColorParameter::TextFill),
360 "dialog-text-line" => ColorParameter::Dialog(BoxColorParameter::TextLine),
361 "dialog-name-fill" => ColorParameter::Dialog(BoxColorParameter::NameFill),
362 "dialog-name-line" => ColorParameter::Dialog(BoxColorParameter::NameLine),
363
364 "choice-default-text-fill" => ColorParameter::Choice(SelectableBoxColorParameter {
365 selected: false,
366 parameter: BoxColorParameter::TextFill,
367 }),
368 "choice-default-text-line" => ColorParameter::Choice(SelectableBoxColorParameter {
369 selected: false,
370 parameter: BoxColorParameter::TextLine,
371 }),
372 "choice-default-name-fill" => ColorParameter::Choice(SelectableBoxColorParameter {
373 selected: false,
374 parameter: BoxColorParameter::NameFill,
375 }),
376 "choice-default-name-line" => ColorParameter::Choice(SelectableBoxColorParameter {
377 selected: false,
378 parameter: BoxColorParameter::NameLine,
379 }),
380 "choice-select-text-fill" => ColorParameter::Choice(SelectableBoxColorParameter {
381 selected: true,
382 parameter: BoxColorParameter::TextFill,
383 }),
384 "choice-select-text-line" => ColorParameter::Choice(SelectableBoxColorParameter {
385 selected: true,
386 parameter: BoxColorParameter::TextLine,
387 }),
388 "choice-select-name-fill" => ColorParameter::Choice(SelectableBoxColorParameter {
389 selected: true,
390 parameter: BoxColorParameter::NameFill,
391 }),
392 "choice-select-name-line" => ColorParameter::Choice(SelectableBoxColorParameter {
393 selected: true,
394 parameter: BoxColorParameter::NameLine,
395 }),
396
397 "revert-default-text-fill" => ColorParameter::Revert(SelectableBoxColorParameter {
398 selected: false,
399 parameter: BoxColorParameter::TextFill,
400 }),
401 "revert-default-text-line" => ColorParameter::Revert(SelectableBoxColorParameter {
402 selected: false,
403 parameter: BoxColorParameter::TextLine,
404 }),
405 "revert-default-name-fill" => ColorParameter::Revert(SelectableBoxColorParameter {
406 selected: false,
407 parameter: BoxColorParameter::NameFill,
408 }),
409 "revert-default-name-line" => ColorParameter::Revert(SelectableBoxColorParameter {
410 selected: false,
411 parameter: BoxColorParameter::NameLine,
412 }),
413 "revert-select-text-fill" => ColorParameter::Revert(SelectableBoxColorParameter {
414 selected: true,
415 parameter: BoxColorParameter::TextFill,
416 }),
417 "revert-select-text-line" => ColorParameter::Revert(SelectableBoxColorParameter {
418 selected: true,
419 parameter: BoxColorParameter::TextLine,
420 }),
421 "revert-select-name-fill" => ColorParameter::Revert(SelectableBoxColorParameter {
422 selected: true,
423 parameter: BoxColorParameter::NameFill,
424 }),
425 "revert-select-name-line" => ColorParameter::Revert(SelectableBoxColorParameter {
426 selected: true,
427 parameter: BoxColorParameter::NameLine,
428 }),
429
430 _ => return None,
431 }
432 .named(character_name),
433 ),
434
435 "Timing" => Parameter::Timing(
436 match parameter_name {
437 "auto-next" => TimingParameter::AutoNext,
438 "letter" => TimingParameter::Letter,
439 "line" => TimingParameter::Line,
440 "select" => TimingParameter::Select,
441 "view" => TimingParameter::View,
442
443 _ => return None,
444 }
445 .named(character_name),
446 ),
447
448 "Image" => {
449 let (layer_name, parameter_name) = parameter_name.rsplit_once(':')?;
450
451 if !context.object_cache.contains_key(layer_name) {
452 context.object_cache.insert(
453 layer_name.into(),
454 ImageObject::new(context.object_cache.len()),
455 );
456 }
457 let ImageObject { index, order } = context
458 .object_cache
459 .get_mut(layer_name)
460 .expect("Invalid layer");
461
462 if !order.contains_key(parameter_name) {
463 order.insert(parameter_name.into(), order.len());
464 }
465 Parameter::Image((*index, order[parameter_name]).named(character_name))
466 }
467
468 "Object" => {
469 let (layer_name, parameter_name) = parameter_name.split_once(':')?;
470 let layer = context
471 .layers
472 .iter()
473 .position(|layer| &*layer.name == layer_name)?;
474
475 match parameter_name {
476 "image" => Parameter::ObjectImage(layer.named(character_name)),
477 "hor" => Parameter::ObjectLayout(
478 ObjectLayoutParameter {
479 layer,
480 layout: ObjectLayerLayoutParameter::Hor,
481 }
482 .named(character_name),
483 ),
484 "ver" => Parameter::ObjectLayout(
485 ObjectLayoutParameter {
486 layer,
487 layout: ObjectLayerLayoutParameter::Ver,
488 }
489 .named(character_name),
490 ),
491 "scale" => Parameter::ObjectLayout(
492 ObjectLayoutParameter {
493 layer,
494 layout: ObjectLayerLayoutParameter::Scale,
495 }
496 .named(character_name),
497 ),
498
499 _ => return None,
500 }
501 }
502
503 "Layout" => Parameter::Layout(
504 {
505 let (subpath, parameter_name) = parameter_name.split_once(':')?;
506 let box_layout_parameter = || {
507 Some(match parameter_name {
508 "hor" => BoxLayoutParameter::Hor,
509 "ver" => BoxLayoutParameter::Ver,
510 "width" => BoxLayoutParameter::Width,
511 "height" => BoxLayoutParameter::Height,
512 "corner" => BoxLayoutParameter::Corner,
513 "line" => BoxLayoutParameter::Line,
514 "text-size" => BoxLayoutParameter::TextSize,
515 "name-size" => BoxLayoutParameter::NameSize,
516
517 _ => return None,
518 })
519 };
520
521 let view_layout_parameter = || {
522 Some(match parameter_name {
523 "hor" => ViewLayoutParameter::Hor,
524 "ver" => ViewLayoutParameter::Ver,
525 "zoom" => ViewLayoutParameter::Zoom,
526
527 _ => return None,
528 })
529 };
530
531 match subpath {
532 "Main" => box_layout_parameter()?.main(),
533 "List" => box_layout_parameter()?.list(),
534 "View" => LayoutParameter::View(view_layout_parameter()?),
535
536 _ => return None,
537 }
538 }
539 .named(character_name),
540 ),
541
542 _ => return None,
543 })
544}
545
546impl DialogParameter for Parameter {
547 type Context = SettingsContext;
548
549 fn create(name: &str, context: &mut SettingsContext) -> Option<Self> {
550 if name == "-" {
551 None
552 } else if let Some(parameter) = create_parameter(name, None, context) {
553 Some(parameter)
554 } else {
555 let result = Self::create_character(name, context);
556 if result.is_none() {
557 eprintln!("Setting not availabe: {name}");
558 }
559 result
560 }
561 }
562}
563
564pub enum Setter {
565 Color(NamedColorParameter, Color),
566 Timing(NamedTimingParameter, f32),
567 Image(NamedImageParameter, Option<Box<str>>),
568 ObjectImage(NamedObjectImageParameter, Option<usize>),
569 ObjectLayout(NamedObjectLayoutParameter, f32),
570 Layout(NamedLayoutParameter, f32),
571 Name(Box<str>, Box<str>),
572}
573
574impl Setter {
575 pub fn change(self) -> Change {
576 match self {
577 Self::Color(parameter, value) => Change::Color(parameter, Some(value)),
578 Self::Timing(parameter, value) => Change::Timing(parameter, Some(value)),
579 Self::Image(parameter, value) => Change::Image(parameter, Some(value)),
580 Self::ObjectImage(parameter, value) => Change::ObjectImage(parameter, Some(value)),
581 Self::ObjectLayout(parameter, value) => Change::ObjectLayout(parameter, Some(value)),
582 Self::Layout(parameter, value) => Change::Layout(parameter, Some(value)),
583 Self::Name(parameter, value) => Change::Name(parameter, Some(value)),
584 }
585 }
586}
587
588pub enum Change {
589 Color(NamedColorParameter, Option<Color>),
590 Timing(NamedTimingParameter, Option<f32>),
591 Image(NamedImageParameter, Option<Option<Box<str>>>),
592 ObjectImage(NamedObjectImageParameter, Option<Option<usize>>),
593 ObjectLayout(NamedObjectLayoutParameter, Option<f32>),
594 Layout(NamedLayoutParameter, Option<f32>),
595 Name(Box<str>, Option<Box<str>>),
596}
597
598impl Change {
599 pub fn parameter(&self) -> Parameter {
600 match self {
601 Self::Color(parameter, _) => Parameter::Color(parameter.clone()),
602 Self::Timing(parameter, _) => Parameter::Timing(parameter.clone()),
603 Self::Image(parameter, _) => Parameter::Image(parameter.clone()),
604 Self::ObjectImage(parameter, _) => Parameter::ObjectImage(parameter.clone()),
605 Self::ObjectLayout(parameter, _) => Parameter::ObjectLayout(parameter.clone()),
606 Self::Layout(parameter, _) => Parameter::Layout(parameter.clone()),
607 Self::Name(parameter, _) => Parameter::Name(parameter.clone()),
608 }
609 }
610}
611
612impl DialogChange for Change {
613 type Parameter = Parameter;
614
615 fn default_change(parameter: Parameter) -> Self {
616 match parameter {
617 Parameter::Color(parameter) => Self::Color(parameter, None),
618 Parameter::Timing(parameter) => Self::Timing(parameter, None),
619 Parameter::Image(parameter) => Self::Image(parameter, None),
620 Parameter::ObjectImage(parameter) => Self::ObjectImage(parameter, None),
621 Parameter::ObjectLayout(parameter) => Self::ObjectLayout(parameter, None),
622 Parameter::Layout(parameter) => Self::Layout(parameter, None),
623 Parameter::Name(parameter) => Self::Name(parameter, None),
624 }
625 }
626
627 fn value_change(parameter: Parameter, value: &str, context: &mut SettingsContext) -> Self {
628 parameter.value_setter(value, context).change()
629 }
630}
631
632impl PlayerSettings {
633 pub fn revert(&mut self, parameter: &Parameter) {
634 use Parameter::*;
635 match parameter {
636 Color(parameter) => self
637 .colors
638 .get_mut(¶meter.parameter)
639 .set_scene(parameter.name.as_deref(), None),
640 Timing(parameter) => self
641 .timing
642 .get_mut(¶meter.parameter)
643 .set_scene(parameter.name.as_deref(), None),
644 Image(parameter) => self
645 .images
646 .get_mut(¶meter.parameter)
647 .set_scene(parameter.name.as_deref(), None),
648 ObjectImage(parameter) => self
649 .objects
650 .get_mut(¶meter.parameter)
651 .set_scene(parameter.name.as_deref(), None),
652 ObjectLayout(parameter) => self
653 .objects
654 .get_mut(¶meter.parameter)
655 .set_scene(parameter.name.as_deref(), None),
656 Layout(parameter) => self
657 .layout
658 .get_mut(¶meter.parameter)
659 .set_scene(parameter.name.as_deref(), None),
660 Name(parameter) => {
661 self.names.scene.remove(parameter);
662 }
663 }
664 }
665
666 pub fn change(&mut self, change: &Change) {
667 use Change::*;
668 match change {
669 Color(parameter, value) => self
670 .colors
671 .get_mut(¶meter.parameter)
672 .set_scene(parameter.name.as_deref(), *value),
673 Timing(parameter, value) => self
674 .timing
675 .get_mut(¶meter.parameter)
676 .set_scene(parameter.name.as_deref(), *value),
677 Image(parameter, value) => self
678 .images
679 .get_mut(¶meter.parameter)
680 .set_scene(parameter.name.as_deref(), value.clone()),
681 ObjectImage(parameter, value) => self
682 .objects
683 .get_mut(¶meter.parameter)
684 .set_scene(parameter.name.as_deref(), *value),
685 ObjectLayout(parameter, value) => self
686 .objects
687 .get_mut(¶meter.parameter)
688 .set_scene(parameter.name.as_deref(), *value),
689 Layout(parameter, value) => self
690 .layout
691 .get_mut(¶meter.parameter)
692 .set_scene(parameter.name.as_deref(), *value),
693 Name(parameter, value) => {
694 if let Some(value) = value {
695 self.names.scene.insert(parameter.clone(), value.clone());
696 } else {
697 self.names.scene.remove(parameter);
698 }
699 }
700 }
701 }
702
703 pub fn set_character_default(&mut self, change: Setter) {
704 use Setter::*;
705 match change {
706 Color(parameter, value) => self
707 .colors
708 .get_mut(¶meter.parameter)
709 .set_default(parameter.name, value),
710 Timing(parameter, value) => self
711 .timing
712 .get_mut(¶meter.parameter)
713 .set_default(parameter.name, value),
714 Image(parameter, value) => self
715 .images
716 .get_mut(¶meter.parameter)
717 .set_default(parameter.name, value),
718 ObjectImage(parameter, value) => self
719 .objects
720 .get_mut(¶meter.parameter)
721 .set_default(parameter.name, value),
722 ObjectLayout(parameter, value) => self
723 .objects
724 .get_mut(¶meter.parameter)
725 .set_default(parameter.name, value),
726 Layout(parameter, value) => self
727 .layout
728 .get_mut(¶meter.parameter)
729 .set_default(parameter.name, value),
730 Name(parameter, value) => {
731 self.names.default.insert(parameter, value);
732 }
733 }
734 }
735}