Esempio n. 1
0
 def on_btn_add_clicked(self, *args):
     response, new_name = self._show_generic_input(
         _('Level Name'), _('Create Level'),
         (_('If you also need a new background for this level, you can '
            'create one under "Map Backrgounds" and assign it to this '
            'level afterwards.')))
     if response != Gtk.ResponseType.OK:
         return
     new_name = new_name.upper()
     if len(new_name) < 1 or len(new_name) > 8:
         md = SkyTempleMessageDialog(
             SkyTempleMainController.window(), Gtk.DialogFlags.MODAL,
             Gtk.MessageType.ERROR, Gtk.ButtonsType.OK,
             _("The length of the level name must be between 1-8 characters."
               ))
         md.run()
         md.destroy()
         return
     new_id = max(l.id for l in self._list.list) + 1
     store: Gtk.ListStore = self.builder.get_object('level_list_tree_store')
     store.append([
         str(new_id), new_name, 0, 0, 0,
         str(-1), self._labels_overworld_strings[0],
         self._labels_maptype[0], self._labels_mapid[0]
     ])
     self.module.create_new_level(new_name)
     self._save()
     md = SkyTempleMessageDialog(SkyTempleMainController.window(),
                                 Gtk.DialogFlags.MODAL,
                                 Gtk.MessageType.INFO,
                                 Gtk.ButtonsType.OK,
                                 _("New level created."),
                                 is_success=True)
     md.run()
     md.destroy()
Esempio n. 2
0
 def on_btn_add_acting_clicked(self, *args):
     response, name = self._show_generic_input(
         _('Scene Name (without file extension)'), _('Create Scene'))
     if response != Gtk.ResponseType.OK:
         return
     name_file = name.lower()
     if len(name) < 1 or len(name) > 8:
         md = SkyTempleMessageDialog(
             SkyTempleMainController.window(), Gtk.DialogFlags.MODAL,
             Gtk.MessageType.ERROR, Gtk.ButtonsType.OK,
             _("The length of the scene name must be between 1-8 characters."
               ))
         md.run()
         md.destroy()
         return
     try:
         self.module.add_scene_acting(self.name, name_file)
     except ValueError as err:
         md = SkyTempleMessageDialog(
             SkyTempleMainController.window(), Gtk.DialogFlags.MODAL,
             Gtk.MessageType.ERROR, Gtk.ButtonsType.OK,
             _("Could not add the scene: ") + str(err))
         md.run()
         md.destroy()
         return
     md = SkyTempleMessageDialog(SkyTempleMainController.window(),
                                 Gtk.DialogFlags.MODAL,
                                 Gtk.MessageType.INFO,
                                 Gtk.ButtonsType.OK,
                                 _("Scene added successfully"),
                                 is_success=True)
     md.run()
     md.destroy()
Esempio n. 3
0
    def on_btn_apply_size_clicked(self, *args):
        try:
            width = int(self.builder.get_object('settings_width').get_text())
            height = int(self.builder.get_object('settings_height').get_text())
            if width == 0 or height == 0:  # 0x0 rooms are allowed to be consistent with the fact that they exist
                width = height = 0
            assert width >= 0 and height >= 0
        except (ValueError, AssertionError):
            display_error(sys.exc_info(),
                          _("Width and height must be numbers >= 0."),
                          _("Invalid values."))
            return

        confirm = True
        if width < self.floor.width or height < self.floor.height:
            md = SkyTempleMessageDialog(
                MainController.window(),
                Gtk.DialogFlags.MODAL,
                Gtk.MessageType.WARNING,
                Gtk.ButtonsType.YES_NO,
                _("You are about to reduce the size of the room. This will delete tiles. Do you want to continue?"
                  ),
                title=_("Warning!"))
            response = md.run()
            md.destroy()
            confirm = response == Gtk.ResponseType.YES
        if confirm:
            self.floor.resize(width, height)
            self.module.mark_fixed_floor_as_modified(self.floor_id)
            MainController.reload_view()
Esempio n. 4
0
    def _create_scene_file(self,
                           level_name,
                           scene_name,
                           ext,
                           matching_ssb=None):
        dir_name = f"{SCRIPT_DIR}/{level_name}"
        if '.' in scene_name:
            raise ValueError(
                _("The file name provided must not have a file extension."))
        if len(scene_name) > 8:
            raise ValueError(
                _("The file name provided is too long (max 8 characters)."))
        ssx_name = f"{dir_name}/{scene_name}.{ext}"

        self.project.ensure_dir(dir_name)
        self.project.create_new_file(ssx_name, self._get_empty_scene(),
                                     FileType.SSA)

        if matching_ssb is not None:
            ssb_name = f"{dir_name}/{scene_name}{matching_ssb}.ssb"

            save_kwargs = {
                'filename': ssb_name,
                'static_data': self.project.get_rom_module().get_static_data(),
                'project_fm': self.project.get_project_file_manager()
            }
            self.project.create_new_file(
                ssb_name, SsbLoadedFileHandler.create(**save_kwargs),
                SsbLoadedFileHandler, **save_kwargs)
            # Update debugger
            SkyTempleMainController.debugger_manager().on_script_added(
                ssb_name, level_name, ext, f'{scene_name}.{ext}')
            return ssx_name, ssb_name
        else:
            return ssx_name, None
