font_manager.rs - icy_draw - icy_draw is the successor to mystic draw. fork / mirror
(HTM) git clone https://git.drkhsh.at/icy_draw.git
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
font_manager.rs (10712B)
---
1 use std::sync::Arc;
2
3 use crate::{AnsiEditor, Message, TerminalResult};
4 use eframe::{
5 egui::{self, Button, Sense, TextStyle, TopBottomPanel, WidgetText},
6 epaint::{FontFamily, FontId, Rounding},
7 };
8 use egui_modal::Modal;
9 use i18n_embed_fl::fl;
10
11 pub struct FontManager {
12 selected: usize,
13 replace_with: usize,
14 do_select: bool,
15 buffer_view: Arc<eframe::epaint::mutex::Mutex<icy_engine_egui::BufferView>>,
16 used_fonts: Vec<usize>,
17 }
18
19 impl FontManager {
20 pub fn new(editor: &AnsiEditor) -> Self {
21 let used_fonts = icy_engine::analyze_font_usage(editor.buffer_view.lock().get_buffer());
22 Self {
23 selected: 0,
24 do_select: false,
25 replace_with: 0,
26 buffer_view: editor.buffer_view.clone(),
27 used_fonts,
28 }
29 }
30
31 fn update_used_fonts(&mut self) {
32 let lock = &self.buffer_view.lock();
33 self.used_fonts = icy_engine::analyze_font_usage(lock.get_buffer());
34 }
35 }
36
37 impl crate::ModalDialog for FontManager {
38 fn show(&mut self, ctx: &egui::Context) -> bool {
39 let mut result = false;
40 let modal = Modal::new(ctx, "manage_font_dialog");
41 modal.show(|ui| {
42 ui.set_height(320.);
43 ui.set_width(600.);
44
45 modal.title(ui, fl!(crate::LANGUAGE_LOADER, "manage-font-dialog-title"));
46 modal.frame(ui, |ui| {
47 egui::CentralPanel::default().show_inside(ui, |ui| {
48 let row_height = 24.0;
49 ui.label(fl!(crate::LANGUAGE_LOADER, "manage-font-used_font_label"));
50 egui::ScrollArea::vertical().id_source("bitfont_scroll_area").show(ui, |ui| {
51 for (i, font) in self.buffer_view.lock().get_buffer().font_iter() {
52 let is_selected = *i == self.selected;
53
54 let (id, rect) = ui.allocate_space([ui.available_width(), row_height].into());
55 let response = ui.interact(rect, id, Sense::click());
56 if response.hovered() {
57 ui.painter()
58 .rect_filled(rect.expand(1.0), Rounding::same(4.0), ui.style().visuals.widgets.active.bg_fill);
59 } else if is_selected {
60 ui.painter()
61 .rect_filled(rect.expand(1.0), Rounding::same(4.0), ui.style().visuals.extreme_bg_color);
62 }
63
64 let font_id = FontId::new(12.0, FontFamily::Monospace);
65 let text: WidgetText = format!("{i:-3}.").into();
66 let galley = text.into_galley(ui, Some(false), f32::INFINITY, font_id.clone());
67 let size = galley.size();
68 let mut title_rect = rect;
69 title_rect.set_left(title_rect.left() + 4.0);
70 title_rect.set_top(title_rect.bottom() - size.y - 8.0);
71 let text_color = if is_selected {
72 ui.style().visuals.strong_text_color()
73 } else {
74 ui.style().visuals.text_color()
75 };
76 ui.painter().galley_with_override_text_color(
77 egui::Align2::LEFT_TOP.align_size_within_rect(galley.size(), title_rect.shrink(4.0)).min,
78 galley,
79 text_color,
80 );
81
82 let font_id = TextStyle::Button.resolve(ui.style());
83 let text: WidgetText = font.name.clone().into();
84 let galley = text.into_galley(ui, Some(false), f32::INFINITY, font_id);
85 let mut title_rect = rect;
86 title_rect.set_left(title_rect.left() + 4.0 + size.x + 4.0);
87 ui.painter().galley_with_override_text_color(
88 egui::Align2::LEFT_TOP.align_size_within_rect(galley.size(), title_rect.shrink(4.0)).min,
89 galley,
90 text_color,
91 );
92
93 let font_id = TextStyle::Button.resolve(ui.style());
94 let text: WidgetText = format!("{}x{}", font.size.width, font.size.height).into();
95 let galley = text.into_galley(ui, Some(false), f32::INFINITY, font_id);
96 let mut title_rect = rect;
97 title_rect.set_left(title_rect.left() + 399.0);
98 ui.painter().galley_with_override_text_color(
99 egui::Align2::LEFT_TOP.align_size_within_rect(galley.size(), title_rect.shrink(4.0)).min,
100 galley,
101 text_color,
102 );
103
104 let font_id = TextStyle::Button.resolve(ui.style());
105 let text: WidgetText = if self.used_fonts.contains(i) {
106 fl!(crate::LANGUAGE_LOADER, "manage-font-used_label")
107 } else {
108 fl!(crate::LANGUAGE_LOADER, "manage-font-not_used_label")
109 }
110 .into();
111 let galley = text.into_galley(ui, Some(false), f32::INFINITY, font_id);
112 let mut title_rect = rect;
113 title_rect.set_left(title_rect.left() + 480.0);
114 ui.painter().galley_with_override_text_color(
115 egui::Align2::LEFT_TOP.align_size_within_rect(galley.size(), title_rect.shrink(4.0)).min,
116 galley,
117 text_color,
118 );
119
120 if response.clicked() {
121 self.selected = *i;
122 }
123 }
124 });
125 });
126 TopBottomPanel::bottom("font_manager_bottom_panel")
127 .exact_height(24.0)
128 .resizable(false)
129 .show_inside(ui, |ui| {
130 ui.add_space(8.0);
131
132 ui.horizontal(|ui| {
133 ui.label(fl!(crate::LANGUAGE_LOADER, "manage-font-replace_label"));
134 let mut tmp_str = self.replace_with.to_string();
135 ui.add(egui::TextEdit::singleline(&mut tmp_str).desired_width(80.0).char_limit(4));
136 if let Ok(new_width) = tmp_str.parse::<usize>() {
137 self.replace_with = new_width;
138 } else {
139 self.replace_with = 0;
140 }
141 let enabled = self.buffer_view.lock().get_buffer().get_font(self.replace_with).is_some();
142 if ui
143 .add_enabled(enabled, Button::new(fl!(crate::LANGUAGE_LOADER, "manage-font-replace_font_button")))
144 .clicked()
145 {
146 if let Err(err) = self
147 .buffer_view
148 .lock()
149 .get_edit_state_mut()
150 .replace_font_usage(self.selected, self.replace_with)
151 {
152 log::error!("Error replacing font {}->{}: {err}", self.selected, self.replace_with);
153 }
154 self.update_used_fonts();
155 self.selected = 0;
156 self.replace_with = 0;
157 self.do_select = true;
158 }
159
160 if ui
161 .add_enabled(!enabled, Button::new(fl!(crate::LANGUAGE_LOADER, "manage-font-change_font_slot_button")))
162 .clicked()
163 {
164 if let Err(err) = self.buffer_view.lock().get_edit_state_mut().change_font_slot(self.selected, self.replace_with) {
165 log::error!("Error change font {}->{}: {err}", self.selected, self.replace_with);
166 }
167 self.update_used_fonts();
168 self.selected = 0;
169 self.replace_with = 0;
170 self.do_select = true;
171 }
172 });
173 });
174 });
175 ui.add_space(8.0);
176 modal.buttons(ui, |ui| {
177 if ui.button(fl!(crate::LANGUAGE_LOADER, "new-file-ok")).clicked() {
178 result = true;
179 }
180
181 let copy_font_button = ui.add(Button::new(fl!(crate::LANGUAGE_LOADER, "manage-font-copy_font_button")));
182 let copy_font_button = copy_font_button.on_hover_ui(|ui| {
183 ui.label(fl!(crate::LANGUAGE_LOADER, "manage-font-copy_font_button-tooltip"));
184 });
185
186 if copy_font_button.clicked() {
187 let lock = &self.buffer_view.lock();
188 if let Some(font) = lock.get_buffer().get_font(self.selected) {
189 ui.output_mut(|o| o.copied_text = font.encode_as_ansi(self.selected));
190 }
191 }
192 let remove_font_button = &ui.add_enabled(self.selected > 0, Button::new(fl!(crate::LANGUAGE_LOADER, "manage-font-remove_font_button")));
193 if remove_font_button.clicked() {
194 if let Err(err) = self.buffer_view.lock().get_edit_state_mut().remove_font(self.selected) {
195 log::error!("Error removing font {}: {err}", self.selected);
196 }
197 self.update_used_fonts();
198 self.replace_with = 0;
199 self.do_select = true;
200 }
201 });
202 });
203 modal.open();
204 result
205 }
206
207 fn should_commit(&self) -> bool {
208 self.do_select
209 }
210
211 fn commit(&self, _editor: &mut AnsiEditor) -> TerminalResult<Option<Message>> {
212 Ok(None)
213 }
214 }