def _run(procedure_name, procedure_params): global config if config.PLUGIN_NAME == config._DEFAULT_PLUGIN_NAME: config.PLUGIN_NAME = procedure_name _init_config_builtin_delayed(config) procedure = _add_gui_excepthook( _procedures_names[procedure_name], procedure_params[0]) if hasattr(gimpui, "gimp_ui_init"): gimpui.gimp_ui_init() procedure(*procedure_params)
def _run(procedure_name, procedure_params): global config if config.PLUGIN_NAME == config._DEFAULT_PLUGIN_NAME: config.PLUGIN_NAME = procedure_name _init_config_builtin_delayed(config) procedure = _add_gui_excepthook(_procedures_names[procedure_name], procedure_params[0]) if hasattr(gimpui, "gimp_ui_init"): gimpui.gimp_ui_init() procedure(*procedure_params)
def do_console(): import pygtk pygtk.require('2.0') import sys, gobject, gtk, gimpenums, gimpshelf, gimpui, pyconsole gimpui.gimp_ui_init() namespace = { '__builtins__': __builtins__, '__name__': '__main__', '__doc__': None, 'gimp': gimp, 'pdb': gimp.pdb, 'shelf': gimpshelf.shelf } for s in gimpenums.__dict__.keys(): if s[0] != '_': namespace[s] = getattr(gimpenums, s) class GimpConsole(pyconsole.Console): def __init__(self, quit_func=None): banner = ('GIMP %s Python Console\nPython %s\n' % (gimp.pdb.gimp_version(), sys.version)) pyconsole.Console.__init__(self, locals=namespace, banner=banner, quit_func=quit_func) def _commit(self): pyconsole.Console._commit(self) gimp.displays_flush() class ConsoleDialog(gimpui.Dialog): def __init__(self): gimpui.Dialog.__init__(self, title=_("Python Console"), role=PROC_NAME, help_id=PROC_NAME, buttons=(gtk.STOCK_SAVE, RESPONSE_SAVE, gtk.STOCK_CLEAR, RESPONSE_CLEAR, _("_Browse..."), RESPONSE_BROWSE, gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)) self.set_alternative_button_order( (gtk.RESPONSE_CLOSE, RESPONSE_BROWSE, RESPONSE_CLEAR, RESPONSE_SAVE)) self.cons = GimpConsole(quit_func=lambda: gtk.main_quit()) self.connect('response', self.response) self.browse_dlg = None self.save_dlg = None vbox = gtk.VBox(False, 12) vbox.set_border_width(12) self.vbox.pack_start(vbox) scrl_win = gtk.ScrolledWindow() scrl_win.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS) vbox.pack_start(scrl_win) scrl_win.add(self.cons) width, height = self.cons.get_default_size() sb_width, sb_height = scrl_win.get_vscrollbar().size_request() # Account for scrollbar width and border width to ensure # the text view gets a width of 80 characters. We don't care # so much whether the height will be exactly 40 characters. self.set_default_size(width + sb_width + 2 * 12, height) def response(self, dialog, response_id): if response_id == RESPONSE_BROWSE: self.browse() elif response_id == RESPONSE_CLEAR: self.cons.banner = None self.cons.clear() elif response_id == RESPONSE_SAVE: self.save_dialog() else: gtk.main_quit() self.cons.grab_focus() def browse_response(self, dlg, response_id): if response_id != gtk.RESPONSE_APPLY: dlg.hide() return proc_name = dlg.get_selected() if not proc_name: return proc = pdb[proc_name] cmd = '' if len(proc.return_vals) > 0: cmd = ', '.join( [x[1].replace('-', '_') for x in proc.return_vals]) + ' = ' cmd = cmd + 'pdb.%s' % proc.proc_name.replace('-', '_') if len(proc.params) > 0 and proc.params[0][1] == 'run-mode': params = proc.params[1:] else: params = proc.params cmd = cmd + '(%s)' % ', '.join( [x[1].replace('-', '_') for x in params]) buffer = self.cons.buffer lines = buffer.get_line_count() iter = buffer.get_iter_at_line_offset(lines - 1, 4) buffer.delete(iter, buffer.get_end_iter()) buffer.place_cursor(buffer.get_end_iter()) buffer.insert_at_cursor(cmd) def browse(self): if not self.browse_dlg: dlg = gimpui.ProcBrowserDialog( _("Python Procedure Browser"), role=PROC_NAME, buttons=(gtk.STOCK_APPLY, gtk.RESPONSE_APPLY, gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)) dlg.set_default_response(gtk.RESPONSE_APPLY) dlg.set_alternative_button_order( (gtk.RESPONSE_CLOSE, gtk.RESPONSE_APPLY)) dlg.connect('response', self.browse_response) dlg.connect('row-activated', lambda dlg: dlg.response(gtk.RESPONSE_APPLY)) self.browse_dlg = dlg self.browse_dlg.present() def save_response(self, dlg, response_id): if response_id == gtk.RESPONSE_DELETE_EVENT: self.save_dlg = None return elif response_id == gtk.RESPONSE_OK: filename = dlg.get_filename() try: logfile = open(filename, 'w') except IOError, e: gimp.message( _("Could not open '%s' for writing: %s") % (filename, e.strerror)) return buffer = self.cons.buffer start = buffer.get_start_iter() end = buffer.get_end_iter() log = buffer.get_text(start, end, False) try: logfile.write(log) logfile.close() except IOError, e: gimp.message( _("Could not write to '%s': %s") % (filename, e.strerror)) return dlg.hide()
def _interact(proc_name, start_params): (blurb, help, author, copyright, date, label, imagetypes, plugin_type, params, results, function, menu, domain, on_query, on_run) = _registered_plugins_[proc_name] def run_script(run_params): params = start_params + tuple(run_params) _set_defaults(proc_name, params) return apply(function, params) params = params[len(start_params):] # short circuit for no parameters ... if len(params) == 0: return run_script([]) import pygtk pygtk.require('2.0') import gimpui import gtk # import pango gimpui.gimp_ui_init() defaults = _get_defaults(proc_name) defaults = defaults[len(start_params):] class EntryValueError(Exception): pass def warning_dialog(parent, primary, secondary=None): dlg = gtk.MessageDialog(parent, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_WARNING, gtk.BUTTONS_CLOSE, primary) if secondary: dlg.format_secondary_text(secondary) dlg.run() dlg.destroy() def error_dialog(parent, proc_name): import sys, traceback exc_str = exc_only_str = _("Missing exception information") try: etype, value, tb = sys.exc_info() exc_str = "".join(traceback.format_exception(etype, value, tb)) exc_only_str = "".join( traceback.format_exception_only(etype, value)) finally: etype = value = tb = None title = _("An error occurred running %s") % proc_name dlg = gtk.MessageDialog(parent, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, title) dlg.format_secondary_text(exc_only_str) alignment = gtk.Alignment(0.0, 0.0, 1.0, 1.0) alignment.set_padding(0, 0, 12, 12) dlg.vbox.pack_start(alignment) alignment.show() expander = gtk.Expander(_("_More Information")) expander.set_use_underline(True) expander.set_spacing(6) alignment.add(expander) expander.show() scrolled = gtk.ScrolledWindow() scrolled.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) scrolled.set_size_request(-1, 200) expander.add(scrolled) scrolled.show() label = gtk.Label(exc_str) label.set_alignment(0.0, 0.0) label.set_padding(6, 6) label.set_selectable(True) scrolled.add_with_viewport(label) label.show() def response(widget, id): widget.destroy() dlg.connect("response", response) dlg.set_resizable(True) dlg.show() # define a mapping of param types to edit objects ... class StringEntry(gtk.Entry): def __init__(self, default=""): gtk.Entry.__init__(self) self.set_text(str(default)) self.set_activates_default(True) def get_value(self): return self.get_text() class TextEntry(gtk.ScrolledWindow): def __init__(self, default=""): gtk.ScrolledWindow.__init__(self) self.set_shadow_type(gtk.SHADOW_IN) self.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) self.set_size_request(100, -1) self.view = gtk.TextView() self.add(self.view) self.view.show() self.buffer = self.view.get_buffer() self.set_value(str(default)) def set_value(self, text): self.buffer.set_text(text) def get_value(self): return self.buffer.get_text(self.buffer.get_start_iter(), self.buffer.get_end_iter()) class IntEntry(StringEntry): def get_value(self): try: return int(self.get_text()) except ValueError, e: raise EntryValueError, e.args
def _interact(proc_name, start_params): ( blurb, help, author, copyright, date, label, imagetypes, plugin_type, params, results, function, menu, domain, on_query, on_run, ) = _registered_plugins_[proc_name] def run_script(run_params): params = start_params + tuple(run_params) _set_defaults(proc_name, params) return apply(function, params) params = params[len(start_params) :] # short circuit for no parameters ... if len(params) == 0: return run_script([]) import pygtk pygtk.require("2.0") import gimpui import gtk # import pango gimpui.gimp_ui_init() defaults = _get_defaults(proc_name) defaults = defaults[len(start_params) :] class EntryValueError(Exception): pass def warning_dialog(parent, primary, secondary=None): dlg = gtk.MessageDialog(parent, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_WARNING, gtk.BUTTONS_CLOSE, primary) if secondary: dlg.format_secondary_text(secondary) dlg.run() dlg.destroy() def error_dialog(parent, proc_name): import sys, traceback exc_str = exc_only_str = _("Missing exception information") try: etype, value, tb = sys.exc_info() exc_str = "".join(traceback.format_exception(etype, value, tb)) exc_only_str = "".join(traceback.format_exception_only(etype, value)) finally: etype = value = tb = None title = _("An error occurred running %s") % proc_name dlg = gtk.MessageDialog(parent, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, title) dlg.format_secondary_text(exc_only_str) alignment = gtk.Alignment(0.0, 0.0, 1.0, 1.0) alignment.set_padding(0, 0, 12, 12) dlg.vbox.pack_start(alignment) alignment.show() expander = gtk.Expander(_("_More Information")) expander.set_use_underline(True) expander.set_spacing(6) alignment.add(expander) expander.show() scrolled = gtk.ScrolledWindow() scrolled.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) scrolled.set_size_request(-1, 200) expander.add(scrolled) scrolled.show() label = gtk.Label(exc_str) label.set_alignment(0.0, 0.0) label.set_padding(6, 6) label.set_selectable(True) scrolled.add_with_viewport(label) label.show() def response(widget, id): widget.destroy() dlg.connect("response", response) dlg.set_resizable(True) dlg.show() # define a mapping of param types to edit objects ... class StringEntry(gtk.Entry): def __init__(self, default=""): gtk.Entry.__init__(self) self.set_text(str(default)) self.set_activates_default(True) def get_value(self): return self.get_text() class TextEntry(gtk.ScrolledWindow): def __init__(self, default=""): gtk.ScrolledWindow.__init__(self) self.set_shadow_type(gtk.SHADOW_IN) self.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) self.set_size_request(100, -1) self.view = gtk.TextView() self.add(self.view) self.view.show() self.buffer = self.view.get_buffer() self.set_value(str(default)) def set_value(self, text): self.buffer.set_text(text) def get_value(self): return self.buffer.get_text(self.buffer.get_start_iter(), self.buffer.get_end_iter()) class IntEntry(StringEntry): def get_value(self): try: return int(self.get_text()) except ValueError, e: raise EntryValueError, e.args
def save_spr(img, drawable, filename, raw_filename): from array import array import pygtk import gtk pygtk.require('2.0') THUMB_MAXSIZE = 128 RESPONSE_EXPORT = 1 MIN_FRAME_ORIGIN = -8192 MAX_FRAME_ORIGIN = 8192 LS_LAYER, LS_PIXBUF, LS_SIZE_INFO, LS_EXPORT, LS_ORIGIN_X, LS_ORIGIN_Y, LS_THUMBDATA = range( 7) spr_img = img.duplicate() gimpui.gimp_ui_init() if spr_img.base_type != INDEXED: try: pdb.gimp_convert_indexed(spr_img, NO_DITHER, MAKE_PALETTE, 256, 0, 0, '') except RuntimeError: # Gimp does not support indexed mode if the image contains layer groups, so delete them for layer in spr_img.layers: if pdb.gimp_item_is_group(layer): pdb.gimp_image_merge_layer_group(spr_img, layer) pdb.gimp_convert_indexed(spr_img, NO_DITHER, MAKE_PALETTE, 256, 0, 0, '') def make_thumbnail_data(layer): width = layer.width height = layer.height indices = layer.get_pixel_rgn(0, 0, width, height)[:, :] if layer.type == INDEXEDA_IMAGE: indices = indices[::2] indices = ''.join(i + i for i in indices) thumbnail_layer = gimp.Layer(spr_img, layer.name + '_temp', width, height, INDEXEDA_IMAGE, 100, NORMAL_MODE) thumbnail_rgn = thumbnail_layer.get_pixel_rgn(0, 0, width, height) thumbnail_rgn[:, :] = indices pdb.gimp_image_insert_layer(spr_img, thumbnail_layer, None, 0) scale = float(THUMB_MAXSIZE) / max(width, height) if scale < 1.0: width = max(int(width * scale), 1) height = max(int(height * scale), 1) pdb.gimp_layer_scale_full(thumbnail_layer, width, height, False, 0) width, height, bpp, unused_, tn_data = pdb.gimp_drawable_thumbnail( thumbnail_layer, width, height) spr_img.remove_layer(thumbnail_layer) return str(bytearray(tn_data)), width, height, bpp def get_thumbnail(thumbnail_data, texture_format): tn_data, width, height, bpp = thumbnail_data last_index = len(spr_img.colormap) // 3 - 1 if texture_format != Sprite.TEXTURE_FORMAT_INDEXALPHA: tn_data = array('B', tn_data) if texture_format == Sprite.TEXTURE_FORMAT_ADDITIVE: for i in xrange(0, len(tn_data), 4): tn_data[i + 3] = sum(tn_data[i:i + 3]) // 3 elif texture_format == Sprite.TEXTURE_FORMAT_ALPHATEST: for i in xrange(0, len(tn_data), 4): tn_data[i + 3] = 0xff - (tn_data[i + 3] // last_index * 0xff) else: for i in xrange(0, len(tn_data), 4): tn_data[i + 3] = 0xff tn_data = tn_data.tostring() return gtk.gdk.pixbuf_new_from_data(tn_data, gtk.gdk.COLORSPACE_RGB, True, 8, width, height, width * bpp) class ExportDialog(gimpui.Dialog): def __init__(self): gimpui.Dialog.__init__( self, title=ugettext('Export Image as Half-Life sprite'), role=EDITOR_PROC, help_id=None, buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CLOSE, ugettext('Export'), RESPONSE_EXPORT)) self.set_name(EDITOR_PROC) self.connect('response', self.on_response) self.connect('destroy', self.on_destroy) export_opt_box = self.make_export_options_box() self.img_view_frame = self.make_frames_view( reversed(spr_img.layers)) hbox = gtk.HBox() hbox.pack_start(export_opt_box, True, True, 20) hbox.pack_start(self.img_view_frame, True, True, 5) self.vbox.pack_start(hbox) self.vbox.show_all() self.set_resizable(False) self.get_widget_for_response(RESPONSE_EXPORT).grab_focus() def update_thumbnails(self): texture_format = self.cb_tf.get_active() for ls in self.liststore: ls[LS_PIXBUF] = get_thumbnail(ls[LS_THUMBDATA], texture_format) def make_export_options_box(self): # Sprite type spr_type = spr_img.parasite_find('spr_type') self.cb_st = gtk.combo_box_new_text() self.cb_st.append_text('VP Parallel Upright') self.cb_st.append_text('Facing Upright') self.cb_st.append_text('VP Parallel') self.cb_st.append_text('Oriented') self.cb_st.append_text('VP Parallel Oriented') self.cb_st.set_tooltip_text(ugettext('Sprite Type')) self.cb_st.set_active(spr_type.flags if spr_type else 0) box = gtk.VBox(True, 5) box.pack_start(self.cb_st, False, False) st_frame = gimpui.Frame('Sprite Type:') st_frame.set_shadow_type(gtk.SHADOW_IN) st_frame.add(box) # Texture format texture_format = spr_img.parasite_find('spr_format') self.cb_tf = gtk.combo_box_new_text() self.cb_tf.append_text('Normal') self.cb_tf.append_text('Additive') self.cb_tf.append_text('Indexalpha') self.cb_tf.append_text('Alphatest') self.cb_tf.set_tooltip_text(ugettext('Texture Format')) self.cb_tf.set_active( texture_format.flags if texture_format else 0) def cb_tf_changed(cb): self.update_thumbnails() self.cb_tf.connect('changed', cb_tf_changed) box = gtk.VBox(True, 5) box.pack_start(self.cb_tf, False, False) tf_frame = gimpui.Frame('Texture Format:') tf_frame.set_shadow_type(gtk.SHADOW_IN) tf_frame.add(box) # Add origins offset lbl_oo_x = gtk.Label('Origin X:') adjustment = gtk.Adjustment(lower=MIN_FRAME_ORIGIN, upper=MAX_FRAME_ORIGIN, step_incr=1) self.sb_oo_x = gtk.SpinButton(adjustment=adjustment, climb_rate=1, digits=0) self.sb_oo_x.set_tooltip_text(ugettext('Offset for origin X')) box_origin_x = gtk.HBox(True, 12) box_origin_x.pack_start(lbl_oo_x, False, False) box_origin_x.pack_start(self.sb_oo_x, False, False) lbl_oo_y = gtk.Label('Origin Y:') adjustment = gtk.Adjustment(lower=MIN_FRAME_ORIGIN, upper=MAX_FRAME_ORIGIN, step_incr=1) self.sb_oo_y = gtk.SpinButton(adjustment=adjustment, climb_rate=1, digits=0) self.sb_oo_y.set_tooltip_text(ugettext('Offset for origin Y')) box_origin_y = gtk.HBox(True, 12) box_origin_y.pack_start(lbl_oo_y, False, False) box_origin_y.pack_start(self.sb_oo_y, False, False) def btn_oo_clicked(btn): offset_x = self.sb_oo_x.get_value_as_int() offset_y = self.sb_oo_y.get_value_as_int() for ls in self.liststore: ls[LS_ORIGIN_X] += offset_x ls[LS_ORIGIN_Y] += offset_y btn_oo = gtk.Button('Add offsets') btn_oo.connect('clicked', btn_oo_clicked) box = gtk.VBox(True, 5) box.pack_start(box_origin_x, False, False) box.pack_start(box_origin_y, False, False) box.pack_start(btn_oo, False, False) oo_frame = gimpui.Frame('Add origin offsets:') oo_frame.set_shadow_type(gtk.SHADOW_IN) oo_frame.add(box) # Main option frame o_box = gtk.VBox() o_box.set_size_request(110, -1) o_box.pack_start(st_frame, False, False, 10) o_box.pack_start(tf_frame, False, False, 10) o_box.pack_start(oo_frame, False, False, 10) box = gtk.VBox() box.set_size_request(140, -1) box.pack_start(o_box, True, False) return box def make_frames_view(self, layers): import gobject texture_format = self.cb_tf.get_active() self.liststore = gtk.ListStore(gobject.TYPE_PYOBJECT, gtk.gdk.Pixbuf, str, gobject.TYPE_BOOLEAN, gobject.TYPE_INT, gobject.TYPE_INT, gobject.TYPE_PYOBJECT) for l in layers: frames = [gl for gl in reversed(l.layers) ] if pdb.gimp_item_is_group(l) else [l] for f in frames: thumbnail_data = make_thumbnail_data(f) pixbuf = get_thumbnail(thumbnail_data, texture_format) size_info = '<b>Size</b>: %d x %d' % (f.width, f.height) parasite_origins = f.parasite_find('spr_origins') if parasite_origins: origin_x, origin_y = unpack('<2i', parasite_origins.data[:8]) else: origin_x, origin_y = -f.width // 2, f.height // 2 self.liststore.append([ f, pixbuf, size_info, True, origin_x, origin_y, thumbnail_data ]) self.export_frames_num = len(self.liststore) self.iconview = gtk.TreeView(self.liststore) self.iconview.set_reorderable(True) self.iconview.set_enable_search(False) self.iconview.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_BOTH) # Column 'Export' def on_cb_export_toggled(widget, path): export = not self.liststore[path][LS_EXPORT] self.liststore[path][LS_EXPORT] = export self.export_frames_num += 1 if export else -1 self.set_btn_export_sensitive(self.export_frames_num > 0) self.img_view_frame.set_label('Frames to export: %d' % self.export_frames_num) cb_export = gtk.CellRendererToggle() cb_export.connect('toggled', on_cb_export_toggled) col_export = gtk.TreeViewColumn('Export', cb_export, active=LS_EXPORT) col_export_header = gtk.Label('Export') col_export_header.show() tt_export = gtk.Tooltips() tt_export.set_tip(col_export_header, 'Export frame to file.') col_export.set_sort_order(gtk.SORT_DESCENDING) col_export.set_sort_column_id(4) col_export.set_widget(col_export_header) self.iconview.append_column(col_export) # Column 'Frame' pixrend = gtk.CellRendererPixbuf() col_pixbuf = gtk.TreeViewColumn('Frame', pixrend, pixbuf=LS_PIXBUF) col_pixbuf.set_min_width(THUMB_MAXSIZE) self.iconview.append_column(col_pixbuf) # Column 'Settings' col_info = gtk.TreeViewColumn() col_info_header = gtk.Label('Settings') col_info_header.show() col_info.set_widget(col_info_header) tt_info = gtk.Tooltips() tt_info.set_tip(col_info_header, 'Frame export options.') # Info text renderer = gtk.CellRendererText() renderer.set_property('yalign', 0.3) renderer.set_property('xalign', 0.0) renderer.set_property('width', 0) renderer.set_property('height', THUMB_MAXSIZE) col_info.pack_start(renderer, False) col_info.set_attributes(renderer, markup=LS_SIZE_INFO) # Label origin X adjustment = gtk.Adjustment(lower=MIN_FRAME_ORIGIN, upper=MAX_FRAME_ORIGIN, step_incr=1) renderer = gtk.CellRendererText() renderer.set_property('markup', '<b>Origin X</b>:') renderer.set_property('width', 64) col_info.pack_start(renderer, False) # crs origin x adjustment = gtk.Adjustment(lower=MIN_FRAME_ORIGIN, upper=MAX_FRAME_ORIGIN, step_incr=1) renderer = gtk.CellRendererSpin() renderer.set_property('editable', True) renderer.set_property('adjustment', adjustment) def on_crs_origin_x_changed(widget, path, val): val = min(max(int(val), MIN_FRAME_ORIGIN), MAX_FRAME_ORIGIN) self.liststore[path][LS_ORIGIN_X] = val renderer.connect('edited', on_crs_origin_x_changed) col_info.pack_start(renderer) col_info.set_attributes(renderer, markup=LS_ORIGIN_X) # Label origin y renderer = gtk.CellRendererText() renderer.set_property('markup', '<b>Origin Y</b>:') renderer.set_property('width', 64) col_info.pack_start(renderer, False) # crs origin y renderer = gtk.CellRendererSpin() renderer.set_property('editable', True) renderer.set_property('adjustment', adjustment) def on_crs_origin_x_changed(widget, path, val): val = min(max(int(val), MIN_FRAME_ORIGIN), MAX_FRAME_ORIGIN) self.liststore[path][LS_ORIGIN_Y] = val renderer.connect('edited', on_crs_origin_x_changed) col_info.pack_start(renderer) col_info.set_attributes(renderer, markup=LS_ORIGIN_Y) self.iconview.append_column(col_info) scrl_win = gtk.ScrolledWindow() scrl_win.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) scrl_win.add(self.iconview) scrl_win.set_size_request(THUMB_MAXSIZE, THUMB_MAXSIZE * 4) frame_imgs = gimpui.Frame('Frames to export: %d' % self.export_frames_num) frame_imgs.set_property('label-xalign', 0.05) frame_imgs.set_shadow_type(gtk.SHADOW_IN) frame_imgs.add(scrl_win) frame_imgs.set_size_request(535, -1) return frame_imgs def export_selected_frames(self): layers = [] for row in self.liststore: if not row[LS_EXPORT]: continue layer = row[LS_LAYER] origins_data = pack('<2i', row[LS_ORIGIN_X], row[LS_ORIGIN_Y]) if layer.parasite_find('spr_origins'): layer.parasite_detach('spr_origins') layer.attach_new_parasite('spr_origins', 0, origins_data) layers.append(layer) # Make grouped layers with parasites grouped_layers, added_layers = [], [] for layer in layers: if layer in added_layers: continue added_layers.append(layer) parent = layer.parent if not parent: grouped_layers.append([layer]) continue if not parent.parasite_find('spr_type'): parent.attach_new_parasite('spr_type', 1, '') group_lst = [ll for ll in layers if ll.parent == parent] for i, ll in enumerate(group_lst): interval = ll.parasite_find('spr_interval') if not interval: ll.attach_new_parasite('spr_interval', 0, pack('<f', (i + 1) * 0.1)) added_layers.append(ll) grouped_layers.append([parent] + group_lst) # Export to file if grouped_layers: Sprite.save_to_file(spr_img, filename, grouped_layers, self.cb_st.get_active(), self.cb_tf.get_active()) def set_btn_export_sensitive(self, sensitive): self.get_widget_for_response(RESPONSE_EXPORT).set_sensitive( sensitive) def on_response(self, dialog, response_id): self.destroy() while gtk.events_pending(): gtk.main_iteration() if response_id == RESPONSE_EXPORT: self.export_selected_frames() def on_destroy(self, widget): gtk.main_quit() def run(self): self.show() gtk.main() ExportDialog().run() pdb.gimp_image_delete(spr_img)