Esempio n. 5
0
    def import_a_sprite__gfxcrunch(self) -> Optional[bytes]:
        md = SkyTempleMessageDialog(
            MainController.window(),
            Gtk.DialogFlags.DESTROY_WITH_PARENT,
            Gtk.MessageType.INFO,
            Gtk.ButtonsType.OK,
            "To import select the directory of the sprite export. If it "
            "is still zipped, unzip it first.",
            title="SkyTemple")
        md.run()
        md.destroy()

        dialog = Gtk.FileChooserNative.new("Import gfxcrunch sprite...",
                                           MainController.window(),
                                           Gtk.FileChooserAction.SELECT_FOLDER,
                                           None, None)

        response = dialog.run()
        fn = dialog.get_filename()
        dialog.destroy()

        if response == Gtk.ResponseType.ACCEPT:
            try:
                return self.get_gfxcrunch().import_sprite(fn)
            except BaseException as e:
                display_error(sys.exc_info(), str(e),
                              "Error importing the sprite.")
                return None
Esempio n. 6
0
    def on_men_palettes_ani_settings_activate(self):
        dialog: Gtk.Dialog = self.parent.builder.get_object(
            'dialog_palettes_animated_settings')
        dialog.set_attached_to(MainController.window())
        dialog.set_transient_for(MainController.window())

        self.parent.builder.get_object(
            'palette_animation11_enabled').set_active(
                self.parent.dpla.has_for_palette(0))
        self.parent.builder.get_object(
            'palette_animation12_enabled').set_active(
                self.parent.dpla.has_for_palette(1))

        for aidx, offset in (11, 0), (12, 16):
            for cidx in range(0, 16):
                self.parent.builder.get_object(
                    f'palette_animation{aidx}_frame_time{cidx}').set_text(
                        str(self.parent.dpla.durations_per_frame_for_colors[
                            offset + cidx]))

        response = dialog.run()
        dialog.hide()

        if response == Gtk.ResponseType.OK:
            had_errors = False
            for palid, aidx, offset in ((0, 11, 0), (1, 12, 16)):
                if self.parent.builder.get_object(
                        f'palette_animation{aidx}_enabled').get_active():
                    # Has palette animations!
                    self.parent.dpla.enable_for_palette(palid)
                else:
                    # Doesn't have
                    self.parent.dpla.disable_for_palette(palid)
                for cidx in range(0, 16):
                    try:
                        time = int(
                            self.parent.builder.get_object(
                                f'palette_animation{aidx}_frame_time{cidx}').
                            get_text())
                    except:
                        time = 0
                        had_errors = True
                    self.parent.dpla.durations_per_frame_for_colors[
                        offset + cidx] = time

            if had_errors:
                md = SkyTempleMessageDialog(
                    MainController.window(),
                    Gtk.DialogFlags.DESTROY_WITH_PARENT,
                    Gtk.MessageType.WARNING,
                    Gtk.ButtonsType.OK,
                    _("Some values were invalid (not a number). "
                      "They were replaced with 0."),
                    title=_("Warning!"))
                md.set_position(Gtk.WindowPosition.CENTER)
                md.run()
                md.destroy()

            self.parent.reload_all()
            self.parent.mark_as_modified()
Esempio n. 7
0
    def on_export_clicked(self, w: Gtk.MenuToolButton):
        self.img.palettes = make_palette_colors_unique(self.img.palettes)
        md = SkyTempleMessageDialog(
            MainController.window(),
            Gtk.DialogFlags.DESTROY_WITH_PARENT, Gtk.MessageType.INFO,
            Gtk.ButtonsType.OK,
            _("This will export the currently selected image with the currently selected palette. "
              "The image file itself contains all palettes, you can choose to import the edited palettes on import."),
            title=_("Export Images")
        )
        md.run()
        md.destroy()
        dialog = Gtk.FileChooserNative.new(
            _("Export current image to folder..."),
            MainController.window(),
            Gtk.FileChooserAction.SAVE,
            _('_Save'), None
        )

        response = dialog.run()
        fn = dialog.get_filename()
        dialog.destroy()

        if response == Gtk.ResponseType.ACCEPT:
            fn = add_extension_if_missing(fn, 'png')
            self.img.to_pil(self.image_idx, self.palette_idx).save(fn)
Esempio n. 8
0
    def on_btn_export_clicked(self, *args):
        md = SkyTempleMessageDialog(
            MainController.window(), Gtk.DialogFlags.MODAL,
            Gtk.MessageType.INFO, Gtk.ButtonsType.OK,
            _("Export is done to a CSV file with the following specifications:\n"
              "- Contains all strings in order, one per row\n"
              "- Strings may be quoted with: \" and escaped with doube-quotes."
              ))
        md.run()
        md.destroy()

        save_diag = Gtk.FileChooserNative.new(_("Export strings as..."),
                                              MainController.window(),
                                              Gtk.FileChooserAction.SAVE, None,
                                              None)

        add_dialog_csv_filter(save_diag)
        response = save_diag.run()
        fn = save_diag.get_filename()
        save_diag.destroy()

        if response == Gtk.ResponseType.ACCEPT:
            if '.' not in fn:
                fn += '.csv'
            with open_utf8(fn, 'w') as result_file:
                wr = csv.writer(result_file)
                wr.writerows([[x] for x in self._str.strings])
