1/* 2* Copyright (c) 2019-2020 Alecaddd (https://alecaddd.com) 3* 4* This file is part of Akira. 5* 6* Akira is free software: you can redistribute it and/or modify 7* it under the terms of the GNU General Public License as published by 8* the Free Software Foundation, either version 3 of the License, or 9* (at your option) any later version. 10 11* Akira is distributed in the hope that it will be useful, 12* but WITHOUT ANY WARRANTY; without even the implied warranty of 13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14* GNU General Public License for more details. 15 16* You should have received a copy of the GNU General Public License 17* along with Akira. If not, see <https://www.gnu.org/licenses/>. 18* 19* Authored by: Alessandro "Alecaddd" Castellani <castellani.ale@gmail.com> 20*/ 21 22public class Akira.Window : Gtk.ApplicationWindow { 23 public FileFormat.AkiraFile? akira_file = null; 24 public FileFormat.FileManager file_manager; 25 26 public weak Akira.Application app { get; construct; } 27 public Akira.Services.EventBus event_bus; 28 public Akira.Lib.Managers.ItemsManager items_manager; 29 30 public Akira.Services.ActionManager action_manager; 31 public Akira.Layouts.HeaderBar headerbar; 32 public Akira.Layouts.MainWindow main_window; 33 public Akira.Utils.Dialogs dialogs; 34 35 public Akira.StateManagers.CoordinatesMiddleware coords_middleware; 36 public Akira.StateManagers.SizeMiddleware size_middleware; 37 38 public SimpleActionGroup actions { get; construct; } 39 public Gtk.AccelGroup accel_group { get; construct; } 40 41 public bool edited { get; set; default = false; } 42 43 public Window (Akira.Application akira_app) { 44 Object ( 45 application: akira_app, 46 app: akira_app, 47 icon_name: "com.github.akiraux.akira" 48 ); 49 } 50 51 construct { 52 accel_group = new Gtk.AccelGroup (); 53 add_accel_group (accel_group); 54 55 event_bus = new Akira.Services.EventBus (); 56 items_manager = new Akira.Lib.Managers.ItemsManager (this); 57 action_manager = new Akira.Services.ActionManager (app, this); 58 file_manager = new Akira.FileFormat.FileManager (this); 59 headerbar = new Akira.Layouts.HeaderBar (this); 60 main_window = new Akira.Layouts.MainWindow (this); 61 coords_middleware = new Akira.StateManagers.CoordinatesMiddleware (this); 62 size_middleware = new Akira.StateManagers.SizeMiddleware (this); 63 dialogs = new Akira.Utils.Dialogs (this); 64 65 build_ui (); 66 67 move (settings.pos_x, settings.pos_y); 68 69 show_app (); 70 71 // Let the canvas grab the focus after the app is visible. 72 main_window.main_canvas.canvas.focus_canvas (); 73 74 event_bus.file_edited.connect (on_file_edited); 75 event_bus.file_saved.connect (on_file_saved); 76 } 77 78 private void build_ui () { 79 set_titlebar (headerbar); 80 set_border_width (0); 81 if (Constants.PROFILE == "development") { 82 headerbar.get_style_context ().add_class ("devel"); 83 } 84 85 delete_event.connect ((e) => { 86 return before_destroy (); 87 }); 88 89 add (main_window); 90 } 91 92 private void apply_user_settings () { 93 Gtk.Settings.get_default ().gtk_application_prefer_dark_theme = settings.dark_theme; 94 95 var css_provider = new Gtk.CssProvider (); 96 css_provider.load_from_resource ("/com/github/akiraux/akira/stylesheet.css"); 97 98 Gtk.StyleContext.add_provider_for_screen ( 99 Gdk.Screen.get_default (), css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION 100 ); 101 102 resize (settings.window_width, settings.window_height); 103 main_window.pane.position = settings.left_paned; 104 main_window.pane2.position = settings.right_paned; 105 } 106 107 private void on_file_edited () { 108 edited = true; 109 } 110 111 private void on_file_saved () { 112 edited = false; 113 } 114 115 public bool before_destroy () { 116 update_status (); 117 118 if (!edited) { 119 close_current_file (); 120 app.get_active_window ().destroy (); 121 on_destroy (); 122 } 123 124 if (edited) { 125 var dialog = dialogs.message_dialog ( 126 _("Are you sure you want to quit?"), 127 _("All unsaved data will be lost and impossible to recover."), 128 "system-shutdown", 129 _("Quit without saving!"), 130 _("Save file") 131 ); 132 133 dialog.show_all (); 134 135 dialog.response.connect ((id) => { 136 switch (id) { 137 case Gtk.ResponseType.ACCEPT: 138 dialog.destroy (); 139 close_current_file (); 140 app.get_active_window ().destroy (); 141 on_destroy (); 142 break; 143 case 2: 144 dialog.destroy (); 145 file_manager.save_file (); 146 break; 147 default: 148 dialog.destroy (); 149 break; 150 } 151 }); 152 153 dialog.run (); 154 } 155 156 return true; 157 } 158 159 public void on_destroy () { 160 uint length = app.windows.length (); 161 162 if (length == 0) { 163 app.quit (); 164 } 165 } 166 167 private void update_status () { 168 int width, height, x, y; 169 170 get_size (out width, out height); 171 get_position (out x, out y); 172 173 settings.pos_x = x; 174 settings.pos_y = y; 175 settings.window_width = width; 176 settings.window_height = height; 177 settings.left_paned = main_window.pane.get_position (); 178 settings.right_paned = main_window.pane2.get_position (); 179 } 180 181 public void show_app () { 182 apply_user_settings (); 183 show_all (); 184 show (); 185 present (); 186 } 187 188 public void open_file (File file) { 189 akira_file = new FileFormat.AkiraFile (file, this); 190 191 akira_file.prepare (); 192 akira_file.load_file (); 193 } 194 195 public void save_new_file (File file, bool overwrite = false) { 196 akira_file = new FileFormat.AkiraFile (file, this); 197 akira_file.overwrite = overwrite; 198 199 akira_file.prepare (); 200 akira_file.save_file (); 201 } 202 203 private void close_current_file () { 204 if (akira_file != null) { 205 akira_file.close (); 206 } 207 } 208} 209