Beispiel #1
0
class TilesEditor(ChildWindow):

    def __init__(self):
        super(TilesEditor, self).__init__()
        self.config = Config()
        self.setWindowTitle('Tiles Editor')
        self.setFixedSize(640, 480)
        self._tab_widget = QtGui.QTabWidget(self)
        self._tab_widget.setGeometry(0, 0, 640, 480)
        self.subscribe('menu.trigger.import_tileset', self.on_import_tileset)
        self.subscribe('picture.mousemove', self.on_picture_mouse_move)
        self.subscribe('new_project', self.on_new_file)
        self.subscribe('open_project', self.on_open_file)
        self._workspaces = []

    def on_new_file(self, message):
        self._workspaces = []
        self._tab_widget.clear()

    def on_open_file(self, message):
        self.current_file = self.config.current_file()
        for tileset in self.current_file.get('tilesets', []):
            workspace = TileSetWorkspace(
                self, self.current_file['pathes'][tileset], self._queue
            )
            workspace.show()
            self._tab_widget.addTab(workspace, workspace.base_name())
            self._workspaces.append(workspace)
            self.send('tileset_editor.new_tileset', {
                'tileset': workspace.base_name()
            })
            self.send('tileset.update', {
                'tileset': workspace.base_name()
            })
            workspace.read_tilesets_config()
        self.send('open_maps')

    def on_import_tileset(self, message):
        file_name = QtGui.QFileDialog.getOpenFileName(
            self, filter='Tilesets (*.png)',
            directory=self.config.get(
                'tilesets_images_dir', os.path.expanduser('~')
            )
        )
        if file_name:
            self.config.set(
                'tilesets_images_dir',
                os.path.dirname(str(file_name))
            )
            self.send('config.save')
            workspace = TileSetWorkspace(
                self, str(file_name), self._queue
            )
            workspace.show()
            self._tab_widget.addTab(workspace, workspace.base_name())
            self._workspaces.append(workspace)
            self.send('tileset_editor.new_tileset', {
                'tileset': workspace.base_name()
            })

    def on_picture_mouse_move(self, message):
        for workspace in self._workspaces:
            workspace.on_picture_mouse_move(message)

    def remove_current(self):
        self._workspaces.pop(self._tab_widget.currentIndex())
        self._tab_widget.removeTab(self._tab_widget.currentIndex())
