Ejemplo n.º 1
0
class NewGameDirDialog(UIDialog):
    title = 'New game'
    field0_label = 'Name of new game folder:'
    field1_label = 'Name of new game:'
    field_width = UIDialog.default_field_width
    fields = [
        Field(label=field0_label, type=str, width=field_width, oneline=False),
        Field(label=field1_label, type=str, width=field_width, oneline=False)
    ]
    confirm_caption = 'Create'
    game_mode_visible = True
    
    # TODO: only allow names that don't already exist
    
    def get_initial_field_text(self, field_number):
        # provide a reasonable non-blank name
        if field_number == 0:
            return 'newgame'
        elif field_number == 1:
            return type(self.ui.app.gw).game_title
    
    def confirm_pressed(self):
        if self.ui.app.gw.create_new_game(self.field_texts[0], self.field_texts[1]):
            self.ui.app.enter_game_mode()
        self.dismiss()
Ejemplo n.º 2
0
class AddRoomDialog(UIDialog):
    title = 'Add new room'
    field0_label = 'Name for new room:'
    field1_label = 'Class of new room:'
    field_width = UIDialog.default_field_width
    fields = [
        Field(label=field0_label, type=str, width=field_width, oneline=False),
        Field(label=field1_label, type=str, width=field_width, oneline=False)
    ]
    confirm_caption = 'Add'
    game_mode_visible = True
    invalid_room_name_error = 'Invalid room name.'
    
    def get_initial_field_text(self, field_number):
        # provide a reasonable non-blank name
        if field_number == 0:
            return 'Room ' + str(len(self.ui.app.gw.rooms) + 1)
        elif field_number == 1:
            return 'GameRoom'
    
    def is_input_valid(self):
        return self.field_texts[0] != '', self.invalid_room_name_error
    
    def confirm_pressed(self):
        valid, reason = self.is_input_valid()
        if not valid: return
        self.ui.app.gw.add_room(self.field_texts[0], self.field_texts[1])
        self.dismiss()
Ejemplo n.º 3
0
class SaveAsDialog(BaseFileDialog):

    title = 'Save art'
    field0_label = 'New filename for art:'
    field2_label = 'Save folder:'
    field3_label = ' %s'
    tile_width = 60
    field0_width = 56
    y_spacing = 0
    fields = [
        Field(label=field0_label, type=str, width=field0_width, oneline=False),
        Field(label='', type=None, width=0, oneline=True),
        Field(label=field2_label, type=None, width=0, oneline=True),
        Field(label=field3_label, type=None, width=0, oneline=True),
        Field(label='', type=None, width=0, oneline=True)
    ]
    confirm_caption = 'Save'
    always_redraw_labels = True

    def get_initial_field_text(self, field_number):
        if field_number == 0:
            # special case: if opening playscii/art/new, change
            # it to documents dir to avoid writing to application dir
            # (still possible if you open other files)
            if os.path.dirname(self.ui.active_art.filename) == ART_DIR[:-1]:
                self.ui.active_art.filename = self.ui.app.documents_dir + self.ui.active_art.filename
            # TODO: handle other files from app dir as well? not as important
            filename = os.path.basename(self.ui.active_art.filename)
            filename = os.path.splitext(filename)[0]
            return filename
        return ''

    def get_file_extension(self):
        """
        Return file extension this dialog saves as; other dialogs
        are based on this class so we don't want to hardcore .psci
        """
        return ART_FILE_EXTENSION

    def get_dir(self):
        return os.path.dirname(self.ui.active_art.filename)

    def get_field_label(self, field_index):
        label = self.fields[field_index].label
        # show dir art will be saved into
        if field_index == 3:
            label %= self.get_dir()
        return label

    def is_input_valid(self):
        return self.is_filename_valid(0)

    def confirm_pressed(self):
        valid, reason = self.is_input_valid()
        if not valid: return
        SaveCommand.execute(self.ui.console, [self.field_texts[0]])
        self.dismiss()
Ejemplo n.º 4
0
class PNGExportOptionsDialog(ExportOptionsDialog):
    title = 'PNG image export options'
    field0_label = 'Scale factor (%s pixels)'
    field1_label = 'CRT filter'
    fields = [
        Field(label=field0_label, type=int, width=6, oneline=False),
        Field(label=field1_label, type=bool, width=0, oneline=True)
    ]
    # redraw dynamic labels
    always_redraw_labels = True
    invalid_scale_error = 'Scale must be greater than 0'

    def get_initial_field_text(self, field_number):
        if field_number == 0:
            return str(DEFAULT_SCALE)
        elif field_number == 1:
            return [' ', UIDialog.true_field_text][DEFAULT_CRT]

    def get_field_label(self, field_index):
        label = self.fields[field_index].label
        if field_index == 0:
            valid, _ = self.is_input_valid()
            if not valid:
                label %= '???'
            else:
                # calculate exported image size
                art = self.ui.active_art
                scale = int(self.field_texts[0])
                width = art.charset.char_width * art.width * scale
                height = art.charset.char_height * art.height * scale
                label %= '%s x %s' % (width, height)
        return label

    def is_input_valid(self):
        # scale factor: >0 int
        try:
            int(self.field_texts[0])
        except:
            return False, self.invalid_scale_error
        if int(self.field_texts[0]) <= 0:
            return False, self.invalid_scale_error
        return True, None

    def confirm_pressed(self):
        valid, reason = self.is_input_valid()
        if not valid: return
        self.dismiss()
        # compile options for exporter
        options = {
            'scale': int(self.field_texts[0]),
            'crt': bool(self.field_texts[1].strip())
        }
        ExportOptionsDialog.do_export(self.ui.app, self.filename, options)
Ejemplo n.º 5
0
class AddFrameDialog(UIDialog):

    title = 'Add new frame'
    field0_label = 'Index to add frame before:'
    field1_label = 'Hold time (in seconds) for new frame:'
    field_width = UIDialog.default_short_field_width
    fields = [
        Field(label=field0_label, type=int, width=field_width, oneline=True),
        Field(label=field1_label, type=float, width=field_width, oneline=False)
    ]
    confirm_caption = 'Add'
    invalid_index_error = 'Invalid index. (1-%s allowed)'
    invalid_delay_error = 'Invalid hold time.'

    def get_initial_field_text(self, field_number):
        if field_number == 0:
            return str(self.ui.active_art.frames + 1)
        elif field_number == 1:
            return str(DEFAULT_FRAME_DELAY)

    def is_valid_frame_index(self, index):
        try:
            index = int(index)
        except:
            return False
        if index < 1 or index > self.ui.active_art.frames + 1:
            return False
        return True

    def is_valid_frame_delay(self, delay):
        try:
            delay = float(delay)
        except:
            return False
        return delay > 0

    def is_input_valid(self):
        if not self.is_valid_frame_index(self.field_texts[0]):
            return False, self.invalid_index_error % str(
                self.ui.active_art.frames + 1)
        if not self.is_valid_frame_delay(self.field_texts[1]):
            return False, self.invalid_delay_error
        return True, None

    def confirm_pressed(self):
        valid, reason = self.is_input_valid()
        if not valid: return
        index = int(self.field_texts[0])
        delay = float(self.field_texts[1])
        self.ui.active_art.insert_frame_before_index(index - 1, delay)
        self.dismiss()
