class SelectableTile(QtGui.QLabel): def __init__(self, parent, callback, tileset, tile): super(SelectableTile, self).__init__(parent) self.config = Config() self.current_file = Config().current_file() tile_infos = self.current_file['tilesets'][tileset][tile] self.setPixmap( QtGui.QPixmap(self.current_file['pathes'][tileset]).copy( tile_infos['crop_x'], tile_infos['crop_y'], tile_infos['crop_width'], tile_infos['crop_height'] ).scaled(50, 50) ) self.config.set_cache('tiles/%s/%s' % (tileset, tile), self.pixmap()) self._callback = callback self._tileset = tileset self._tile = tile def tile(self): return self._tile def tileset(self): return self._tileset def mousePressEvent(self, event): self._callback(self)
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 __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 __init__(self, name): super(ActorWorkspace, self).__init__() self._actor_name = name self._current_conf = Config().current_file()["actors"][name] self.setGeometry(0, 50, 640, 430) self._animations_list = QtGui.QListWidget(self) self._animations_list.setGeometry(485, 40, 150, 405) self._animations_list.itemClicked.connect(self.on_choose_animation) self._new_animation_button = QtGui.QPushButton("New animation", self) self._new_animation_button.setGeometry(485, 2, 150, 36) self._new_animation_button.clicked.connect(self.on_new_animation) self._animation_areas = {}
def __init__(self): super(SpritesEditor, self).__init__() self.setFixedSize(640, 480) self.setWindowTitle("Sprites Editor") self._tabs_widget = QtGui.QTabWidget(self) self._tabs_widget.setGeometry(0, 0, 640, 480) self._tabs_widget.setTabsClosable(True) self._tabs_widget.tabCloseRequested.connect(self.on_actor_delete) self._current_file = Config().current_file() self.subscribe("menu.trigger.new_actor", self.on_new_actor) self.subscribe("open_project", self.on_open_file) self.subscribe("new_project", self.on_new_file)
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 __init__(self): super(FightEnvironmentEditor, self).__init__() self.setWindowTitle('Fight Environment Editor') self.setFixedSize(320, 240) self._tabs_widget = QtGui.QTabWidget(self) self._tabs_widget.setGeometry(0, 0, 320, 240) self._tabs_widget.setTabsClosable(True) self._tabs_widget.tabCloseRequested.connect(self.on_environment_delete) self.subscribe( 'menu.trigger.new_fight_environment', self.on_new_environment ) self._current_file = Config().current_file() self.subscribe('open_project', self.on_open_file)
class FightEnvironmentEditor(ChildWindow): def __init__(self): super(FightEnvironmentEditor, self).__init__() self.setWindowTitle('Fight Environment Editor') self.setFixedSize(320, 240) self._tabs_widget = QtGui.QTabWidget(self) self._tabs_widget.setGeometry(0, 0, 320, 240) self._tabs_widget.setTabsClosable(True) self._tabs_widget.tabCloseRequested.connect(self.on_environment_delete) self.subscribe( 'menu.trigger.new_fight_environment', self.on_new_environment ) self._current_file = Config().current_file() self.subscribe('open_project', self.on_open_file) def on_open_file(self, message): self._current_file = Config().current_file() for name in self._current_file.get('fightenv', {}): workspace = FightEnvironmentWorkspace(name) workspace.read_conf() self._tabs_widget.addTab(workspace, name) def on_environment_delete(self, index): name = self._tabs_widget.widget(index).name() msg_box = QtGui.QMessageBox(self) msg_box.setWindowTitle('Delete Fight Environment') msg_box.setText('Do you want to delete "%s" ?' % 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: del self._current_file['fightenv'][name] self._tabs_widget.removeTab(index) def on_new_environment(self, message): name, status = QtGui.QInputDialog.getText( self, 'Fight Environment name', 'Name :' ) if status: name = str(name) if not 'fightenv' in self._current_file: self._current_file['fightenv'] = {} self._current_file['fightenv'][name] = {} self._tabs_widget.addTab(FightEnvironmentWorkspace(name), name)
class SpritesEditor(ChildWindow): def __init__(self): super(SpritesEditor, self).__init__() self.setFixedSize(640, 480) self.setWindowTitle("Sprites Editor") self._tabs_widget = QtGui.QTabWidget(self) self._tabs_widget.setGeometry(0, 0, 640, 480) self._tabs_widget.setTabsClosable(True) self._tabs_widget.tabCloseRequested.connect(self.on_actor_delete) self._current_file = Config().current_file() self.subscribe("menu.trigger.new_actor", self.on_new_actor) self.subscribe("open_project", self.on_open_file) self.subscribe("new_project", self.on_new_file) def on_actor_delete(self, index): actor_name = self._tabs_widget.widget(index).actor_name() msg_box = QtGui.QMessageBox(self) msg_box.setWindowTitle("Delete Actor") msg_box.setText('Do you want to delete "%s" ?' % actor_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._tabs_widget.widget(index).remove_actor() self._tabs_widget.removeTab(index) def on_new_actor(self, message): name, status = QtGui.QInputDialog.getText(self, "Actor name", "Name :") if status: name = str(name) if not "actors" in self._current_file: self._current_file["actors"] = {} self._current_file["actors"][name] = {} self._tabs_widget.addTab(ActorWorkspace(name), name) def on_new_file(self, message): self._tabs_widget.clear() def on_open_file(self, message): self._current_file = Config().current_file() for name in self._current_file.get("actors", {}): workspace = ActorWorkspace(name) workspace.read_conf() self._tabs_widget.addTab(workspace, name)
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 __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 __init__(self, name): super(FightEnvironmentWorkspace, self).__init__() self._name = name self._height_ratio = 1.0 self.config = Config() self.setGeometry(0, 0, 320, 220) self._layers = {} self._buttons = [] self._current_conf = Config().current_file()['fightenv'][name] for layer_name in self.LAYERS: self._layers[layer_name] = self.new_layer() self._layers['screen'].setStyleSheet( 'QLabel {' 'background-color: black;' 'border: 3px solid #ccccff;' '}' ) self.new_button('Set background 1', 2, self.on_choose_background1, False) self.new_button('Set background 2', 104, self.on_choose_background2, False) self.new_button('Set background 3', 206, self.on_choose_background3) self._play_animation = IconButton(self, 'play_animation', 30, 30) self._play_animation.setGeometry(145, 182, 30, 30) self._play_animation.clicked.connect(self.on_play_animation)
class SpritesGenerator(object): def __init__(self, actor_name): self._actor_name = actor_name self.current_conf = Config().current_file()['actors'][actor_name] self._sps_infos = {} self._crop_x = 0 self._crop_y = 0 def save(self, directory): animation_images = {} width = 0 for animation_name in self.current_conf.get('animations', {}): animation_images[animation_name] = self.get_animation_as_image( animation_name ) im_width, im_height = animation_images[animation_name].size if width < im_width: width = im_width sprites_image = Image.new('RGBA', (width, self._crop_y)) y_offset = 0 for animation_name in self.current_conf.get('animations', {}): sprites_image.paste( animation_images[animation_name], (0, y_offset) ) im_width, im_height = animation_images[animation_name].size y_offset += im_height base_path = os.path.join(directory, self._actor_name) sprites_image.save(base_path + '.png') with open(base_path + '.sps', 'w') as sps: sps.write(json.dumps(self._sps_infos)) def infos(self): return self._sps_infos def get_animation_as_image(self, animation_name): self._crop_x = 0 max_crop_height = 0 n_frame = len(self.current_conf['animations'][animation_name]) - 1 self._sps_infos[animation_name] = { 'fps': self.current_conf['animations'][animation_name]['fps'], 'count': n_frame } frames_images = {} for frame_index in range(n_frame): frames_images[frame_index] = self.get_frame_as_image( animation_name, frame_index ) current_sps = self._sps_infos[ '%s_%s' % (animation_name, frame_index) ] current_sps.update({ 'crop_x': self._crop_x, 'crop_y': self._crop_y, 'crop_width': int(current_sps['width'] * 32), 'crop_height': int(current_sps['height'] * 32), }) if max_crop_height < current_sps['crop_height']: max_crop_height = current_sps['crop_height'] self._crop_x += current_sps['crop_width'] animation_image = Image.new('RGBA', (self._crop_x, max_crop_height)) for frame_index in range(n_frame): current_sps = self._sps_infos[ '%s_%s' % (animation_name, frame_index) ] animation_image.paste(frames_images[frame_index], ( current_sps['crop_x'], 0 )) self._crop_y += max_crop_height return animation_image def get_frame_as_image(self, animation_name, frame_index): frame_key = 'frame_%d' % frame_index if not len(self.current_conf['animations'][animation_name][frame_key]): return None left = None top = None right = None bottom = None conf = None for obj in self.current_conf['animations'][animation_name][frame_key]: if obj.get('type', None) != 'conf': if left is None or left > obj['x']: left = obj['x'] if top is None or top > obj['y']: top = obj['y'] if right is None or right < obj['x'] + obj['width']: right = obj['x'] + obj['width'] if bottom is None or bottom < obj['y'] + obj['height']: bottom = obj['y'] + obj['height'] image = Image.new('RGBA', ( int((right - left) * 32), int((bottom - top) * 32) )) for obj in self.current_conf['animations'][animation_name][frame_key]: if obj.get('type', None) != 'conf': sub_image = Image.open( Config().current_file()['pathes'][obj['id']] ) sub_image = sub_image.resize( (int(obj['width'] * 32), int(obj['height'] * 32)) ) image.paste(sub_image, ( int((obj['x'] - left) * 32), int((obj['y'] - top) * 32) )) else: conf = obj self._sps_infos['%s_%s' % (animation_name, frame_index)] = { 'x': left, 'y': top, 'width': right - left, 'height': bottom - top } if conf is not None: self._sps_infos[ '%s_%s' % (animation_name, frame_index) ].update(conf) return image
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())
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 )
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()
def on_open_file(self, message): self._current_file = Config().current_file() for name in self._current_file.get('fightenv', {}): workspace = FightEnvironmentWorkspace(name) workspace.read_conf() self._tabs_widget.addTab(workspace, name)
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 ))
class FightEnvironmentWorkspace(QtGui.QFrame): LAYERS = ('screen', 'background3', 'background2', 'background1') def __init__(self, name): super(FightEnvironmentWorkspace, self).__init__() self._name = name self._height_ratio = 1.0 self.config = Config() self.setGeometry(0, 0, 320, 220) self._layers = {} self._buttons = [] self._current_conf = Config().current_file()['fightenv'][name] for layer_name in self.LAYERS: self._layers[layer_name] = self.new_layer() self._layers['screen'].setStyleSheet( 'QLabel {' 'background-color: black;' 'border: 3px solid #ccccff;' '}' ) self.new_button('Set background 1', 2, self.on_choose_background1, False) self.new_button('Set background 2', 104, self.on_choose_background2, False) self.new_button('Set background 3', 206, self.on_choose_background3) self._play_animation = IconButton(self, 'play_animation', 30, 30) self._play_animation.setGeometry(145, 182, 30, 30) self._play_animation.clicked.connect(self.on_play_animation) def on_play_animation(self): self._preview = FightEnvironmentPreview(self._name) self._preview.show() def name(self): return self._name def read_conf(self): for layer_name in self.LAYERS: if layer_name in self._current_conf: path = Config().current_file()['pathes'][self._current_conf[layer_name]] pixmap = QtGui.QPixmap(path) self.show_background(pixmap, layer_name) def show_background(self, pixmap, name): height = self._layers[name].height() width = (pixmap.width() * height) / pixmap.height() self._height_ratio = float(height) / pixmap.height() self._layers[name].setPixmap(pixmap.scaled(width, height)) for button in self._buttons: button.setEnabled(True) def on_choose_background3(self): pixmap = self.choose_and_save_image('background3') if pixmap: self.show_background(pixmap, 'background3') def on_choose_background2(self): pixmap = self.choose_and_save_image('background2') if pixmap: self.show_background(pixmap, 'background2') def on_choose_background1(self): pixmap = self.choose_and_save_image('background1') if pixmap: self.show_background(pixmap, 'background1') def choose_and_save_image(self, image_name): file_name = QtGui.QFileDialog.getOpenFileName( self, filter='Image (*.png)', directory=self.config.get( 'fightenv_image_dir', os.path.expanduser('~') ) ) if file_name: from mqme.mainwindow import MainWindow file_name = unicode(file_name) self.config.set('fightenv_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 self._current_conf[image_name] = image_id return QtGui.QPixmap(file_name) def new_button(self, name, x, callback, enabled=True): button = QtGui.QPushButton(name, self) button.setGeometry(x, 155, 100, 20) button.clicked.connect(callback) button.setEnabled(enabled) button.setStyleSheet( 'QPushButton {' 'font-size: 10px;' '}' ) button.show() self._buttons.append(button) def new_layer(self): layer = QtGui.QLabel(self) layer.setGeometry(7, 0, 300, 150) layer.show() return layer
class ActorWorkspace(QtGui.QFrame): def __init__(self, name): super(ActorWorkspace, self).__init__() self._actor_name = name self._current_conf = Config().current_file()["actors"][name] self.setGeometry(0, 50, 640, 430) self._animations_list = QtGui.QListWidget(self) self._animations_list.setGeometry(485, 40, 150, 405) self._animations_list.itemClicked.connect(self.on_choose_animation) self._new_animation_button = QtGui.QPushButton("New animation", self) self._new_animation_button.setGeometry(485, 2, 150, 36) self._new_animation_button.clicked.connect(self.on_new_animation) self._animation_areas = {} def read_conf(self): for name in self._current_conf.get("animations", {}): self._animation_areas[name] = AnimationArea(self, self._actor_name, name) self._animation_areas[name].read_conf() self._animation_areas[name].hide() self._animations_list.addItem(name) def on_choose_animation(self, item): for name, area in self._animation_areas.items(): if name == item.text(): area.show() else: area.hide() def remove_animation(self, animation_name): msg_box = QtGui.QMessageBox(self) msg_box.setWindowTitle("Remove Animation") msg_box.setText('Do you want to remove animation "%s" ?' % animation_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._animation_areas[animation_name].remove_animation() for index in range(self._animations_list.count()): item = self._animations_list.item(index) if item.text() == animation_name: self._animations_list.takeItem(index) break item = self._animations_list.item(0) self._animations_list.setCurrentItem(item) self._animation_areas[str(item.text())].show() del self._animation_areas[animation_name] def remove_actor(self): actors = Config().current_file()["actors"] del actors[self._actor_name] def actor_name(self): return self._actor_name def on_new_animation(self): name, status = QtGui.QInputDialog.getText(self, "Animation name", "Name :") if status: name = str(name) if not "animations" in self._current_conf: self._current_conf["animations"] = {} self._current_conf["animations"][name] = {} self._animations_list.addItem(name) self._animation_areas[name] = AnimationArea(self, self._actor_name, name) self._animation_areas[name].show()
def __init__(self, actor_name): self._actor_name = actor_name self.current_conf = Config().current_file()['actors'][actor_name] self._sps_infos = {} self._crop_x = 0 self._crop_y = 0
def on_open_file(self, message): self._current_file = Config().current_file() for name in self._current_file.get("actors", {}): workspace = ActorWorkspace(name) workspace.read_conf() self._tabs_widget.addTab(workspace, name)
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]