Esempio n. 9
0
    def on_men_map_export_activate(self):
        dialog: Gtk.Dialog = self.parent.builder.get_object(
            'dialog_map_export')
        dialog.set_attached_to(MainController.window())
        dialog.set_transient_for(MainController.window())

        resp = dialog.run()
        dialog.hide()
        if resp == ResponseType.OK:
            dialog = Gtk.FileChooserNative.new(
                "Export PNGs of map...", MainController.window(),
                Gtk.FileChooserAction.SELECT_FOLDER, "_Save", None)

            response = dialog.run()
            fn = dialog.get_filename()
            dialog.destroy()

            if response == Gtk.ResponseType.ACCEPT:
                base_filename = os.path.join(
                    fn,
                    f'{self.parent.module.bgs.level[self.parent.item_id].bma_name}_layer'
                )

                layer1 = self.parent.bma.to_pil_single_layer(
                    self.parent.bpc, self.parent.bpl.palettes,
                    self.parent.bpas, 0)
                layer1.save(base_filename + '1.png')

                if self.parent.bma.number_of_layers > 1:
                    layer2 = self.parent.bma.to_pil_single_layer(
                        self.parent.bpc, self.parent.bpl.palettes,
                        self.parent.bpas, 2)
                    layer2.save(base_filename + '2.png')
Esempio n. 10
0
    def _import_tiles(self, layer):
        dialog: Gtk.Dialog = self.parent.builder.get_object(
            'dialog_tiles_import')
        dialog.set_attached_to(MainController.window())
        dialog.set_transient_for(MainController.window())

        # Set dialog settings to map settings
        tiles_import_file: Gtk.FileChooserButton = self.parent.builder.get_object(
            'tiles_import_file')
        tiles_import_file.unselect_all()

        resp = dialog.run()
        dialog.hide()

        if resp == ResponseType.OK:
            try:
                if tiles_import_file.get_filename() is None:
                    md = SkyTempleMessageDialog(
                        MainController.window(),
                        Gtk.DialogFlags.DESTROY_WITH_PARENT,
                        Gtk.MessageType.ERROR,
                        Gtk.ButtonsType.OK,
                        "An image must be selected.",
                        title="Error!")
                    md.set_position(Gtk.WindowPosition.CENTER)
                    md.run()
                    md.destroy()
                else:
                    with open(tiles_import_file.get_filename(), 'rb') as f:
                        self.parent.bpc.pil_to_tiles(layer, Image.open(f))
            except Exception as err:
                display_error(sys.exc_info(), str(err))
            self.parent.reload_all()
            self.parent.mark_as_modified()
Esempio n. 11
0
    def on_men_palettes_ani_edit_activate(self):
        if not self.parent.bpl.has_palette_animation:
            md = SkyTempleMessageDialog(MainController.window(),
                                        Gtk.DialogFlags.DESTROY_WITH_PARENT,
                                        Gtk.MessageType.ERROR,
                                        Gtk.ButtonsType.OK,
                                        "Palette Animation is not enabled.",
                                        title="Warning!")
            md.set_position(Gtk.WindowPosition.CENTER)
            md.run()
            md.destroy()
            return
        # This is controlled by a separate controller
        dict_pals = OrderedDict()

        for i, pal in enumerate(self.parent.bpl.animation_palette):
            dict_pals[f'F{i + 1}'] = pal.copy()

        cntrl = PaletteEditorController(MainController.window(), dict_pals,
                                        False, True, False)
        edited_palettes = cntrl.show()
        if edited_palettes:
            self.parent.bpl.animation_palette = edited_palettes
            self.parent.reload_all()
            self.parent.mark_as_modified()
        del cntrl
Esempio n. 12
0
    def _export_tiles(self, layer):
        dialog: Gtk.Dialog = self.parent.builder.get_object(
            'dialog_tiles_export')
        dialog.set_attached_to(MainController.window())
        dialog.set_transient_for(MainController.window())

        resp = dialog.run()
        dialog.hide()
        if resp == ResponseType.OK:
            dialog = Gtk.FileChooserNative.new("Export PNG of tiles...",
                                               MainController.window(),
                                               Gtk.FileChooserAction.SAVE,
                                               None, None)

            add_dialog_png_filter(dialog)

            response = dialog.run()
            fn = dialog.get_filename()
            if '.' not in fn:
                fn += '.png'
            dialog.destroy()

            if response == Gtk.ResponseType.ACCEPT:
                self.parent.bpc.tiles_to_pil(layer, self.parent.bpl.palettes,
                                             20).save(fn)
