Implemented basic tdf support. - icy_draw - icy_draw is the successor to mystic draw. fork / mirror
HTML git clone https://git.drkhsh.at/icy_draw.git
DIR Log
DIR Files
DIR Refs
DIR README
DIR LICENSE
---
DIR commit a2414b526b2a1393decbc70b1761bc5ada7ef3ea
DIR parent 340063f062165a17b0b808f2cce99524f5474b04
HTML Author: Mike Krüger <mkrueger@posteo.de>
Date: Thu, 31 Aug 2023 23:04:57 +0200
Implemented basic tdf support.
Diffstat:
M Cargo.toml | 9 +++++----
M i18n/en/icy_draw.ftl | 11 ++++++++---
M src/model/tools/brush_imp.rs | 19 ++++++++-----------
M src/model/tools/click_imp.rs | 18 ++++++------------
M src/model/tools/draw_ellipse_fille… | 9 ++++-----
M src/model/tools/draw_ellipse_imp.rs | 10 +++++-----
M src/model/tools/draw_rectangle_fil… | 12 +++++-------
M src/model/tools/draw_rectangle_imp… | 10 +++++-----
M src/model/tools/erase_imp.rs | 8 ++++----
M src/model/tools/fill_imp.rs | 17 +++++++++++------
M src/model/tools/flip_imp.rs | 8 ++++----
M src/model/tools/font_imp.rs | 171 ++++++++++++++++++++++++-------
M src/model/tools/line_imp.rs | 12 +++++-------
M src/model/tools/mod.rs | 16 ++++------------
M src/model/tools/move_layer_imp.rs | 8 ++++----
M src/model/tools/pencil_imp.rs | 10 +++++-----
M src/model/tools/pipette_imp.rs | 8 ++++----
M src/ui/dialogs/about_dialog.rs | 2 +-
M src/ui/dialogs/edit_layer_dialog.rs | 2 +-
M src/ui/dialogs/edit_sauce_dialog.rs | 2 +-
M src/ui/dialogs/mod.rs | 4 ++++
M src/ui/dialogs/new_file_dialog.rs | 2 +-
M src/ui/dialogs/select_character_di… | 3 +--
A src/ui/dialogs/select_font_dialog.… | 296 +++++++++++++++++++++++++++++++
M src/ui/dialogs/select_outline_dial… | 2 +-
M src/ui/dialogs/set_canvas_size_dia… | 2 +-
M src/ui/document.rs | 1 -
M src/ui/editor/mod.rs | 28 ++++++----------------------
M src/ui/main_window.rs | 53 +++++++++++++++++++------------
M src/ui/messages.rs | 35 ++++++++++++++++++++++++++++---
M src/ui/top_bar.rs | 16 +++++-----------
31 files changed, 605 insertions(+), 199 deletions(-)
---
DIR diff --git a/Cargo.toml b/Cargo.toml
@@ -19,11 +19,12 @@ egui_file = "0.10.0"
egui_tiles = "0.2"
egui-notify = "0.8.0"
log = "0.4.20"
+open = "5.0.0"
-#icy_engine = { git ="https://github.com/mkrueger/icy_engine" }
-#icy_engine_egui = { git ="https://github.com/mkrueger/icy_engine_egui" }
-icy_engine = { path = "../icy_engine" }
-icy_engine_egui = { path = "../icy_engine_egui" }
+icy_engine = { git ="https://github.com/mkrueger/icy_engine" }
+icy_engine_egui = { git ="https://github.com/mkrueger/icy_engine_egui" }
+#icy_engine = { path = "../icy_engine" }
+#icy_engine_egui = { path = "../icy_engine_egui" }
walkdir = "2"
serde = { version = "1", features = ["derive"], optional = true }
lazy_static = "1.4.0"
DIR diff --git a/i18n/en/icy_draw.ftl b/i18n/en/icy_draw.ftl
@@ -105,7 +105,6 @@ about-dialog-description =
Source code is available at www.github.com/mkrueger/icy_draw
about-dialog-created_by = Created by { $authors }
-
edit-layer-dialog-title=Layer properties
edit-layer-dialog-name-label=Name:
edit-layer-dialog-is-visible-checkbox=Visible
@@ -116,5 +115,11 @@ edit-layer-dialog-is-y-offset-label=Y offset:
edit-layer-dialog-has-alpha-checkbox=Has alpha
edit-layer-dialog-is-alpha-locked-checkbox=Alpha locked
+error-load-file=Error loading file: { $error }
+
-error-load-file=Error loading file: { $error }
-\ No newline at end of file
+select-font-dialog-title=Select Font ({ $fontcount} available)
+select-font-dialog-select=Select
+select-font-dialog-filter-text=Filter fonts
+select-font-dialog-no-fonts=No fonts matches the filter
+select-font-dialog-no-fonts-installed=No fonts installed
+\ No newline at end of file
DIR diff --git a/src/model/tools/brush_imp.rs b/src/model/tools/brush_imp.rs
@@ -7,9 +7,9 @@ use i18n_embed_fl::fl;
use icy_engine::AttributedChar;
use std::{cell::RefCell, rc::Rc};
-use crate::{AnsiEditor, SelectCharacterDialog};
+use crate::{AnsiEditor, Message};
-use super::{Position, Tool, ToolUiResult};
+use super::{Position, Tool};
#[derive(PartialEq, Eq)]
pub enum BrushType {
@@ -116,8 +116,8 @@ impl Tool for BrushTool {
_ctx: &egui::Context,
ui: &mut egui::Ui,
buffer_opt: &AnsiEditor,
- ) -> ToolUiResult {
- let mut result = ToolUiResult::default();
+ ) -> Option<Message> {
+ let mut result = None;
ui.vertical_centered(|ui| {
ui.horizontal(|ui| {
if ui
@@ -154,7 +154,7 @@ impl Tool for BrushTool {
fl!(crate::LANGUAGE_LOADER, "tool-character"),
);
- draw_glyph(ui, buffer_opt, &mut result, &self.char_code, self.font_page);
+ result = draw_glyph(ui, buffer_opt, &self.char_code, self.font_page);
});
ui.radio_value(
&mut self.brush_type,
@@ -190,10 +190,9 @@ impl Tool for BrushTool {
pub fn draw_glyph(
ui: &mut egui::Ui,
editor: &AnsiEditor,
- ui_result: &mut ToolUiResult,
ch: &Rc<RefCell<char>>,
font_page: usize,
-) {
+) -> Option<Message> {
if let Some(font) = editor.buffer_view.lock().buf.get_font(font_page) {
let scale = 1.5;
let (id, stroke_rect) = ui.allocate_space(Vec2::new(
@@ -209,10 +208,7 @@ pub fn draw_glyph(
};
if response.clicked() {
- ui_result.modal_dialog = Some(Box::new(SelectCharacterDialog::new(
- editor.buffer_view.clone(),
- ch.clone(),
- )));
+ return Some(crate::Message::ShowCharacterSelectionDialog(ch.clone()));
}
let painter = ui.painter_at(stroke_rect);
@@ -261,4 +257,5 @@ pub fn draw_glyph(
});
}
}
+ None
}
DIR diff --git a/src/model/tools/click_imp.rs b/src/model/tools/click_imp.rs
@@ -2,9 +2,9 @@ use eframe::egui;
use egui_extras::RetainedImage;
use icy_engine::Selection;
-use crate::AnsiEditor;
+use crate::{AnsiEditor, Message};
-use super::{Event, Position, Tool, ToolUiResult};
+use super::{Event, Position, Tool};
pub struct ClickTool {}
@@ -18,17 +18,14 @@ impl Tool for ClickTool {
_ctx: &egui::Context,
_ui: &mut egui::Ui,
_buffer_opt: &AnsiEditor,
- ) -> ToolUiResult {
- ToolUiResult::default()
+ ) -> Option<Message> {
+ None
}
fn handle_click(&mut self, editor: &mut AnsiEditor, button: i32, pos: Position) -> Event {
if button == 1 {
editor.set_caret_position(pos);
- editor
- .buffer_view
- .lock()
- .clear_selection();
+ editor.buffer_view.lock().clear_selection();
}
Event::None
}
@@ -62,10 +59,7 @@ impl Tool for ClickTool {
}
if start == cur {
- editor
- .buffer_view
- .lock()
- .clear_selection();
+ editor.buffer_view.lock().clear_selection();
}
Event::None
DIR diff --git a/src/model/tools/draw_ellipse_filled_imp.rs b/src/model/tools/draw_ellipse_filled_imp.rs
@@ -2,11 +2,10 @@ use eframe::egui;
use i18n_embed_fl::fl;
use icy_engine::{Rectangle, TextAttribute};
-use crate::AnsiEditor;
+use crate::{AnsiEditor, Message};
use super::{
brush_imp::draw_glyph, plot_point, DrawMode, Event, Plottable, Position, ScanLines, Tool,
- ToolUiResult,
};
pub struct DrawEllipseFilledTool {
@@ -51,8 +50,8 @@ impl Tool for DrawEllipseFilledTool {
_ctx: &egui::Context,
ui: &mut egui::Ui,
editor: &AnsiEditor,
- ) -> ToolUiResult {
- let mut result = ToolUiResult::default();
+ ) -> Option<Message> {
+ let mut result = None;
ui.vertical_centered(|ui| {
ui.horizontal(|ui| {
if ui
@@ -82,7 +81,7 @@ impl Tool for DrawEllipseFilledTool {
fl!(crate::LANGUAGE_LOADER, "tool-character"),
);
- draw_glyph(ui, editor, &mut result, &self.char_code, self.font_page);
+ result = draw_glyph(ui, editor, &self.char_code, self.font_page);
});
ui.radio_value(
&mut self.draw_mode,
DIR diff --git a/src/model/tools/draw_ellipse_imp.rs b/src/model/tools/draw_ellipse_imp.rs
@@ -2,11 +2,11 @@ use eframe::egui;
use i18n_embed_fl::fl;
use icy_engine::{Rectangle, TextAttribute};
-use crate::AnsiEditor;
+use crate::{AnsiEditor, Message};
use super::{
brush_imp::draw_glyph, line_imp::set_half_block, DrawMode, Event, Plottable, Position,
- ScanLines, Tool, ToolUiResult,
+ ScanLines, Tool,
};
pub struct DrawEllipseTool {
@@ -51,8 +51,8 @@ impl Tool for DrawEllipseTool {
_ctx: &egui::Context,
ui: &mut egui::Ui,
editor: &AnsiEditor,
- ) -> ToolUiResult {
- let mut result = ToolUiResult::default();
+ ) -> Option<Message> {
+ let mut result = None;
ui.vertical_centered(|ui| {
ui.horizontal(|ui| {
if ui
@@ -82,7 +82,7 @@ impl Tool for DrawEllipseTool {
fl!(crate::LANGUAGE_LOADER, "tool-character"),
);
- draw_glyph(ui, editor, &mut result, &self.char_code, self.font_page);
+ result = draw_glyph(ui, editor, &self.char_code, self.font_page);
});
ui.radio_value(
&mut self.draw_mode,
DIR diff --git a/src/model/tools/draw_rectangle_filled_imp.rs b/src/model/tools/draw_rectangle_filled_imp.rs
@@ -2,11 +2,9 @@ use eframe::egui;
use i18n_embed_fl::fl;
use icy_engine::{Position, Rectangle, TextAttribute};
-use crate::AnsiEditor;
+use crate::{AnsiEditor, Message};
-use super::{
- brush_imp::draw_glyph, plot_point, DrawMode, Event, Plottable, ScanLines, Tool, ToolUiResult,
-};
+use super::{brush_imp::draw_glyph, plot_point, DrawMode, Event, Plottable, ScanLines, Tool};
pub struct DrawRectangleFilledTool {
pub draw_mode: DrawMode,
@@ -51,8 +49,8 @@ impl Tool for DrawRectangleFilledTool {
_ctx: &egui::Context,
ui: &mut egui::Ui,
editor: &AnsiEditor,
- ) -> ToolUiResult {
- let mut result = ToolUiResult::default();
+ ) -> Option<Message> {
+ let mut result = None;
ui.vertical_centered(|ui| {
ui.horizontal(|ui| {
if ui
@@ -82,7 +80,7 @@ impl Tool for DrawRectangleFilledTool {
fl!(crate::LANGUAGE_LOADER, "tool-character"),
);
- draw_glyph(ui, editor, &mut result, &self.char_code, self.font_page);
+ result = draw_glyph(ui, editor, &self.char_code, self.font_page);
});
ui.radio_value(
&mut self.draw_mode,
DIR diff --git a/src/model/tools/draw_rectangle_imp.rs b/src/model/tools/draw_rectangle_imp.rs
@@ -2,11 +2,11 @@ use eframe::egui;
use i18n_embed_fl::fl;
use icy_engine::{Rectangle, TextAttribute};
-use crate::AnsiEditor;
+use crate::{AnsiEditor, Message};
use super::{
brush_imp::draw_glyph, line_imp::set_half_block, DrawMode, Event, Plottable, Position,
- ScanLines, Tool, ToolUiResult,
+ ScanLines, Tool,
};
pub struct DrawRectangleTool {
@@ -51,8 +51,8 @@ impl Tool for DrawRectangleTool {
_ctx: &egui::Context,
ui: &mut egui::Ui,
editor: &AnsiEditor,
- ) -> ToolUiResult {
- let mut result = ToolUiResult::default();
+ ) -> Option<Message> {
+ let mut result = None;
ui.vertical_centered(|ui| {
ui.horizontal(|ui| {
if ui
@@ -82,7 +82,7 @@ impl Tool for DrawRectangleTool {
fl!(crate::LANGUAGE_LOADER, "tool-character"),
);
- draw_glyph(ui, editor, &mut result, &self.char_code, self.font_page);
+ result = draw_glyph(ui, editor, &self.char_code, self.font_page);
});
ui.radio_value(
&mut self.draw_mode,
DIR diff --git a/src/model/tools/erase_imp.rs b/src/model/tools/erase_imp.rs
@@ -2,9 +2,9 @@ use eframe::egui;
use i18n_embed_fl::fl;
use icy_engine::{AttributedChar, TextAttribute};
-use crate::AnsiEditor;
+use crate::{AnsiEditor, Message};
-use super::{Position, Tool, ToolUiResult};
+use super::{Position, Tool};
#[derive(PartialEq, Eq)]
pub enum EraseType {
@@ -83,7 +83,7 @@ impl Tool for EraseTool {
_ctx: &egui::Context,
ui: &mut egui::Ui,
_buffer_opt: &AnsiEditor,
- ) -> ToolUiResult {
+ ) -> Option<Message> {
ui.horizontal(|ui| {
ui.label(fl!(crate::LANGUAGE_LOADER, "tool-size-label"));
ui.add(
@@ -102,7 +102,7 @@ impl Tool for EraseTool {
EraseType::Shade,
fl!(crate::LANGUAGE_LOADER, "tool-shade"),
);
- ToolUiResult::default()
+ None
}
fn handle_click(
DIR diff --git a/src/model/tools/fill_imp.rs b/src/model/tools/fill_imp.rs
@@ -4,9 +4,9 @@ use eframe::egui;
use i18n_embed_fl::fl;
use icy_engine::{AttributedChar, TextAttribute};
-use crate::AnsiEditor;
+use crate::{AnsiEditor, Message};
-use super::{brush_imp::draw_glyph, Event, Position, Tool, ToolUiResult};
+use super::{brush_imp::draw_glyph, Event, Position, Tool};
#[derive(PartialEq, Eq)]
pub enum FillType {
@@ -33,7 +33,12 @@ impl FillTool {
old_ch: AttributedChar,
new_ch: AttributedChar,
) {
- if pos.x < 0 || pos.y < 0 || pos.x >= editor.buffer_view.lock().buf.get_width() as i32 || pos.x >= editor.buffer_view.lock().buf.get_height() as i32 || !visited.insert(pos) {
+ if pos.x < 0
+ || pos.y < 0
+ || pos.x >= editor.buffer_view.lock().buf.get_width() as i32
+ || pos.x >= editor.buffer_view.lock().buf.get_height() as i32
+ || !visited.insert(pos)
+ {
return;
}
@@ -122,8 +127,8 @@ impl Tool for FillTool {
_ctx: &egui::Context,
ui: &mut egui::Ui,
editor: &AnsiEditor,
- ) -> ToolUiResult {
- let mut result = ToolUiResult::default();
+ ) -> Option<Message> {
+ let mut result = None;
ui.vertical_centered(|ui| {
ui.horizontal(|ui| {
if ui
@@ -148,7 +153,7 @@ impl Tool for FillTool {
fl!(crate::LANGUAGE_LOADER, "tool-character"),
);
- draw_glyph(ui, editor, &mut result, &self.char_code, self.font_page);
+ result = draw_glyph(ui, editor, &self.char_code, self.font_page);
});
ui.radio_value(
&mut self.fill_type,
DIR diff --git a/src/model/tools/flip_imp.rs b/src/model/tools/flip_imp.rs
@@ -1,8 +1,8 @@
use eframe::egui;
-use crate::AnsiEditor;
+use crate::{AnsiEditor, Message};
-use super::{Event, Position, Tool, ToolUiResult};
+use super::{Event, Position, Tool};
pub struct FlipTool {}
impl Tool for FlipTool {
@@ -20,8 +20,8 @@ impl Tool for FlipTool {
_ctx: &egui::Context,
_ui: &mut egui::Ui,
_buffer_opt: &AnsiEditor,
- ) -> ToolUiResult {
- ToolUiResult::default()
+ ) -> Option<Message> {
+ None
}
fn handle_click(&mut self, editor: &mut AnsiEditor, button: i32, pos: Position) -> Event {
DIR diff --git a/src/model/tools/font_imp.rs b/src/model/tools/font_imp.rs
@@ -1,18 +1,21 @@
-use std::fs;
+use std::{
+ fs,
+ sync::{Arc, Mutex},
+};
-use crate::{AnsiEditor, SETTINGS};
+use crate::{AnsiEditor, Message, SETTINGS};
-use super::{Event, MKey, MModifiers, Position, Tool, ToolUiResult};
+use super::{Event, MKey, MModifiers, Position, Tool};
use directories::ProjectDirs;
use eframe::{
- egui::{self, ComboBox},
- epaint::{text::LayoutJob, Color32, FontId},
+ egui::{self, RichText},
+ epaint::{FontFamily, FontId},
};
use icy_engine::{Rectangle, Size, TextAttribute, TheDrawFont};
use walkdir::{DirEntry, WalkDir};
pub struct FontTool {
- pub selected_font: i32,
- pub fonts: Vec<TheDrawFont>,
+ pub selected_font: Arc<Mutex<i32>>,
+ pub fonts: Arc<Mutex<Vec<TheDrawFont>>>,
pub sizes: Vec<Size>,
}
@@ -39,7 +42,7 @@ impl FontTool {
)
});
}
- self.fonts.clear();
+ let mut fonts = Vec::new();
let walker = WalkDir::new(tdf_dir).into_iter();
for entry in walker.filter_entry(|e| !FontTool::is_hidden(e)) {
if let Err(e) = entry {
@@ -64,10 +67,12 @@ impl FontTool {
if extension == "tdf" {
if let Some(font) = TheDrawFont::load(path) {
- self.fonts.push(font);
+ fonts.push(font);
}
}
}
+
+ self.fonts = Arc::new(Mutex::new(fonts));
}
}
}
@@ -85,49 +90,148 @@ impl Tool for FontTool {
_ctx: &egui::Context,
ui: &mut egui::Ui,
_buffer_opt: &AnsiEditor,
- ) -> ToolUiResult {
+ ) -> Option<Message> {
+ let mut select = false;
+ let font_count = self.fonts.lock().unwrap().len();
+ let selected_font = *self.selected_font.lock().unwrap();
+
ui.vertical_centered(|ui| {
+ ui.label("Selected font");
+
let mut selected_text = "<none>".to_string();
- if self.selected_font >= 0 && (self.selected_font as usize) < self.fonts.len() {
- if let Some(font) = self.fonts.get(self.selected_font as usize) {
+ if selected_font >= 0 && (selected_font as usize) < font_count {
+ if let Some(font) = self.fonts.lock().unwrap().get(selected_font as usize) {
selected_text = font.name.clone();
}
}
+ let selected_text =
+ RichText::new(selected_text).font(FontId::new(18.0, FontFamily::Proportional));
+ select = ui.button(selected_text).clicked();
+ });
+
+ ui.add_space(8.0);
+
+ ui.vertical_centered(|ui| {
+ ui.horizontal(|ui| {
+ if let Some(font) = self.fonts.lock().unwrap().get(selected_font as usize) {
+ for ch in '!'..'@' {
+ ui.spacing_mut().item_spacing = eframe::epaint::Vec2::new(0.0, 0.0);
+ let color = if font.has_char(ch as u8) {
+ ui.style().visuals.strong_text_color()
+ } else {
+ ui.style().visuals.text_color()
+ };
- ComboBox::from_label("Font")
- .wrap(false)
- .selected_text(selected_text)
- .show_ui(ui, |ui| {
- for i in 0..self.fonts.len() {
- let text = LayoutJob::simple_singleline(
- self.fonts[i].name.clone(),
- FontId::default(),
- Color32::WHITE,
+ ui.colored_label(
+ color,
+ RichText::new(ch.to_string())
+ .font(FontId::new(12.0, FontFamily::Monospace)),
);
- ui.selectable_value(&mut self.selected_font, i as i32, text);
}
- });
+ }
+ });
+
+ ui.horizontal(|ui| {
+ if let Some(font) = self.fonts.lock().unwrap().get(selected_font as usize) {
+ for ch in '@'..'_' {
+ ui.spacing_mut().item_spacing = eframe::epaint::Vec2::new(0.0, 0.0);
+ let color = if font.has_char(ch as u8) {
+ ui.style().visuals.strong_text_color()
+ } else {
+ ui.style().visuals.text_color()
+ };
+
+ ui.colored_label(
+ color,
+ RichText::new(ch.to_string())
+ .font(FontId::new(12.0, FontFamily::Monospace)),
+ );
+ }
+ }
+ });
+
+ ui.horizontal(|ui| {
+ if let Some(font) = self.fonts.lock().unwrap().get(selected_font as usize) {
+ ui.spacing_mut().item_spacing = eframe::epaint::Vec2::new(0.0, 0.0);
+ for ch in '_'..'~' {
+ let color = if font.has_char(ch as u8) {
+ ui.style().visuals.strong_text_color()
+ } else {
+ ui.style().visuals.text_color()
+ };
+
+ ui.colored_label(
+ color,
+ RichText::new(ch.to_string())
+ .font(FontId::new(12.0, FontFamily::Monospace)),
+ );
+ }
+ }
+ });
+ ui.horizontal(|ui| {
+ if let Some(font) = self.fonts.lock().unwrap().get(selected_font as usize) {
+ ui.spacing_mut().item_spacing = eframe::epaint::Vec2::new(0.0, 0.0);
+ for ch in '~'..='~' {
+ let color = if font.has_char(ch as u8) {
+ ui.style().visuals.strong_text_color()
+ } else {
+ ui.style().visuals.text_color()
+ };
+
+ ui.colored_label(
+ color,
+ RichText::new(ch.to_string())
+ .font(FontId::new(12.0, FontFamily::Monospace)),
+ );
+ }
+ }
+ });
});
- ToolUiResult::default()
+ ui.add_space(32.0);
+ if ui.button("Select Font Outline").clicked() {
+ return Some(Message::ShowOutlineDialog);
+ }
+
+ ui.add_space(32.0);
+ ui.label("Install new fonts in the font directory.");
+ if ui.button("Open font directory").clicked() {
+ if let Some(proj_dirs) = ProjectDirs::from("com", "GitHub", "icy_draw") {
+ let tdf_dir = proj_dirs.config_dir().join("tdf");
+ if let Err(err) = open::that(tdf_dir) {
+ return Some(Message::ShowError(format!(
+ "Can't open font directory: {}",
+ err
+ )));
+ }
+ }
+ }
+
+ if select {
+ Some(Message::SelectFontDialog(
+ self.fonts.clone(),
+ self.selected_font.clone(),
+ ))
+ } else {
+ None
+ }
}
fn handle_click(&mut self, editor: &mut AnsiEditor, button: i32, pos: Position) -> Event {
if button == 1 {
editor.set_caret_position(pos);
- editor
- .buffer_view
- .lock()
- .clear_selection();
+ editor.buffer_view.lock().clear_selection();
}
Event::None
}
fn handle_key(&mut self, editor: &mut AnsiEditor, key: MKey, modifier: MModifiers) -> Event {
- if self.selected_font < 0 || self.selected_font >= self.fonts.len() as i32 {
+ let selected_font = *self.selected_font.lock().unwrap();
+
+ if selected_font < 0 || selected_font >= self.fonts.lock().unwrap().len() as i32 {
return Event::None;
}
- let font = &self.fonts[self.selected_font as usize];
+ let font = &self.fonts.lock().unwrap()[selected_font as usize];
let pos = editor.buffer_view.lock().caret.get_position();
match key {
@@ -190,10 +294,7 @@ impl Tool for FontTool {
MKey::Backspace => {
let letter_size = self.sizes.pop().unwrap_or_else(|| Size::new(1, 1));
- editor
- .buffer_view
- .lock()
- .clear_selection();
+ editor.buffer_view.lock().clear_selection();
let pos = editor.get_caret_position();
if pos.x > 0 {
editor.set_caret_position(pos + Position::new(-(letter_size.width as i32), 0));
@@ -236,7 +337,7 @@ impl Tool for FontTool {
let c_pos = editor.get_caret_position();
editor.begin_atomic_undo();
let attr = editor.buffer_view.lock().caret.get_attribute();
- let opt_size = font.render(
+ let opt_size: Option<Size> = font.render(
&mut editor.buffer_view.lock().buf,
0,
c_pos.as_uposition(),
DIR diff --git a/src/model/tools/line_imp.rs b/src/model/tools/line_imp.rs
@@ -2,11 +2,9 @@ use eframe::egui;
use i18n_embed_fl::fl;
use icy_engine::{AttributedChar, Rectangle, TextAttribute};
-use crate::{model::ScanLines, AnsiEditor};
+use crate::{model::ScanLines, AnsiEditor, Message};
-use super::{
- brush_imp::draw_glyph, plot_point, DrawMode, Event, Plottable, Position, Tool, ToolUiResult,
-};
+use super::{brush_imp::draw_glyph, plot_point, DrawMode, Event, Plottable, Position, Tool};
pub struct LineTool {
pub draw_mode: DrawMode,
@@ -194,8 +192,8 @@ impl Tool for LineTool {
_ctx: &egui::Context,
ui: &mut egui::Ui,
editor: &AnsiEditor,
- ) -> ToolUiResult {
- let mut result = ToolUiResult::default();
+ ) -> Option<Message> {
+ let mut result = None;
ui.vertical_centered(|ui| {
ui.horizontal(|ui| {
if ui
@@ -225,7 +223,7 @@ impl Tool for LineTool {
fl!(crate::LANGUAGE_LOADER, "tool-character"),
);
- draw_glyph(ui, editor, &mut result, &self.char_code, self.font_page);
+ result = draw_glyph(ui, editor, &self.char_code, self.font_page);
});
ui.radio_value(
&mut self.draw_mode,
DIR diff --git a/src/model/tools/mod.rs b/src/model/tools/mod.rs
@@ -20,7 +20,7 @@ use egui_extras::RetainedImage;
use icy_engine::{AttributedChar, Position, TextAttribute};
pub use scan_lines::*;
-use crate::{AnsiEditor, Event};
+use crate::{AnsiEditor, Event, Message};
pub mod scan_lines;
#[derive(Copy, Clone, Debug)]
@@ -76,11 +76,6 @@ impl MModifiers {
}
}
-#[derive(Default)]
-pub struct ToolUiResult {
- pub modal_dialog: Option<Box<dyn crate::ModalDialog>>,
-}
-
pub trait Tool {
fn get_icon_name(&self) -> &'static RetainedImage;
@@ -97,7 +92,7 @@ pub trait Tool {
ctx: &egui::Context,
ui: &mut egui::Ui,
buffer_opt: &AnsiEditor,
- ) -> ToolUiResult;
+ ) -> Option<Message>;
fn handle_key(&mut self, editor: &mut AnsiEditor, key: MKey, modifier: MModifiers) -> Event {
// TODO Keys:
@@ -389,11 +384,8 @@ fn handle_outline_insertion(editor: &mut AnsiEditor, modifier: MModifiers, outli
return;
}
}
- editor
- .buffer_view
- .lock()
- .clear_selection();
-let ch = editor.get_outline_char_code(outline);
+ editor.buffer_view.lock().clear_selection();
+ let ch = editor.get_outline_char_code(outline);
if let Ok(ch) = ch {
editor.type_key(unsafe { char::from_u32_unchecked(ch as u32) });
}
DIR diff --git a/src/model/tools/move_layer_imp.rs b/src/model/tools/move_layer_imp.rs
@@ -1,5 +1,5 @@
-use super::{Event, Position, Tool, ToolUiResult};
-use crate::AnsiEditor;
+use super::{Event, Position, Tool};
+use crate::{AnsiEditor, Message};
use eframe::egui;
pub struct MoveLayer {
@@ -21,8 +21,8 @@ impl Tool for MoveLayer {
_ctx: &egui::Context,
_ui: &mut egui::Ui,
_buffer_opt: &AnsiEditor,
- ) -> ToolUiResult {
- ToolUiResult::default()
+ ) -> Option<Message> {
+ None
}
fn handle_drag_begin(
DIR diff --git a/src/model/tools/pencil_imp.rs b/src/model/tools/pencil_imp.rs
@@ -6,9 +6,9 @@ use egui_extras::RetainedImage;
use i18n_embed_fl::fl;
use icy_engine::{AttributedChar, Rectangle};
-use crate::{model::ScanLines, AnsiEditor};
+use crate::{model::ScanLines, AnsiEditor, Message};
-use super::{brush_imp::draw_glyph, line_imp::set_half_block, Position, Tool, ToolUiResult};
+use super::{brush_imp::draw_glyph, line_imp::set_half_block, Position, Tool};
#[derive(PartialEq, Eq)]
pub enum PencilType {
@@ -125,8 +125,8 @@ impl Tool for PencilTool {
_ctx: &egui::Context,
ui: &mut egui::Ui,
buffer_opt: &AnsiEditor,
- ) -> ToolUiResult {
- let mut result = ToolUiResult::default();
+ ) -> Option<Message> {
+ let mut result = None;
ui.vertical_centered(|ui| {
ui.horizontal(|ui| {
if ui
@@ -160,7 +160,7 @@ impl Tool for PencilTool {
fl!(crate::LANGUAGE_LOADER, "tool-character"),
);
- draw_glyph(ui, buffer_opt, &mut result, &self.char_code, self.font_page);
+ result = draw_glyph(ui, buffer_opt, &self.char_code, self.font_page);
});
ui.radio_value(
&mut self.brush_type,
DIR diff --git a/src/model/tools/pipette_imp.rs b/src/model/tools/pipette_imp.rs
@@ -1,8 +1,8 @@
use eframe::egui;
-use crate::AnsiEditor;
+use crate::{AnsiEditor, Message};
-use super::{Event, Position, Tool, ToolUiResult};
+use super::{Event, Position, Tool};
pub struct PipetteTool {}
impl Tool for PipetteTool {
@@ -20,8 +20,8 @@ impl Tool for PipetteTool {
_ctx: &egui::Context,
_ui: &mut egui::Ui,
_buffer_opt: &AnsiEditor,
- ) -> ToolUiResult {
- ToolUiResult::default()
+ ) -> Option<Message> {
+ None
}
fn handle_click(&mut self, editor: &mut AnsiEditor, button: i32, pos: Position) -> Event {
DIR diff --git a/src/ui/dialogs/about_dialog.rs b/src/ui/dialogs/about_dialog.rs
@@ -12,7 +12,7 @@ pub struct AboutDialog {
impl crate::ModalDialog for AboutDialog {
fn show(&mut self, ctx: &egui::Context) -> bool {
let mut result = false;
- let modal = Modal::new(ctx, "my_modal");
+ let modal = Modal::new(ctx, "help_dialog");
modal.show(|ui| {
modal.title(ui, fl!(crate::LANGUAGE_LOADER, "about-dialog-title"));
DIR diff --git a/src/ui/dialogs/edit_layer_dialog.rs b/src/ui/dialogs/edit_layer_dialog.rs
@@ -48,7 +48,7 @@ impl EditLayerDialog {
impl ModalDialog for EditLayerDialog {
fn show(&mut self, ctx: &egui::Context) -> bool {
let mut result = false;
- let modal: Modal = Modal::new(ctx, "my_modal");
+ let modal: Modal = Modal::new(ctx, "edit_layer_dialog");
modal.show(|ui| {
modal.title(ui, fl!(crate::LANGUAGE_LOADER, "edit-layer-dialog-title"));
DIR diff --git a/src/ui/dialogs/edit_sauce_dialog.rs b/src/ui/dialogs/edit_sauce_dialog.rs
@@ -28,7 +28,7 @@ impl EditSauceDialog {
impl ModalDialog for EditSauceDialog {
fn show(&mut self, ctx: &egui::Context) -> bool {
let mut result = false;
- let modal: Modal = Modal::new(ctx, "my_modal");
+ let modal: Modal = Modal::new(ctx, "edit_sauce_dialog");
modal.show(|ui| {
modal.title(ui, fl!(crate::LANGUAGE_LOADER, "edit-sauce-title"));
DIR diff --git a/src/ui/dialogs/mod.rs b/src/ui/dialogs/mod.rs
@@ -24,5 +24,9 @@ pub use edit_layer_dialog::*;
mod open_file_dialog;
pub use open_file_dialog::*;
+
mod save_file_dialog;
pub use save_file_dialog::*;
+
+mod select_font_dialog;
+pub use select_font_dialog::*;
DIR diff --git a/src/ui/dialogs/new_file_dialog.rs b/src/ui/dialogs/new_file_dialog.rs
@@ -25,7 +25,7 @@ impl Default for NewFileDialog {
impl crate::ModalDialog for NewFileDialog {
fn show(&mut self, ctx: &egui::Context) -> bool {
let mut result = false;
- let modal = Modal::new(ctx, "my_modal");
+ let modal = Modal::new(ctx, "new_file_dialog");
modal.show(|ui| {
modal.title(ui, fl!(crate::LANGUAGE_LOADER, "new-file-title"));
DIR diff --git a/src/ui/dialogs/select_character_dialog.rs b/src/ui/dialogs/select_character_dialog.rs
@@ -33,7 +33,7 @@ impl ModalDialog for SelectCharacterDialog {
fn show(&mut self, ctx: &egui::Context) -> bool {
let font_page = 0;
let mut result = false;
- let modal = Modal::new(ctx, "my_modal");
+ let modal = Modal::new(ctx, "select_character_dialog");
modal.show(|ui| {
modal.title(ui, fl!(crate::LANGUAGE_LOADER, "select-character-title"));
@@ -73,7 +73,6 @@ impl ModalDialog for SelectCharacterDialog {
}
}
});
- // });
ui.horizontal(|ui| {
ui.label(RichText::new(fl!(crate::LANGUAGE_LOADER, "glyph-char-label")).small());
DIR diff --git a/src/ui/dialogs/select_font_dialog.rs b/src/ui/dialogs/select_font_dialog.rs
@@ -0,0 +1,296 @@
+use std::sync::{Arc, Mutex};
+
+use eframe::{
+ egui::{self, RichText, TextEdit},
+ epaint::{ahash::HashMap, ColorImage, FontFamily, FontId, Stroke},
+};
+use egui_extras::RetainedImage;
+use egui_modal::Modal;
+use i18n_embed_fl::fl;
+use icy_engine::{Buffer, Size, TextAttribute, TheDrawFont, UPosition};
+
+use crate::MainWindow;
+
+pub struct SelectFontDialog {
+ fonts: Arc<Mutex<Vec<TheDrawFont>>>,
+ selected_font_arc: Arc<Mutex<i32>>,
+ selected_font: i32,
+ pub do_select: bool,
+ filter: String,
+ show_outline: bool,
+ show_color: bool,
+ show_block: bool,
+
+ image_cache: HashMap<usize, RetainedImage>,
+}
+
+impl SelectFontDialog {
+ pub fn new(fonts: Arc<Mutex<Vec<TheDrawFont>>>, selected_font_arc: Arc<Mutex<i32>>) -> Self {
+ let selected_font = *selected_font_arc.lock().unwrap();
+
+ Self {
+ do_select: false,
+ fonts,
+ selected_font_arc,
+ selected_font,
+ filter: String::new(),
+ show_outline: true,
+ show_color: true,
+ show_block: true,
+ image_cache: HashMap::default(),
+ }
+ }
+}
+
+impl crate::ModalDialog for SelectFontDialog {
+ fn show(&mut self, ctx: &egui::Context) -> bool {
+ let mut result = false;
+ let modal = Modal::new(ctx, "select_font_dialog");
+ let font_count = self.fonts.lock().unwrap().len();
+ modal.show(|ui| {
+ modal.title(
+ ui,
+ fl!(
+ crate::LANGUAGE_LOADER,
+ "select-font-dialog-title",
+ fontcount = font_count
+ ),
+ );
+ modal.frame(ui, |ui| {
+ let row_height = 176.0 / 2.0;
+ ui.horizontal(|ui: &mut egui::Ui| {
+ ui.add_sized(
+ [250.0, 20.0],
+ TextEdit::singleline(&mut self.filter).hint_text(fl!(
+ crate::LANGUAGE_LOADER,
+ "select-font-dialog-filter-text"
+ )),
+ );
+ let response = ui.button("🗙");
+ if response.clicked() {
+ self.filter.clear();
+ }
+
+ let response = ui.selectable_label(self.show_color, "COLOR");
+ if response.clicked() {
+ self.show_color = !self.show_color;
+ }
+
+ let response = ui.selectable_label(self.show_block, "BLOCK");
+ if response.clicked() {
+ self.show_block = !self.show_block;
+ }
+
+ let response = ui.selectable_label(self.show_outline, "OUTLINE");
+ if response.clicked() {
+ self.show_outline = !self.show_outline;
+ }
+ });
+ ui.add_space(4.0);
+
+ let mut filtered_fonts = Vec::new();
+
+ for i in 0..font_count {
+ let font = &self.fonts.lock().unwrap()[i];
+ if font
+ .name
+ .to_lowercase()
+ .contains(&self.filter.to_lowercase())
+ && (self.show_outline
+ && matches!(font.font_type, icy_engine::TheDrawFontType::Outline)
+ || self.show_block
+ && matches!(font.font_type, icy_engine::TheDrawFontType::Block)
+ || self.show_color
+ && matches!(font.font_type, icy_engine::TheDrawFontType::Color))
+ {
+ filtered_fonts.push(i);
+ }
+ }
+ if filtered_fonts.is_empty() {
+ if font_count == 0 {
+ ui.label(fl!(
+ crate::LANGUAGE_LOADER,
+ "select-font-dialog-no-fonts-installed"
+ ));
+ } else {
+ ui.label(fl!(crate::LANGUAGE_LOADER, "select-font-dialog-no-fonts"));
+ }
+ } else {
+ egui::ScrollArea::vertical().max_height(300.).show_rows(
+ ui,
+ row_height,
+ filtered_fonts.len(),
+ |ui, range| {
+ for row in range {
+ let font = &self.fonts.lock().unwrap()[filtered_fonts[row]];
+ ui.horizontal(|ui: &mut egui::Ui| {
+ ui.vertical(|ui| {
+ ui.horizontal(|ui| {
+ let font_type = match font.font_type {
+ icy_engine::TheDrawFontType::Outline => "OUTLINE",
+ icy_engine::TheDrawFontType::Block => "BLOCK",
+ icy_engine::TheDrawFontType::Color => "COLOR",
+ };
+ let response = ui.label(font_type);
+ ui.painter().rect_stroke(
+ response.rect.expand(2.0),
+ 4.0,
+ Stroke::new(1.0, ctx.style().visuals.text_color()),
+ );
+
+ let sel = ui.selectable_label(
+ self.selected_font == filtered_fonts[row] as i32,
+ font.name.clone(),
+ );
+ if sel.clicked() {
+ self.selected_font = filtered_fonts[row] as i32;
+ }
+ if sel.double_clicked() {
+ self.selected_font = filtered_fonts[row] as i32;
+ self.do_select = true;
+ result = true;
+ }
+ });
+ ui.horizontal(|ui| {
+ for ch in '!'..'P' {
+ ui.spacing_mut().item_spacing =
+ eframe::epaint::Vec2::new(0.0, 0.0);
+ let color = if font.has_char(ch as u8) {
+ ui.style().visuals.strong_text_color()
+ } else {
+ ui.style().visuals.text_color()
+ };
+
+ ui.colored_label(
+ color,
+ RichText::new(ch.to_string()).font(
+ FontId::new(12.0, FontFamily::Monospace),
+ ),
+ );
+ }
+ });
+
+ ui.horizontal(|ui| {
+ ui.spacing_mut().item_spacing =
+ eframe::epaint::Vec2::new(0.0, 0.0);
+ for ch in 'P'..='~' {
+ let color = if font.has_char(ch as u8) {
+ ui.style().visuals.strong_text_color()
+ } else {
+ ui.style().visuals.text_color()
+ };
+
+ ui.colored_label(
+ color,
+ RichText::new(ch.to_string()).font(
+ FontId::new(12.0, FontFamily::Monospace),
+ ),
+ );
+ }
+ });
+ });
+
+ if let Some(img) = self.image_cache.get(&filtered_fonts[row]) {
+ img.show_scaled(ui, 0.5);
+ } else {
+ let mut buffer = Buffer::new((100, 11));
+ let mut pos = UPosition::default();
+ let attr = TextAttribute::default();
+ let outline_style = 0;
+
+ for ch in "HELLO".bytes() {
+ let opt_size: Option<Size> = font.render(
+ &mut buffer,
+ 0,
+ pos,
+ attr,
+ outline_style,
+ ch,
+ );
+ if let Some(size) = opt_size {
+ pos.x += size.width + font.spaces as usize;
+ }
+ }
+ let img = create_retained_image(&buffer);
+ img.show_scaled(ui, 0.5);
+ self.image_cache.insert(filtered_fonts[row], img);
+ }
+ });
+ }
+ },
+ );
+ }
+ });
+
+ modal.buttons(ui, |ui| {
+ if ui
+ .button(fl!(crate::LANGUAGE_LOADER, "select-font-dialog-select"))
+ .clicked()
+ {
+ self.do_select = true;
+ result = true;
+ }
+ if ui
+ .button(fl!(crate::LANGUAGE_LOADER, "new-file-cancel"))
+ .clicked()
+ {
+ result = true;
+ }
+ });
+ });
+ modal.open();
+ result
+ }
+
+ fn should_commit(&self) -> bool {
+ self.do_select
+ }
+
+ fn commit_self(&self, _window: &mut MainWindow) -> crate::TerminalResult<bool> {
+ *self.selected_font_arc.lock().unwrap() = self.selected_font;
+ Ok(true)
+ }
+}
+
+pub fn create_retained_image(buf: &Buffer) -> RetainedImage {
+ let font_size = buf.get_font(0).unwrap().size;
+
+ let px_width = buf.get_width() * font_size.width;
+ let px_height = buf.get_height() * font_size.height;
+ let line_bytes = px_width * 3;
+ let mut pixels = vec![0; line_bytes * px_height];
+
+ for y in 0..buf.get_height() {
+ for x in 0..buf.get_width() {
+ let ch = buf.get_char((x, y));
+ let font = buf.get_font(ch.get_font_page()).unwrap();
+
+ let (fg_r, fg_g, fg_b) =
+ buf.palette.colors[ch.attribute.get_foreground() as usize].get_rgb();
+ let (bg_r, bg_g, bg_b) =
+ buf.palette.colors[ch.attribute.get_background() as usize].get_rgb();
+
+ if let Some(glyph) = font.get_glyph(ch.ch) {
+ for cy in 0..font_size.height {
+ for cx in 0..font_size.width {
+ let offset = (x * font_size.width + cx) * 3
+ + (y * font_size.height + cy) * line_bytes;
+ if glyph.data[cy] & (128 >> cx) != 0 {
+ pixels[offset] = fg_r;
+ pixels[offset + 1] = fg_g;
+ pixels[offset + 2] = fg_b;
+ } else {
+ pixels[offset] = bg_r;
+ pixels[offset + 1] = bg_g;
+ pixels[offset + 2] = bg_b;
+ }
+ }
+ }
+ }
+ }
+ }
+ RetainedImage::from_color_image(
+ "buf_img",
+ ColorImage::from_rgb([px_width, px_height], &pixels),
+ )
+}
DIR diff --git a/src/ui/dialogs/select_outline_dialog.rs b/src/ui/dialogs/select_outline_dialog.rs
@@ -101,7 +101,7 @@ const OUTLINE_FONT_CHAR: [u8; 48] = [
impl ModalDialog for SelectOutlineDialog {
fn show(&mut self, ctx: &egui::Context) -> bool {
let mut result = false;
- let modal = Modal::new(ctx, "my_modal");
+ let modal = Modal::new(ctx, "select_outline_dialog");
modal.show(|ui| {
modal.title(
DIR diff --git a/src/ui/dialogs/set_canvas_size_dialog.rs b/src/ui/dialogs/set_canvas_size_dialog.rs
@@ -24,7 +24,7 @@ impl SetCanvasSizeDialog {
impl ModalDialog for SetCanvasSizeDialog {
fn show(&mut self, ctx: &egui::Context) -> bool {
let mut result = false;
- let modal = Modal::new(ctx, "my_modal");
+ let modal = Modal::new(ctx, "set_canvas_size_dialog");
modal.show(|ui| {
modal.title(ui, fl!(crate::LANGUAGE_LOADER, "edit-canvas-size-title"));
DIR diff --git a/src/ui/document.rs b/src/ui/document.rs
@@ -21,7 +21,6 @@ pub trait Document {
fn get_ansi_editor_mut(&mut self) -> Option<&mut AnsiEditor>;
fn get_ansi_editor(&self) -> Option<&AnsiEditor>;
-
}
pub struct DocumentOptions {
DIR diff --git a/src/ui/editor/mod.rs b/src/ui/editor/mod.rs
@@ -323,7 +323,7 @@ impl AnsiEditor {
self.buffer_view.lock().buf.layers[self.cur_layer].get_char(pos)
}
- pub fn set_char(&mut self, pos: impl Into <UPosition>, dos_char: AttributedChar) {
+ pub fn set_char(&mut self, pos: impl Into<UPosition>, dos_char: AttributedChar) {
let pos = pos.into();
self.redo_stack.clear();
let old = self.buffer_view.lock().buf.layers[self.cur_layer].get_char(pos);
@@ -383,16 +383,10 @@ impl AnsiEditor {
}
fn cur_selection(&self) -> Option<icy_engine::Selection> {
- self
- .buffer_view
- .lock()
- .get_selection().clone()
+ self.buffer_view.lock().get_selection().clone()
}
fn clear_selection(&self) {
- self
- .buffer_view
- .lock()
- .clear_selection();
+ self.buffer_view.lock().clear_selection();
}
pub fn type_key(&mut self, char_code: char) {
@@ -417,7 +411,7 @@ impl AnsiEditor {
println!("delete selection! {} - {} ", min, max);
for y in min.y..=max.y {
for x in min.x..=max.x {
- self.set_char( (x, y), AttributedChar::invisible());
+ self.set_char((x, y), AttributedChar::invisible());
}
}
self.end_atomic_undo();
@@ -434,20 +428,10 @@ impl AnsiEditor {
if let Some(selection) = &self.cur_selection() {
let min = selection.min();
let max = selection.max();
- (
- min.x,
- min.y,
- max.x,
- max.y,
- )
+ (min.x, min.y, max.x, max.y)
} else {
let size = self.buffer_view.lock().buf.get_buffer_size();
- (
- 0,
- 0,
- size.width as i32 - 1,
- size.height as i32 - 1,
- )
+ (0, 0, size.width as i32 - 1, size.height as i32 - 1)
}
}
DIR diff --git a/src/ui/main_window.rs b/src/ui/main_window.rs
@@ -1,4 +1,11 @@
-use std::{cell::RefCell, fs, path::Path, rc::Rc, sync::{Arc, Mutex}, time::Duration};
+use std::{
+ cell::RefCell,
+ fs,
+ path::Path,
+ rc::Rc,
+ sync::{Arc, Mutex},
+ time::Duration,
+};
use crate::{
add_child, model::Tool, AnsiEditor, DockingContainer, Document, DocumentOptions, FontEditor,
@@ -14,8 +21,8 @@ use icy_engine::{BitFont, Buffer, Position};
pub struct MainWindow {
pub tree: egui_tiles::Tree<Tab>,
- toasts: egui_notify::Toasts,
-
+ pub toasts: egui_notify::Toasts,
+
pub tab_viewer: TabBehavior,
pub gl: Arc<Context>,
@@ -36,8 +43,8 @@ impl MainWindow {
pub fn new(cc: &eframe::CreationContext<'_>) -> Self {
let mut fnt = crate::model::font_imp::FontTool {
- selected_font: 0,
- fonts: Vec::new(),
+ selected_font: Arc::new(Mutex::new(0)),
+ fonts: Arc::new(Mutex::new(Vec::new())),
sizes: Vec::new(),
};
fnt.load_fonts();
@@ -135,7 +142,7 @@ impl MainWindow {
toasts: egui_notify::Toasts::default(),
tree: DockingContainer::default(),
gl: cc.gl.clone().unwrap(),
- dialog_open: false,
+ dialog_open: false,
modal_dialog: None,
id: 0,
left_panel: true,
@@ -176,9 +183,12 @@ impl MainWindow {
Err(err) => {
log::error!("Error loading file: {}", err);
self.toasts
- .error(fl!(crate::LANGUAGE_LOADER, "error-load-file", error = err.to_string()))
- .set_duration(Some(Duration::from_secs(5)));
-
+ .error(fl!(
+ crate::LANGUAGE_LOADER,
+ "error-load-file",
+ error = err.to_string()
+ ))
+ .set_duration(Some(Duration::from_secs(5)));
}
}
}
@@ -257,8 +267,6 @@ impl MainWindow {
}
}
-
-
pub fn get_active_document_mut(&mut self) -> Option<&mut Box<dyn Document>> {
if let Some(pane) = self.get_active_pane() {
return Some(&mut pane.doc);
@@ -320,18 +328,21 @@ impl eframe::App for MainWindow {
}
}
crate::add_tool_switcher(ctx, ui, self);
- let modal = if let Some(tool) = self.tab_viewer.tools.clone().lock().unwrap().get_mut(self.tab_viewer.selected_tool) {
+ if let Some(tool) = self
+ .tab_viewer
+ .tools
+ .clone()
+ .lock()
+ .unwrap()
+ .get_mut(self.tab_viewer.selected_tool)
+ {
if let Some(doc) = self.get_active_document_mut() {
- let doc = doc.get_ansi_editor();
+ let doc = doc.get_ansi_editor();
if let Some(editor) = doc {
let tool_result = tool.show_ui(ctx, ui, editor);
- tool_result.modal_dialog
- } else { None }
- } else { None }
- } else { None };
-
- if modal.is_some() {
- self.modal_dialog = modal;
+ self.handle_message(tool_result);
+ }
+ }
}
});
@@ -391,7 +402,7 @@ impl eframe::App for MainWindow {
fn on_exit(&mut self, _gl: Option<&glow::Context>) {
/* TODO
-
+
self.enumerate_documents( move |doc| {
doc.destroy(gl);
});*/
DIR diff --git a/src/ui/messages.rs b/src/ui/messages.rs
@@ -1,9 +1,17 @@
-use std::path::PathBuf;
+use std::{
+ cell::RefCell,
+ path::PathBuf,
+ rc::Rc,
+ sync::{Arc, Mutex},
+};
use eframe::egui;
-use icy_engine::Selection;
+use icy_engine::{Selection, TheDrawFont};
-use crate::{MainWindow, NewFileDialog, OpenFileDialog, SaveFileDialog, SelectOutlineDialog};
+use crate::{
+ MainWindow, NewFileDialog, OpenFileDialog, SaveFileDialog, SelectCharacterDialog,
+ SelectOutlineDialog,
+};
pub enum Message {
NewFile,
@@ -29,6 +37,9 @@ pub enum Message {
DeleteSelection,
ShowAboutDialog,
+ ShowCharacterSelectionDialog(Rc<RefCell<char>>),
+ SelectFontDialog(Arc<Mutex<Vec<TheDrawFont>>>, Arc<Mutex<i32>>),
+ ShowError(String),
}
pub const CTRL_SHIFT: egui::Modifiers = egui::Modifiers {
@@ -139,6 +150,19 @@ impl MainWindow {
}
}
+ Message::ShowCharacterSelectionDialog(ch) => {
+ if let Some(doc) = self.get_active_document_mut() {
+ let doc = doc.get_ansi_editor_mut();
+ if let Some(editor) = doc {
+ let buf = editor.buffer_view.clone();
+ self.open_dialog(SelectCharacterDialog::new(buf, ch));
+ }
+ }
+ }
+ Message::SelectFontDialog(fonts, selected_font) => {
+ self.open_dialog(crate::SelectFontDialog::new(fonts, selected_font));
+ }
+
Message::EditSauce => {
let mut buffer_opt = None;
if let Some(doc) = self.get_active_document_mut() {
@@ -244,6 +268,11 @@ impl MainWindow {
Message::ShowAboutDialog => {
self.open_dialog(crate::AboutDialog::default());
}
+
+ Message::ShowError(msg) => {
+ log::error!("{msg}");
+ self.toasts.error(msg);
+ }
}
}
}
DIR diff --git a/src/ui/top_bar.rs b/src/ui/top_bar.rs
@@ -13,21 +13,15 @@ impl MainWindow {
frame: &mut eframe::Frame,
) -> Option<Message> {
let mut result = None;
- TopBottomPanel::top("top_panel")
- .show(ctx, |ui| {
- result = self.main_menu(ui, frame);
- });
+ TopBottomPanel::top("top_panel").show(ctx, |ui| {
+ result = self.main_menu(ui, frame);
+ });
result
}
- fn main_menu(
- &mut self,
- ui: &mut Ui,
- frame: &mut eframe::Frame,
- ) -> Option<Message> {
+ fn main_menu(&mut self, ui: &mut Ui, frame: &mut eframe::Frame) -> Option<Message> {
let mut result = None;
menu::bar(ui, |ui| {
-
let mut buffer_opt = None;
if let Some(doc) = self.get_active_document_mut() {
buffer_opt = doc.get_ansi_editor_mut();
@@ -362,7 +356,7 @@ impl MainWindow {
fn top_bar_ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame) {
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
// From right-to-left:
-/*
+ /*
if hypex_ui::CUSTOM_WINDOW_DECORATIONS {
ui.add_space(8.0);
hypex_ui::native_window_buttons_ui(frame, ui);