Beispiel #2
0
class MainWindow(QtGui.QMainWindow):

    resources_directories = (
        'fightenv', 'images', 'maps', 'sprites', 'tiles'
    )

    queue = Queue.Queue()

    CHILDREN = (
        TilesEditor, MapEditor,
        LayersDialog, SpritesEditor,
        FightEnvironmentEditor
    )

    def __init__(self, resolution, title):
        super(MainWindow, self).__init__()
        self.config = Config()
        self.config.init_from_file(settings.CONFIG_FILE_PATH)
        self._timer = QtCore.QTimer(self)
        self.setWindowIcon(QtGui.QIcon(os.path.join(
            settings.IMAGES_PATH, 'mqme.png'
        )))
        MainWindow._subscriptions = {
            'config.save': self.on_save_config_request,
            'menu.trigger.save_project': self.on_save_project_request,
            'menu.trigger.new_project': self.on_new_project_request,
            'menu.trigger.open_project': self.on_open_project_request,
            'menu.trigger.export_to_resources': self.on_export_request
        }
        self.connect(self._timer, QtCore.SIGNAL("timeout()"), self.update)
        self.workspace = QtGui.QWorkspace()
        width, height = resolution
        self.resize(width, height)
        self.setWindowTitle(title)
        self.setCentralWidget(self.workspace)
        self.setMenuBar(MenuBar(self, self.on_menu_triggered))
        self._children = []
        for child_type in self.CHILDREN:
            child = child_type()
            self.workspace.addWindow(child)
            child.set_queue(MainWindow.queue)
            self._children.append(child)
        self._timer.start(settings.QUEUE_READ_LOOP_DELAY)

    def keyPressEvent(self, event):
        super(MainWindow, self).keyPressEvent(event)
        self.send('key_press', {'key': event.key()})

    def keyReleaseEvent(self, event):
        super(MainWindow, self).keyReleaseEvent(event)
        self.send('key_release', {'key': event.key()})

    def send(self, name, body=None):
        message = {'name': name}
        if body is not None:
            message.update(body)
        MainWindow.queue.put(message)

    @staticmethod
    def subscribe(message_name, callback):
        MainWindow._subscriptions[message_name] = callback

    def receive(self, message):
        name = message.get('name')
        if name in MainWindow._subscriptions:
            MainWindow._subscriptions[name](message)

    def on_menu_triggered(self, menu_name):
        self.send('menu.trigger.%s' % menu_name)

    def update(self):
        try:
            index = 0
            while index < settings.QUEUE_READ_LOOP_DELAY:
                message = MainWindow.queue.get_nowait()
                self.receive(message)
                for child in self._children:
                    child.receive(message)
                index += 1
        except Queue.Empty:
            pass

    def on_save_config_request(self, message):
        self.config.save(settings.CONFIG_FILE_PATH)

    def on_save_project_request(self, message):
        file_name = QtGui.QFileDialog.getSaveFileName(
            self, filter='MQME Projects (*.mqp)',
            directory=self.config.get(
                'project_dir', os.path.expanduser('~')
            )
        )
        if file_name:
            file_name = unicode(file_name)
            self.config.set(
                'project_dir', os.path.dirname(file_name)
            )
            self.config.save(settings.CONFIG_FILE_PATH)
            self.config.save_current_file(file_name)

    def on_open_project_request(self, message):
        file_name = QtGui.QFileDialog.getOpenFileName(
            self, filter='MQME Projects (*.mqp)',
            directory=self.config.get(
                'project_dir', os.path.expanduser('~')
            )
        )
        if file_name:
            self.send('new_project')
            file_name = unicode(file_name)
            self.config.set(
                'project_dir', os.path.dirname(file_name)
            )
            self.config.save(settings.CONFIG_FILE_PATH)
            self.config.read_current_file(file_name)
            self.send('open_project')

    def on_new_project_request(self, message):
        self.config.reset_current_file()
        self.send('new_project')

    def on_export_request(self, message):
        if self.config.has_changed():
            msg_box = QtGui.QMessageBox(self)
            msg_box.setWindowTitle('Config has changed')
            msg_box.setText(
                'You need to save the project before exporting'
            )
            msg_box.setDefaultButton(QtGui.QMessageBox.Cancel)
            msg_box.exec_()
            return
        current_file = self.config.current_file()
        directory = None
        if 'pathes' in current_file:
            directory = current_file['pathes'].get('resources_dir', None)
        if directory is None:
            directory = QtGui.QFileDialog.getExistingDirectory(
                self, directory=self.config.get(
                    'resources_dir', os.path.expanduser('~')
                )
            )
        if directory is not None:
            directory = str(directory)
            if not 'pathes' in current_file:
                current_file['pathes'] = {}
            current_file['pathes']['resources_dir'] = directory
            self.config.set('resources_dir', directory)
            self.config.save(settings.CONFIG_FILE_PATH)
            for sub_directory in self.resources_directories:
                subpath = os.path.join(directory, sub_directory)
                if not os.path.exists(subpath):
                    os.makedirs(subpath)
            self.export_maps(directory)
            self.export_tilesets(directory)
            self.export_sprites(directory)
            self.export_fight_environments(directory)
            msg_box = QtGui.QMessageBox(self)
            msg_box.setWindowTitle('Export')
            msg_box.setText(
                'Project exported successfully !'
            )
            msg_box.setDefaultButton(QtGui.QMessageBox.Cancel)
            msg_box.exec_()

    def export_physics(self, sps_obj, id, directory):
        svg_path = os.path.join(directory, id + '.svg')
        if os.path.exists(svg_path):
            with open(svg_path) as raw_file:
                dom = parse(raw_file)
                root = dom.getElementsByTagName('svg')[0]
                image = root.getElementsByTagName('image')[0]
                width = float(image.getAttribute('width'))
                height = float(image.getAttribute('height'))
                x = float(image.getAttribute('x'))
                y = float(image.getAttribute('y'))
                for rect in root.getElementsByTagName('rect'):
                    physics_type = rect.getAttribute('id').split('_')[0]
                    if physics_type != 'platform':
                        physics_type = 'ground'
                    sps_obj['physics'][id].append({
                        'x': (float(rect.getAttribute('x')) - x) / width,
                        'y': (float(rect.getAttribute('y')) - y) / height,
                        'width': float(rect.getAttribute('width')) / width,
                        'height': float(rect.getAttribute('height')) / height,
                        'type': physics_type
                    })
                for circle in root.getElementsByTagName('path'):
                    sodipodi_type = circle.getAttribute('sodipodi:type')
                    if sodipodi_type == 'arc':
                        cx = float(circle.getAttribute('sodipodi:cx'))
                        transform_raw = circle.getAttribute('transform')
                        transform_raw = transform_raw.replace('translate(', '').replace(')', '')
                        foe_x = float(transform_raw.split(',')[0]) + cx
                        sps_obj['foes'][id].append({
                            'x': (foe_x - x) / width
                        })
                        if id.find('town_d') > -1:
                            print cx, transform_raw, foe_x, x, (foe_x - x) / width

    def export_fight_environments(self, directory):
        fightenv_directory = os.path.join(directory, 'fightenv')
        environments = self.config.current_file().get('fightenv', {})
        layers = ('background3', 'background2')
        for name, fight_env in environments.items():
            sps_obj = {'backgrounds': [], 'physics': {}, 'foes': {}}
            max_width = 0
            max_height = 0
            images = {}
            bg1_path = self.config.current_file()['pathes'][
                fight_env['background1']
            ]
            bg1_key = os.path.basename(bg1_path).split('_')[0]
            bg1_directory = os.path.dirname(bg1_path)
            for image_name in os.listdir(bg1_directory):
                if image_name.startswith(bg1_key) and image_name.endswith('.png'):
                    image_id = image_name.split('_', 1)[1].split('.')[0]
                    image_path = os.path.join(bg1_directory, image_name)
                    sps_obj['physics'][name + '_' + image_id] = []
                    sps_obj['foes'][name + '_' + image_id] = []
                    self.export_physics(
                        sps_obj, name + '_' + image_id, os.path.dirname(image_path)
                    )
                    image = utils.get_resized_image(image_path)    
                    output_path = os.path.join(
                        fightenv_directory,
                        name + '_' + image_id + '.png'
                    )
                    image.save(output_path)
                    sps_obj['backgrounds'].append('fightenv/' + name + '_' + image_id)
            for layer_index in (2, 3):
                image = utils.get_resized_image(
                    self.config.current_file()['pathes'][
                        fight_env['background' + str(layer_index)]
                    ]
                )
                output_path = os.path.join(
                    fightenv_directory,
                    name + '_bg' + str(layer_index) + '.png'
                )
                image.save(output_path)
                sps_obj['backgrounds'].append(
                    'fightenv/' + name + '_bg' + str(layer_index)
                )
            base_path = os.path.join(fightenv_directory, name)
            with open(base_path + '.sps', 'w') as sps:
                sps.write(json.dumps(sps_obj))

    def export_sprites(self, directory):
        sprites_directory = os.path.join(directory, 'sprites')
        actors = self.config.current_file().get('actors', {})
        for actor_name in actors:
            SpritesGenerator(actor_name).save(sprites_directory)

    def export_maps(self, directory):
        maps = self.config.current_file().get('maps', {})
        for map_name, map_obj in maps.items():
            path = os.path.join(directory, 'maps', map_name + '.map')
            map_obj['camera'] = [
                map_obj['camera_width'],
                map_obj['camera_height']
            ]
            map_obj['size'] = [
                map_obj['width'],
                map_obj['height']
            ]
            x = 0
            for matrix_line in map_obj['specials']:
                y = 0
                for special_conf in matrix_line:
                    if special_conf['class_name'] == 'start_pos':
                        map_obj['start_pos'] = [x, y]
                    y += 1
                x += 1
            with open(path, 'w') as map_file:
                map_file.write(json.dumps(map_obj, sort_keys=True, indent=4))

    def export_tilesets(self, directory):
        tilesets = self.config.current_file().get('tilesets', {})
        for tileset_name, tileset_obj in tilesets.items():
            path = os.path.join(directory, 'tiles', tileset_name + '.sps')
            with open(path, 'w') as tileset_file:
                tileset_file.write(json.dumps(
                    tileset_obj, sort_keys=True, indent=4
                ))