Esempio n. 13
0
    def on_item_categories_add_clicked(self, *args):
        store: Gtk.Store = self.builder.get_object('item_categories_store')
        dialog: Gtk.Dialog = self.builder.get_object('dialog_category_add')
        dialog.set_attached_to(MainController.window())
        dialog.set_transient_for(MainController.window())

        # Init available categories
        cb_store: Gtk.ListStore = self.builder.get_object('category_add_store')
        cb: Gtk.ComboBoxText = self.builder.get_object('category_add_cb')
        available_categories = self._fill_available_categories_into_store(
            cb_store)
        # Show error if no categories available
        if len(available_categories) < 1:
            display_error(None, 'All categories are already in the list.',
                          'Can not add category')
            return
        cb.set_active_iter(cb_store.get_iter_first())

        resp = dialog.run()
        dialog.hide()
        if resp == Gtk.ResponseType.APPLY:
            row = cb_store[cb.get_active_iter()]
            store.append([row[0], row[1], False, "0%", "0"])
            self._save_item_spawn_rates()
            self._update_cr_item_cat_name_store()
Esempio n. 14
0
    def on_btn_add_clicked(self, widget):
        dialog: Gtk.Dialog = self.builder.get_object('dialog_choose_char')

        self.builder.get_object('entry_char_id').set_text(str(0))
        self.builder.get_object('entry_char_id').set_increments(1,1)
        self.builder.get_object('entry_char_id').set_range(0, 255)
        
        dialog.set_attached_to(MainController.window())
        dialog.set_transient_for(MainController.window())

        resp = dialog.run()
        dialog.hide()
        if resp == ResponseType.OK:
            cb_store: Gtk.ListStore = self.builder.get_object('table_store')
            cb: Gtk.ComboBoxText = self.builder.get_object('cb_table_select')
            v : int = cb_store[cb.get_active_iter()][0]
            char = int(self.builder.get_object('entry_char_id').get_text())
            try:
                for e in self.entries:
                    if e.get_properties()["char"]==char:
                        raise ValueError(f"Character {char} already exists in the table!")
                entry = self.font.create_entry_for_table(v)
                entry.set_properties({"char": char})
                self.entries.append(entry)
                
                entry_tree: Gtk.TreeView = self.builder.get_object('entry_tree')
                store: Gtk.ListStore = entry_tree.get_model()
                self._add_property_row(store, entry)
                self.module.mark_font_as_modified(self.spec)
            except Exception as err:
                display_error(
                    sys.exc_info(),
                    str(err),
                    "Error adding character."
                )
Esempio n. 15
0
 def on_import_attack_clicked(self, w: Gtk.MenuToolButton):
     sprite = self.module.import_a_sprite()
     if sprite is None:
         return
     self.module.save_monster_attack_sprite(self.item_id, sprite, raw=True)
     self._mark_as_modified_cb()
     MainController.reload_view()
Esempio n. 16
0
    def on_men_chunks_layer1_export_activate(self):
        dialog: Gtk.Dialog = self.parent.builder.get_object(
            'dialog_chunks_export')
        dialog.set_attached_to(MainController.window())
        dialog.set_transient_for(MainController.window())

        resp = dialog.run()
        dialog.hide()
        if resp == Gtk.ResponseType.OK:
            dialog = Gtk.FileChooserNative.new("Export PNG of chunks...",
                                               MainController.window(),
                                               Gtk.FileChooserAction.SAVE,
                                               None, None)

            add_dialog_png_filter(dialog)

            response = dialog.run()
            fn = dialog.get_filename()
            if '.' not in fn:
                fn += '.png'
            dialog.destroy()

            if response == Gtk.ResponseType.ACCEPT:
                try:
                    self.parent.dpc.chunks_to_pil(self.parent.dpci,
                                                  self.parent.dpl.palettes,
                                                  16).save(fn)
                except BaseException as err:
                    display_error(sys.exc_info(), str(err),
                                  "Error exporting the tileset.")
Esempio n. 17
0
    def on_men_tiles_ani_export_activate(self):
        dialog: Gtk.Dialog = self.parent.builder.get_object(
            'dialog_tiles_animated_export')
        dialog.set_attached_to(MainController.window())
        dialog.set_transient_for(MainController.window())
        cb: Gtk.ComboBox = self.parent.builder.get_object(
            'dialog_tiles_animated_export_select_bpa')
        store = Gtk.ListStore(str, int)

        label_sep: Gtk.Label = self.parent.builder.get_object(
            'dialog_tiles_animated_export_label_sep')
        label_sep.set_text(label_sep.get_text().replace(
            '@@@name_pattern@@@', self._get_bpa_export_name_pattern('X', 'Y')))

        for i, bpa in enumerate(self.parent.bpas):
            if bpa is not None:
                store.append([f'BPA{i+1}', i])
        cb.set_model(store)
        cell = Gtk.CellRendererText()
        cb.pack_start(cell, True)
        cb.add_attribute(cell, 'text', 0)
        cb.set_active(0)

        dialog.run()
        # The dialog has two buttons with separate connected signals (
        #   on_dialog_tiles_animated_export_export_btn_activate, on_dialog_tiles_animated_export_import_btn_activate
        # )
        dialog.hide()
