home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2006 November (DVD) / PCWELT_11_2006.ISO / casper / filesystem.squashfs / usr / lib / gimp / 2.0 / python / gimpfu.pyc (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2006-08-31  |  19.6 KB  |  598 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.4)
  3.  
  4. '''Simple interface to writing GIMP plugins in python.
  5.  
  6. Instead of worrying about all the user interaction, saving last used values
  7. and everything, the gimpfu module can take care of it for you.  It provides
  8. a simple register() function that will register your plugin if needed, and
  9. cause your plugin function to be called when needed.
  10.  
  11. Gimpfu will also handle showing a user interface for editing plugin parameters
  12. if the plugin is called interactively, and will also save the last used
  13. parameters, so the RUN_WITH_LAST_VALUES run_type will work correctly.  It
  14. will also make sure that the displays are flushed on completion if the plugin
  15. was run interactively.
  16.  
  17. When registering the plugin, you do not need to worry about specifying
  18. the run_type parameter.  And if the plugin is an image plugin (the menu
  19. path starts with <Image>/), the image and drawable parameters are also
  20. automatically added.
  21.  
  22. A typical gimpfu plugin would look like this:
  23.   from gimpfu import *
  24.  
  25.   def plugin_func(image, drawable, args):
  26.               #do what plugins do best
  27.   register(
  28.               "plugin_func",
  29.               "blurb",
  30.               "help message",
  31.               "author",
  32.               "copyright",
  33.               "year",
  34.               "<Image>/Somewhere/My plugin",
  35.               "*",
  36.               [(PF_STRING, "arg", "The argument", "default-value")],
  37.               [],
  38.               plugin_func)
  39.   main()
  40.  
  41. The call to "from gimpfu import *" will import all the gimp constants into
  42. the plugin namespace, and also import the symbols gimp, pdb, register and
  43. main.  This should be just about all any plugin needs.  You can use any
  44. of the PF_* constants below as parameter types, and an appropriate user
  45. interface element will be displayed when the plugin is run in interactive
  46. mode.  Note that the the PF_SPINNER and PF_SLIDER types expect a fifth
  47. element in their description tuple -- a 3-tuple of the form (lower,upper,step),
  48. which defines the limits for the slider or spinner.'''
  49. import string as _string
  50. import gimp
  51. from gimpenums import *
  52. pdb = gimp.pdb
  53.  
  54. class error(RuntimeError):
  55.     pass
  56.  
  57.  
  58. class CancelError(RuntimeError):
  59.     pass
  60.  
  61. PF_INT8 = PDB_INT8
  62. PF_INT16 = PDB_INT16
  63. PF_INT32 = PDB_INT32
  64. PF_INT = PF_INT32
  65. PF_FLOAT = PDB_FLOAT
  66. PF_STRING = PDB_STRING
  67. PF_VALUE = PF_STRING
  68. PF_COLOR = PDB_COLOR
  69. PF_COLOUR = PF_COLOR
  70. PF_REGION = PDB_REGION
  71. PF_IMAGE = PDB_IMAGE
  72. PF_LAYER = PDB_LAYER
  73. PF_CHANNEL = PDB_CHANNEL
  74. PF_DRAWABLE = PDB_DRAWABLE
  75. PF_TOGGLE = 1000
  76. PF_BOOL = PF_TOGGLE
  77. PF_SLIDER = 1001
  78. PF_SPINNER = 1002
  79. PF_ADJUSTMENT = PF_SPINNER
  80. PF_FONT = 1003
  81. PF_FILE = 1004
  82. PF_BRUSH = 1005
  83. PF_PATTERN = 1006
  84. PF_GRADIENT = 1007
  85. PF_RADIO = 1008
  86. PF_TEXT = 1009
  87. PF_PALETTE = 1010
  88. _type_mapping = {
  89.     PF_INT8: PDB_INT8,
  90.     PF_INT16: PDB_INT16,
  91.     PF_INT32: PDB_INT32,
  92.     PF_FLOAT: PDB_FLOAT,
  93.     PF_STRING: PDB_STRING,
  94.     PF_COLOUR: PDB_COLOR,
  95.     PF_REGION: PDB_REGION,
  96.     PF_IMAGE: PDB_IMAGE,
  97.     PF_LAYER: PDB_LAYER,
  98.     PF_CHANNEL: PDB_CHANNEL,
  99.     PF_DRAWABLE: PDB_DRAWABLE,
  100.     PF_TOGGLE: PDB_INT32,
  101.     PF_SLIDER: PDB_FLOAT,
  102.     PF_SPINNER: PDB_INT32,
  103.     PF_FONT: PDB_STRING,
  104.     PF_FILE: PDB_STRING,
  105.     PF_BRUSH: PDB_STRING,
  106.     PF_PATTERN: PDB_STRING,
  107.     PF_GRADIENT: PDB_STRING,
  108.     PF_RADIO: PDB_STRING,
  109.     PF_TEXT: PDB_STRING,
  110.     PF_PALETTE: PDB_STRING }
  111. _registered_plugins_ = { }
  112.  
  113. def register(func_name, blurb, help, author, copyright, date, menupath, imagetypes, params, results, function, on_query = None, on_run = None):
  114.     '''This is called to register a new plugin.'''
  115.     
  116.     def letterCheck(str):
  117.         allowed = _string.letters + _string.digits + '_'
  118.         for ch in str:
  119.             if ch not in allowed:
  120.                 return 0
  121.                 continue
  122.         else:
  123.             return 1
  124.  
  125.     if not letterCheck(func_name):
  126.         raise error, 'function name contains illegal characters'
  127.     
  128.     for ent in params:
  129.         if len(ent) < 4:
  130.             raise error, 'parameter definition must contain at least 4 elements (%s given: %s)' % (len(ent), ent)
  131.         
  132.         if type(ent[0]) != type(42):
  133.             raise error, 'parameter types must be integers'
  134.         
  135.         if not letterCheck(ent[1]):
  136.             raise error, 'parameter name contains illegal characters'
  137.             continue
  138.     
  139.     for ent in results:
  140.         if len(ent) < 3:
  141.             raise error, 'result definition must contain at least 3 elements (%s given: %s)' % (len(ent), ent)
  142.         
  143.         if type(ent[0]) != type(42):
  144.             raise error, 'result types must be integers'
  145.         
  146.         if not letterCheck(ent[1]):
  147.             raise error, 'result name contains illegal characters'
  148.             continue
  149.     
  150.     if menupath[:8] == '<Image>/' and menupath[:7] == '<Load>/' and menupath[:7] == '<Save>/' or menupath[:10] == '<Toolbox>/':
  151.         plugin_type = PLUGIN
  152.     else:
  153.         raise error, 'Invalid menu path'
  154.     if not (func_name[:7] == 'python_') and not (func_name[:10] == 'extension_') and not (func_name[:8] == 'plug_in_') and not (func_name[:5] == 'file_'):
  155.         func_name = 'python_fu_' + func_name
  156.     
  157.     _registered_plugins_[func_name] = (blurb, help, author, copyright, date, menupath, imagetypes, plugin_type, params, results, function, on_query, on_run)
  158.  
  159. file_params = [
  160.     (PDB_STRING, 'filename', 'The name of the file'),
  161.     (PDB_STRING, 'raw_filename', 'The name of the file')]
  162.  
  163. def _query():
  164.     for plugin in _registered_plugins_.keys():
  165.         (blurb, help, author, copyright, date, menupath, imagetypes, plugin_type, params, results, function, on_query, on_run) = _registered_plugins_[plugin]
  166.         
  167.         fn = lambda x: (_type_mapping[x[0]], x[1], x[2])
  168.         params = map(fn, params)
  169.         params.insert(0, (PDB_INT32, 'run_mode', 'Interactive, Non-Interactive'))
  170.         if plugin_type == PLUGIN:
  171.             if menupath[:7] == '<Load>/':
  172.                 params[1:1] = file_params
  173.             elif menupath[:10] != '<Toolbox>/':
  174.                 params.insert(1, (PDB_IMAGE, 'image', 'The image to work on'))
  175.                 params.insert(2, (PDB_DRAWABLE, 'drawable', 'The drawable to work on'))
  176.                 if menupath[:7] == '<Save>/':
  177.                     params[3:3] = file_params
  178.                 
  179.             
  180.         
  181.         results = map(fn, results)
  182.         gimp.install_procedure(plugin, blurb, help, author, copyright, date, menupath, imagetypes, plugin_type, params, results)
  183.         if on_query:
  184.             on_query()
  185.             continue
  186.     
  187.  
  188.  
  189. def _get_defaults(func_name):
  190.     import gimpshelf
  191.     (blurb, help, author, copyright, date, menupath, imagetypes, plugin_type, params, results, function, on_query, on_run) = _registered_plugins_[func_name]
  192.     key = 'python-fu-save--' + func_name
  193.     if gimpshelf.shelf.has_key(key):
  194.         return gimpshelf.shelf[key]
  195.     else:
  196.         return map((lambda x: x[3]), params)
  197.  
  198.  
  199. def _set_defaults(func_name, defaults):
  200.     import gimpshelf
  201.     key = 'python-fu-save--' + func_name
  202.     gimpshelf.shelf[key] = defaults
  203.  
  204.  
  205. def _interact(func_name, start_params):
  206.     (blurb, help, author, copyright, date, menupath, imagetypes, plugin_type, params, results, function, on_query, on_run) = _registered_plugins_[func_name]
  207.     
  208.     def run_script(run_params):
  209.         params = start_params + tuple(run_params)
  210.         return apply(function, params)
  211.  
  212.     if len(params) == 0:
  213.         return run_script([])
  214.     
  215.     import pygtk
  216.     pygtk.require('2.0')
  217.     import gtk
  218.     import gimpui
  219.     gtk.rc_parse(gimp.gtkrc())
  220.     defaults = _get_defaults(func_name)
  221.     
  222.     class EntryValueError(Exception):
  223.         pass
  224.  
  225.     
  226.     def error_dialog(parent, msg):
  227.         dlg = gtk.MessageDialog(parent, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_WARNING, gtk.BUTTONS_CLOSE, msg)
  228.         dlg.run()
  229.         dlg.destroy()
  230.  
  231.     
  232.     class StringEntry(gtk.Entry):
  233.         
  234.         def __init__(self, default = ''):
  235.             gtk.Entry.__init__(self)
  236.             self.set_text(str(default))
  237.  
  238.         
  239.         def get_value(self):
  240.             return self.get_text()
  241.  
  242.  
  243.     
  244.     class TextEntry(gtk.ScrolledWindow):
  245.         
  246.         def __init__(self, default = ''):
  247.             gtk.ScrolledWindow.__init__(self)
  248.             self.set_shadow_type(gtk.SHADOW_IN)
  249.             self.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
  250.             self.set_size_request(100, -1)
  251.             self.view = gtk.TextView()
  252.             self.add(self.view)
  253.             self.view.show()
  254.             self.buffer = self.view.get_buffer()
  255.             self.set_value(str(default))
  256.  
  257.         
  258.         def set_value(self, text):
  259.             self.buffer.set_text(text)
  260.  
  261.         
  262.         def get_value(self):
  263.             return self.buffer.get_text(self.buffer.get_start_iter(), self.buffer.get_end_iter())
  264.  
  265.  
  266.     
  267.     class IntEntry(StringEntry):
  268.         
  269.         def get_value(self):
  270.             
  271.             try:
  272.                 return int(self.get_text())
  273.             except ValueError:
  274.                 e = None
  275.                 raise EntryValueError, e.args
  276.  
  277.  
  278.  
  279.     
  280.     class FloatEntry(StringEntry):
  281.         
  282.         def get_value(self):
  283.             
  284.             try:
  285.                 return float(self.get_text())
  286.             except ValueError:
  287.                 e = None
  288.                 raise EntryValueError, e.args
  289.  
  290.  
  291.  
  292.     
  293.     class SliderEntry(gtk.HScale):
  294.         
  295.         def __init__(self, default = 0, bounds = (0, 100, 5)):
  296.             self.adj = gtk.Adjustment(default, bounds[0], bounds[1], bounds[2], bounds[2], 0)
  297.             gtk.HScale.__init__(self, self.adj)
  298.  
  299.         
  300.         def get_value(self):
  301.             return self.adj.value
  302.  
  303.  
  304.     
  305.     class SpinnerEntry(gtk.SpinButton):
  306.         
  307.         def __init__(self, default = 0, bounds = (0, 100, 5)):
  308.             self.adj = gtk.Adjustment(default, bounds[0], bounds[1], bounds[2], bounds[2], 0)
  309.             gtk.SpinButton.__init__(self, self.adj, 1, 0)
  310.  
  311.         
  312.         def get_value(self):
  313.             
  314.             try:
  315.                 return int(self.get_text())
  316.             except ValueError:
  317.                 e = None
  318.                 raise EntryValueError, e.args
  319.  
  320.  
  321.  
  322.     
  323.     class ToggleEntry(gtk.ToggleButton):
  324.         
  325.         def __init__(self, default = 0):
  326.             gtk.ToggleButton.__init__(self)
  327.             self.label = gtk.Label('No')
  328.             self.add(self.label)
  329.             self.label.show()
  330.             self.connect('toggled', self.changed)
  331.             self.set_active(default)
  332.  
  333.         
  334.         def changed(self, tog):
  335.             if tog.get_active():
  336.                 self.label.set_text('Yes')
  337.             else:
  338.                 self.label.set_text('No')
  339.  
  340.         
  341.         def get_value(self):
  342.             return self.get_active()
  343.  
  344.  
  345.     
  346.     class RadioEntry(gtk.Frame):
  347.         
  348.         def __init__(self, default = 0, items = (('Yes', 1), ('No', 0))):
  349.             gtk.Frame.__init__(self)
  350.             box = gtk.VBox(gtk.FALSE, 5)
  351.             self.add(box)
  352.             box.show()
  353.             button = None
  354.             for label, value in items:
  355.                 button = gtk.RadioButton(button, label)
  356.                 button.connect('toggled', self.changed, value)
  357.                 box.pack_start(button)
  358.                 button.show()
  359.                 if value == default:
  360.                     button.set_active(gtk.TRUE)
  361.                     self.active_value = value
  362.                     continue
  363.             
  364.  
  365.         
  366.         def changed(self, radio, value):
  367.             if radio.get_active():
  368.                 self.active_value = value
  369.             
  370.  
  371.         
  372.         def get_value(self):
  373.             return self.active_value
  374.  
  375.  
  376.     _edit_mapping = {
  377.         PF_INT8: IntEntry,
  378.         PF_INT16: IntEntry,
  379.         PF_INT32: IntEntry,
  380.         PF_FLOAT: FloatEntry,
  381.         PF_STRING: StringEntry,
  382.         PF_COLOUR: gimpui.ColourSelector,
  383.         PF_REGION: IntEntry,
  384.         PF_IMAGE: gimpui.ImageSelector,
  385.         PF_LAYER: gimpui.LayerSelector,
  386.         PF_CHANNEL: gimpui.ChannelSelector,
  387.         PF_DRAWABLE: gimpui.DrawableSelector,
  388.         PF_TOGGLE: ToggleEntry,
  389.         PF_SLIDER: SliderEntry,
  390.         PF_SPINNER: SpinnerEntry,
  391.         PF_RADIO: RadioEntry,
  392.         PF_FONT: gimpui.FontSelector,
  393.         PF_FILE: gimpui.FileSelector,
  394.         PF_BRUSH: gimpui.BrushSelector,
  395.         PF_PATTERN: gimpui.PatternSelector,
  396.         PF_GRADIENT: gimpui.GradientSelector,
  397.         PF_PALETTE: gimpui.PaletteSelector,
  398.         PF_TEXT: TextEntry }
  399.     if on_run:
  400.         on_run()
  401.     
  402.     need_progress = menupath[:8] != '<Image>/'
  403.     tooltips = gtk.Tooltips()
  404.     dialog = gtk.Dialog(func_name, None, 0, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK, gtk.RESPONSE_OK))
  405.     hbox = gtk.HBox(gtk.FALSE, 5)
  406.     hbox.set_border_width(5)
  407.     dialog.vbox.pack_start(hbox, expand = gtk.FALSE)
  408.     hbox.show()
  409.     table = gtk.Table(len(params), 2, gtk.FALSE)
  410.     table.set_border_width(5)
  411.     table.set_row_spacings(4)
  412.     table.set_col_spacings(10)
  413.     hbox.pack_end(table, expand = gtk.FALSE)
  414.     table.show()
  415.     vbox = gtk.VBox(gtk.FALSE, 10)
  416.     hbox.pack_start(vbox, expand = gtk.FALSE)
  417.     vbox.show()
  418.     pix = _get_logo()
  419.     if pix:
  420.         vbox.pack_start(pix, expand = gtk.FALSE)
  421.         pix.show()
  422.     
  423.     label = gtk.Label(blurb)
  424.     label.set_line_wrap(gtk.TRUE)
  425.     label.set_justify(gtk.JUSTIFY_LEFT)
  426.     label.set_size_request(100, -1)
  427.     vbox.pack_start(label, expand = gtk.FALSE)
  428.     label.show()
  429.     progress_callback = None
  430.     
  431.     def response(dlg, id):
  432.         if id == gtk.RESPONSE_OK:
  433.             params = []
  434.             
  435.             try:
  436.                 for wid in edit_wids:
  437.                     params.append(wid.get_value())
  438.             except EntryValueError:
  439.                 error_dialog(dialog, 'Invalid input for "%s"' % wid.desc)
  440.  
  441.             _set_defaults(func_name, params)
  442.             dialog.res = run_script(params)
  443.         
  444.         if progress_callback:
  445.             gimp.progress_uninstall(progress_callback)
  446.         
  447.         gtk.main_quit()
  448.  
  449.     dialog.connect('response', response)
  450.     edit_wids = []
  451.     for i in range(len(params)):
  452.         pf_type = params[i][0]
  453.         name = params[i][1]
  454.         desc = params[i][2]
  455.         def_val = defaults[i]
  456.         label = gtk.Label(desc)
  457.         label.set_alignment(1.0, 0.5)
  458.         table.attach(label, 1, 2, i, i + 1, xoptions = gtk.FILL)
  459.         label.show()
  460.         if pf_type in (PF_SPINNER, PF_SLIDER, PF_RADIO):
  461.             wid = _edit_mapping[pf_type](def_val, params[i][4])
  462.         else:
  463.             wid = _edit_mapping[pf_type](def_val)
  464.         table.attach(wid, 2, 3, i, i + 1, yoptions = 0)
  465.         if pf_type != PF_TEXT:
  466.             tooltips.set_tip(wid, desc, None)
  467.         else:
  468.             tooltips.set_tip(wid.view, desc, None)
  469.         wid.show()
  470.         wid.desc = desc
  471.         edit_wids.append(wid)
  472.     
  473.     if need_progress:
  474.         frame = gtk.Frame('Script Progress')
  475.         frame.set_border_width(5)
  476.         dialog.vbox.pack_start(frame)
  477.         frame.show()
  478.         vbox = gtk.VBox(gtk.FALSE, 5)
  479.         vbox.set_border_width(5)
  480.         frame.add(vbox)
  481.         vbox.show()
  482.         progress_label = gtk.Label('(none)')
  483.         progress_label.set_alignment(0.0, 0.5)
  484.         vbox.pack_start(progress_label)
  485.         progress_label.show()
  486.         progress = gtk.ProgressBar()
  487.         progress.set_text(' ')
  488.         vbox.pack_start(progress)
  489.         progress.show()
  490.         
  491.         def progress_update(message = -1, fraction = None):
  492.             if message == -1:
  493.                 pass
  494.             elif message:
  495.                 progress.set_text(message)
  496.             else:
  497.                 progress.set_text(' ')
  498.             if fraction is not None:
  499.                 progress.set_fraction(fraction)
  500.             
  501.             while gtk.events_pending():
  502.                 gtk.main_iteration()
  503.  
  504.         
  505.         def progress_start(message, cancelable):
  506.             progress_update(message, 0.0)
  507.  
  508.         
  509.         def progress_end():
  510.             progress_update(None, 0.0)
  511.  
  512.         
  513.         def progress_text(message):
  514.             progress_update(message)
  515.  
  516.         
  517.         def progress_value(percentage):
  518.             progress_update(fraction = percentage)
  519.  
  520.         progress_callback = gimp.progress_install(progress_start, progress_end, progress_text, progress_value)
  521.     
  522.     tooltips.enable()
  523.     dialog.show()
  524.     gtk.main()
  525.     if hasattr(dialog, 'res'):
  526.         res = dialog.res
  527.         dialog.destroy()
  528.         return res
  529.     else:
  530.         dialog.destroy()
  531.         raise CancelError
  532.  
  533.  
  534. def _run(func_name, params):
  535.     run_mode = params[0]
  536.     plugin_type = _registered_plugins_[func_name][7]
  537.     menupath = _registered_plugins_[func_name][5]
  538.     func = _registered_plugins_[func_name][10]
  539.     if plugin_type == PLUGIN and menupath[:10] != '<Toolbox>/':
  540.         if menupath[:7] == '<Save>/':
  541.             end = 5
  542.         else:
  543.             end = 3
  544.         start_params = params[1:end]
  545.         extra_params = params[end:]
  546.     else:
  547.         start_params = ()
  548.         extra_params = params[1:]
  549.     if run_mode == RUN_INTERACTIVE:
  550.         
  551.         try:
  552.             res = _interact(func_name, start_params)
  553.         except CancelError:
  554.             return None
  555.         except:
  556.             None<EXCEPTION MATCH>CancelError
  557.         
  558.  
  559.     None<EXCEPTION MATCH>CancelError
  560.     if run_mode == RUN_WITH_LAST_VALS:
  561.         extra_params = _get_defaults(func_name)
  562.     
  563.     params = start_params + tuple(extra_params)
  564.     res = apply(func, params)
  565.     if run_mode != RUN_NONINTERACTIVE:
  566.         gimp.displays_flush()
  567.     
  568.     return res
  569.  
  570.  
  571. def main():
  572.     '''This should be called after registering the plugin.'''
  573.     gimp.main(None, None, _query, _run)
  574.  
  575.  
  576. def fail(msg):
  577.     '''Display and error message and quit'''
  578.     gimp.message(msg)
  579.     raise error, msg
  580.  
  581.  
  582. def _get_logo():
  583.     import gtk
  584.     import gobject
  585.     import os.path as os
  586.     logofile = os.path.join(os.path.dirname(__file__), 'pygimp-logo.png')
  587.     
  588.     try:
  589.         pixbuf = gtk.gdk.pixbuf_new_from_file(logofile)
  590.     except gobject.GError:
  591.         e = None
  592.         return None
  593.  
  594.     image = gtk.Image()
  595.     image.set_from_pixbuf(pixbuf)
  596.     return image
  597.  
  598.