def on_file_opened(self): """Update the UI after a ROM file has been opened.""" assert current_thread() == main_thread logger.debug('File opened.') # Init the sprite provider RomProject.get_current().get_sprite_provider().init_loader( self.window.get_screen()) self._init_window_after_rom_load( os.path.basename(RomProject.get_current().filename)) try: # Load root node, ROM project = RomProject.get_current() rom_module = project.get_rom_module() rom_module.load_rom_data() # Initialize patch-specific properties for this rom project project.init_patch_properties() logger.info( f'Loaded ROM {project.filename} ({rom_module.get_static_data().game_edition})' ) logger.debug(f"Loading ROM module tree items...") rom_module.load_tree_items(self._item_store, None) root_node = rom_module.get_root_node() # Tell the debugger self._debugger_manager.handle_project_change() # Load item tree items for module in sorted(project.get_modules(False), key=lambda m: m.sort_order()): logger.debug( f"Loading {module.__class__.__name__} module tree items..." ) module.load_tree_items(self._item_store, root_node) if module.__class__.__name__ == 'MapBgModule': self._loaded_map_bg_module = module # TODO: Load settings from ROM for history, bookmarks, etc? - separate module? logger.debug(f"Loaded all modules.") # Trigger event EventManager.instance().trigger(EVT_PROJECT_OPEN, project=project) # Select & load main ROM item by default selection: TreeSelection = self._main_item_list.get_selection() selection.select_path(self._item_store.get_path(root_node)) self.load_view(self._item_store, root_node, self._main_item_list) except BaseException as ex: self.on_file_opened_error(sys.exc_info(), ex) return if self._loading_dialog is not None: self._loading_dialog.hide() self._loading_dialog = None # Show the initial assistant window if not self.settings.get_assistant_shown(): self.on_settings_show_assistant_clicked()
def _open_file(self, filename: str): """Open a file""" if self._check_open_file(): self._loading_dialog = self.builder.get_object('file_opening_dialog') self.builder.get_object('file_opening_dialog_label').set_label( f'Loading ROM "{os.path.basename(filename)}"...' ) logger.debug(f'Opening {filename}.') RomProject.open(filename, self) # Add to the list of recent files and save self._update_recent_files(filename) # Show loading spinner self._loading_dialog.run()
def open_scene_editor_for_map(self, map_name): try: RomProject.get_current().request_open(OpenRequest( REQUEST_TYPE_SCENE, map_name ), True) self._manager.main_window.present() except ValueError: md = Gtk.MessageDialog(self._manager.get_window(), Gtk.DialogFlags.DESTROY_WITH_PARENT, Gtk.MessageType.INFO, Gtk.ButtonsType.OK, f"A scene for this script was not found.", title="No Scenes Found") md.run() md.destroy()
def _open_file(self, filename: str): """Open a file""" if self._check_open_file(filename): self._loading_dialog = self.builder.get_object( 'file_opening_dialog') # noinspection PyUnusedLocal rom_name = os.path.basename(filename) self.builder.get_object('file_opening_dialog_label').set_label( f(_('Loading ROM "{rom_name}"...'))) logger.debug(f(_('Opening {filename}.'))) RomProject.open(filename, self) # type: ignore # Add to the list of recent files and save self._update_recent_files(filename) # Show loading spinner self._loading_dialog.run()
def _get_special_words_uncached(self): pro = RomProject.get_current() yield from self.get_static_data().script_data.op_codes__by_name.keys() yield from (x.name.replace('$', '') for x in SsbConstant.collect_all( self.get_static_data().script_data)) yield from EXPS_KEYWORDS yield from pro.get_string_provider().get_all(StringType.POKEMON_NAMES)
def on_main_item_list_button_press_event(self, tree: TreeView, event: Gdk.Event): """Handle click on item: Switch view""" assert current_thread() == main_thread if event.type == Gdk.EventType.DOUBLE_BUTTON_PRESS: model, treeiter = tree.get_selection().get_selected() if model is not None and treeiter is not None and RomProject.get_current() is not None: self.load_view(model, treeiter, tree, False)
def get_ssb(self, filename, ssb_file_manager: 'SsbFileManager') -> 'SsbLoadedFile': f: 'SsbLoadedFile' = RomProject.get_current().open_file_in_rom(filename, SsbLoadedFileHandler, filename=filename, static_data=self.get_static_data(), project_fm=self._project_fm) f.file_manager = ssb_file_manager return f
def edit_position_mark(self, mapname: str, scene_name: str, scene_type: str, pos_marks: List[SourceMapPositionMark], pos_mark_to_edit: int) -> bool: try: cntrl: PosMarkEditorController = RomProject.get_current( ).get_module( 'script').get_pos_mark_editor_controller( # type: ignore self._manager.get_window(), mapname, scene_name.split('/')[-1], scene_type, pos_marks, pos_mark_to_edit) return cntrl.run() == Gtk.ResponseType.OK except IndexError: md = SkyTempleMessageDialog( self._manager.get_window(), Gtk.DialogFlags.DESTROY_WITH_PARENT, Gtk.MessageType.INFO, Gtk.ButtonsType.OK, f"SkyTemple is missing the 'script' " f"module to handle this request.") md.run() md.destroy() except ValueError as err: md = SkyTempleMessageDialog(self._manager.get_window(), Gtk.DialogFlags.DESTROY_WITH_PARENT, Gtk.MessageType.INFO, Gtk.ButtonsType.OK, str(err)) md.run() md.destroy() return False
def on_save_as_button_clicked(self, wdg): project = RomProject.get_current() dialog = Gtk.FileChooserNative.new( "Save As...", self.window, Gtk.FileChooserAction.SAVE, None, None ) dialog.set_filename(project.filename) add_dialog_file_filters(dialog) response = dialog.run() fn = dialog.get_filename() if '.' not in fn: fn += '.nds' dialog.destroy() if response == Gtk.ResponseType.ACCEPT: project.filename = fn self._save(True) project.get_rom_module().update_filename() self._update_recent_files(fn) self.reload_view()
def save_ssb(self, filename, ssb_model, ssb_file_manager: 'SsbFileManager'): project = RomProject.get_current() ssb_loaded_file = self.get_ssb(filename, ssb_file_manager) ssb_loaded_file.ssb_model = ssb_model project.prepare_save_model(filename, assert_that=ssb_loaded_file) project.save_as_is()
def handle_project_change(self): """ If the debugger is currently open, handles changing the project for it. The global singleton instance of RomProject is used. """ project = RomProject.get_current() if project is not None and self.is_opened(): self._opened_main_controller.load_rom()
def on_file_saved(self): if self._loading_dialog is not None: self._loading_dialog.hide() self._loading_dialog = None rom = RomProject.get_current() self._set_title(os.path.basename(rom.filename), False) recursive_down_item_store_mark_as_modified(self._item_store[self._item_store.get_iter_first()], False)
def __init__(self, rom_project: RomProject): """Loads the list of backgrounds for the ROM.""" self.project = rom_project self.bgs: BgList = rom_project.open_file_in_rom( MAP_BG_LIST, FileType.BG_LIST_DAT) self._tree_model = None self._tree_level_iter = []
def _init_window_before_view_load(self, node: TreeModelRow): """Update the subtitle / breadcrumb before switching views""" bc = "" parent = node bc_array = [] while parent: bc = f" > {parent[6]}" + bc bc_array.append(parent[6]) parent = parent.parent bc = bc[3:] self._current_breadcrumbs = bc_array self.window.get_titlebar().set_subtitle(bc) # Check if files are modified if RomProject.get_current().has_modifications(): self._set_title( os.path.basename(RomProject.get_current().filename), True)
def __init__(self, rom_project: RomProject): """Loads the list of backgrounds for the ROM.""" self.project = rom_project self.bgs: BgListProtocol = rom_project.open_file_in_rom(MAP_BG_LIST, FileType.BG_LIST_DAT) self._tree_model: Gtk.TreeModel self._tree_level_iter: List[Gtk.TreeIter] = [] self._sub_nodes: Gtk.TreeIter self._other_node: Gtk.TreeIter
def on_intro_dialog_created_with_clicked(self, *args): if RomProject.get_current() is None or self._loaded_map_bg_module is None: md = SkyTempleMessageDialog(MainController.window(), Gtk.DialogFlags.DESTROY_WITH_PARENT, Gtk.MessageType.ERROR, Gtk.ButtonsType.OK, _("A project must be opened to use this.")) md.set_position(Gtk.WindowPosition.CENTER) md.run() md.destroy() return self._loaded_map_bg_module.add_created_with_logo()
def _open_file(self, filename: str): """Open a file""" if self._check_open_file(): self._loading_dialog = self.builder.get_object( 'file_opening_dialog') self.builder.get_object('file_opening_dialog_label').set_label( f'Loading ROM "{os.path.basename(filename)}"...') logger.debug(f'Opening {filename}.') RomProject.open(filename, self) # Add to the list of recent files and save new_recent_files = [] for rf in self.recent_files: if rf != filename and rf not in new_recent_files: new_recent_files.append(rf) new_recent_files.insert(0, filename) self.recent_files = new_recent_files self.settings.set_recent_files(self.recent_files) # TODO: Update recent files store too! # Show loading spinner self._loading_dialog.run()
def _init_window_before_view_load(self, node: Gtk.TreeModelRow): """Update the subtitle / breadcrumb before switching views""" try: bc = "" parent = node bc_array = [] while parent: bc = f" > {parent[6]}" + bc bc_array.append(parent[6]) parent = parent.parent bc = bc[3:] self._current_breadcrumbs = bc_array self._window.get_titlebar().set_subtitle(bc) # Check if files are modified if RomProject.get_current().has_modifications(): # type: ignore self._set_title( os.path.basename(RomProject.get_current().filename), True) # type: ignore except BaseException as ex: logger.warning("Failed updating window titles.", exc_info=ex)
def open_scene_editor(self, type_of_scene, path): try: map_name, filename = path.split('/')[-2:] if type_of_scene == 'ssa': RomProject.get_current().request_open(OpenRequest( REQUEST_TYPE_SCENE_SSA, (map_name, filename.replace(SSB_EXT, SSA_EXT)) ), True) elif type_of_scene == 'sss': RomProject.get_current().request_open(OpenRequest( REQUEST_TYPE_SCENE_SSS, (map_name, filename.replace(SSB_EXT, SSS_EXT)) ), True) elif type_of_scene == 'sse': RomProject.get_current().request_open(OpenRequest( REQUEST_TYPE_SCENE_SSE, map_name ), True) else: raise ValueError() self._manager.main_window.present() except ValueError: md = Gtk.MessageDialog(self._manager.get_window(), Gtk.DialogFlags.DESTROY_WITH_PARENT, Gtk.MessageType.INFO, Gtk.ButtonsType.OK, f"A scene for this script was not found.", title="No Scenes Found") md.run() md.destroy()
def collect_state_context() -> Dict[str, 'Captured']: from skytemple.controller.main import MainController from skytemple.core.rom_project import RomProject from skytemple_files.common.util import capture_any rom_project = RomProject.get_current() try: view_state = MainController._instance._current_view_module.collect_debugging_info( # type: ignore MainController._instance._current_view_controller # type: ignore ) if "models" in view_state: # type: ignore view_state["models"] = { k: capture_any(v) for k, v in view_state["models"].items() } # type: ignore except Exception as ex: view_state = {"error_collecting": str(ex)} w, h = MainController.window().get_size() dw = if_not_none(MainController.debugger_manager()._opened_main_window, lambda w: w.get_size()[0]) dh = if_not_none(MainController.debugger_manager()._opened_main_window, lambda w: w.get_size()[1]) return { "skytemple": { "window": { "width": w, "height": h, }, "rom": { "filename": if_not_none(rom_project, lambda p: p.get_rom_name()), "edition": if_not_none(rom_project, lambda p: p.get_rom_module().get_static_data()), }, "module": type(MainController._instance._current_view_module).__qualname__, "view": MainController._instance._current_view_controller_class. __qualname__, # type: ignore "view_state": view_state }, "ssb_debugger": { "window": { "width": dw, "height": dh, }, "open_scripts": debugger_open_scripts(MainController.debugger_manager()), "focused_script": debugger_focused_script(MainController.debugger_manager()), #"emulator_state": debugger_emulator_state(MainController.debugger_manager()) } }
def _save(self, force=False): rom = RomProject.get_current() if rom.has_modifications() or force: self._loading_dialog = self.builder.get_object( 'file_opening_dialog') self.builder.get_object('file_opening_dialog_label').set_label( f'Saving ROM "{os.path.basename(rom.filename)}"...') logger.debug(f'Saving {rom.filename}.') # This will trigger a signal. rom.save(self) self._loading_dialog.run()
def _save(self, force=False, after_save_action=None): rom = RomProject.get_current() if rom is not None and (rom.has_modifications() or force): self._after_save_action = after_save_action self._loading_dialog = self.builder.get_object( 'file_opening_dialog') # noinspection PyUnusedLocal rom_name = os.path.basename(rom.filename) self.builder.get_object('file_opening_dialog_label').set_label( f(_('Saving ROM "{rom_name}"...'))) logger.debug(f(_('Saving {rom.filename}.'))) # This will trigger a signal. rom.save(self) # type: ignore self._loading_dialog.run()
def on_main_window_delete_event(self, *args): if not self._debugger_manager.close(): # Cancel return True rom = RomProject.get_current() if rom is not None and rom.has_modifications(): response = self._show_are_you_sure(rom) if response == 0: return False elif response == 1: # Save (True on success, False on failure. Don't close the file if we can't save it...) self._save(after_save_action=lambda: self._window.destroy()) return True else: # Cancel return True return False
def open_scene_editor_for_map(self, map_name): try: current = RomProject.get_current() assert current is not None current.request_open(OpenRequest(REQUEST_TYPE_SCENE, map_name), True) if self._manager.main_window is not None: self._manager.main_window.present() except ValueError: md = SkyTempleMessageDialog( self._manager.get_window(), Gtk.DialogFlags.DESTROY_WITH_PARENT, Gtk.MessageType.INFO, Gtk.ButtonsType.OK, _("A scene for this script was not found."), title=_("No Scenes Found")) md.run() md.destroy()
def _check_open_file(self, filename): """Check for open files, and ask the user what to do. Returns false if they cancel.""" rom = RomProject.get_current() if not self._debugger_manager.check_save(): # Cancel return False if rom is not None and rom.has_modifications(): response = self._show_are_you_sure(rom) if response == 0: # Don't save return True elif response == 1: # Save (True on success, False on failure. Don't close the file if we can't save it...) return self._save(after_save_action=lambda: self._open_file(filename)) else: # Cancel return False return True
def on_main_window_delete_event(self, *args): if not self._debugger_manager.close(): # Cancel return True rom = RomProject.get_current() if rom is not None and rom.has_modifications(): response = self._show_are_you_sure(rom) if response == 0: return False elif response == 1: # Save (True on success, False on failure. Don't close the file if we can't save it...) self._save() # TODO: we just cancel atm, because the saving is done async. It would probably be nice to also # exit, when it's done without error return True else: # Cancel return True return False
def _check_open_file(self): """Check for open files, and ask the user what to do. Returns false if they cancel.""" rom = RomProject.get_current() if not self._debugger_manager.check_save(): # Cancel return False if rom is not None and rom.has_modifications(): response = self._show_are_you_sure(rom) if response == 0: # Don't save return True elif response == 1: # Save (True on success, False on failure. Don't close the file if we can't save it...) # TODO: NOT TRUE. We are using signals. This is broken right now! return self._save() else: # Cancel return False return True
def on_save_as_button_clicked(self, wdg): project = RomProject.get_current() if project is None: return dialog = Gtk.FileChooserNative.new(_("Save As..."), self._window, Gtk.FileChooserAction.SAVE, None, None) dialog.set_filename(project.filename) add_dialog_file_filters(dialog) response = dialog.run() fn = dialog.get_filename() dialog.destroy() if response == Gtk.ResponseType.ACCEPT: fn = add_extension_if_missing(fn, 'nds') project.filename = fn self._save(True) project.get_rom_module().update_filename() self._update_recent_files(fn)
def save_rom(self): # We only save the current ROM contents! current = RomProject.get_current() if current: current.save_as_is()
def get_rom_filename(self) -> str: return RomProject.get_current().filename # type: ignore