Esempio n. 18
0
    def on_men_palettes_ani_settings_activate(self):
        dialog: Gtk.Dialog = self.parent.builder.get_object(
            'dialog_palettes_animated_settings')
        dialog.set_attached_to(MainController.window())
        dialog.set_transient_for(MainController.window())

        self.parent.builder.get_object(
            'palette_animation11_enabled').set_active(
                self.parent.dpla.has_for_palette(0))
        self.parent.builder.get_object(
            'palette_animation12_enabled').set_active(
                self.parent.dpla.has_for_palette(1))

        self.parent.builder.get_object(
            f'palette_animation11_frame_time').set_text(
                str(self.parent.dpla.get_duration_for_palette(0)))
        self.parent.builder.get_object(
            f'palette_animation12_frame_time').set_text(
                str(self.parent.dpla.get_duration_for_palette(1)))

        response = dialog.run()
        dialog.hide()

        if response == Gtk.ResponseType.OK:
            had_errors = False
            for palid, enabled, frame_time in (
                (0, 'palette_animation11_enabled',
                 'palette_animation11_frame_time'),
                (1, 'palette_animation12_enabled',
                 'palette_animation12_frame_time')):
                if self.parent.builder.get_object(enabled).get_active():
                    # Has palette animations!
                    self.parent.dpla.enable_for_palette(palid)
                else:
                    # Doesn't have
                    self.parent.dpla.disable_for_palette(palid)
                try:
                    time = int(
                        self.parent.builder.get_object(frame_time).get_text())
                except:
                    time = 0
                    had_errors = True
                self.parent.dpla.set_duration_for_palette(palid, time)

            if had_errors:
                md = Gtk.MessageDialog(
                    MainController.window(),
                    Gtk.DialogFlags.DESTROY_WITH_PARENT,
                    Gtk.MessageType.WARNING,
                    Gtk.ButtonsType.OK,
                    "Some values were invalid (not a number). "
                    "They were replaced with 0.",
                    title="Warning!")
                md.set_position(Gtk.WindowPosition.CENTER)
                md.run()
                md.destroy()

            self.parent.reload_all()
            self.parent.mark_as_modified()
Esempio n. 19
0
    def on_btn_add_clicked(self, *args):
        from skytemple.module.map_bg.module import MAP_BG_PATH
        response, name = self._show_generic_input(_('Map Background Name'),
                                                  _('Create Background'))
        if response != Gtk.ResponseType.OK:
            return
        name = name.lower()
        name_bg_list = name.upper()
        if len(name) < 1 or len(name) > 8:
            md = SkyTempleMessageDialog(
                SkyTempleMainController.window(), Gtk.DialogFlags.MODAL,
                Gtk.MessageType.ERROR, Gtk.ButtonsType.OK,
                _("The length of the map background name must be between 1-8 characters."
                  ))
            md.run()
            md.destroy()
            return
        bpl_name = f'{name}.bpl'
        bpc_name = f'{name}.bpc'
        bma_name = f'{name}.bma'
        if self.module.project.file_exists(MAP_BG_PATH + bpl_name) or \
                self.module.project.file_exists(MAP_BG_PATH + bpc_name) or \
                self.module.project.file_exists(MAP_BG_PATH + bma_name):
            md = SkyTempleMessageDialog(
                SkyTempleMainController.window(), Gtk.DialogFlags.MODAL,
                Gtk.MessageType.ERROR, Gtk.ButtonsType.OK,
                _("A map background with this name already exists."))
            md.run()
            md.destroy()
            return

        with open(os.path.join(data_dir(), 'empty.bpl'), 'rb') as f:
            empty_bpl = FileType.BPL.deserialize(f.read())
        with open(os.path.join(data_dir(), 'empty.bma'), 'rb') as f:
            empty_bma = FileType.BMA.deserialize(f.read())
        with open(os.path.join(data_dir(), 'empty.bpc'), 'rb') as f:
            empty_bpc = FileType.BPC.deserialize(f.read())

        # Write to ROM
        self.module.project.create_new_file(MAP_BG_PATH + bpl_name, empty_bpl,
                                            FileType.BPL)
        self.module.project.create_new_file(MAP_BG_PATH + bma_name, empty_bma,
                                            FileType.BMA)
        self.module.project.create_new_file(MAP_BG_PATH + bpc_name, empty_bpc,
                                            FileType.BPC)
        self.module.add_map(name_bg_list)

        md = SkyTempleMessageDialog(SkyTempleMainController.window(),
                                    Gtk.DialogFlags.MODAL,
                                    Gtk.MessageType.INFO,
                                    Gtk.ButtonsType.OK,
                                    _("Map background added successfully"),
                                    is_success=True)
        md.run()
        md.destroy()