Ejemplo n.º 6
0
class AddLayerDialog(UIDialog):

    title = 'Add new layer'
    field0_label = 'Name for new layer:'
    field1_label = 'Z-depth for new layer:'
    field0_width = UIDialog.default_field_width
    field1_width = UIDialog.default_short_field_width
    fields = [
        Field(label=field0_label, type=str, width=field0_width, oneline=False),
        Field(label=field1_label, type=float, width=field1_width, oneline=True)
    ]
    confirm_caption = 'Add'
    name_exists_error = 'Layer by that name already exists.'
    invalid_z_error = 'Invalid number.'

    def get_initial_field_text(self, field_number):
        if field_number == 0:
            return 'Layer %s' % str(self.ui.active_art.layers + 1)
        elif field_number == 1:
            return str(
                self.ui.active_art.layers_z[self.ui.active_art.active_layer] +
                DEFAULT_LAYER_Z_OFFSET)

    def is_valid_layer_name(self, name, exclude_active_layer=False):
        for i, layer_name in enumerate(self.ui.active_art.layer_names):
            if exclude_active_layer and i == self.ui.active_layer:
                continue
            if layer_name == name:
                return False
        return True

    def is_input_valid(self):
        valid_name = self.is_valid_layer_name(self.field_texts[0])
        if not valid_name:
            return False, self.name_exists_error
        try:
            z = float(self.field_texts[1])
        except:
            return False, self.invalid_z_error
        return True, None

    def confirm_pressed(self):
        valid, reason = self.is_input_valid()
        if not valid: return
        name = self.field_texts[0]
        z = float(self.field_texts[1])
        self.ui.active_art.add_layer(z, name)
        self.dismiss()
Ejemplo n.º 7
0
class EDSCIIImportOptionsDialog(ImportOptionsDialog):
    title = 'Import EDSCII (legacy format) art'
    field0_label = 'Width override (leave 0 to guess):'
    field_width = UIDialog.default_short_field_width
    fields = [
        Field(label=field0_label, type=int, width=field_width, oneline=False)
    ]
    invalid_width_error = 'Invalid width override.'
    
    def get_initial_field_text(self, field_number):
        if field_number == 0:
            return '0'
        return ''
    
    def is_input_valid(self):
        # valid widths: any >=0 int
        try: int(self.field_texts[0])
        except: return False, self.invalid_width_error
        if int(self.field_texts[0]) < 0:
            return False, self.invalid_width_error
        return True, None
    
    def confirm_pressed(self):
        valid, reason = self.is_input_valid()
        if not valid: return
        width = int(self.field_texts[0])
        width = width if width > 0 else None
        options = {'width_override':width}
        self.dismiss()
        # self.filename is set in our importer's file_chooser_dialog_class
        ImportOptionsDialog.do_import(self.ui.app, self.filename, options)
Ejemplo n.º 8
0
class EditObjectPropertyDialog(UIDialog):

    "dialog invoked by panel property click, modified at runtime as needed"
    base_title = 'Set %s'
    field0_base_label = 'New %s for %s:'
    field_width = UIDialog.default_field_width
    fields = [
        Field(label=field0_base_label,
              type=str,
              width=field_width,
              oneline=False)
    ]
    confirm_caption = 'Set'
    center_in_window = False
    game_mode_visible = True

    def is_input_valid(self):
        try:
            self.fields[0].type(self.field_texts[0])
        except:
            return False, ''
        return True, None

    def confirm_pressed(self):
        valid, reason = self.is_input_valid()
        if not valid: return
        # set property for selected object(s)
        new_value = self.fields[0].type(self.field_texts[0])
        for obj in self.ui.app.gw.selected_objects:
            obj.set_object_property(self.item.prop_name, new_value)
        self.dismiss()
        # restore keyboard focus to edit panel
        self.ui.keyboard_focus_element = self.ui.edit_object_panel
Ejemplo n.º 9
0
class FrameDelayDialog(AddFrameDialog):

    field0_label = 'New hold time (in seconds) for frame:'
    field_width = UIDialog.default_short_field_width
    fields = [
        Field(label=field0_label, type=float, width=field_width, oneline=False)
    ]
    confirm_caption = 'Set'

    def get_initial_field_text(self, field_number):
        if field_number == 0:
            return str(self.ui.active_art.frame_delays[
                self.ui.active_art.active_frame])

    def is_input_valid(self):
        if not self.is_valid_frame_delay(self.field_texts[0]):
            return False, self.invalid_delay_error
        return True, None

    def confirm_pressed(self):
        valid, reason = self.is_input_valid()
        if not valid: return
        delay = float(self.field_texts[0])
        self.ui.active_art.frame_delays[
            self.ui.active_art.active_frame] = delay
        self.dismiss()
Ejemplo n.º 10
0
class SetCameraZoomDialog(UIDialog):
    title = 'Set camera zoom'
    field0_label = 'New camera zoom %:'
    field_width = UIDialog.default_short_field_width
    fields = [
        Field(label=field0_label, type=float, width=field_width, oneline=True)
    ]
    confirm_caption = 'Set'
    invalid_zoom_error = 'Zoom % must be a number greater than zero.'
    all_modes_visible = True
    game_mode_visible = True

    def get_initial_field_text(self, field_number):
        if field_number == 0:
            return '%.1f' % self.ui.app.camera.get_current_zoom_pct()
        return ''

    def is_input_valid(self):
        try:
            zoom = float(self.field_texts[0])
        except:
            return False, self.invalid_zoom_error
        if zoom <= 0:
            return False, self.invalid_zoom_error
        return True, None

    def confirm_pressed(self):
        valid, reason = self.is_input_valid()
        if not valid: return
        new_zoom_pct = float(self.field_texts[0])
        camera = self.ui.app.camera
        camera.z = camera.get_base_zoom() / (new_zoom_pct / 100)
        self.dismiss()
