win.rs

extern crate gtk ; extern crate gio ; extern crate gdk ; use gtk ::{ ResponseType , TextViewExt , TextBufferExt , WidgetExt , FileChooserExt , DialogExt , ContainerExt , BinExt , Cast , WindowExt , }; use gio ::{ FileExt , SimpleActionExt , ActionMapExt }; use std :: cell :: RefCell ; use std :: rc :: Rc ; use std :: path :: Path ; pub struct WindowCore { window : gtk :: ApplicationWindow , file : Option < gio :: File > , text_view : gtk :: TextView , changed : bool , } pub type Window = Rc < RefCell < WindowCore >> ; pub trait WindowExtend { fn create ( app : & gtk :: Application ) -> Window ; fn init ( & self ); fn load_file ( & self , file : gio :: File ); fn save_file ( & self ); fn save_buffer ( & self ); fn save_as ( & self ); fn save_file_chooser_run ( & self ) -> Option < gio :: File > ; fn window ( & self ) -> gtk :: ApplicationWindow ; fn file ( & self ) -> Option < gio :: File > ; fn set_file ( & self , file : Option < gio :: File > ); fn text_view ( & self ) -> gtk :: TextView ; fn set_changed ( & self , changed : bool ); fn set_title ( & self , title : & str ); } impl WindowExtend for Window { fn create ( app : & gtk :: Application ) -> Window { let window = gtk :: ApplicationWindow :: new ( app ); window .set_default_size ( 800 , 600 ); window .set_title ( "Vanilla Text" ); let scr_win = gtk :: ScrolledWindow :: new ( None , None ); let txt_view = gtk :: TextView :: new (); scr_win .add ( & txt_view ); window .add ( & scr_win ); let win = Rc :: new ( RefCell :: new ( WindowCore { window : window .clone (), file : None , text_view : txt_view .clone (), changed : false })); let copy_action = gio :: SimpleAction :: new ( "copy" , None ); { let txt_view = txt_view .clone (); copy_action .connect_activate ( move | _ , _ | { let clipboard = txt_view .get_clipboard ( & gdk :: SELECTION_CLIPBOARD ); txt_view .get_buffer () .unwrap () .copy_clipboard ( & clipboard ); }); } let paste_action = gio :: SimpleAction :: new ( "paste" , None ); { let txt_view = txt_view .clone (); paste_action .connect_activate ( move | _ , _ | { let clipboard = txt_view .get_clipboard ( & gdk :: SELECTION_CLIPBOARD ); let buf = txt_view .get_buffer () .unwrap (); buf .paste_clipboard ( & clipboard , None , txt_view .get_editable ()); }); } let save_action = gio :: SimpleAction :: new ( "save" , None ); { let win = win .clone (); save_action .connect_activate ( move | _ , _ | { win .save_file (); }); } window .add_action ( & copy_action ); window .add_action ( & paste_action ); window .add_action ( & save_action ); window .show_all (); win } fn init ( & self ) { self .borrow () .window .show_all (); } fn load_file ( & self , file : gio :: File ) { if let Ok (( v , _ )) = file .load_contents ( None ) { let text = String :: from_utf8 ( v ) .unwrap (); let scr_win = self .window () .get_child () .unwrap () .downcast :: < gtk :: ScrolledWindow > () .ok () .unwrap (); let txt_view = scr_win .get_child () .unwrap () .downcast :: < gtk :: TextView > () .ok () .unwrap (); let buf = txt_view .get_buffer () .unwrap (); buf .set_text ( & text ); } } fn save_file ( & self ) { if self .file () .is_some () { self .save_buffer (); } else { self .save_as () } } fn save_buffer ( & self ) { if let Some ( buf ) = self .text_view () .get_buffer () { let ( start , end ) = buf .get_bounds (); if let Some ( text ) = buf .get_text ( & start , & end , true ) { if self .file () .as_ref () .unwrap () .replace_contents ( text .as_bytes (), None , true , gio :: FILE_CREATE_NONE , None ) .is_ok () { self .set_changed ( false ); } else { let dialog = gtk :: MessageDialog :: new ( Some ( & self .window ()), gtk :: DIALOG_MODAL , gtk :: MessageType :: Error , gtk :: ButtonsType :: Close , "Error: Cannot save file" ); dialog .run (); dialog .destroy (); } } } } fn save_as ( & self ) { if let Some ( file ) = self .save_file_chooser_run () { self .set_title ( file .get_basename () .unwrap () .to_str () .unwrap ()); self .set_file ( Some ( file )); self .save_buffer (); } } fn save_file_chooser_run ( & self ) -> Option < gio :: File > { let dialog = gtk :: FileChooserDialog :: new :: < gtk :: Window > ( Some ( "Save File" ), Some ( & self .window () .upcast ()), gtk :: FileChooserAction :: Save ); dialog .add_button ( "Cancel" , ResponseType :: Cancel .into ()); dialog .add_button ( "Save" , ResponseType :: Accept .into ()); dialog .set_do_overwrite_confirmation ( true ); if let Some ( ref f ) = self .file () { dialog .set_filename ( f .get_path () .unwrap () .as_path ()); } else { dialog .set_current_name ( Path :: new ( "untitled" )); } let file ; if dialog .run () == ResponseType :: Accept .into () { if let Some ( path ) = dialog .get_filename () { file = Some ( gio :: File :: new_for_path ( path .as_path ())) } else { file = None } } else { file = None } dialog .destroy (); file } fn window ( & self ) -> gtk :: ApplicationWindow { self .borrow () .window .clone () } fn file ( & self ) -> Option < gio :: File > { self .borrow () .file .clone () } fn set_file ( & self , file : Option < gio :: File > ) { self .borrow_mut () .file = file ; } fn set_changed ( & self , changed : bool ) { self .borrow_mut () .changed = changed ; } fn text_view ( & self ) -> gtk :: TextView { self .borrow () .text_view .clone () } fn set_title ( & self , title : & str ) { self .borrow () .window .set_title ( title ); } }