예제 #1
0
 def on_view_loaded(
         self, module: AbstractModule, controller: AbstractController, item_id: int
 ):
     """A new module view was loaded! Present it!"""
     assert current_thread() == main_thread
     # Check if current view still matches expected
     logger.debug('View loaded.')
     try:
         view = controller.get_view()
     except Exception as err:
         logger.debug("Error retreiving the loaded view")
         self.on_view_loaded_error(err)
         return
     if self._current_view_module != module or self._current_view_controller_class != controller.__class__ or self._current_view_item_id != item_id:
         logger.warning('Loaded view not matching selection.')
         view.destroy()
         return
     # Insert the view at page 3 [0,1,2,3] of the stack. If there is already a page, remove it.
     old_view = self._editor_stack.get_child_by_name('es__loaded_view')
     if old_view:
         logger.debug('Destroying old view...')
         self._editor_stack.remove(old_view)
         old_view.destroy()
     logger.debug('Adding and showing new view...')
     self._editor_stack.add_named(view, 'es__loaded_view')
     view.show_all()
     self._editor_stack.set_visible_child(view)
     logger.debug('Unlocking view trees.')
     self._unlock_trees()
     EventManager.instance().trigger(EVT_VIEW_SWITCH, module=module, controller=controller,
                                     breadcrumbs=self._current_breadcrumbs)
예제 #2
0
 def on_main_window_state_event(self, w: Gtk.Window,
                                evt: Gdk.EventWindowState):
     if evt.changed_mask & Gdk.WindowState.FOCUSED:
         if evt.new_window_state & Gdk.WindowState.FOCUSED:
             EventManager.instance().main_window_has_focus()
         else:
             EventManager.instance().main_window_lost_focus()
예제 #3
0
    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()
예제 #4
0
 def load(cls):
     try:
         # Start the server
         server = WebsocketServer(port=DEFAULT_PORT,
                                  loglevel=SKYTEMPLE_LOGLEVEL)
         EventThread(server).start()
         # Register the event handler to the event manager
         EventManager.instance().register_listener(EventHandler(server))
     except BaseException as e:
         logger.error(f"Failed loading websocket eventserver", exc_info=e)
예제 #5
0
 def run_main(cls, main: Callable, *main_args, **main_kwargs):
     try:
         main(*main_args, **main_kwargs)
         if cls.config_type(
         ).event_loop_type == AsyncEventLoopType.GLIB_ONLY:
             Gtk.main()
         elif cls.config_type().event_loop_type == AsyncEventLoopType.GBULB:
             gbulb.install(gtk=True)
             gbulb.get_event_loop().set_exception_handler(
                 async_handle_exeception)
             from skytemple.core.events.manager import EventManager
             GLib.idle_add(EventManager.instance().async_init)
             asyncio.get_event_loop().run_forever()
         else:
             raise RuntimeError("Invalid async configuration")
     except OSError as ex:
         if hasattr(ex, 'winerror') and ex.winerror == 6:  # type: ignore
             # [WinError 6] The handle is invalid
             # Originates in gi/_ossighelper.py - Some issues with socket cleanup. We will ignore that.
             pass
         else:
             raise
     except (SystemExit, KeyboardInterrupt):
         pass
     finally:
         # TODO: Currently always required for Debugger compatibility
         #  (since that ALWAYS uses this async implementation)
         AsyncTaskRunner.end()
예제 #6
0
 def _tick(self):
     if self._draw_area is None:
         return False
     if self._draw_area is not None and self._draw_area.get_parent() is None:
         # XXX: Gtk doesn't remove the widget on switch sometimes...
         self._draw_area.destroy()
         return False
     if EventManager.instance().get_if_main_window_has_fous():
         self._draw_area.queue_draw()
     self._frame_counter += 1
     return self._drawing_is_active
예제 #7
0
 def on_selected_string_changed(self, string: str):
     EventManager.instance().trigger(EVT_DEBUGGER_SELECTED_STRING_CHANGED,
                                     string)
예제 #8
0
 def on_blur(self):
     EventManager.instance().debugger_window_lost_focus()
예제 #9
0
 def on_focus(self):
     EventManager.instance().debugger_window_has_focus()
예제 #10
0
 def on_script_edit(self, filename):
     EventManager.instance().trigger(EVT_DEBUGGER_SCRIPT_OPEN, filename)
예제 #11
0
def main():
    # TODO: Gtk.Application: https://python-gtk-3-tutorial.readthedocs.io/en/latest/application.html
    path = os.path.abspath(os.path.dirname(__file__))

    # Load settings
    settings = SkyTempleSettingsStore()

    if sys.platform.startswith('win'):
        # Load theming under Windows
        _load_theme(settings)
        # Solve issue #12
        try:
            from skytemple_files.common.platform_utils.win import win_set_error_mode
            win_set_error_mode()
        except BaseException:
            # This really shouldn't fail, but it's not important enough to crash over
            pass

    if sys.platform.startswith('darwin'):
        # Load theming under macOS
        _load_theme(settings)

        # The search path is wrong if SkyTemple is executed as an .app bundle
        if getattr(sys, 'frozen', False):
            path = os.path.dirname(sys.executable)

    if sys.platform.startswith('linux') and gdk_backend() == GDK_BACKEND_BROADWAY:
        gtk_settings = Gtk.Settings.get_default()
        gtk_settings.set_property("gtk-theme-name", 'Arc-Dark')
        gtk_settings.set_property("gtk-application-prefer-dark-theme", True)

    itheme: Gtk.IconTheme = Gtk.IconTheme.get_default()
    itheme.append_search_path(os.path.abspath(icons()))
    itheme.append_search_path(os.path.abspath(os.path.join(data_dir(), "icons")))
    itheme.append_search_path(os.path.abspath(os.path.join(get_debugger_data_dir(), "icons")))
    itheme.rescan_if_needed()

    # Load Builder and Window
    builder = make_builder(os.path.join(path, "skytemple.glade"))
    main_window: Window = builder.get_object("main_window")
    main_window.set_role("SkyTemple")
    GLib.set_application_name("SkyTemple")
    GLib.set_prgname("skytemple")
    # TODO: Deprecated but the only way to set the app title on GNOME...?
    main_window.set_wmclass("SkyTemple", "SkyTemple")

    # Load CSS
    style_provider = Gtk.CssProvider()
    with open(os.path.join(path, "skytemple.css"), 'rb') as f:
        css = f.read()
    style_provider.load_from_data(css)
    Gtk.StyleContext.add_provider_for_screen(
        Gdk.Screen.get_default(), style_provider,
        Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
    )

    # Load async task runner thread
    AsyncTaskRunner.instance()

    # Init. core events
    event_manager = EventManager.instance()
    if settings.get_integration_discord_enabled():
        try:
            from skytemple.core.events.impl.discord import DiscordPresence
            discord_listener = DiscordPresence()
            event_manager.register_listener(discord_listener)
        except BaseException:
            pass

    # Load modules
    Modules.load()

    # Load main window + controller
    MainController(builder, main_window, settings)

    main_window.present()
    main_window.set_icon_name('skytemple')
    try:
        Gtk.main()
    except (KeyboardInterrupt, SystemExit):
        AsyncTaskRunner.end()