Ejemplo n.º 11
0
class SetLayerZDialog(UIDialog):
    title = 'Set layer Z-depth'
    field0_label = 'Z-depth for layer:'
    field_width = UIDialog.default_short_field_width
    fields = [
        Field(label=field0_label, type=float, width=field_width, oneline=False)
    ]
    confirm_caption = 'Set'
    invalid_z_error = 'Invalid number.'

    def get_initial_field_text(self, field_number):
        # populate with existing z
        if field_number == 0:
            return str(
                self.ui.active_art.layers_z[self.ui.active_art.active_layer])

    def is_input_valid(self):
        try:
            z = float(self.field_texts[0])
        except:
            return False, self.invalid_z_error
        return True, None

    def confirm_pressed(self):
        valid, reason = self.is_input_valid()
        if not valid: return
        new_z = float(self.field_texts[0])
        self.ui.active_art.layers_z[self.ui.active_art.active_layer] = new_z
        self.ui.active_art.set_unsaved_changes(True)
        self.ui.app.grid.reset()
        self.dismiss()
Ejemplo n.º 12
0
class PaletteFromFileDialog(UIDialog):
    title = 'Create palette from file'
    field0_label = 'Filename to create palette from:'
    field1_label = 'Filename for new palette:'
    field2_label = 'Colors in new palette:'
    field0_width = field1_width = UIDialog.default_field_width
    field2_width = UIDialog.default_short_field_width
    fields = [
        Field(label=field0_label, type=str, width=field0_width, oneline=False),
        Field(label=field1_label, type=str, width=field1_width, oneline=False),
        Field(label=field2_label, type=int, width=field2_width, oneline=True)
    ]
    confirm_caption = 'Create'
    invalid_color_error = 'Palettes must be between 2 and 256 colors.'
    bad_output_filename_error = 'Enter a filename for the new palette.'

    def get_initial_field_text(self, field_number):
        # NOTE: PaletteFromImageChooserDialog.confirm_pressed which invokes us
        # sets fields 0 and 1
        if field_number == 2:
            return str(256)
        return ''

    def valid_colors(self, colors):
        try:
            c = int(colors)
        except:
            return False
        return 2 <= c <= 256

    def is_input_valid(self):
        valid_colors = self.valid_colors(self.field_texts[2])
        if not valid_colors:
            return False, self.invalid_color_error
        if not self.field_texts[1].strip():
            return False, self.bad_output_filename_error
        return True, None

    def confirm_pressed(self):
        valid, reason = self.is_input_valid()
        if not valid: return
        src_filename = self.field_texts[0]
        palette_filename = self.field_texts[1]
        colors = int(self.field_texts[2])
        new_pal = PaletteFromFile(self.ui.app, src_filename, palette_filename,
                                  colors)
        self.dismiss()
Ejemplo n.º 13
0
class SaveGameStateDialog(UIDialog):
    
    title = 'Save game state'
    field_label = 'New filename for game state:'
    field_width = UIDialog.default_field_width
    fields = [
        Field(label=field_label, type=str, width=field_width, oneline=False)
    ]
    confirm_caption = 'Save'
    game_mode_visible = True
    
    def confirm_pressed(self):
        SaveGameStateCommand.execute(self.ui.console, [self.field_texts[0]])
        self.dismiss()
Ejemplo n.º 14
0
class FrameDelayAllDialog(FrameDelayDialog):
    field0_label = 'New hold time (in seconds) for all frames:'
    field_width = UIDialog.default_short_field_width
    fields = [
        Field(label=field0_label, type=float, width=field_width, oneline=False)
    ]

    def confirm_pressed(self):
        valid, reason = self.is_input_valid()
        if not valid: return
        delay = float(self.field_texts[0])
        for i in range(self.ui.active_art.frames):
            self.ui.active_art.frame_delays[i] = delay
        self.dismiss()
Ejemplo n.º 15
0
class SetRoomEdgeWarpsDialog(UIDialog):
    title = 'Set room edge warps'
    tile_width = 48
    fields = 4
    field0_label = 'Name of room/object to warp at LEFT edge:'
    field1_label = 'Name of room/object to warp at RIGHT edge:'
    field2_label = 'Name of room/object to warp at TOP edge:'
    field3_label = 'Name of room/object to warp at BOTTOM edge:'
    field_width = UIDialog.default_field_width
    fields = [
        Field(label=field0_label, type=str, width=field_width, oneline=False),
        Field(label=field1_label, type=str, width=field_width, oneline=False),
        Field(label=field2_label, type=str, width=field_width, oneline=False),
        Field(label=field3_label, type=str, width=field_width, oneline=False)
    ]
    confirm_caption = 'Set'
    game_mode_visible = True
    
    def get_initial_field_text(self, field_number):
        room = self.ui.app.gw.current_room
        names = {0: room.left_edge_warp_dest_name, 1: room.right_edge_warp_dest_name,
                 2: room.top_edge_warp_dest_name, 3: room.bottom_edge_warp_dest_name}
        return names[field_number]
    
    def dismiss(self):
        self.ui.edit_list_panel.set_list_operation(LO_NONE)
        UIDialog.dismiss(self)
    
    def confirm_pressed(self):
        room = self.ui.app.gw.current_room
        room.left_edge_warp_dest_name = self.field_texts[0]
        room.right_edge_warp_dest_name = self.field_texts[1]
        room.top_edge_warp_dest_name = self.field_texts[2]
        room.bottom_edge_warp_dest_name = self.field_texts[3]
        room.reset_edge_warps()
        self.dismiss()
Ejemplo n.º 16
0
class SetLayerNameDialog(AddLayerDialog):

    title = 'Set layer name'
    field0_label = 'New name for this layer:'
    field_width = UIDialog.default_field_width
    fields = [
        Field(label=field0_label, type=str, width=field_width, oneline=False)
    ]
    confirm_caption = 'Rename'

    def confirm_pressed(self):
        new_name = self.field_texts[0]
        self.ui.active_art.layer_names[
            self.ui.active_art.active_layer] = new_name
        self.ui.active_art.set_unsaved_changes(True)
        self.dismiss()
Ejemplo n.º 17
0
class LoadGameStateDialog(UIDialog):
    
    title = 'Open game state'
    field_label = 'Game state file to open:'
    field_width = UIDialog.default_field_width
    fields = [
        Field(label=field_label, type=str, width=field_width, oneline=False)
    ]
    confirm_caption = 'Open'
    game_mode_visible = True
    
    # TODO: only allow valid game state file in current game directory
    
    def confirm_pressed(self):
        LoadGameStateCommand.execute(self.ui.console, [self.field_texts[0]])
        self.dismiss()