Esempio n. 20
0
    def on_separate_import_activate(self, *args):
        md = SkyTempleMessageDialog(
            MainController.window(),
            Gtk.DialogFlags.DESTROY_WITH_PARENT,
            Gtk.MessageType.INFO,
            Gtk.ButtonsType.OK,
            f(
                _("To import, select a directory to import from. Files with the pattern '{self.item_id + 1}_XX.png'\n"
                  "will be imported, where XX is a number between 0 and 40.")),
            title=_("Import Portraits"))
        md.run()
        md.destroy()
        dialog = Gtk.FileChooserNative.new(_("Import portraits from PNGs..."),
                                           MainController.window(),
                                           Gtk.FileChooserAction.SELECT_FOLDER,
                                           None, None)

        response = dialog.run()
        fn = dialog.get_filename()
        dialog.destroy()

        if response == Gtk.ResponseType.ACCEPT:
            r = re.compile(rf"{self.item_id + 1}_(\d+)\.png", re.IGNORECASE)
            imgs = {
                int(match[1]): name
                for match, name in self._try_match_import(r, os.listdir(fn))
                if match is not None and int(match[1]) <= 40
            }
            for subindex, image_fn in imgs.items():
                try:
                    with open(os.path.join(fn, image_fn), 'rb') as f:
                        image = Image.open(f)
                        kao = self.kao.get(self.item_id, subindex)
                        if kao:
                            # Replace
                            kao.set(image)
                        else:
                            # New
                            self.kao.set(self.item_id, subindex,
                                         KaoImage.new(image))
                except Exception as err:
                    name = self._get_portrait_name(subindex)
                    logger.error(f"Failed importing image '{name}'.",
                                 exc_info=err)
                    display_error(
                        sys.exc_info(),
                        f(_('Failed importing image "{name}":\n{err}')),
                        f(_(f"Error for '{name}'.")))
            # Re-render
            self._portrait_provider.reset()
            for draw in self._draws:
                draw.queue_draw()
            # Mark as modified
            self.module.mark_as_modified()
            self._mark_as_modified_cb()
Esempio n. 21
0
    def on_men_map_import_activate(self):
        dialog: Gtk.Dialog = self.parent.builder.get_object(
            'dialog_map_import')
        dialog.set_attached_to(MainController.window())
        dialog.set_transient_for(MainController.window())

        # Set dialog settings to map settings
        map_import_layer1_file: Gtk.FileChooserButton = self.parent.builder.get_object(
            'map_import_layer1_file')
        map_import_layer2_file: Gtk.FileChooserButton = self.parent.builder.get_object(
            'map_import_layer2_file')
        map_import_layer1_file.unselect_all()
        map_import_layer2_file.unselect_all()
        if self.parent.bma.number_of_layers < 2:
            map_import_layer2_file.set_sensitive(False)

        resp = dialog.run()
        dialog.hide()

        if resp == ResponseType.OK:
            try:
                img1_path = map_import_layer1_file.get_filename()
                img2_path = map_import_layer2_file.get_filename()
                palettes_from_lower_layer = self.parent.builder.get_object(
                    'dialog_map_import_palette_config').get_value()
                if self.parent.bma.number_of_layers < 2 and img1_path is not None:
                    with open(img1_path, 'rb') as f:
                        self.parent.bma.from_pil(self.parent.bpc,
                                                 self.parent.bpl,
                                                 Image.open(f), None, True)
                elif img1_path is not None and img2_path is None:
                    with open(img1_path, 'rb') as f1:
                        self.parent.bma.from_pil(self.parent.bpc,
                                                 self.parent.bpl,
                                                 Image.open(f1), None, True)
                elif img1_path is None and img2_path is not None:
                    with open(img2_path, 'rb') as f2:
                        self.parent.bma.from_pil(self.parent.bpc,
                                                 self.parent.bpl, None,
                                                 Image.open(f2), True)
                elif img1_path is not None and img2_path is not None:
                    with open(img1_path, 'rb') as f1:
                        with open(img2_path, 'rb') as f2:
                            self.parent.bma.from_pil(
                                self.parent.bpc,
                                self.parent.bpl,
                                Image.open(f1),
                                Image.open(f2),
                                True,
                                how_many_palettes_lower_layer=int(
                                    palettes_from_lower_layer))
            except Exception as err:
                display_error(sys.exc_info(), str(err))
            self.parent.reload_all()
            self.parent.mark_as_modified()
Esempio n. 22
0
 def _run_window(self):
     dialog: Gtk.Dialog = self.builder.get_object('dialog')
     dialog.resize(750, 350)
     dialog.set_transient_for(MainController.window())
     dialog.set_attached_to(MainController.window())
     self.buffer.delete(self.buffer.get_start_iter(), self.buffer.get_end_iter())
     self._update_status(GfxcrunchStatus.RUNNING)
     self.builder.get_object('spinner').start()
     self.builder.get_object('close').set_sensitive(False)
     dialog.run()
     dialog.hide()
Esempio n. 23
0
    def _setup_dialog(self):
        dialog: Gtk.Dialog = self.builder.get_object('dialog_add_remove')

        self.builder.get_object('id_key_add_remove').set_increments(1, 1)
        self.builder.get_object('id_key_add_remove').set_range(
            0, self._get_max_key())
        self.builder.get_object('id_key_add_remove').set_text(str(0))

        dialog.set_attached_to(MainController.window())
        dialog.set_transient_for(MainController.window())

        return dialog