Beispiel #3
0
class MapEditor(ChildWindow):

    LAYERS = [
        MapBackgroundLayer,
        MapBlockMatrixLayer,
        MapForegroundLayer,
        MapSpecialsLayer
    ]

    def __init__(self):
        super(MapEditor, self).__init__()
        self.config = Config()
        self.setFixedSize(900, 600)
        self.setWindowTitle('Map Editor')
        self.subscribe('menu.trigger.new_map', self.on_new_map)
        self.subscribe('tileset_editor.new_tileset', self.on_new_tileset)
        self.subscribe('tileset.update', self.on_tileset_update)
        self.subscribe('open_maps', self.on_open_maps)
        self.subscribe('hide_map_layer', self.on_hide_layer)
        self.subscribe('show_map_layer', self.on_show_layer)
        self._toolbox = QtGui.QToolBar(self)
        self._toolbox.setGeometry(0, 0, 100, 600)
        self._actions = {}
        for tool in MapSpecialsLayer.TOOLS:
            ref, name = tool
            action = MenuAction(self._toolbox, ref, self.on_action_checked)
            action.setIcon(QtGui.QIcon(os.path.join(
                settings.IMAGES_PATH, '%s.png' % ref
            )))
            action.setText(name)
            action.setCheckable(True)
            self._toolbox.addAction(action)
            self._actions[ref] = action
        self._tab_widget = QtGui.QTabWidget(self)
        self._tab_widget.setTabsClosable(True)
        self._tab_widget.tabCloseRequested.connect(self.on_map_delete)
        self._tab_widget.setGeometry(100, 0, 550, 550)
        self._zoom_in = IconButton(self, 'zoom_in', 30, 30)
        self._zoom_in.setGeometry(150, 560, 30, 30)
        self._zoom_in.clicked.connect(self.on_zoom_in)
        self._zoom_out = IconButton(self, 'zoom_out', 30, 30)
        self._zoom_out.setGeometry(110, 560, 30, 30)
        self._zoom_out.clicked.connect(self.on_zoom_out)
        self._tileset_cb = QtGui.QComboBox(self)
        self._tileset_cb.setGeometry(665, 5, 220, 20)
        self._tileset_cb.currentIndexChanged.connect(self.update)
        self._tiles_widgets = {}
        self._current_tool = None

    def on_map_delete(self, index):
        map_name = self._tab_widget.widget(index).map_name()
        msg_box = QtGui.QMessageBox(self)
        msg_box.setWindowTitle('Delete Map')
        msg_box.setText('Do you want to delete "%s" ?' % map_name)
        msg_box.setStandardButtons(
            QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel
        )
        msg_box.setDefaultButton(QtGui.QMessageBox.Cancel)
        status = msg_box.exec_()
        if status == QtGui.QMessageBox.Ok:
            self._tab_widget.widget(index).remove_map()
            self._tab_widget.removeTab(index)

    def on_hide_layer(self, message):
        index = 0
        while index < self._tab_widget.count():
            self._tab_widget.widget(index).hide_layer(message['layer_type'])
            index += 1

    def on_show_layer(self, message):
        index = 0
        while index < self._tab_widget.count():
            self._tab_widget.widget(index).show_layer(message['layer_type'])
            index += 1

    def on_action_checked(self, action_ref):
        for ref, action in self._actions.items():
            if ref != action_ref:
                action.setChecked(False)
        if self._actions[action_ref].isChecked():
            self._current_tool = action_ref
        else:
            self._current_tool = None
        self._tab_widget.currentWidget().set_current_tool(self._current_tool)

    def on_open_maps(self, message):
        current_file = self.config.current_file()
        for map_name, map_obj in current_file.get('maps', {}).items():
            map_grid = MapGrid(self, map_obj, self.LAYERS)
            map_grid.read_map_conf()
            map_grid.show_layer(MapBackgroundLayer)
            self._tab_widget.addTab(map_grid, map_name)

    def on_new_project(self, message):
        self._current_tool = None
        for widget in self._tiles_widgets.values():
            widget.hide()
        self._tileset_cb.clear()
        self._tiles_widgets = {}
        self._tab_widget.clear()

    def on_select_tile(self, tile):
        for selector in self._tiles_widgets.values():
            selector.unselect_all()
        self._current_tool = tile
        self._tab_widget.currentWidget().set_current_tool(tile)

    def on_new_tileset(self, message):
        self._tileset_cb.addItem(message['tileset'])
        self._tiles_widgets[message['tileset']] = TilesSelector(
            self, self.on_select_tile, message['tileset']
        )
        self._tiles_widgets[message['tileset']].setGeometry(665, 30, 220, 560)
        self.update()

    def update(self, index=None):
        for name in self._tiles_widgets.keys():
            self._tiles_widgets[name].hide()
        current_tileset = str(self._tileset_cb.currentText())
        if current_tileset in self._tiles_widgets:
            self._tiles_widgets[current_tileset].show()

    def on_tileset_update(self, message):
        if message['tileset'] in self._tiles_widgets:
            self._tiles_widgets[message['tileset']].update()

    def on_new_map(self, message):
        map_obj = NewMapDialog.get_new_map(self)
        if map_obj is not None:
            self._tab_widget.addTab(MapGrid(
                self, map_obj, self.LAYERS), map_obj['name']
            )

    def on_zoom_in(self):
        self._tab_widget.currentWidget().on_zoom_in()

    def on_zoom_out(self):
        self._tab_widget.currentWidget().on_zoom_out()