Ejemplo n.º 18
0
class SetRoomCamDialog(UIDialog):
    title = 'Set room camera marker'
    tile_width = 48
    field0_label = 'Name of location marker object for this room:'
    field_width = UIDialog.default_field_width
    fields = [
        Field(label=field0_label, type=str, width=field_width, oneline=False)
    ]
    confirm_caption = 'Set'
    game_mode_visible = True
    
    def dismiss(self):
        self.ui.edit_list_panel.set_list_operation(LO_NONE)
        UIDialog.dismiss(self)
    
    def confirm_pressed(self):
        self.ui.app.gw.current_room.set_camera_marker_name(self.field_texts[0])
        self.dismiss()
Ejemplo n.º 19
0
 def __init__(self, ui, options):
     self.ui = ui
     # semikludge: track whether user has selected anything in a new dir,
     # so double click behavior is consistent even on initial selections
     self.first_selection_made = False
     if self.ui.width_tiles - 20 > self.big_width:
         self.tile_width = self.big_width
         self.fields[0] = Field(label='', type=str,
                                width=self.tile_width - 4, oneline=True)
     if self.ui.height_tiles - 30 > self.big_height:
         self.tile_height = self.big_height
     self.items_in_view = self.tile_height - self.item_start_y - 3
     self.field_texts = ['']
     # set active field earlier than UIDialog.init so set_initial_dir
     # can change its text
     self.active_field = 0
     if self.directory_aware:
         self.set_initial_dir()
     self.selected_item_index = 0
     # scroll index - how far into items list current screen view begins
     self.scroll_index = 0
     self.items = self.get_items()
     self.set_selected_item_index(self.get_initial_selection(), True, False)
     self.load_selected_item()
     # start scroll index higher if initial selection would be offscreen
     if self.selected_item_index >= self.items_in_view:
         self.scroll_index = self.selected_item_index - self.items_in_view + 1
     # for convenience, create another list where 1st item button starts at 0
     self.item_buttons = []
     self.up_arrow_button, self.down_arrow_button = None, None
     # marker for preview drawing
     self.description_end_y = 0
     # UIDialog init runs: reset_art, draw_buttons etc
     UIDialog.__init__(self, ui, options)
     # UIDialog/UIElement initializes self.buttons, create item buttons after
     self.init_buttons()
     self.reset_art(False)
     # preview SpriteRenderable (loaded on item change?)
     self.preview_renderable = UISpriteRenderable(ui.app)
     # don't blend preview images, eg charsets
     self.preview_renderable.blend = False
     # offset into items list view provided by buttons starts from
     self.position_preview()
Ejemplo n.º 20
0
class FrameIndexDialog(AddFrameDialog):
    field0_label = 'Move this frame before index:'
    field_width = UIDialog.default_short_field_width
    fields = [
        Field(label=field0_label, type=int, width=field_width, oneline=False)
    ]
    confirm_caption = 'Set'

    def is_input_valid(self):
        if not self.is_valid_frame_index(self.field_texts[0]):
            return False, self.invalid_index_error % str(
                self.ui.active_art.frames + 1)
        return True, None

    def confirm_pressed(self):
        valid, reason = self.is_input_valid()
        if not valid: return
        # set new frame index (effectively moving it in the sequence)
        dest_index = int(self.field_texts[0])
        self.ui.active_art.move_frame_to_index(self.ui.active_art.active_frame,
                                               dest_index)
        self.dismiss()
Ejemplo n.º 21
0
class SetRoomBoundsObjDialog(UIDialog):
    title = 'Set room edge object'
    field0_label = 'Name of object to use for room bounds:'
    field_width = UIDialog.default_field_width
    fields = [
        Field(label=field0_label, type=str, width=field_width, oneline=False)
    ]
    confirm_caption = 'Set'
    game_mode_visible = True
    
    def get_initial_field_text(self, field_number):
        if field_number == 0:
            return self.ui.app.gw.current_room.warp_edge_bounds_obj_name
    
    def dismiss(self):
        self.ui.edit_list_panel.set_list_operation(LO_NONE)
        UIDialog.dismiss(self)
    
    def confirm_pressed(self):
        room = self.ui.app.gw.current_room
        room.warp_edge_bounds_obj_name = self.field_texts[0]
        room.reset_edge_warps()
        self.dismiss()
Ejemplo n.º 22
0
    def clicked_item(self, item):
        # if property is a bool just toggle/set it, no need for a dialog
        if item.prop_type is bool:
            for obj in self.world.selected_objects:
                # if multiple object values vary, set it True
                if item.prop_value == PropertyItem.multi_value_text:
                    obj.set_object_property(item.prop_name, True)
                else:
                    val = getattr(obj, item.prop_name)
                    obj.set_object_property(item.prop_name, not val)
            return
        # set dialog values appropriate to property being edited
        EditObjectPropertyDialog.title = EditObjectPropertyDialog.base_title % item.prop_name

        # can't set named tuple values directly, build a new one and set it
        old_field = EditObjectPropertyDialog.fields[0]
        new_label = EditObjectPropertyDialog.field0_base_label % (
            item.prop_type.__name__, item.prop_name)
        new_type = item.prop_type
        # if None, assume string
        if item.prop_type is type(None):
            new_type = str
        new_field = Field(label=new_label,
                          type=new_type,
                          width=old_field.width,
                          oneline=old_field.oneline)
        EditObjectPropertyDialog.fields[0] = new_field

        tile_x = int(self.ui.width_tiles * self.ui.scale) - self.tile_width
        tile_x -= EditObjectPropertyDialog.tile_width
        # give dialog a handle to item
        EditObjectPropertyDialog.item = item
        self.ui.open_dialog(EditObjectPropertyDialog)
        self.ui.active_dialog.field_texts[0] = str(item.prop_value)
        self.ui.active_dialog.tile_x, self.ui.active_dialog.tile_y = tile_x, self.tile_y
        self.ui.active_dialog.reset_loc()