Esempio n. 24
0
    def on_import_clicked(self, w: Gtk.MenuToolButton):
        md = SkyTempleMessageDialog(
            MainController.window(),
            Gtk.DialogFlags.DESTROY_WITH_PARENT,
            Gtk.MessageType.INFO,
            Gtk.ButtonsType.OK,
            _("To import, select a folder containing all the files that were created when exporting the font.\n"
              "IMPORTANT: All image files must be indexed PNGs and use the same palette!"
              ),
            title=_("Import Font"))
        md.run()
        md.destroy()
        fdialog = Gtk.FileChooserNative.new(
            _("Import font from folder..."), MainController.window(),
            Gtk.FileChooserAction.SELECT_FOLDER, None, None)

        response = fdialog.run()
        fn = fdialog.get_filename()
        fdialog.destroy()

        if response == Gtk.ResponseType.ACCEPT:
            assert self.builder
            dialog: Gtk.Dialog = self.builder.get_object('dialog_import')

            self.builder.get_object('nb_entries_import').set_increments(1, 1)
            self.builder.get_object('nb_entries_import').set_range(
                1, MAX_ENTRIES - 1)
            self.builder.get_object('nb_entries_import').set_text(
                str(self.font.get_nb_entries()))  # type: ignore

            dialog.set_attached_to(MainController.window())
            dialog.set_transient_for(MainController.window())

            resp = dialog.run()
            dialog.hide()
            if resp == Gtk.ResponseType.OK:
                try:
                    lst_entries: List[Optional[Image.Image]] = []
                    for i in range(
                            int(
                                self.builder.get_object(
                                    'nb_entries_import').get_text())):
                        path = os.path.join(fn, f'{i:0>4}.png')
                        if os.path.exists(path):
                            lst_entries.append(Image.open(path, 'r'))
                        else:
                            lst_entries.append(None)
                    self.font.set_entries(lst_entries)  # type: ignore
                    self.module.mark_font_as_modified(self.spec)
                except Exception as err:
                    display_error(sys.exc_info(), str(err),
                                  _("Error importing font."))
                self._init_font()
Esempio n. 25
0
    def do_import(self, item_id: int, cb=lambda: None):
        is_zip = self._zip_is_active()

        dialog = Gtk.FileChooserNative.new(
            _("Import spritesheet..."), MainController.window(),
            Gtk.FileChooserAction.SELECT_FOLDER
            if not is_zip else Gtk.FileChooserAction.OPEN, None, None)

        if is_zip:
            self._add_zip_filter_to_dialog(dialog)

        response = dialog.run()
        fn = dialog.get_filename()
        dialog.destroy()

        if response == Gtk.ResponseType.ACCEPT:
            try:
                wan = FileType.WAN.CHARA.import_sheets(fn) if not is_zip \
                    else FileType.WAN.CHARA.import_sheets_from_zip(fn)
                monster, ground, attack = FileType.WAN.CHARA.split_wan(wan)

                md = SkyTempleMessageDialog(
                    MainController.window(),
                    Gtk.DialogFlags.DESTROY_WITH_PARENT,
                    Gtk.MessageType.INFO,
                    Gtk.ButtonsType.OK,
                    _("The spritesheet was successfully imported."),
                    title=_("Success!"),
                    is_success=True)
                md.run()
                md.destroy()
                self.module.save_monster_monster_sprite(item_id, monster)
                self.module.save_monster_ground_sprite(item_id, ground)
                self.module.save_monster_attack_sprite(item_id, attack)

                # Shadow size
                if not is_zip:
                    tree = ElementTree.parse(os.path.join(
                        fn, 'AnimData.xml')).getroot()
                else:
                    with ZipFile(fn, 'r') as ZipObj:
                        tree = ElementTree.fromstring(
                            ZipObj.read('AnimData.xml'))
                self._set_shadow_size_cb(int(
                    tree.find('ShadowSize').text))  # type: ignore

                cb()
                self._mark_as_modified_cb()
                MainController.reload_view()
            except BaseException as e:
                display_error(sys.exc_info(), str(e),
                              _("Error importing the spritesheet."))
Esempio n. 26
0
    def on_export_clicked(self, w: Gtk.MenuToolButton):
        is_zip = self._zip_is_active()

        dialog = Gtk.FileChooserNative.new(
            _("Export spritesheet..."), MainController.window(),
            Gtk.FileChooserAction.SELECT_FOLDER
            if not is_zip else Gtk.FileChooserAction.SAVE, _('_Save'), None)

        if is_zip:
            self._add_zip_filter_to_dialog(dialog)

        response = dialog.run()
        fn = dialog.get_filename()
        dialog.destroy()

        if response == Gtk.ResponseType.ACCEPT:
            try:
                monster: WanFile = self.module.get_monster_monster_sprite_chara(
                    self.item_id)  # type: ignore
                ground: WanFile = self.module.get_monster_ground_sprite_chara(
                    self.item_id)  # type: ignore
                attack: WanFile = self.module.get_monster_attack_sprite_chara(
                    self.item_id)  # type: ignore
                merged = FileType.WAN.CHARA.merge_wan(monster, ground, attack)
                merged.sdwSize = self._get_shadow_size_cb()
                try:
                    animation_names = self.module.project.get_rom_module(
                    ).get_static_data().animation_names[self.item_id]
                except KeyError:
                    # Fall back to Bulbasaur
                    animation_names = self.module.project.get_rom_module(
                    ).get_static_data().animation_names[0]
                if not is_zip:
                    FileType.WAN.CHARA.export_sheets(fn, merged,
                                                     animation_names)
                else:
                    FileType.WAN.CHARA.export_sheets_as_zip(
                        fn, merged, animation_names)

                md = SkyTempleMessageDialog(
                    MainController.window(),
                    Gtk.DialogFlags.DESTROY_WITH_PARENT,
                    Gtk.MessageType.INFO,
                    Gtk.ButtonsType.OK,
                    _("The spritesheet was successfully exported."),
                    title=_("Success!"),
                    is_success=True)
                md.run()
                md.destroy()
            except BaseException as e:
                display_error(sys.exc_info(), str(e),
                              _("Error exporting the spritesheet."))
