URI: 
       app.rs - icy_draw - [fork] icy_draw is the successor to mystic draw.
  HTML git clone https://git.drkhsh.at/icy_draw.git
   DIR Log
   DIR Files
   DIR Refs
   DIR README
       ---
       app.rs (10260B)
       ---
            1 #![allow(unsafe_code, clippy::wildcard_imports)]
            2 
            3 use std::{path::PathBuf, sync::Arc, time::Duration};
            4 
            5 use directories::UserDirs;
            6 use eframe::egui::{self};
            7 use egui::{mutex::Mutex, FontId, Rect};
            8 use icy_engine::Position;
            9 use icy_net::{
           10     protocol::TransferState,
           11     telnet::{TermCaps, TerminalEmulation},
           12     ConnectionType,
           13 };
           14 use web_time::Instant;
           15 
           16 use crate::{
           17     features::AutoFileTransfer,
           18     get_unicode_converter,
           19     ui::{connect::OpenConnectionData, dialogs, terminal_thread::TerminalThread, BufferView, MainWindowState, ScreenMode},
           20     util::SoundThread,
           21     AddressBook, Options,
           22 };
           23 
           24 use super::{MainWindow, MainWindowMode};
           25 
           26 impl MainWindow {
           27     pub fn new(cc: &eframe::CreationContext<'_>, options: Options) -> Self {
           28         use egui::FontFamily::Proportional;
           29         use egui::TextStyle::{Body, Button, Heading, Monospace, Small};
           30         egui_extras::install_image_loaders(&cc.egui_ctx);
           31 
           32         let gl = cc.gl.as_ref().expect("You need to run eframe with the glow backend");
           33         let mut view = BufferView::new(gl);
           34         view.interactive = true;
           35         view.get_edit_state_mut().set_unicode_converter(get_unicode_converter(&TerminalEmulation::Ansi));
           36 
           37         let addresses: AddressBook = match crate::addresses::start_read_book() {
           38             Ok(addresses) => addresses,
           39             Err(e) => {
           40                 log::error!("Error reading dialing_directory: {e}");
           41                 AddressBook::default()
           42             }
           43         };
           44 
           45         //  #[cfg(not(target_arch = "wasm32"))]
           46         // let is_fullscreen_mode = cc.integration_info.window_info.fullscreen;
           47         //  #[cfg(target_arch = "wasm32")]
           48         let is_fullscreen_mode = false;
           49 
           50         // try to detect dark vs light mode from the host system; default to dark
           51         let is_dark = if let Some(dark_mode) = &options.is_dark_mode {
           52             *dark_mode
           53         } else {
           54             dark_light::detect() != dark_light::Mode::Light
           55         };
           56         let ctx: &egui::Context = &cc.egui_ctx;
           57         ctx.set_visuals(if is_dark { egui::Visuals::dark() } else { egui::Visuals::light() });
           58 
           59         let mut initial_upload_directory = None;
           60 
           61         if let Some(dirs) = UserDirs::new() {
           62             initial_upload_directory = Some(dirs.home_dir().to_path_buf());
           63         }
           64         let buffer_update_view = Arc::new(eframe::epaint::mutex::Mutex::new(view));
           65 
           66         let buffer_update_thread = Arc::new(Mutex::new(TerminalThread {
           67             buffer_view: buffer_update_view.clone(),
           68             capture_dialog: dialogs::capture_dialog::DialogState::default(),
           69             auto_file_transfer: AutoFileTransfer::default(),
           70             auto_transfer: None,
           71             auto_login: None,
           72             sound_thread: Arc::new(eframe::epaint::mutex::Mutex::new(SoundThread::new())),
           73             terminal_type: None,
           74             mouse_field: Vec::new(),
           75             cache_directory: PathBuf::new(),
           76             is_connected: false,
           77             connection_time: Instant::now(),
           78             current_transfer: TransferState::new(String::new()),
           79         }));
           80 
           81         let data = OpenConnectionData {
           82             address: "".to_string(),
           83             user_name: "".to_string(),
           84             password: "".to_string(),
           85             connection_type: ConnectionType::Telnet,
           86             timeout: Duration::from_secs(1000),
           87             use_ansi_music: icy_engine::ansi::MusicOption::Off,
           88             baud_emulation: icy_engine::ansi::BaudEmulation::Off,
           89             proxy_command: None,
           90             term_caps: TermCaps {
           91                 window_size: (0, 0),
           92                 terminal: TerminalEmulation::Ascii,
           93             },
           94             modem: None,
           95         };
           96 
           97         let (update_thread_handle, tx, rx) = crate::ui::terminal_thread::start_update_thread(&cc.egui_ctx, data, buffer_update_thread.clone());
           98         let mut parser = icy_engine::ansi::Parser::default();
           99         parser.bs_is_ctrl_char = true;
          100         let buffer_parser = Box::new(parser);
          101         let mut view = MainWindow {
          102             buffer_view: buffer_update_view.clone(),
          103             //address_list: HoverList::new(),
          104             state: MainWindowState { options, ..Default::default() },
          105             initial_upload_directory,
          106             screen_mode: ScreenMode::default(),
          107             #[cfg(target_arch = "wasm32")]
          108             poll_thread,
          109             is_fullscreen_mode,
          110             export_dialog: dialogs::export_dialog::DialogState::default(),
          111             upload_dialog: dialogs::upload_dialog::DialogState::default(),
          112             dialing_directory_dialog: dialogs::dialing_directory_dialog::DialogState::new(addresses),
          113             drag_start: None,
          114             last_pos: Position::default(),
          115             terminal_thread: buffer_update_thread,
          116             terminal_thread_handle: Some(update_thread_handle),
          117             tx,
          118             rx,
          119             show_find_dialog: false,
          120             find_dialog: dialogs::find_dialog::DialogState::default(),
          121             shift_pressed_during_selection: false,
          122             use_rip: false,
          123             buffer_parser,
          124             title: String::new(),
          125             show_disconnect: false,
          126         };
          127 
          128         #[cfg(not(target_arch = "wasm32"))]
          129         parse_command_line(&ctx, &mut view);
          130 
          131         let mut style: egui::Style = (*ctx.style()).clone();
          132         style.spacing.window_margin = egui::Margin::same(8.0);
          133 
          134         //        style.spacing.button_padding = Vec2::new(4., 2.);
          135         style.text_styles = [
          136             (Heading, FontId::new(24.0, Proportional)),
          137             (Body, FontId::new(18.0, Proportional)),
          138             (Monospace, FontId::new(18.0, egui::FontFamily::Monospace)),
          139             (Button, FontId::new(18.0, Proportional)),
          140             (Small, FontId::new(14.0, Proportional)),
          141         ]
          142         .into();
          143         ctx.set_style(style);
          144         view
          145     }
          146 }
          147 
          148 #[cfg(not(target_arch = "wasm32"))]
          149 fn parse_command_line(ctx: &egui::Context, view: &mut MainWindow) {
          150     let args: Vec<String> = std::env::args().collect();
          151     if let Some(arg) = args.get(1) {
          152         view.dialing_directory_dialog.addresses.addresses[0].address = arg.clone();
          153         view.call_bbs(ctx, 0);
          154     }
          155 }
          156 
          157 impl eframe::App for MainWindow {
          158     fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
          159         #[cfg(not(target_arch = "wasm32"))]
          160         self.update_title(ctx);
          161 
          162         ctx.input(|i| {
          163             if let Some(or) = i.viewport().outer_rect {
          164                 if let Some(ir) = i.viewport().inner_rect {
          165                     let rect = Rect {
          166                         min: or.min,
          167                         max: (ir.max - ir.min).to_pos2(),
          168                     };
          169                     if self.state.options.window_rect != Some(rect) {
          170                         self.state.options.window_rect = Some(rect);
          171                         self.state.store_options();
          172                     }
          173                 }
          174             }
          175         });
          176 
          177         match self.get_mode() {
          178             MainWindowMode::ShowTerminal => {
          179                 self.handle_terminal_key_binds(ctx);
          180                 self.update_terminal_window(ctx, frame, false);
          181             }
          182             MainWindowMode::ShowDialingDirectory => {
          183                 self.update_terminal_window(ctx, frame, true);
          184             }
          185             MainWindowMode::ShowSettings => {
          186                 self.update_terminal_window(ctx, frame, false);
          187                 self.state.show_settings(ctx, frame);
          188             }
          189             MainWindowMode::DeleteSelectedAddress(uuid) => {
          190                 self.update_terminal_window(ctx, frame, true);
          191                 super::dialogs::show_delete_address_confirmation::show_dialog(self, ctx, uuid);
          192             }
          193 
          194             MainWindowMode::SelectProtocol(download) => {
          195                 self.update_terminal_window(ctx, frame, false);
          196                 dialogs::protocol_selector::view_selector(self, ctx, frame, download);
          197             }
          198 
          199             MainWindowMode::FileTransfer(download) => {
          200                 self.update_terminal_window(ctx, frame, false);
          201                 let state = self.terminal_thread.lock().current_transfer.clone();
          202                 // auto close uploads.
          203                 if !download && state.is_finished {
          204                     self.set_mode(ctx, MainWindowMode::ShowTerminal);
          205                 }
          206                 match dialogs::up_download_dialog::FileTransferDialog::new().show_dialog(ctx, frame, &state, download) {
          207                     dialogs::up_download_dialog::FileTransferDialogAction::Run => {}
          208                     dialogs::up_download_dialog::FileTransferDialogAction::Close | dialogs::up_download_dialog::FileTransferDialogAction::CancelTransfer => {
          209                         if state.is_finished {
          210                             self.set_mode(ctx, MainWindowMode::ShowTerminal);
          211                         } else {
          212                             self.send_data(super::connect::SendData::CancelTransfer);
          213                             self.set_mode(ctx, MainWindowMode::ShowTerminal);
          214                         }
          215                     }
          216                 }
          217             }
          218             MainWindowMode::ShowCaptureDialog => {
          219                 self.update_terminal_window(ctx, frame, false);
          220                 if !self.terminal_thread.lock().capture_dialog.show_caputure_dialog(ctx) {
          221                     self.set_mode(ctx, MainWindowMode::ShowTerminal);
          222                 }
          223             }
          224             MainWindowMode::ShowExportDialog => {
          225                 self.update_terminal_window(ctx, frame, false);
          226                 self.show_export_dialog(ctx);
          227             }
          228             MainWindowMode::ShowUploadDialog => {
          229                 self.update_terminal_window(ctx, frame, false);
          230                 self.show_upload_dialog(ctx);
          231             }
          232             MainWindowMode::ShowIEMSI => {
          233                 self.update_terminal_window(ctx, frame, false);
          234                 dialogs::show_iemsi::show_iemsi(self, ctx);
          235             } // MainWindowMode::AskDeleteEntry => todo!(),
          236 
          237             MainWindowMode::ShowDisconnectedMessage(time, system) => {
          238                 self.update_terminal_window(ctx, frame, false);
          239                 dialogs::show_disconnected_message::show_disconnected(self, ctx, time, system);
          240             }
          241         }
          242     }
          243 
          244     /*  fn on_exit(&mut self, gl: Option<&glow::Context>) {
          245         if let Some(gl) = gl {
          246             self.buffer_view.lock().destroy(gl);
          247         }
          248     }*/
          249 }