Ejemplo n.º 23
0
class RenameRoomDialog(UIDialog):
    title = 'Rename room'
    field0_label = 'New name for current room:'
    field_width = UIDialog.default_field_width
    fields = [
        Field(label=field0_label, type=str, width=field_width, oneline=False)
    ]
    confirm_caption = 'Rename'
    game_mode_visible = True
    invalid_room_name_error = 'Invalid room name.'
    
    def get_initial_field_text(self, field_number):
        if field_number == 0:
            return self.ui.app.gw.current_room.name
    
    def is_input_valid(self):
        return self.field_texts[0] != '', self.invalid_room_name_error
    
    def confirm_pressed(self):
        valid, reason = self.is_input_valid()
        if not valid: return
        world = self.ui.app.gw
        world.rename_room(world.current_room, self.field_texts[0])
        self.dismiss()
Ejemplo n.º 24
0
class ResizeArtDialog(UIDialog):

    title = 'Resize art'
    field_width = UIDialog.default_short_field_width
    field0_label = 'New Width:'
    field1_label = 'New Height:'
    field2_label = 'Crop Start X:'
    field3_label = 'Crop Start Y:'
    field4_label = 'Fill new tiles with BG color'
    fields = [
        Field(label=field0_label, type=int, width=field_width, oneline=True),
        Field(label=field1_label, type=int, width=field_width, oneline=True),
        Field(label=field2_label, type=int, width=field_width, oneline=True),
        Field(label=field3_label, type=int, width=field_width, oneline=True),
        Field(label=field4_label, type=bool, width=0, oneline=True)
    ]
    confirm_caption = 'Resize'
    invalid_width_error = 'Invalid width.'
    invalid_height_error = 'Invalid height.'
    invalid_start_error = 'Invalid crop origin.'

    def get_initial_field_text(self, field_number):
        if field_number == 0:
            return str(self.ui.active_art.width)
        elif field_number == 1:
            return str(self.ui.active_art.height)
        elif field_number == 4:
            return UIDialog.true_field_text
        else:
            return '0'

    def is_input_valid(self):
        "file can't already exist, dimensions must be >0 and <= max"
        if not self.is_valid_dimension(self.field_texts[0],
                                       self.ui.app.max_art_width):
            return False, self.invalid_width_error
        if not self.is_valid_dimension(self.field_texts[1],
                                       self.ui.app.max_art_height):
            return False, self.invalid_height_error
        try:
            int(self.field_texts[2])
        except:
            return False, self.invalid_start_error
        if not 0 <= int(self.field_texts[2]) < self.ui.active_art.width:
            return False, self.invalid_start_error
        try:
            int(self.field_texts[3])
        except:
            return False, self.invalid_start_error
        if not 0 <= int(self.field_texts[3]) < self.ui.active_art.height:
            return False, self.invalid_start_error
        return True, None

    def is_valid_dimension(self, dimension, max_dimension):
        try:
            dimension = int(dimension)
        except:
            return False
        return 0 < dimension <= max_dimension

    def confirm_pressed(self):
        valid, reason = self.is_input_valid()
        if not valid: return
        w, h = int(self.field_texts[0]), int(self.field_texts[1])
        start_x, start_y = int(self.field_texts[2]), int(self.field_texts[3])
        bg_fill = bool(self.field_texts[4].strip())
        self.ui.resize_art(self.ui.active_art, w, h, start_x, start_y, bg_fill)
        self.dismiss()
Ejemplo n.º 25
0
class NewArtDialog(BaseFileDialog):

    title = 'New art'
    field0_label = 'Filename of new art:'
    field2_label = 'Width:'
    field4_label = 'Height:'
    field6_label = 'Save folder:'
    field7_label = ' %s'
    tile_width = 60
    field0_width = 56
    y_spacing = 0
    field1_width = field2_width = UIDialog.default_short_field_width
    fields = [
        Field(label=field0_label, type=str, width=field0_width, oneline=False),
        Field(label='', type=None, width=0, oneline=True),
        Field(label=field2_label, type=int, width=field1_width, oneline=True),
        Field(label='', type=None, width=0, oneline=True),
        Field(label=field4_label, type=int, width=field2_width, oneline=True),
        Field(label='', type=None, width=0, oneline=True),
        Field(label=field6_label, type=None, width=0, oneline=True),
        Field(label=field7_label, type=None, width=0, oneline=True),
        Field(label='', type=None, width=0, oneline=True)
    ]
    confirm_caption = 'Create'
    invalid_width_error = 'Invalid width.'
    invalid_height_error = 'Invalid height.'

    def get_initial_field_text(self, field_number):
        if field_number == 0:
            return 'new%s' % len(self.ui.app.art_loaded_for_edit)
        elif field_number == 2:
            return str(DEFAULT_WIDTH)
        elif field_number == 4:
            return str(DEFAULT_HEIGHT)
        return ''

    def get_field_label(self, field_index):
        label = self.fields[field_index].label
        # show dir art will be saved into
        if field_index == 7:
            label %= self.get_dir()
        return label

    def get_file_extension(self):
        return ART_FILE_EXTENSION

    def get_dir(self):
        return self.ui.app.documents_dir + ART_DIR

    def is_input_valid(self):
        "warn if file already exists, dimensions must be >0 and <= max"
        if not self.is_valid_dimension(self.field_texts[2],
                                       self.ui.app.max_art_width):
            return False, self.invalid_width_error
        if not self.is_valid_dimension(self.field_texts[4],
                                       self.ui.app.max_art_height):
            return False, self.invalid_height_error
        return self.is_filename_valid(0)

    def is_valid_dimension(self, dimension, max_dimension):
        try:
            dimension = int(dimension)
        except:
            return False
        return 0 < dimension <= max_dimension

    def confirm_pressed(self):
        valid, reason = self.is_input_valid()
        if not valid: return
        name = self.field_texts[0]
        w, h = int(self.field_texts[2]), int(self.field_texts[4])
        self.ui.app.new_art_for_edit(name, w, h)
        self.ui.app.log('Created %s.psci with size %s x %s' % (name, w, h))
        self.dismiss()