class TileSetPicture(QtGui.QLabel):

    def __init__(self, parent, picture_path, queue):
        super(TileSetPicture, self).__init__(parent)
        self._parent = parent
        self._queue = queue
        self._items = []
        self._base_pixmap = QtGui.QPixmap(picture_path)
        self.config = Config()
        self.current_file = self.config.current_file()
        path_elements = os.path.split(picture_path)
        self._base_name = os.path.splitext(
            path_elements[len(path_elements) - 1]
        )[0]
        if not 'tilesets' in self.current_file:
            self.current_file['tilesets'] = {}
        if not 'pathes' in self.current_file:
            self.current_file['pathes'] = {}
        self.current_file['pathes'][self._base_name] = picture_path
        if not self._base_name in self.current_file['tilesets']:
            self.current_file['tilesets'][self._base_name] = {}
        self._current_item = None

    def base_name(self):
        return self._base_name

    def pixmap(self):
        return self._base_pixmap

    def read_tilesets_config(self):
        self.current_file = self.config.current_file()
        tileset_dict = self.current_file['tilesets'][self._base_name]
        for tile_name, tile in tileset_dict.items():
            item = TileItem(self, self._queue,
                tile['crop_x'], tile['crop_y'],
                tile['crop_width'], tile['crop_height']
            )
            item.set_name(tile_name)
            item.show()
            self._items.append(item)

    def set_height(self, height):
        pixmap = self._base_pixmap.scaledToHeight(height)
        self.setGeometry(0, 0, pixmap.width(), pixmap.height())
        self.setPixmap(pixmap)
        for item in self._items:
            item.update_geometry()

    def mousePressEvent(self, event):
        self._current_item = TileItem(self, self._queue, event.x(), event.y())
        self._current_item.show()

    def mouseReleaseEvent(self, event):
        if self._current_item is not None:
            if self._current_item.real_width() == 1:
                self._current_item.hide()
            else:
                status = False
                while not status:
                    name, status = QtGui.QInputDialog.getText(
                        self._parent, 'Tile name', 'Name :'
                    )
                name = str(name)
                self._current_item.set_name(name)
                self.current_file['tilesets'][
                    self._base_name
                ][name] = self._current_item.to_dict()
                self.current_file['tilesets']
                self._items.append(self._current_item)
                self._queue.put({'name': 'config.save'})
                self._queue.put({
                    'name': 'tileset.update',
                    'tileset': self._base_name
                })
            self._current_item = None

    def mouseMoveEvent(self, event):
        if self._current_item is not None:
            rect = self._current_item.geometry()
            width = event.x() - rect.x()
            if width < 3:
                width = 3
            height = event.y() - rect.y()
            if height < 3:
                height = 3
            self._current_item.set_size(width, height)

    def remove_item(self, item):
        self._items.pop(self._items.index(item))
        item.hide()
        del self.current_file[
            'tilesets'
        ][self._base_name][item.to_dict()['name']]

    def remove(self):
        del self.current_file['tilesets'][self._base_name]
