1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
//! A resource to hold handles for the fonts used in the game.
//!
//! This is intended to make it trivial to change which font face is used for
//! each type of text in the game. For example, if the user wanted to make it
//! easier to read the text in the game, they could change the font face for
//! the text in the game to a more readable font face.

use bevy::prelude::*;
use bevy_inspector_egui::prelude::*;
use serde::{Deserialize, Serialize};

/// A resource to hold handles for the fonts used in the game.
#[derive(Resource, Debug, Clone, Default, Reflect, InspectorOptions)]
#[reflect(InspectorOptions)]
pub struct FontResource {
    /// The font face used for "display" text.
    ///
    /// This should probably never be changed, as it is used for the game logo.
    pub display_font: Handle<Font>,
    /// The font face used for menus and other interface elements.
    pub interface_font: Handle<Font>,
    /// The font face used for the main text in the game.
    pub main_font: Handle<Font>,
    /// The font face used for the console.
    ///
    /// This should probably never be changed, as it is used for the console.
    pub console_font: Handle<Font>,
    /// The font handle for FontFamily::Display
    pub display_font_handle: Handle<Font>,
    /// The font handle for FontFamily::Fancy
    pub fancy_font_handle: Handle<Font>,
    /// The font handle for FontFamily::Dyslexic
    pub dyslexic_font_handle: Handle<Font>,
    /// The font handle for FontFamily::SansSerif
    pub sans_serif_font_handle: Handle<Font>,
    /// The font handle for FontFamily::Monospace
    pub monospace_font_handle: Handle<Font>,
}

impl FontResource {
    /// Get the font handle for the specified font family.
    #[must_use]
    pub fn get_font_handle(&self, font_family: FontFamily) -> Handle<Font> {
        match font_family {
            FontFamily::Display => self.display_font_handle.clone(),
            FontFamily::Fancy => self.fancy_font_handle.clone(),
            FontFamily::Dyslexic => self.dyslexic_font_handle.clone(),
            FontFamily::SansSerif => self.sans_serif_font_handle.clone(),
            FontFamily::Monospace => self.monospace_font_handle.clone(),
        }
    }
}

/// A choice of font to change.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, InspectorOptions)]
#[reflect(InspectorOptions)]
pub enum FontChoice {
    /// The font face used for "display" text.
    Display,
    /// The font face used for menus and other interface elements.
    Interface,
    /// The font face used for the main text in the game.
    Main,
    /// The font face used for the console.
    Console,
    /// All of the font faces.
    All,
}

/// The generic font-family options. This is used in [`crate::settings::AccessibilitySettings`]
#[derive(
    Debug,
    Clone,
    Copy,
    PartialEq,
    Eq,
    Hash,
    Reflect,
    InspectorOptions,
    Serialize,
    Deserialize,
    Default,
)]
#[reflect(InspectorOptions)]
pub enum FontFamily {
    /// The display font (for the game logo)
    Display,
    /// "Fancy" display text.
    #[default]
    Fancy,
    /// OpenDyslexic
    Dyslexic,
    /// Sans-serif
    SansSerif,
    /// Monospace
    Monospace,
}

impl std::fmt::Display for FontFamily {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Display | Self::Fancy => write!(f, "Fancy"),
            Self::Dyslexic => write!(f, "OpenDyslexic"),
            Self::SansSerif => write!(f, "Sans-Serif"),
            Self::Monospace => write!(f, "Monospace"),
        }
    }
}

impl From<FontFamily> for String {
    fn from(val: FontFamily) -> Self {
        match val {
            FontFamily::Display => "Display".to_string(),
            FontFamily::Fancy => "Fancy".to_string(),
            FontFamily::Dyslexic => "OpenDyslexic".to_string(),
            FontFamily::SansSerif => "Sans-Serif".to_string(),
            FontFamily::Monospace => "Monospace".to_string(),
        }
    }
}

/// Change a font choice. Sending this event will update the specified font
/// choice to the specified font.
#[derive(Event)]
pub struct ChangeFont {
    /// The font choice to change.
    pub font_choice: FontChoice,
    /// The new font to use for the specified font choice.
    pub new_font: Handle<Font>,
}

/// A system to change the font choice.
///
/// This system will change the font choice to the specified font, when the
/// [`ChangeFont`] event is sent.
///
/// Ensure that the [`FontResource`] is inserted into the app resources before
/// this system is run, otherwise bevy will panic.
#[allow(dead_code)]
pub fn change_font(
    mut font_resource: ResMut<FontResource>,
    mut change_font_events: EventReader<ChangeFont>,
) {
    for change_font_event in change_font_events.read() {
        match change_font_event.font_choice {
            FontChoice::Display => {
                font_resource.display_font = change_font_event.new_font.clone();
            }
            FontChoice::Interface => {
                font_resource.interface_font = change_font_event.new_font.clone();
            }
            FontChoice::Main => {
                font_resource.main_font = change_font_event.new_font.clone();
            }
            FontChoice::Console => {
                font_resource.console_font = change_font_event.new_font.clone();
            }
            FontChoice::All => {
                font_resource.interface_font = change_font_event.new_font.clone();
                font_resource.main_font = change_font_event.new_font.clone();
            }
        }
    }
}