Ejemplo n.º 26
0
class ChooserDialog(UIDialog):
    
    title = 'Chooser'
    confirm_caption = 'Set'
    cancel_caption = 'Close'
    message = ''
    # if True, chooser shows files; show filename on first line of description
    show_filenames = False
    directory_aware = False
    tile_width, tile_height = 60, 20
    # use these if screen is big enough
    big_width, big_height = 80, 30
    fields = [
        Field(label='', type=str, width=tile_width - 4, oneline=True)
    ]
    item_start_x, item_start_y = 2, 4
    no_preview_label = 'No preview available!'
    show_preview_image = True
    item_button_class = ChooserItemButton
    chooser_item_class = ChooserItem
    scrollbar_shade_char = 54
    flip_preview_y = True
    
    def __init__(self, ui, options):
        self.ui = ui
        # semikludge: track whether user has selected anything in a new dir,
        # so double click behavior is consistent even on initial selections
        self.first_selection_made = False
        if self.ui.width_tiles - 20 > self.big_width:
            self.tile_width = self.big_width
            self.fields[0] = Field(label='', type=str,
                                   width=self.tile_width - 4, oneline=True)
        if self.ui.height_tiles - 30 > self.big_height:
            self.tile_height = self.big_height
        self.items_in_view = self.tile_height - self.item_start_y - 3
        self.field_texts = ['']
        # set active field earlier than UIDialog.init so set_initial_dir
        # can change its text
        self.active_field = 0
        if self.directory_aware:
            self.set_initial_dir()
        self.selected_item_index = 0
        # scroll index - how far into items list current screen view begins
        self.scroll_index = 0
        self.items = self.get_items()
        self.set_selected_item_index(self.get_initial_selection(), True, False)
        self.load_selected_item()
        # start scroll index higher if initial selection would be offscreen
        if self.selected_item_index >= self.items_in_view:
            self.scroll_index = self.selected_item_index - self.items_in_view + 1
        # for convenience, create another list where 1st item button starts at 0
        self.item_buttons = []
        self.up_arrow_button, self.down_arrow_button = None, None
        # marker for preview drawing
        self.description_end_y = 0
        # UIDialog init runs: reset_art, draw_buttons etc
        UIDialog.__init__(self, ui, options)
        # UIDialog/UIElement initializes self.buttons, create item buttons after
        self.init_buttons()
        self.reset_art(False)
        # preview SpriteRenderable (loaded on item change?)
        self.preview_renderable = UISpriteRenderable(ui.app)
        # don't blend preview images, eg charsets
        self.preview_renderable.blend = False
        # offset into items list view provided by buttons starts from
        self.position_preview()
    
    def init_buttons(self):
        for i in range(self.items_in_view):
            button = self.item_button_class(self)
            button.x = self.item_start_x
            button.y = i + self.item_start_y
            self.buttons.append(button)
            self.item_buttons.append(button)
        # create scrollbar buttons
        self.item_button_width = self.item_buttons[0].width
        self.up_arrow_button = ScrollArrowButton(self)
        self.up_arrow_button.x = self.item_start_x + self.item_button_width
        self.up_arrow_button.y = self.item_start_y
        self.down_arrow_button = ScrollArrowButton(self)
        self.down_arrow_button.x = self.item_start_x + self.item_button_width
        self.down_arrow_button.y = self.item_start_y + self.items_in_view - 1
        self.down_arrow_button.up = False
        self.buttons += [self.up_arrow_button, self.down_arrow_button]
    
    def set_initial_dir(self):
        # for directory-aware dialogs, subclasses specify here where to start
        self.current_dir = '.'
    
    def change_current_dir(self, new_dir):
        # check permissions:
        # os.access(new_dir, os.R_OK) seems to always return True,
        # so try/catch listdir instead
        try:
            l = os.listdir(new_dir)
        except PermissionError as e:
            line = 'No permission to access %s!' % os.path.abspath(new_dir)
            self.ui.message_line.post_line(line, error=True)
            return False
        self.current_dir = new_dir
        if not self.current_dir.endswith('/'):
            self.current_dir += '/'
        # redo items and redraw
        self.selected_item_index = 0
        self.scroll_index = 0
        self.field_texts[self.active_field] = self.current_dir
        self.items = self.get_items()
        self.reset_art(False)
        return True
    
    def set_selected_item_index(self, new_index, set_field_text=True,
                                update_view=True):
        """
        set the view's selected item to specified index
        perform usually-necessary refresh functions for convenience
        """
        move_dir = new_index - self.selected_item_index
        self.selected_item_index = new_index
        can_scroll = len(self.items) > self.items_in_view
        should_scroll = self.selected_item_index >= self.scroll_index + self.items_in_view or self.selected_item_index < self.scroll_index
        if not can_scroll:
            self.scroll_index = 0
        elif should_scroll:
            # keep selection in bounds
            self.selected_item_index = min(self.selected_item_index, len(self.items)-1)
            # scrolling up
            if move_dir <= 0:
                self.scroll_index = self.selected_item_index
            # scrolling down
            elif move_dir > 0 and self.selected_item_index - self.scroll_index == self.items_in_view:
                self.scroll_index = self.selected_item_index - self.items_in_view + 1
            # keep scroll in bounds
            self.scroll_index = min(self.scroll_index, self.get_max_scroll())
        # don't select/load null items
        if set_field_text:
            item = self.get_selected_item()
            if item:
                self.field_texts[self.active_field] = item.name
        if update_view:
            self.load_selected_item()
            self.reset_art(False)
            self.position_preview()
    
    def get_max_scroll(self):
        return len(self.items) - self.items_in_view
    
    def get_selected_item(self):
        # return None if out of bounds
        return self.items[self.selected_item_index] if self.selected_item_index < len(self.items) else None
    
    def load_selected_item(self):
        item = self.get_selected_item()
        item.load(self.ui.app)
    
    def get_initial_selection(self):
        # subclasses return index of initial selection
        return 0
    
    def set_preview(self):
        item = self.get_selected_item()
        if self.show_preview_image:
            self.preview_renderable.texture = item.get_preview_texture(self.ui.app)
    
    def get_items(self):
        # subclasses generate lists of items here
        return []
    
    def position_preview(self, reset=True):
        if reset:
            self.set_preview()
        if not self.preview_renderable.texture:
            return
        qw, qh = self.art.quad_width, self.art.quad_height
        # determine x position, then width as (dialog width - x)
        x = (self.item_button_width + self.item_start_x + 3) * qw
        self.preview_renderable.x = self.x + x
        self.preview_renderable.scale_x = (self.tile_width - 2) * qw - x
        # determine height based on width, then y position
        img_inv_aspect = self.preview_renderable.texture.height / self.preview_renderable.texture.width
        screen_aspect = self.ui.app.window_width / self.ui.app.window_height
        self.preview_renderable.scale_y = self.preview_renderable.scale_x * img_inv_aspect * screen_aspect
        y = (self.description_end_y + 1) * qh
        # if preview height is above max allotted size, set height to fill size
        # and scale down width
        max_y = (self.tile_height - 3) * qh
        if self.preview_renderable.scale_y > max_y - y:
            self.preview_renderable.scale_y = max_y - y
            self.preview_renderable.scale_x = self.preview_renderable.scale_y * (1 / img_inv_aspect) * (1 / screen_aspect)
        # flip in Y for some (palettes) but not for others (charsets)
        if self.flip_preview_y:
            self.preview_renderable.scale_y = -self.preview_renderable.scale_y
        else:
            y += self.preview_renderable.scale_y
        self.preview_renderable.y = self.y - y
    
    def get_height(self, msg_lines):
        return self.tile_height
    
    def reset_buttons(self):
        # (re)generate buttons from contents of self.items
        for i,button in enumerate(self.item_buttons):
            # ??? each button's callback loads charset/palette/whatev
            if i >= len(self.items):
                button.never_draw = True
                # clear item, might be left over from a previous dir view!
                button.item = None
                continue
            item = self.items[self.scroll_index + i]
            button.caption = item.label
            button.item = item
            button.never_draw = False
            # highlight selected item
            if i == self.selected_item_index - self.scroll_index:
                button.normal_fg_color = UIButton.clicked_fg_color
                button.normal_bg_color = UIButton.clicked_bg_color
                # still allow hover and click
                button.hovered_fg_color = UIButton.clicked_fg_color
                button.hovered_bg_color = UIButton.clicked_bg_color
            else:
                button.normal_fg_color = UIButton.normal_fg_color
                button.normal_bg_color = UIButton.normal_bg_color
                button.hovered_fg_color = UIButton.hovered_fg_color
                button.hovered_bg_color = UIButton.hovered_bg_color
        # init_buttons has not yet run on first reset_art
        if not self.up_arrow_button:
            return
        # dim scroll buttons if we don't have enough items to scroll
        state, hover = 'normal', True
        if len(self.items) <= self.items_in_view:
            state = 'dimmed'
            hover = False
        for button in [self.up_arrow_button, self.down_arrow_button]:
            button.set_state(state)
            button.can_hover = hover
    
    def get_description_filename(self, item):
        "returns a description-appropriate filename for given item"
        # truncate from start to fit in description area if needed
        max_width = self.tile_width
        max_width -= self.item_start_x + self.item_button_width + 5
        if len(item.name) > max_width - 1:
            return '…' + item.name[-max_width:]
        return item.name
    
    def get_selected_description_lines(self):
        item = self.get_selected_item()
        lines = []
        if self.show_filenames:
            lines += [self.get_description_filename(item)]
        lines += item.get_description_lines() or []
        return lines
    
    def draw_selected_description(self):
        x = self.tile_width - 2
        y = self.item_start_y
        lines = self.get_selected_description_lines()
        for line in lines:
            # trim line if it's too long
            max_width = self.tile_width - self.item_button_width - 7
            line = line[:max_width]
            self.art.write_string(0, 0, x, y, line, None, None,
                                  right_justify=True)
            y += 1
        self.description_end_y = y
    
    def reset_art(self, resize=True):
        self.reset_buttons()
        # UIDialog does: clear window, draw titlebar and confirm/cancel buttons
        # doesn't: draw message or fields
        UIDialog.reset_art(self, resize, clear_buttons=False)
        # init_buttons hasn't run yet on first call to reset_art
        if not self.up_arrow_button:
            return
        self.draw_selected_description()
        # draw scrollbar shading
        # dim if no scrolling
        fg = self.up_arrow_button.normal_fg_color
        if len(self.items) <= self.items_in_view:
            fg = self.up_arrow_button.dimmed_fg_color
        for y in range(self.up_arrow_button.y + 1, self.down_arrow_button.y):
            self.art.set_tile_at(0, 0, self.up_arrow_button.x, y,
                                 self.scrollbar_shade_char, fg)
    
    def update_drag(self, mouse_dx, mouse_dy):
        UIDialog.update_drag(self, mouse_dx, mouse_dy)
        # update thumbnail renderable's position too
        self.position_preview(False)
    
    def handle_input(self, key, shift_pressed, alt_pressed, ctrl_pressed):
        keystr = sdl2.SDL_GetKeyName(key).decode()
        # up/down keys navigate list
        new_index = self.selected_item_index
        navigated = False
        if keystr == 'Return':
            # if handle_enter returns True, bail before rest of input handling -
            # make sure any changes to handle_enter are safe for this!
            if self.handle_enter(shift_pressed, alt_pressed, ctrl_pressed):
                return
        elif keystr == 'Up':
            navigated = True
            if self.selected_item_index > 0:
                new_index -= 1
        elif keystr == 'Down':
            navigated = True
            if self.selected_item_index < len(self.items) - 1:
                new_index += 1
        elif keystr == 'PageUp':
            navigated = True
            page_size = int(self.items_in_view / 2)
            new_index -= page_size
            new_index = max(0, new_index)
            # scroll follows selection jumps
            self.scroll_index -= page_size
            self.scroll_index = max(0, self.scroll_index)
        elif keystr == 'PageDown':
            navigated = True
            page_size = int(self.items_in_view / 2)
            new_index += page_size
            new_index = min(new_index, len(self.items) - 1)
            self.scroll_index += page_size
            self.scroll_index = min(self.scroll_index, self.get_max_scroll())
        # home/end: beginning/end of list, respectively
        elif keystr == 'Home':
            navigated = True
            new_index = 0
            self.scroll_index = 0
        elif keystr == 'End':
            navigated = True
            new_index = len(self.items) - 1
            self.scroll_index = len(self.items) - self.items_in_view
        self.set_selected_item_index(new_index, set_field_text=navigated)
        # handle alphanumeric input etc
        UIDialog.handle_input(self, key, shift_pressed, alt_pressed, ctrl_pressed)
        # if we didn't navigate, seek based on new alphanumeric input
        if not navigated:
            self.text_input_seek()
    
    def text_input_seek(self):
        field_text = self.field_texts[self.active_field]
        if field_text.strip() == '':
            return
        # seek should be case-insensitive
        field_text = field_text.lower()
        # field text may be a full path; only care about the base
        field_text = os.path.basename(field_text)
        for i,item in enumerate(self.items):
            # match to base item name within dir
            # (if it's a dir, snip last / for match)
            item_base = item.name.lower()
            if item_base.endswith('/'):
                item_base = item_base[:-1]
            item_base = os.path.basename(item_base)
            item_base = os.path.splitext(item_base)[0]
            if item_base.startswith(field_text):
                self.set_selected_item_index(i, set_field_text=False)
                break
    
    def handle_enter(self, shift_pressed, alt_pressed, ctrl_pressed):
        "handle Enter key, return False if rest of handle_input should continue"
        # if selected item is already in text field, pick it
        field_text = self.field_texts[self.active_field]
        selected_item = self.get_selected_item()
        if field_text.strip() == '':
            self.field_texts[self.active_field] = field_text = selected_item.name
            return True
        if field_text == selected_item.name:
            # this (and similar following cases) should count as having
            # made a selection
            self.first_selection_made = True
            selected_item.picked(self)
            return True
        # else navigate to directory or file if it's real
        if not os.path.exists(field_text):
            self.field_texts[self.active_field] = selected_item.name
            return True
        # special case for parent dir ..
        if self.directory_aware and field_text == self.current_dir and selected_item.name == '..':
            self.first_selection_made = True
            return self.change_current_dir('..')
        if self.directory_aware and os.path.isdir(field_text):
            self.first_selection_made = True
            return self.change_current_dir(field_text)
        if os.path.isfile(field_text):
            file_dir_name = os.path.dirname(field_text)
            # if a file, change to its dir and select it
            if self.directory_aware and file_dir_name != self.current_dir:
                if self.change_current_dir(file_dir_name):
                    for i,item in enumerate(self.items):
                        if item.name == field_text:
                            self.set_selected_item_index(i)
                            item.picked(self)
                    return True
        return False
    
    def render(self):
        UIDialog.render(self)
        if self.show_preview_image and self.preview_renderable.texture:
            self.preview_renderable.render()