class AnimationArea(QtGui.QFrame):

    FPS_VALUES = [40, 35, 30, 25, 20, 15, 10, 5, 2, 1]
    NB_MULTIPLIERS = 100

    def __init__(self, parent, actor_name, animation_name):
        super(AnimationArea, self).__init__(parent)
        self._parent = parent
        self.config = Config()
        self.current_conf = Config().current_file()[
            'actors'
        ][actor_name]['animations'][animation_name]
        self._current_frame = 0
        self._actor_name = actor_name
        self._animation_name = animation_name
        self.setGeometry(0, 0, 480, 450)
        self._frames_list = QtGui.QComboBox(self)
        self._frames_list.setGeometry(5, 420, 100, 20)
        self._frames_list.currentIndexChanged.connect(self.on_change_frame)
        self._add_frame_button = IconButton(self, 'add_frame', 50, 50)
        self._add_frame_button.setGeometry(110, 420, 20, 20)
        self._add_frame_button.clicked.connect(self.on_add_frame)
        self._remove_frame_button = IconButton(self, 'remove_frame', 50, 50)
        self._remove_frame_button.setGeometry(135, 420, 20, 20)
        self._remove_frame_button.clicked.connect(self.on_remove_frame)
        self._scroll_areas = {}
        self._add_picture_button = IconButton(self, 'add_picture', 50, 50)
        self._add_picture_button.setGeometry(402, 2, 50, 50)
        self._add_picture_button.clicked.connect(self.on_new_picture)
        self._remove_animation_button = IconButton(
            self, 'remove_animation', 50, 50
        )
        self._remove_animation_button.setGeometry(402, 54, 50, 50)
        self._remove_animation_button.clicked.connect(self.on_remove_animation)
        self._resize_button = QtGui.QRadioButton('Resize', self)
        self._resize_button.setGeometry(170, 420, 70, 20)
        self._move_button = QtGui.QRadioButton('Move', self)
        self._move_button.setGeometry(240, 420, 70, 20)
        self._move_button.setChecked(True)
        self._multiplier = QtGui.QComboBox(self)
        self._multiplier.setGeometry(402, 380, 50, 20)
        for multiplier in range(1, self.NB_MULTIPLIERS + 1):
            self._multiplier.addItem('x' + str(multiplier))
        self._pos_label = QtGui.QLabel(self)
        self._pos_label.setGeometry(402, 100, 50, 100)
        self._play_animation = IconButton(self, 'play_animation', 50, 50)
        self._play_animation.setGeometry(402, 210, 50, 50)
        self._play_animation.clicked.connect(self.on_play_animation)
        self._fps_choice = QtGui.QComboBox(self)
        self._fps_choice.setGeometry(310, 420, 150, 20)
        if not len(self.current_conf):
            self._scroll_areas[0] = QtGui.QScrollArea(self)
            self._scroll_areas[0].setGeometry(0, 0, 400, 400)
            self._scroll_areas[0].setWidget(SpriteGridWidget(self))
            self._frames_list.addItem('Frame 0')
            self.current_conf['fps'] = 40
        for value in self.FPS_VALUES:
            period = 1000 / value
            self._fps_choice.addItem('%d FPS - %d ms' % (value, period))
        self._fps_choice.setCurrentIndex(self.FPS_VALUES.index(
            self.current_conf['fps']
        ))
        self._fps_choice.currentIndexChanged.connect(self.on_change_fps)
        self._multiplier.currentIndexChanged.connect(self.on_change_multiplier)

    def on_change_multiplier(self):
        frame_key = 'frame_%d' % self._current_frame
        conf = None
        for elem in self.current_conf[frame_key]:
            if elem.get('type', None) == 'conf':
                conf = elem
                break
        if conf is None:
            conf = {'type': 'conf'}
            self.current_conf[frame_key].append(conf)
        multiplier = self._multiplier.currentIndex() + 1
        conf['multiplier'] = multiplier

    def on_play_animation(self):
        preview = AnimationPreview(
            self, self._actor_name, self._animation_name
        )
        preview.show()

    def read_conf(self):
        for index in range(len(self.current_conf) - 1):
            frame_key = 'frame_%d' % index
            self._scroll_areas[index] = QtGui.QScrollArea(self)
            self._scroll_areas[index].setGeometry(0, 0, 400, 400)
            self._scroll_areas[index].setWidget(SpriteGridWidget(self))
            for obj in self.current_conf[frame_key]:
                if obj.get('type', None) != 'conf':
                    frame_image = FrameImage(
                        self._scroll_areas[index].widget(),
                        self.config.current_file()['pathes'][obj['id']],
                        obj['id'], frame_key
                    )
                    frame_image.setGeometry(
                        200 + obj['x'] * 100,
                        200 + obj['y'] * 100,
                        obj['width'] * 100,
                        obj['height'] * 100,
                    )
                    frame_image.show()
                    self._frames_list.addItem('Frame %d' % index)
            self._scroll_areas[index].hide()
        self._current_frame = 0
        self._scroll_areas[0].show()
        self._frames_list.setCurrentIndex(0)
        frame_key = 'frame_%d' % self._current_frame
        conf = None
        for elem in self.current_conf[frame_key]:
            if elem.get('type', None) == 'conf':
                conf = elem
                break
        if conf is None:
            conf = {'type': 'conf'}
            self.current_conf[frame_key].append(conf)
        multiplier = conf.get('multiplier', 1)
        self._multiplier.setCurrentIndex(multiplier - 1)

    def remove_animation(self):
        animations = Config().current_file()[
            'actors'][self._actor_name]['animations']
        del animations[self._animation_name]

    def on_remove_animation(self):
        self._parent.remove_animation(self._animation_name)

    def on_change_fps(self):
        self.current_conf['fps'] = self.FPS_VALUES[
            self._fps_choice.currentIndex()
        ]

    def on_remove_frame(self):
        if len(self._scroll_areas) > 1:
            if self._current_frame == len(self._scroll_areas) - 1:
                frame_key = self.get_frame_key()
                if frame_key in self.current_conf:
                    del self.current_conf[frame_key]
                self._scroll_areas[self._current_frame].hide()
                del self._scroll_areas[self._current_frame]
                self._current_frame -= 1
                self._frames_list.setCurrentIndex(self._current_frame)
                self._frames_list.removeItem(len(self._scroll_areas))

    def move_image(self, image, gap):
        gap_x, gap_y = gap
        obj = None
        rect = image.geometry()
        for image_obj in self.current_conf[image.frame_key()]:
            if image_obj.get('type', None) != 'conf':
                if image_obj['id'] == image.image_id():
                    obj = image_obj
        if self._move_button.isChecked():
            x, y = rect.x() + gap_x, rect.y() + gap_y
            image.setGeometry(x, y, rect.width(), rect.height())
            obj['x'] = (x - 200.0) / 100.0
            obj['y'] = (y - 200.0) / 100.0
        else:
            width = rect.width() + gap_x
            height = width * rect.height() / rect.width()
            image.setGeometry(rect.x(), rect.y(), width, height)
            obj['width'] = width / 100.0
            obj['height'] = height / 100.0
        self.update_label(obj)

    def update_label(self, image_obj):
        self._pos_label.setText(
            'X : %s\nY : %s\nW : %s\nH : %s' % (
                str(image_obj['x']),
                str(image_obj['y']),
                str(image_obj['width']),
                str(image_obj['height'])
            )
        )

    def on_change_frame(self):
        self._scroll_areas[self._current_frame].hide()
        self._current_frame = self._frames_list.currentIndex()
        frame_key = 'frame_%d' % self._current_frame
        if frame_key in self.current_conf:
            conf = None
            for elem in self.current_conf.get(frame_key, []):
                if elem.get('type', None) == 'conf':
                    conf = elem
                    break
            if conf is None:
                conf = {'type': 'conf'}
                self.current_conf[frame_key].append(conf)
            multiplier = conf.get('multiplier', 1)
        else:
            multiplier = 1
        self._multiplier.setCurrentIndex(multiplier - 1)
        self._scroll_areas[self._current_frame].show()

    def on_add_frame(self):
        if self._current_frame == len(self._scroll_areas) - 1:
            self._scroll_areas[self._current_frame].hide()
            self._current_frame += 1
            frame_label = 'Frame %d' % self._current_frame
            self._scroll_areas[self._current_frame] = QtGui.QScrollArea(self)
            self._scroll_areas[self._current_frame].setGeometry(0, 0, 400, 400)
            self._scroll_areas[self._current_frame].setWidget(
                SpriteGridWidget(self)
            )
            self._frames_list.addItem(frame_label)
            self._frames_list.setCurrentIndex(self._current_frame)
            frame_key = self.get_frame_key()
            if not frame_key in self.current_conf:
                self.current_conf[frame_key] = []

    def get_frame_key(self):
        return 'frame_%d' % self._current_frame

    def remove_image(self, frame_image):
        frame_image.hide()
        index = 0

        for image_obj in self.current_conf[frame_image.frame_key()]:
            if not 'type' in image_obj or image_obj['type'] != 'conf':
                if image_obj['id'] == frame_image.image_id():
                    self.current_conf[frame_image.frame_key()].pop(index)
            index += 1

    def on_new_picture(self):
        file_name = QtGui.QFileDialog.getOpenFileName(
            self, filter='Image (*.png)',
            directory=self.config.get(
                'frame_image_dir', os.path.expanduser('~')
            )
        )
        if file_name:
            from mqme.mainwindow import MainWindow
            file_name = unicode(file_name)
            self.config.set('frame_image_dir', os.path.dirname(file_name))
            MainWindow.queue.put({'name': 'config.save'})
            if not 'pathes' in Config().current_file():
                Config().current_file()['pathes'] = {}
            image_id = str(uuid.uuid1())
            Config().current_file()['pathes'][image_id] = file_name
            frame_key = self.get_frame_key()
            if not frame_key in self.current_conf:
                self.current_conf[frame_key] = []
            frame_image = FrameImage(
                self._scroll_areas[self._current_frame].widget(),
                file_name, image_id, frame_key
            )
            frame_image.show()
            width, height = frame_image.ratio()
            x = 0.5 - (width / 2.0)
            y = 1.0 - height
            self.current_conf[frame_key].append({
                'id': image_id,
                'width': width, 'height': height,
                'x': x, 'y': y
            })
            frame_image.setGeometry(
                200 + x * 100, 200 + y * 100, width * 100, height * 100
            )