URI: 
       Pipette has now a rectangle preview. - 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 88ee4fb050ff59a9c22b4fd5b8c370a4099cb1af
   DIR parent ea7c02267c95733eefbd38ec493d3857ff1182b2
  HTML Author: Mike Krüger <mkrueger@posteo.de>
       Date:   Wed,  4 Oct 2023 14:43:11 +0200
       
       Pipette has now a rectangle preview.
       
       + fixed dock button icons.
       
       Diffstat:
         M src/main.rs                         |       2 +-
         M src/model/tools/pipette_imp.rs      |      20 +++++++++++++++++---
         M src/ui/editor/animation/gif_encode… |      17 +++++++++++------
         M src/ui/editor/animation/mod.rs      |     402 +++++++++++++++----------------
         M src/ui/top_bar.rs                   |       4 ++--
       
       5 files changed, 230 insertions(+), 215 deletions(-)
       ---
   DIR diff --git a/src/main.rs b/src/main.rs
       @@ -56,7 +56,7 @@ fn main() {
                initial_window_size: Some(egui::vec2(1280., 841.)),
                multisampling: 0,
                renderer: eframe::Renderer::Glow,
       -        icon_data: Some(IconData::try_from_png_bytes(&include_bytes!("../build/linux/256x256.png")[..]).unwrap(),),
       +        icon_data: Some(IconData::try_from_png_bytes(&include_bytes!("../build/linux/256x256.png")[..]).unwrap()),
                ..Default::default()
            };
        
   DIR diff --git a/src/model/tools/pipette_imp.rs b/src/model/tools/pipette_imp.rs
       @@ -67,11 +67,18 @@ impl Tool for PipetteTool {
                None
            }
        
       -    fn handle_hover(&mut self, _ui: &egui::Ui, response: egui::Response, editor: &mut AnsiEditor, cur: Position, _cur_abs: Position) -> egui::Response {
       +    fn handle_hover(&mut self, _ui: &egui::Ui, response: egui::Response, editor: &mut AnsiEditor, cur: Position, cur_abs: Position) -> egui::Response {
                unsafe {
                    CUR_CHAR = Some(editor.get_char(cur));
                }
       -        self.cur_pos = Some(cur);
       +        if self.cur_pos != Some(cur) {
       +            self.cur_pos = Some(cur);
       +            let lock = &mut editor.buffer_view.lock();
       +            let get_tool_overlay_mask_mut = lock.get_edit_state_mut().get_tool_overlay_mask_mut();
       +            get_tool_overlay_mask_mut.clear();
       +            get_tool_overlay_mask_mut.set_is_selected(cur_abs, true);
       +            lock.get_edit_state_mut().is_buffer_dirty = true;
       +        }
        
                response.on_hover_cursor(egui::CursorIcon::Crosshair)
            }
       @@ -84,11 +91,18 @@ impl Tool for PipetteTool {
                }
            }
        
       -    fn handle_no_hover(&mut self, _editor: &mut AnsiEditor) {
       +    fn handle_no_hover(&mut self, editor: &mut AnsiEditor) {
                unsafe {
                    CUR_CHAR = None;
                }
                self.cur_pos = None;
       +
       +        let lock: &mut eframe::epaint::mutex::MutexGuard<'_, icy_engine_egui::BufferView> = &mut editor.buffer_view.lock();
       +        let get_edit_state_mut = lock.get_edit_state_mut();
       +        if !get_edit_state_mut.get_tool_overlay_mask_mut().is_empty() {
       +            get_edit_state_mut.get_tool_overlay_mask_mut().clear();
       +            get_edit_state_mut.is_buffer_dirty = true;
       +        }
            }
        
            fn handle_click(&mut self, editor: &mut AnsiEditor, button: i32, pos: Position, _pos_abs: Position, _response: &egui::Response) -> Option<Message> {
   DIR diff --git a/src/ui/editor/animation/gif_encoder.rs b/src/ui/editor/animation/gif_encoder.rs
       @@ -19,25 +19,30 @@ impl AnimationEncoder for GifEncoder {
            }
        
            fn encode(&self, path: &Path, frames: Vec<(Vec<u8>, u32)>, width: usize, height: usize, sender: Sender<usize>) -> TerminalResult<()> {
       -        
       -        let settings = gifski::Settings { width: Some(width as u32), height: Some(height as u32), quality: 100, fast: true, repeat: Repeat::Infinite };
       +        let settings = gifski::Settings {
       +            width: Some(width as u32),
       +            height: Some(height as u32),
       +            quality: 100,
       +            fast: true,
       +            repeat: Repeat::Infinite,
       +        };
        
                let (c, w) = gifski::new(settings)?;
                let mut time = 0.0;
                let mut pb = NoProgress {};
                let path = path.to_path_buf();
       -        std::thread::spawn(move || w.write(std::fs::File::create(path).unwrap(), &mut pb) .unwrap());
       +        std::thread::spawn(move || w.write(std::fs::File::create(path).unwrap(), &mut pb).unwrap());
        
                for (frame_idx, (data, duration)) in frames.into_iter().enumerate() {
                    sender.send(frame_idx)?;
       -            let mut n = 0; 
       +            let mut n = 0;
                    let mut d = Vec::new();
                    while n < data.len() {
       -                d.push(rgb::RGBA::new (data[n], data[n+1], data[n+2], data[n+3]));
       +                d.push(rgb::RGBA::new(data[n], data[n + 1], data[n + 2], data[n + 3]));
                        n += 4;
                    }
        
       -            let img: ImgVec<RGBA8> = imgref::Img::new( d, width, height);
       +            let img: ImgVec<RGBA8> = imgref::Img::new(d, width, height);
                    c.add_frame_rgba(frame_idx, img, time / 1000.0)?;
                    time += duration as f64;
                }
   DIR diff --git a/src/ui/editor/animation/mod.rs b/src/ui/editor/animation/mod.rs
       @@ -147,7 +147,7 @@ impl Document for AnimationEditor {
                self.undostack
            }
        
       -    fn show_ui(&mut self, ui: &mut eframe::egui::Ui, _cur_tool: &mut Box<dyn Tool>, _selected_tool: usize, options: &DocumentOptions) -> Option<Message> {
       +    fn show_ui(&mut self, ui: &mut eframe::egui::Ui, _cur_tool: &mut Box<dyn Tool>, _selected_tool: usize, _options: &DocumentOptions) -> Option<Message> {
                let mut message = None;
        
                if self.first_frame && self.animator.lock().unwrap().success() {
       @@ -160,7 +160,7 @@ impl Document for AnimationEditor {
                    self.first_frame = false;
                }
                if let Some(next) = &self.next_animator {
       -            if next.lock().unwrap().success() || !next.lock().unwrap().error.is_empty()  {
       +            if next.lock().unwrap().success() || !next.lock().unwrap().error.is_empty() {
                        self.animator = next.clone();
                        self.next_animator = None;
                        let animator = &mut self.animator.lock().unwrap();
       @@ -173,237 +173,233 @@ impl Document for AnimationEditor {
                    .default_width(ui.available_width() / 2.0)
                    .min_width(660.0)
                    .show_inside(ui, |ui| {
       -             
       -            ui.horizontal(|ui| {
       -                if !self.animator.lock().unwrap().error.is_empty() {
       -                    ui.set_enabled(false);
       -                }
       +                ui.horizontal(|ui| {
       +                    if !self.animator.lock().unwrap().error.is_empty() {
       +                        ui.set_enabled(false);
       +                    }
        
       -                if self.animator.lock().unwrap().success() {
       -                    let animator = &mut self.animator.lock().unwrap();
       -                    let frame_count = animator.frames.len();
       -                    if animator.is_playing() {
       -                        if ui.add(ImageButton::new(crate::PAUSE_SVG.clone())).clicked() {
       -                            animator.set_is_playing(false);
       -                        }
       -                    } else {
       -                        let image: &Image<'static> = if animator.get_cur_frame() + 1 < frame_count {
       -                            &crate::PLAY_SVG
       +                    if self.animator.lock().unwrap().success() {
       +                        let animator = &mut self.animator.lock().unwrap();
       +                        let frame_count = animator.frames.len();
       +                        if animator.is_playing() {
       +                            if ui.add(ImageButton::new(crate::PAUSE_SVG.clone())).clicked() {
       +                                animator.set_is_playing(false);
       +                            }
                                } else {
       -                            &crate::REPLAY_SVG
       -                        };
       -                        if ui.add(ImageButton::new(image.clone())).clicked() {
       -                            if animator.get_cur_frame() + 1 >= frame_count {
       -                                animator.set_cur_frame(0);
       +                            let image: &Image<'static> = if animator.get_cur_frame() + 1 < frame_count {
       +                                &crate::PLAY_SVG
       +                            } else {
       +                                &crate::REPLAY_SVG
       +                            };
       +                            if ui.add(ImageButton::new(image.clone())).clicked() {
       +                                if animator.get_cur_frame() + 1 >= frame_count {
       +                                    animator.set_cur_frame(0);
       +                                }
       +                                animator.start_playback(self.buffer_view.clone());
                                    }
       -                            animator.start_playback(self.buffer_view.clone());
                                }
       -                    }
       -                    if ui
       -                        .add_enabled(animator.get_cur_frame() + 1 < frame_count, ImageButton::new(crate::SKIP_NEXT_SVG.clone()))
       -                        .clicked()
       -                    {
       -                        animator.set_cur_frame(frame_count - 1);
       -                        animator.display_frame(self.buffer_view.clone());
       -                    }
       -                    let is_loop = animator.get_is_loop();
       -                    if ui.add(ImageButton::new(crate::REPEAT_SVG.clone()).selected(is_loop)).clicked() {
       -                        animator.set_is_loop(!is_loop);
       -                    }
       -
       -                    let mut cf = animator.get_cur_frame() + 1;
       -
       -                    
       -
       -                    if frame_count > 0 && ui.add(Slider::new(&mut cf, 1..=frame_count).text(fl!(
       -                        crate::LANGUAGE_LOADER,
       -                        "animation_of_frame_count",
       -                        total = frame_count
       -                    ))).changed() {
       -                        animator.set_cur_frame(cf - 1);
       -                        animator.display_frame(self.buffer_view.clone());
       -                    }
       -
       -                    if ui
       -                        .add_enabled(animator.get_cur_frame() > 0, ImageButton::new(crate::NAVIGATE_PREV.clone()))
       -                        .clicked()
       -                    {
       -                        let cf = animator.get_cur_frame() - 1;
       -                        animator.set_cur_frame(cf);
       -                        animator.display_frame(self.buffer_view.clone());
       -                    }
       +                        if ui
       +                            .add_enabled(animator.get_cur_frame() + 1 < frame_count, ImageButton::new(crate::SKIP_NEXT_SVG.clone()))
       +                            .clicked()
       +                        {
       +                            animator.set_cur_frame(frame_count - 1);
       +                            animator.display_frame(self.buffer_view.clone());
       +                        }
       +                        let is_loop = animator.get_is_loop();
       +                        if ui.add(ImageButton::new(crate::REPEAT_SVG.clone()).selected(is_loop)).clicked() {
       +                            animator.set_is_loop(!is_loop);
       +                        }
        
       -                    if ui
       -                        .add_enabled(
       -                            animator.get_cur_frame() + 1 < animator.frames.len(),
       -                            ImageButton::new(crate::NAVIGATE_NEXT.clone()),
       -                        )
       -                        .clicked()
       -                    {
       -                        let cf = animator.get_cur_frame() + 1;
       -                        animator.set_cur_frame(cf);
       -                        animator.display_frame(self.buffer_view.clone());
       -                    }
       +                        let mut cf = animator.get_cur_frame() + 1;
        
       -                    ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
       -                        if ui.button(if self.scale < 2.0 { "2x" } else { "1x" }).clicked() {
       -                            if self.scale < 2.0 {
       -                                self.scale = 2.0;
       -                            } else {
       -                                self.scale = 1.0;
       -                            }
       +                        if frame_count > 0
       +                            && ui
       +                                .add(Slider::new(&mut cf, 1..=frame_count).text(fl!(crate::LANGUAGE_LOADER, "animation_of_frame_count", total = frame_count)))
       +                                .changed()
       +                        {
       +                            animator.set_cur_frame(cf - 1);
       +                            animator.display_frame(self.buffer_view.clone());
                                }
       -                    });
       -                }
       -            });
        
       +                        if ui
       +                            .add_enabled(animator.get_cur_frame() > 0, ImageButton::new(crate::NAVIGATE_PREV.clone()))
       +                            .clicked()
       +                        {
       +                            let cf = animator.get_cur_frame() - 1;
       +                            animator.set_cur_frame(cf);
       +                            animator.display_frame(self.buffer_view.clone());
       +                        }
        
       -            if self.animator.lock().unwrap().success() {
       -                let cur_frame = self.animator.lock().unwrap().get_cur_frame();
       +                        if ui
       +                            .add_enabled(
       +                                animator.get_cur_frame() + 1 < animator.frames.len(),
       +                                ImageButton::new(crate::NAVIGATE_NEXT.clone()),
       +                            )
       +                            .clicked()
       +                        {
       +                            let cf = animator.get_cur_frame() + 1;
       +                            animator.set_cur_frame(cf);
       +                            animator.display_frame(self.buffer_view.clone());
       +                        }
        
       -                let monitor_settings = if let Some((_, settings, _)) = self.animator.lock().unwrap().frames.get(cur_frame) {
       -                    settings.clone()
       -                } else {
       -                    MonitorSettings::default()
       -                };
       -                let mut scale = Vec2::splat(self.scale);
       -                if self.buffer_view.lock().get_buffer().use_aspect_ratio() {
       -                    scale.y *= 1.35;
       -                }
       -                let opt = icy_engine_egui::TerminalOptions {
       -                    stick_to_bottom: false,
       -                    scale: Some(scale),
       -                    monitor_settings,
       -                    id: Some(Id::new(self.id + 20000)),
       -                    ..Default::default()
       -                };
       -                ui.allocate_ui(Vec2::new(ui.available_width(), ui.available_height() - 100.0), |ui|  {
       -                    self.buffer_view.lock().get_caret_mut().set_is_visible(false);
       -                    let (_, _) = show_terminal_area(ui, self.buffer_view.clone(), opt);
       +                        ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
       +                            if ui.button(if self.scale < 2.0 { "2x" } else { "1x" }).clicked() {
       +                                if self.scale < 2.0 {
       +                                    self.scale = 2.0;
       +                                } else {
       +                                    self.scale = 1.0;
       +                                }
       +                            }
       +                        });
       +                    }
                        });
       -                ui.add_space(8.0);
       -            }
        
       -            if let Some(rx) = &self.rx {
       -                if let Ok(x) = rx.recv() {
       -                    self.cur_encoding_frame = x;
       -                }
       +                if self.animator.lock().unwrap().success() {
       +                    let cur_frame = self.animator.lock().unwrap().get_cur_frame();
        
       -                ui.label(fl!(
       -                    crate::LANGUAGE_LOADER,
       -                    "animation_encoding_frame",
       -                    cur = self.cur_encoding_frame,
       -                    total = self.encoding_frames
       -                ));
       -                ui.add(ProgressBar::new(self.cur_encoding_frame as f32 / self.encoding_frames as f32));
       -                if self.cur_encoding_frame >= self.encoding_frames {
       -                    if let Some(thread) = self.thread.take() {
       -                        if let Ok(Err(err)) = thread.join() {
       -                            log::error!("Error during encoding: {err}");
       -                            self.encoding_error = format!("{err}");
       -                        }
       -                    }
       -                    self.rx = None;
       -                } else if let Some(thread) = &self.thread {
       -                    if thread.is_finished() {
       -                        if let Err(err) = self.thread.take().unwrap().join() {
       -                            let msg = if let Some(msg) = err.downcast_ref::<&'static str>() {
       -                                msg.to_string()
       -                            } else if let Some(msg) = err.downcast_ref::<String>() {
       -                                msg.clone()
       -                            } else {
       -                                format!("?{:?}", err)
       -                            };
       -                            log::error!("Error during encoding: {:?}", msg);
       -                            self.encoding_error = format!("Thread aborted: {:?}", msg);
       -                        }
       -                        self.rx = None;
       +                    let monitor_settings = if let Some((_, settings, _)) = self.animator.lock().unwrap().frames.get(cur_frame) {
       +                        settings.clone()
       +                    } else {
       +                        MonitorSettings::default()
       +                    };
       +                    let mut scale = Vec2::splat(self.scale);
       +                    if self.buffer_view.lock().get_buffer().use_aspect_ratio() {
       +                        scale.y *= 1.35;
                            }
       +                    let opt = icy_engine_egui::TerminalOptions {
       +                        stick_to_bottom: false,
       +                        scale: Some(scale),
       +                        monitor_settings,
       +                        id: Some(Id::new(self.id + 20000)),
       +                        ..Default::default()
       +                    };
       +                    ui.allocate_ui(Vec2::new(ui.available_width(), ui.available_height() - 100.0), |ui| {
       +                        self.buffer_view.lock().get_caret_mut().set_is_visible(false);
       +                        let (_, _) = show_terminal_area(ui, self.buffer_view.clone(), opt);
       +                    });
       +                    ui.add_space(8.0);
                        }
       -            } else {
       -                ui.horizontal(|ui| {
       -                    ui.label(fl!(crate::LANGUAGE_LOADER, "animation_editor_path_label"));
       -                    let mut path_edit = self.export_path.to_str().unwrap().to_string();
       -                    let response = ui.add(
       -                        //    ui.available_size(),
       -                        TextEdit::singleline(&mut path_edit).desired_width(f32::INFINITY),
       -                    );
       -                    if response.changed() {
       -                        self.export_path = path_edit.into();
       -                    }
       -                });
       -                ui.add_space(8.0);
       -                ui.horizontal(|ui| {
       -                    for (i, enc) in ENCODERS.iter().enumerate() {
       -                        if ui.selectable_label(self.export_type == i, enc.label()).clicked() {
       -                            self.export_type = i;
       -                            self.export_path.set_extension(enc.extension());
       -                        }
       +
       +                if let Some(rx) = &self.rx {
       +                    if let Ok(x) = rx.recv() {
       +                        self.cur_encoding_frame = x;
                            }
        
       -                    if ui.button(fl!(crate::LANGUAGE_LOADER, "animation_editor_export_button")).clicked() {
       -                        if let Err(err) = self.export() {
       -                            message = Some(Message::ShowError(format!("Could not export: {}", err)));
       +                    ui.label(fl!(
       +                        crate::LANGUAGE_LOADER,
       +                        "animation_encoding_frame",
       +                        cur = self.cur_encoding_frame,
       +                        total = self.encoding_frames
       +                    ));
       +                    ui.add(ProgressBar::new(self.cur_encoding_frame as f32 / self.encoding_frames as f32));
       +                    if self.cur_encoding_frame >= self.encoding_frames {
       +                        if let Some(thread) = self.thread.take() {
       +                            if let Ok(Err(err)) = thread.join() {
       +                                log::error!("Error during encoding: {err}");
       +                                self.encoding_error = format!("{err}");
       +                            }
       +                        }
       +                        self.rx = None;
       +                    } else if let Some(thread) = &self.thread {
       +                        if thread.is_finished() {
       +                            if let Err(err) = self.thread.take().unwrap().join() {
       +                                let msg = if let Some(msg) = err.downcast_ref::<&'static str>() {
       +                                    msg.to_string()
       +                                } else if let Some(msg) = err.downcast_ref::<String>() {
       +                                    msg.clone()
       +                                } else {
       +                                    format!("?{:?}", err)
       +                                };
       +                                log::error!("Error during encoding: {:?}", msg);
       +                                self.encoding_error = format!("Thread aborted: {:?}", msg);
       +                            }
       +                            self.rx = None;
                                }
                            }
       -                });
       -
       -                if !self.encoding_error.is_empty() {
       -                    ui.colored_label(ui.style().visuals.error_fg_color, RichText::new(&self.encoding_error));
                        } else {
                            ui.horizontal(|ui| {
       -                        ui.small(fl!(crate::LANGUAGE_LOADER, "animation_icy_play_note"));
       -                        ui.hyperlink_to(RichText::new("Icy Play").small(), "https://github.com/mkrueger/icy_play");
       +                        ui.label(fl!(crate::LANGUAGE_LOADER, "animation_editor_path_label"));
       +                        let mut path_edit = self.export_path.to_str().unwrap().to_string();
       +                        let response = ui.add(
       +                            //    ui.available_size(),
       +                            TextEdit::singleline(&mut path_edit).desired_width(f32::INFINITY),
       +                        );
       +                        if response.changed() {
       +                            self.export_path = path_edit.into();
       +                        }
       +                    });
       +                    ui.add_space(8.0);
       +                    ui.horizontal(|ui| {
       +                        for (i, enc) in ENCODERS.iter().enumerate() {
       +                            if ui.selectable_label(self.export_type == i, enc.label()).clicked() {
       +                                self.export_type = i;
       +                                self.export_path.set_extension(enc.extension());
       +                            }
       +                        }
       +
       +                        if ui.button(fl!(crate::LANGUAGE_LOADER, "animation_editor_export_button")).clicked() {
       +                            if let Err(err) = self.export() {
       +                                message = Some(Message::ShowError(format!("Could not export: {}", err)));
       +                            }
       +                        }
                            });
       +
       +                    if !self.encoding_error.is_empty() {
       +                        ui.colored_label(ui.style().visuals.error_fg_color, RichText::new(&self.encoding_error));
       +                    } else {
       +                        ui.horizontal(|ui| {
       +                            ui.small(fl!(crate::LANGUAGE_LOADER, "animation_icy_play_note"));
       +                            ui.hyperlink_to(RichText::new("Icy Play").small(), "https://github.com/mkrueger/icy_play");
       +                        });
       +                    }
                        }
       -            }
       -        });
       +            });
        
                egui::CentralPanel::default().show_inside(ui, |ui| {
                    TopBottomPanel::bottom("code_error_bottom_panel").exact_height(200.).show_inside(ui, |ui| {
       -            if !self.animator.lock().unwrap().error.is_empty() {
       -                ui.colored_label(ui.style().visuals.error_fg_color, RichText::new(&self.animator.lock().unwrap().error).small());
       -            } else {
       -                egui::ScrollArea::vertical().max_width(f32::INFINITY).show(ui, |ui| {
       -                    self.animator.lock().unwrap().log.iter().for_each(|line| {
       -                        ui.horizontal(|ui| {
       -                            ui.label(RichText::new(format!("Frame {}:", line.frame)).strong());
       -                            ui.label(RichText::new(&line.text));
       -                            ui.add_space(ui.available_width());
       +                if !self.animator.lock().unwrap().error.is_empty() {
       +                    ui.colored_label(ui.style().visuals.error_fg_color, RichText::new(&self.animator.lock().unwrap().error).small());
       +                } else {
       +                    egui::ScrollArea::vertical().max_width(f32::INFINITY).show(ui, |ui| {
       +                        self.animator.lock().unwrap().log.iter().for_each(|line| {
       +                            ui.horizontal(|ui| {
       +                                ui.label(RichText::new(format!("Frame {}:", line.frame)).strong());
       +                                ui.label(RichText::new(&line.text));
       +                                ui.add_space(ui.available_width());
       +                            });
                                });
                            });
       -                });
       -            }
       -        });
       +                }
       +            });
        
       -        let r = CodeEditor::default()
       -            .id_source("code editor")
       -            .with_rows(12)
       -            .with_fontsize(14.0)
       -            .with_theme(if ui.style().visuals.dark_mode {
       -                egui_code_editor::ColorTheme::GITHUB_DARK
       -            } else {
       -                egui_code_editor::ColorTheme::GITHUB_LIGHT
       -            })
       -            .with_syntax(highlighting::lua())
       -            .with_numlines(true)
       -            .show(ui, &mut self.txt);
       -
       -        if self.shedule_update && self.last_update.elapsed().as_millis() > 1000 {
       -            self.shedule_update = false;
       -
       -            let path = self.parent_path.clone();
       -            let txt = self.txt.clone();
       -            self.set_frame = self.animator.lock().unwrap().get_cur_frame();
       -            self.next_animator = Some(Animator::run(&path, txt));
       -        }
       +            let r = CodeEditor::default()
       +                .id_source("code editor")
       +                .with_rows(12)
       +                .with_fontsize(14.0)
       +                .with_theme(if ui.style().visuals.dark_mode {
       +                    egui_code_editor::ColorTheme::GITHUB_DARK
       +                } else {
       +                    egui_code_editor::ColorTheme::GITHUB_LIGHT
       +                })
       +                .with_syntax(highlighting::lua())
       +                .with_numlines(true)
       +                .show(ui, &mut self.txt);
       +
       +            if self.shedule_update && self.last_update.elapsed().as_millis() > 1000 {
       +                self.shedule_update = false;
       +
       +                let path = self.parent_path.clone();
       +                let txt = self.txt.clone();
       +                self.set_frame = self.animator.lock().unwrap().get_cur_frame();
       +                self.next_animator = Some(Animator::run(&path, txt));
       +            }
        
       -        if r.response.changed {
       -            self.shedule_update = true;
       -            self.last_update = Instant::now();
       -            self.undostack += 1;
       -        }
       -    });
       +            if r.response.changed {
       +                self.shedule_update = true;
       +                self.last_update = Instant::now();
       +                self.undostack += 1;
       +            }
       +        });
        
                let buffer_view = self.buffer_view.clone();
                if self.animator.lock().unwrap().success() {
   DIR diff --git a/src/ui/top_bar.rs b/src/ui/top_bar.rs
       @@ -580,12 +580,12 @@ impl<'a> MainWindow<'a> {
        
            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| {
       -            let right = medium_toggle_button(ui, &DOCK_LEFT_SVG, self.right_panel);
       +            let right = medium_toggle_button(ui, &DOCK_RIGHT_SVG, self.right_panel);
                    if right.clicked() {
                        self.right_panel = !self.right_panel;
                    }
        
       -            let left = medium_toggle_button(ui, &DOCK_RIGHT_SVG, self.left_panel);
       +            let left = medium_toggle_button(ui, &DOCK_LEFT_SVG, self.left_panel);
                    if left.clicked() {
                        self.left_panel = !self.left_panel;
                    }