Ejemplo n.º 27
0
class ConvertImageOptionsDialog(ImportOptionsDialog):

    title = 'Convert bitmap image options'
    field0_label = 'Color palette:'
    field1_label = 'Current palette (%s)'
    field2_label = 'From source image; # of colors:'
    field3_label = '  '
    field5_label = 'Converted art size:'
    field6_label = 'Best fit to current size (%s)'
    field7_label = '%% of source image: (%s)'
    field8_label = '  '
    field10_label = 'Smooth (bicubic) scale source image'
    radio_groups = [(1, 2), (6, 7)]
    field_width = UIDialog.default_short_field_width
    # to get the layout we want, we must specify 0 padding lines and
    # add some blank ones :/
    y_spacing = 0
    fields = [
        Field(label=field0_label, type=None, width=0, oneline=True),
        Field(label=field1_label, type=bool, width=0, oneline=True),
        Field(label=field2_label, type=bool, width=0, oneline=True),
        Field(label=field3_label, type=int, width=field_width, oneline=True),
        Field(label='', type=None, width=0, oneline=True),
        Field(label=field5_label, type=None, width=0, oneline=True),
        Field(label=field6_label, type=bool, width=0, oneline=True),
        Field(label=field7_label, type=bool, width=0, oneline=True),
        Field(label=field8_label, type=float, width=field_width, oneline=True),
        Field(label='', type=None, width=0, oneline=True),
        Field(label=field10_label, type=bool, width=0, oneline=True),
        Field(label='', type=None, width=0, oneline=True)
    ]
    invalid_color_error = 'Palettes must be between 2 and 256 colors.'
    invalid_scale_error = 'Scale must be greater than 0.0'
    # redraw dynamic labels
    always_redraw_labels = True

    def get_initial_field_text(self, field_number):
        if field_number == 1:
            return UIDialog.true_field_text
        elif field_number == 3:
            # # of colors from source image
            return '64'
        elif field_number == 6:
            return UIDialog.true_field_text
        elif field_number == 8:
            # % of source image size
            return '50.0'
        elif field_number == 10:
            return ' '
        return ''

    def get_field_label(self, field_index):
        label = self.fields[field_index].label
        # custom label replacements to show palette, possible convert sizes
        if field_index == 1:
            label %= self.ui.active_art.palette.name if self.ui.active_art else DEFAULT_PALETTE
        elif field_index == 6:
            # can't assume any art is open, use defaults if needed
            w = self.ui.active_art.width if self.ui.active_art else DEFAULT_WIDTH
            h = self.ui.active_art.height if self.ui.active_art else DEFAULT_HEIGHT
            label %= '%s x %s' % (w, h)
        elif field_index == 7:
            # scale # might not be valid
            valid, _ = self.is_input_valid()
            if not valid:
                return label % '???'
            label %= '%s x %s' % self.get_tile_scale()
        return label

    def get_tile_scale(self):
        "returns scale in tiles of image dimensions"
        # filename won't be set just after dialog is created
        if not hasattr(self, 'filename'):
            return 0, 0
        scale = float(self.field_texts[8]) / 100
        # can't assume any art is open, use defaults if needed
        if self.ui.active_art:
            cw = self.ui.active_art.charset.char_width
            ch = self.ui.active_art.charset.char_height
        else:
            charset = self.ui.app.load_charset(DEFAULT_CHARSET)
            cw, ch = charset.char_width, charset.char_height
        width = self.image_width / cw
        height = self.image_height / ch
        width *= scale
        height *= scale
        return int(width), int(height)

    def is_input_valid(self):
        # colors: int between 2 and 256
        try:
            int(self.field_texts[3])
        except:
            return False, self.invalid_color_error
        colors = int(self.field_texts[3])
        if colors < 2 or colors > 256:
            return False, self.invalid_color_error
        # % scale: >0 float
        try:
            float(self.field_texts[8])
        except:
            return False, self.invalid_scale_error
        if float(self.field_texts[8]) <= 0:
            return False, self.invalid_scale_error
        return True, None

    def confirm_pressed(self):
        valid, reason = self.is_input_valid()
        if not valid: return
        self.dismiss()
        # compile options for importer
        options = {}
        # create new palette from image?
        if self.field_texts[1].strip():
            options[
                'palette'] = self.ui.active_art.palette.name if self.ui.active_art else DEFAULT_PALETTE
        else:
            # create new palette
            palette_filename = os.path.basename(self.filename)
            colors = int(self.field_texts[3])
            new_pal = PaletteFromFile(self.ui.app, self.filename,
                                      palette_filename, colors)
            # palette now loaded and saved to disk
            options['palette'] = new_pal.name
        # rescale art?
        if self.field_texts[6].strip():
            options[
                'art_width'] = self.ui.active_art.width if self.ui.active_art else DEFAULT_WIDTH
            options[
                'art_height'] = self.ui.active_art.height if self.ui.active_art else DEFAULT_HEIGHT
        else:
            # art dimensions = scale% of image dimensions, in tiles
            options['art_width'], options['art_height'] = self.get_tile_scale()
        options['bicubic_scale'] = bool(self.field_texts[10].strip())
        ImportOptionsDialog.do_import(self.ui.app, self.filename, options)