Esempio n. 27
0
    def on_btn_import_clicked(self, *args):
        md = SkyTempleMessageDialog(MainController.window(),
                                    Gtk.DialogFlags.DESTROY_WITH_PARENT, Gtk.MessageType.INFO,
                                    Gtk.ButtonsType.OK, _("To import select the XML file in the DTEF tileset package. If it "
                                                          "is still zipped, unzip it first."),
                                    title="SkyTemple")
        md.run()
        md.destroy()

        dialog = Gtk.FileChooserNative.new(
            _("Import dungeon tileset..."),
            MainController.window(),
            Gtk.FileChooserAction.OPEN,
            None, None
        )

        filter = Gtk.FileFilter()
        filter.set_name(_("DTEF XML document (*.dtef.xml)"))
        filter.add_pattern("*.dtef.xml")
        dialog.add_filter(filter)
        add_dialog_xml_filter(dialog)

        response = dialog.run()
        fn = dialog.get_filename()
        dialog.destroy()

        if response == Gtk.ResponseType.ACCEPT:
            try:
                dirname = os.path.dirname(fn)
                fn_xml = fn
                fn_var0 = os.path.join(dirname, VAR0_FN)
                fn_var1 = os.path.join(dirname, VAR1_FN)
                fn_var2 = os.path.join(dirname, VAR2_FN)
                dtef_importer = ExplorersDtefImporter(self.dma, self.dpc, self.dpci, self.dpl, self.dpla)
                dtef_importer.do_import(
                    dirname, fn_xml, fn_var0, fn_var1, fn_var2
                )

                md = SkyTempleMessageDialog(MainController.window(),
                                            Gtk.DialogFlags.DESTROY_WITH_PARENT, Gtk.MessageType.INFO,
                                            Gtk.ButtonsType.OK, _("The tileset was successfully imported."),
                                            title=_("Success!"), is_success=True)
                md.run()
                md.destroy()
                self.mark_as_modified()
                MainController.reload_view()
            except BaseException as e:
                display_error(
                    sys.exc_info(),
                    str(e),
                    _("Error importing the tileset.")
                )
Esempio n. 28
0
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())
        }
    }
Esempio n. 29
0
    def on_dialog_tiles_animated_export_export_btn_clicked(self):
        bpa_select = self.parent.builder.get_object(
            'dialog_tiles_animated_export_select_bpa')
        active_bpa_index = bpa_select.get_model()[
            bpa_select.get_active_iter()][1]
        active_bpa = self.parent.bpas[active_bpa_index]
        is_single_mode = self.parent.builder.get_object(
            'dialog_tiles_animated_export_radio_single').get_active()
        file_chooser_mode = Gtk.FileChooserAction.SAVE if is_single_mode else Gtk.FileChooserAction.SELECT_FOLDER
        dialog = Gtk.FileChooserNative.new(_("Export animated tiles (BPA)"),
                                           MainController.window(),
                                           file_chooser_mode, None, None)

        if is_single_mode:
            add_dialog_png_filter(dialog)

        response = dialog.run()
        fn = dialog.get_filename()
        dialog.destroy()

        if response == Gtk.ResponseType.ACCEPT:
            # TODO: Support specifying palette
            pal = self.parent.bpl.palettes[0]
            try:
                if is_single_mode:
                    if not fn.endswith('.png'):
                        fn += '.png'
                    active_bpa.tiles_to_pil(pal).save(fn)
                else:
                    for i, img in enumerate(
                            active_bpa.tiles_to_pil_separate(pal, 20)):
                        img.save(
                            os.path.join(
                                fn,
                                self._get_bpa_export_name_pattern(
                                    active_bpa_index + 1, i)))
                md = SkyTempleMessageDialog(
                    MainController.window(),
                    Gtk.DialogFlags.DESTROY_WITH_PARENT,
                    Gtk.MessageType.INFO,
                    Gtk.ButtonsType.OK,
                    _("The animated tiles were successfully exported."),
                    title=_("SkyTemple - Success!"),
                    is_success=True)
                md.run()
                md.destroy()
            except Exception as err:
                logger.error(_("Error during BPA export"), exc_info=err)
                display_error(sys.exc_info(), str(err))
Esempio n. 30
0
    def on_btn_import_clicked(self, *args):
        save_diag = Gtk.FileChooserNative.new(_("Import Pokémon from..."),
                                              SkyTempleMainController.window(),
                                              Gtk.FileChooserAction.OPEN, None,
                                              None)

        add_dialog_xml_filter(save_diag)
        response = save_diag.run()
        fn = save_diag.get_filename()
        save_diag.destroy()

        if response == Gtk.ResponseType.ACCEPT:
            self.module.import_from_xml([self.entry.md_index],
                                        ElementTree.parse(fn).getroot())
            SkyTempleMainController.reload_view()