"Fossies" - the Fresh Open Source Software Archive

Member "btn4ws-0.7.0/btn4ws.py" (5 Jan 2008, 46656 Bytes) of package /linux/privat/old/btn4ws-0.7.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "btn4ws.py" see the Fossies "Dox" file reference documentation.

    1 #!/usr/bin/env python
    2 # -*- coding: utf-8 -*-
    3 # This is the main file of btn4ws.
    4 #
    5 # Copyright (c) 1999-2008 Jan Dittberner <jan@dittberner.info>
    6 #
    7 # This file is part of btn4ws.
    8 #
    9 # btn4ws is free software; you can redistribute it and/or modify
   10 # it under the terms of the GNU General Public License as published by
   11 # the Free Software Foundation; either version 2 of the License, or
   12 # (at your option) any later version.
   13 #
   14 # btn4ws is distributed in the hope that it will be useful,
   15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
   16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   17 # GNU General Public License for more details.
   18 #
   19 # You should have received a copy of the GNU General Public License
   20 # along with btn4ws; if not, write to the Free Software
   21 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
   22 #
   23 # version: $Id: btn4ws.py 14 2008-01-05 22:19:03Z jan $
   24 #
   25 
   26 """
   27 Gimp script to generate button images for websites. This script is a
   28 port of the older gimp-perl version to python.
   29 
   30 (c) 2007, 2008 Jan Dittberner <jan@dittberner.info>
   31 """
   32 import os, urllib, logging, sys, pickle
   33 import gimp, gimpplugin, gimpui, gimpcolor
   34 import pygtk
   35 pygtk.require('2.0')
   36 import gtk
   37 from gimpenums import *
   38 from gimpshelf import shelf
   39 pdb = gimp.pdb
   40 
   41 btn4ws_version = "0.7.0"
   42 
   43 logging.basicConfig(level=logging.DEBUG,
   44                     format='%(asctime)s %(levelname)s %(message)s',
   45                     stream=sys.stderr)
   46 
   47 class text_to_name_mapper:
   48     """
   49     Text string to name mapper class. This class provides mappings for several target
   50     environments.
   51     """
   52     def __init__(self, strings):
   53         self.mapping = {}
   54         for string in strings: self.mapping[string] = {}
   55         self.idnum = 1
   56         logging.debug("self.mapping=" + str(self.mapping))
   57     
   58     def asitemid(self, text):
   59         """
   60         Get a img itemid for the given text.
   61         """
   62         if 'itemid' not in self.mapping[text]:
   63             self.mapping[text]['itemid'] = "id%03d" % (self.idnum)
   64             self.idnum += 1
   65         #logging.debug("self.mapping=" + str(self.mapping))
   66         return self.mapping[text]['itemid']
   67 
   68     def asjavascriptid(self, text):
   69         """
   70         Get a javascript itemid for the given text.
   71         """
   72         if 'jsid' not in self.mapping[text]:
   73             self.mapping[text]['jsid'] = "img%03d" % (self.idnum)
   74             self.idnum += 1
   75         #logging.debug("self.mapping=" + str(self.mapping))
   76         return self.mapping[text]['jsid']
   77 
   78     def aslinktarget(self, text):
   79         """
   80         Get a link target for the given text.
   81         """
   82         if 'link' not in self.mapping[text]:
   83             self.mapping[text]['link'] = urllib.quote(text)
   84         #logging.debug("self.mapping=" + str(self.mapping))
   85         return "%s.html" % (self.mapping[text]['link'])
   86 
   87     def asfilename(self, text, extension = 'png', prefix= '', dirname = None):
   88         """
   89         Get a filename for the given text with optional extension, prefix and dirname.
   90         """
   91         if 'file' not in self.mapping[text]:
   92             self.mapping[text]['file'] = text.encode('ascii', 'ignore')
   93         fname = "%s%s.%s" % (prefix, self.mapping[text]['file'], extension)
   94         #logging.debug("self.mapping=" + str(self.mapping))
   95         if dirname:
   96             return os.path.join(dirname, fname)
   97         return fname
   98 
   99 class text_to_name_mapper:
  100     """
  101     Text string to name mapper class. This class provides mappings for
  102     several target environments.
  103     """
  104     def __init__(self, strings):
  105         self.mapping = {}
  106         for string in strings: self.mapping[string] = {}
  107         self.idnum = 1
  108         logging.debug("self.mapping=" + str(self.mapping))
  109     
  110     def asitemid(self, text):
  111         """
  112         Get a img itemid for the given text.
  113         """
  114         if 'itemid' not in self.mapping[text]:
  115             self.mapping[text]['itemid'] = "id%03d" % (self.idnum)
  116             self.idnum += 1
  117         logging.debug("self.mapping=" + str(self.mapping))
  118         return self.mapping[text]['itemid']
  119 
  120     def asjavascriptid(self, text):
  121         """
  122         Get a javascript itemid for the given text.
  123         """
  124         if 'jsid' not in self.mapping[text]:
  125             self.mapping[text]['jsid'] = "img%03d" % (self.idnum)
  126             self.idnum += 1
  127         logging.debug("self.mapping=" + str(self.mapping))
  128         return self.mapping[text]['jsid']
  129 
  130     def aslinktarget(self, text):
  131         """
  132         Get a link target for the given text.
  133         """
  134         if 'link' not in self.mapping[text]:
  135             self.mapping[text]['link'] = urllib.quote(text)
  136         logging.debug("self.mapping=" + str(self.mapping))
  137         return "%s.html" % (self.mapping[text]['link'])
  138 
  139     def asfilename(self, text, extension = 'png', prefix= '', dirname = None):
  140         """
  141         Get a filename for the given text with optional extension,
  142         prefix and dirname.
  143         """
  144         if 'file' not in self.mapping[text]:
  145             self.mapping[text]['file'] = text.encode('ascii', 'ignore')
  146         fname = "%s%s.%s" % (prefix, self.mapping[text]['file'], extension)
  147         logging.debug("self.mapping=" + str(self.mapping))
  148         if dirname:
  149             return os.path.join(dirname, fname)
  150         return fname
  151 
  152 class IntEntry(gtk.Entry):
  153     """Input field for integer numbers."""
  154 
  155     def __init__(self, max = 0):
  156         gtk.Entry.__init__(self, max)
  157         self.set_property("truncate-multiline", True)
  158         self.connect("insert-text", self._cb_int_field_insert)
  159 
  160     def _cb_int_field_insert(self, w, new_text, new_text_length, position):
  161         """Allow integer input only."""
  162         if not new_text.isdigit():
  163             w.stop_emission("insert-text")
  164 
  165 class Btn4wsDialog(gtk.Assistant):
  166     """This class is the input dialog field for btn4ws"""
  167     def _cb_delete_event(self, widget, event, data = None):
  168         logging.debug("delete_event")
  169         return False
  170 
  171     def __init__(self, args):
  172         self.data = args
  173         self.pages = {}
  174         gtk.Assistant.__init__(self)
  175 
  176         self._addIntroPage()
  177         self._addPathSelectionPage()
  178         self._addBasicSettingsPage()
  179         self._addLayoutPage()
  180         self._addEffectsPage()
  181         self._addLastPage()
  182         self.show()
  183         self.connect("delete_event", self._cb_delete_event)
  184 
  185         for pagename in self.pages.iterkeys():
  186             self.checkcompletion(pagename)
  187 
  188     def _addIntroPage(self):
  189         label = gtk.Label("""Buttons for website allows you to produce a series of buttons for use on a website. On the next pages you may choose several options to change the content and the look of the buttons.""")
  190         label.set_line_wrap(True)
  191         label.show()
  192         self.append_page(label)
  193         self.set_page_title(label, "Introduction")
  194         self.set_page_complete(label, True)
  195 
  196     def _addPathSelectionPage(self):
  197         page = gtk.VBox(False, 5)
  198         self.pages["pathselection"] = page
  199         page.set_border_width(5)
  200         page.show()
  201         self.append_page(page)
  202         self.set_page_title(page,
  203                             "Select the input file and output directory")
  204         self.set_page_type(page, gtk.ASSISTANT_PAGE_CONTENT)
  205         
  206         label = gtk.Label("Please choose the file containing your button labels and the directory where the generated files should be put.")
  207         label.set_line_wrap(True)
  208         label.show()
  209         page.pack_start(label, True, True, 0)
  210 
  211         table = gtk.Table(rows=2, columns=2, homogeneous=False)
  212         table.show()
  213         label = gtk.Label("Button label file")
  214         label.show()
  215         table.attach(label, 0, 1, 0, 1)
  216         button = gtk.FileChooserButton("Choose file")
  217         button.set_action(gtk.FILE_CHOOSER_ACTION_OPEN)
  218         if self.data["filename"]:
  219             button.set_filename(self.data["filename"])
  220         button.connect("selection-changed", self._cb_file_selected)
  221         button.show()
  222         table.attach(button, 1, 2, 0, 1)
  223 
  224         label = gtk.Label("Output directory")
  225         label.show()    
  226         table.attach(label, 0, 1, 1, 2)
  227         button = gtk.FileChooserButton("Choose directory")
  228         button.set_action(gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER)
  229         if self.data["outdir"]:
  230             button.set_filename(self.data["outdir"])
  231         else:
  232             self.data["outdir"] = button.get_filename()
  233         button.connect("selection-changed", self._cb_dir_selected)
  234         button.show()
  235         table.attach(button, 1, 2, 1, 2)
  236         
  237         page.pack_end(table)
  238 
  239     def _addBasicSettingsPage(self):
  240         page = gtk.VBox(False, 5)
  241         self.pages["basicsettings"] = page
  242         page.set_border_width(5)
  243         page.show()
  244         self.append_page(page)
  245         self.set_page_title(page,
  246                            "Select the basic button settings")
  247         self.set_page_type(page, gtk.ASSISTANT_PAGE_CONTENT)
  248 
  249         label = gtk.Label("Please choose the basic layout settings of your buttons.")
  250         label.set_line_wrap(True)
  251         label.show()
  252         page.pack_start(label, True, True, 0)
  253 
  254         table = gtk.Table(rows=4, columns=2, homogeneous=False)
  255         table.show()
  256 
  257         # font
  258         label = gtk.Label("Button text font")
  259         label.show()
  260         table.attach(label, 0, 1, 0, 1)
  261         fontsel = gtk.FontButton()
  262         fontsel.set_show_size(True)
  263         if self.data["font"]:
  264             fontsel.set_font_name(self.data["font"])
  265         else:
  266             self.data["font"] = fontsel.get_font_name()
  267         fontsel.show()
  268         fontsel.connect("font-set", self._cb_set_font)
  269         table.attach(fontsel, 1, 2, 0, 1)
  270 
  271         # strcolor
  272         label = gtk.Label("Button text color")
  273         label.show()
  274         table.attach(label, 0, 1, 1, 2)
  275         colorsel = gimpui.ColorSelector()
  276         if self.data["strcolor"]:
  277             colorsel.set_color(self.data["strcolor"])
  278         else:
  279             self.data["strcolor"] = colorsel.get_color()
  280         colorsel.show()
  281         colorsel.connect("color-changed", self._cb_set_color, "strcolor",
  282                          "basicsettings")
  283         table.attach(colorsel, 1, 2, 1, 2)
  284 
  285         # background toggle
  286         bgtoggle = gtk.CheckButton("Use a pattern for button")
  287         bgtoggle.set_active(self.data["usepattern"])
  288         bgtoggle.show()
  289         table.attach(bgtoggle, 1, 2, 2, 3)
  290 
  291         # background color / pattern
  292         if self.data["usepattern"]:
  293             label = gtk.Label("Button pattern")
  294         else:
  295             label = gtk.Label("Button color")
  296         label.show()
  297         patternsel = gimpui.PatternSelectButton()
  298         if self.data["pattern"]:
  299             patternsel.set_pattern(self.data["pattern"])
  300         patternsel.connect("pattern-set", self._cb_set_pattern)
  301         colorsel = gimpui.ColorSelector()
  302         if self.data["buttoncolor"]:
  303             colorsel.set_color(self.data["buttoncolor"])
  304         else:
  305             self.data["buttoncolor"] = colorsel.get_color()
  306         colorsel.connect("color-changed", self._cb_set_color, "buttoncolor",
  307                          "basicsettings")
  308         bgtoggle.connect("toggled", self._cb_bgtoggle_toggle, label,
  309                          "Button pattern", patternsel,
  310                          "Button color", colorsel)
  311         if self.data["usepattern"]:
  312             patternsel.show()
  313         else:
  314             colorsel.show()
  315 
  316         table.attach(label, 0, 1, 3, 4)
  317         table.attach(patternsel, 1, 2, 3, 4)
  318         table.attach(colorsel, 1, 2, 3, 4)
  319 
  320         page.pack_end(table)
  321 
  322     def _addLayoutPage(self):
  323         page = gtk.VBox(False, 5)
  324         self.pages["layout"] = page
  325         page.set_border_width(5)
  326         page.show()
  327         self.append_page(page)
  328         self.set_page_title(page,
  329                            "Select the layout settings")
  330         self.set_page_type(page, gtk.ASSISTANT_PAGE_CONTENT)
  331 
  332         label = gtk.Label("Select the layout options for your buttons")
  333         label.set_line_wrap(True)
  334         label.show()
  335         page.pack_start(label, True, True, 0)
  336 
  337         table = gtk.Table(rows=5, columns=2, homogeneous=False)
  338         table.show()
  339 
  340         #roundradius
  341         label = gtk.Label("Round radius")
  342         label.show()
  343         entry = IntEntry(max = 2)
  344         if self.data["roundradius"]:
  345             entry.set_text(str(self.data["roundradius"]))
  346         entry.connect("changed", self._cb_set_intvalue, "roundradius",
  347                       "layout")
  348         entry.show()
  349         table.attach(label, 0, 1, 0, 1)
  350         table.attach(entry, 1, 2, 0, 1)
  351 
  352         #bevelwidth
  353         label = gtk.Label("Bevel width")
  354         label.show()
  355         entry = IntEntry(max = 2)
  356         entry.connect("changed", self._cb_set_intvalue, "bevelwidth",
  357                       "layout")
  358         entry.show()
  359         table.attach(label, 0, 1, 1, 2)
  360         table.attach(entry, 1, 2, 1, 2)
  361 
  362         #padding
  363         label = gtk.Label("Padding")
  364         label.show()
  365         entry = IntEntry(max = 2)
  366         entry.connect("changed", self._cb_set_intvalue, "padding",
  367                       "layout")
  368         entry.show()
  369         table.attach(label, 0, 1, 2, 3)
  370         table.attach(entry, 1, 2, 2, 3)
  371 
  372         #transparency
  373         transp = gtk.CheckButton("Transparent button background")
  374         transp.set_active(self.data["transparency"])
  375         transp.show()
  376         transp.connect("toggled", self._cb_toggle_simple, "transparency",
  377                        "layout")
  378         table.attach(transp, 1, 2, 3, 4)
  379 
  380         #bgcolor
  381         label = gtk.Label("Background color")
  382         label.show()
  383         colorsel = gimpui.ColorSelector()
  384         if self.data["bgcolor"]:
  385             colorsel.set_color(self.data["bgcolor"])
  386         else:
  387             self.data["bgcolor"] = colorsel.get_color()
  388         colorsel.connect("color-changed", self._cb_set_color, "bgcolor",
  389                          "layout")
  390         colorsel.show()
  391         table.attach(label, 0, 1, 4, 5)
  392         table.attach(colorsel, 1, 2, 4, 5)
  393 
  394         page.pack_end(table)
  395 
  396     def _addEffectsPage(self):
  397         page = gtk.VBox(False, 5)
  398         self.pages["effects"] = page
  399         page.set_border_width(5)
  400         page.show()
  401         self.append_page(page)
  402         self.set_page_title(page,
  403                            "Select the effect settings")
  404         self.set_page_type(page, gtk.ASSISTANT_PAGE_CONTENT)
  405 
  406         table = gtk.Table(rows=7, columns=2, homogeneous=False)
  407         table.show()
  408 
  409         #nova
  410         novatoggle = gtk.CheckButton("Enable nova effect")
  411         novatoggle.set_active(self.data["nova"])
  412         novatoggle.show()
  413         table.attach(novatoggle, 1, 2, 0, 1)
  414 
  415         #novacolor
  416         label = gtk.Label("Nova color")
  417         label.show()
  418         novacolor = gimpui.ColorSelector()
  419         if self.data["novacolor"]:
  420             novacolor.set_color(self.data["novacolor"])
  421         else:
  422             self.data["novacolor"] = novacolor.get_color()
  423         novacolor.connect("color-changed", self._cb_set_color, "novacolor",
  424                           "effects")
  425         novacolor.set_sensitive(self.data["nova"])
  426         novacolor.show()
  427         table.attach(label, 0, 1, 1, 2)
  428         table.attach(novacolor, 1, 2, 1, 2)
  429         
  430         #novaradius
  431         label = gtk.Label("Nova radius")
  432         label.show()
  433         novaradius = IntEntry(max = 2)
  434         if self.data["novaradius"] is not None:
  435             novaradius.set_text(str(self.data["novaradius"]))
  436         novaradius.connect("changed", self._cb_set_intvalue, "novaradius",
  437                            "effects")
  438         novaradius.set_sensitive(self.data["nova"])
  439         novaradius.show()
  440         table.attach(label, 0, 1, 2, 3)
  441         table.attach(novaradius, 1, 2, 2, 3)
  442 
  443         #novasparkles
  444         label = gtk.Label("Nova sparkles")
  445         label.show()
  446         novasparkles = IntEntry(max = 2)
  447         if self.data["novasparkles"] is not None:
  448             novasparkles.set_text(str(self.data["novasparkles"]))
  449         novasparkles.connect("changed", self._cb_set_intvalue, "novasparkles",
  450                              "effects")
  451         novasparkles.set_sensitive(self.data["nova"])
  452         novasparkles.show()
  453         table.attach(label, 0, 1, 3, 4)
  454         table.attach(novasparkles, 1, 2, 3, 4)
  455         novatoggle.connect("toggled", self._cb_nova_toggle, novacolor,
  456                            novaradius, novasparkles)
  457         
  458         #glow
  459         glowtoggle = gtk.CheckButton("Enable glow effect")
  460         glowtoggle.set_active(self.data["glow"])
  461         glowtoggle.show()
  462         table.attach(glowtoggle, 1, 2, 4, 5)
  463 
  464         #glowcolor        
  465         label = gtk.Label("Glow color")
  466         label.show()
  467         glowcolor = gimpui.ColorSelector()
  468         if self.data["glowcolor"]:
  469             glowcolor.set_color(self.data["glowcolor"])
  470         else:
  471             self.data["glowcolor"] = glowcolor.get_color()
  472         glowcolor.connect("color-changed", self._cb_set_color, "glowcolor",
  473                           "effects")
  474         glowcolor.set_sensitive(self.data["glow"])
  475         glowcolor.show()
  476         table.attach(label, 0, 1, 5, 6)
  477         table.attach(glowcolor, 1, 2, 5, 6)
  478 
  479         #glowsize
  480         label = gtk.Label("Glow size")
  481         label.show()
  482         glowsize = IntEntry(max = 2)
  483         glowsize.connect("changed", self._cb_set_intvalue, "glowsize",
  484                          "effects")
  485         glowsize.set_sensitive(self.data["glow"])
  486         glowsize.show()
  487         table.attach(label, 0, 1, 6, 7)
  488         table.attach(glowsize, 1, 2, 6, 7)
  489         glowtoggle.connect("toggled", self._cb_glow_toggle, glowcolor,
  490                            glowsize)
  491 
  492         page.pack_end(table)
  493 
  494     def _addLastPage(self):
  495         page = gtk.VBox(False, 5)
  496         self.pages["output"] = page
  497         page.set_border_width(5)
  498         page.show()
  499         self.append_page(page)
  500         self.set_page_title(page,
  501                            "Output formats")
  502         self.set_page_type(page, gtk.ASSISTANT_PAGE_CONFIRM)
  503 
  504         label = gtk.Label("Choose the output data.")
  505         label.show()
  506         page.pack_start(label)
  507 
  508         #makejscript
  509         toggle = gtk.CheckButton("Make HTML, CSS and JavaScript")
  510         toggle.set_active(self.data["makejscript"])
  511         toggle.connect("toggled", self._cb_toggle_simple, "makejscript",
  512                        "output")
  513         toggle.show()
  514         page.pack_start(toggle)
  515 
  516         #makeinactive
  517         toggle = gtk.CheckButton("Make inactive buttons")
  518         toggle.set_active(self.data["makeinactive"])
  519         toggle.connect("toggled", self._cb_toggle_simple, "makeinactive",
  520                        "output")
  521         toggle.show()
  522         page.pack_start(toggle)
  523 
  524         #makeactive
  525         toggle = gtk.CheckButton("Make active buttons")
  526         toggle.set_active(self.data["makeactive"])
  527         toggle.connect("toggled", self._cb_toggle_simple, "makeactive",
  528                        "output")
  529         toggle.show()
  530         page.pack_start(toggle)
  531 
  532         #makepressed
  533         toggle = gtk.CheckButton("Make pressed buttons")
  534         toggle.set_active(self.data["makepressed"])
  535         toggle.connect("toggled", self._cb_toggle_simple, "makepressed",
  536                        "output")
  537         toggle.show()
  538         page.pack_start(toggle)
  539 
  540         #writexcf
  541         toggle = gtk.CheckButton("Write the XCF file")
  542         toggle.set_active(self.data["writexcf"])
  543         toggle.connect("toggled", self._cb_toggle_simple, "writexcf",
  544                        "output")
  545         toggle.show()
  546         page.pack_start(toggle)
  547 
  548     def checkcompletion(self, pagename):
  549         criteriamatched = False
  550         if pagename == "pathselection":
  551             criteriamatched = self.data["filename"] is not None and \
  552                 self.data["outdir"] is not None
  553         elif pagename == "basicsettings":
  554             criteriamatched = self.data["font"] is not None and \
  555                 self.data["strcolor"] is not None and \
  556                 ((self.data["usepattern"] and self.data["pattern"]) or \
  557                      (not self.data["usepattern"] and \
  558                           self.data["buttoncolor"]))
  559         elif pagename == "layout":
  560             criteriamatched = self.data["roundradius"] is not None and \
  561                 self.data["bevelwidth"] is not None and \
  562                 self.data["padding"] is not None and \
  563                 (self.data["transparency"] or self.data["bgcolor"] is not None)
  564         elif pagename == "effects":
  565             criteriamatched = (self.data["nova"] == False or ( \
  566                     self.data["novacolor"] is not None and \
  567                         self.data["novaradius"] is not None and \
  568                         self.data["novasparkles"] is not None)) and \
  569                         (self.data["glow"] == False or ( \
  570                     self.data["glowcolor"] is not None and \
  571                         self.data["glowsize"] is not None))
  572         elif pagename == "output":
  573             criteriamatched = self.data["makejscript"] is not None and \
  574                 self.data["makeinactive"] is not None and \
  575                 self.data["makeactive"] is not None and \
  576                 self.data["makepressed"] is not None and \
  577                 self.data["writexcf"] is not None
  578         if criteriamatched:
  579             self.set_page_complete(self.pages[pagename], True)
  580         else:
  581             self.set_page_complete(self.pages[pagename], False)
  582 
  583     def _cb_set_intvalue(self, w, fieldname, pagename):
  584         try:
  585             self.data[fieldname] = int (w.get_text())
  586         except ValueError:
  587             pass
  588         self.checkcompletion(pagename)
  589 
  590     def _cb_toggle_simple(self, w, datafield, pagename):
  591         self.data[datafield] = w.get_active()
  592         self.checkcompletion(pagename)
  593 
  594     def _cb_file_selected(self, w):
  595         self.data["filename"] = w.get_filename()
  596         self.checkcompletion("pathselection")
  597 
  598     def _cb_dir_selected(self, w):
  599         self.data["outdir"] = w.get_filename()
  600         self.checkcompletion("pathselection")
  601 
  602     def _cb_set_font(self, w):
  603         self.data["font"] = w.get_font_name()
  604         self.checkcompletion("basicsettings")
  605 
  606     def _cb_set_color(self, w, fieldname, pagename):
  607         self.data[fieldname] = w.get_color()
  608         self.checkcompletion(pagename)
  609 
  610     def _cb_set_pattern(self, w, patternname, width, height, bpp, mask_data,
  611                         finished):
  612         if finished:
  613             self.data["pattern"] = patternname
  614         self.checkcompletion("basicsettings")
  615 
  616     def _cb_bgtoggle_toggle(self, w, label, patterntext, patternsel,
  617                             colortext, colorsel):
  618         if w.get_active():
  619             self.data["usepattern"] = True
  620             colorsel.hide()
  621             patternsel.show()
  622             label.set_text(patterntext)
  623         else:
  624             self.data["usepattern"] = False
  625             patternsel.hide()
  626             colorsel.show()
  627             label.set_text(colortext)
  628         self.checkcompletion("basicsettings")
  629 
  630     def _cb_nova_toggle(self, w, colorfield, radiusfield, sparksfield):
  631         if w.get_active():
  632             self.data["nova"] = True
  633             colorfield.set_sensitive(True)
  634             radiusfield.set_sensitive(True)
  635             sparksfield.set_sensitive(True)
  636         else:
  637             self.data["nova"] = False
  638             colorfield.set_sensitive(False)
  639             radiusfield.set_sensitive(False)
  640             sparksfield.set_sensitive(False)
  641         self.checkcompletion("effects")
  642 
  643     def _cb_glow_toggle(self, w, colorfield, sizefield):
  644         if w.get_active():
  645             self.data["glow"] = True
  646             colorfield.set_sensitive(True)
  647             sizefield.set_sensitive(True)
  648         else:
  649             self.data["glow"] = False
  650             colorfield.set_sensitive(False)
  651             sizefield.set_sensitive(False)
  652         self.checkcompletion("effects")
  653 
  654 class btn4wsplugin(gimpplugin.plugin):
  655     """This is the btn4ws gimp plugin."""
  656     def gimp2html_color(self, color):
  657         """
  658         Converts a color tuple to a hex encoded color for CSS.
  659         """
  660         return "#%02x%02x%02x" % (color[0], color[1], color[2])
  661 
  662     def parsefont(self, font):
  663         """
  664         Parses a font into its fontname and size parts.
  665         """
  666         parts = font.split(" ")
  667         return (" ".join(parts[:-1]), parts[-1])
  668 
  669     def toprocess(self, item):
  670         """
  671         Decides whether the plugin is able to process the item or not.
  672         """
  673         item = item.strip()
  674         return len(item) > 0 and not item.startswith('#')
  675 
  676     def getmaxextents(self, strings, fontsize, fontname):
  677         """
  678         Gets the maximum width and height of texts in strings array
  679         with the given font.
  680         """
  681         getextents = pdb['gimp_text_get_extents_fontname']
  682         maxx = 0
  683         maxy = 0
  684         for extents in [getextents(string, fontsize, 1, fontname)
  685                         for string in strings]:
  686             maxx = max(maxx, extents[0])
  687             maxy = max(maxy, extents[1])
  688         return (maxx, maxy)
  689 
  690     def writejs(self, dirname, strings, width, height, t2nm):
  691         buf = [
  692         "//",
  693         "// JavaScript generated by btn4ws version %s" % (btn4ws_version),
  694         "//",
  695         "",
  696         "// function to show image for given image_object",
  697         "function hilite(ObjID, imgObjName) {",
  698         "  ObjID.src = eval(imgObjName + '.src');",
  699         "  return true;",
  700         "}",
  701         ""
  702         ]
  703         for item in strings:
  704             for prefix in ('a_', 'i_', 'p_'):
  705                 buf.append(
  706                     "%(prefix)s%(jsid)s = new Image(%(width)d, %(height)d); "
  707                     "%(prefix)s%(jsid)s.src = '%(fname)s';"
  708                     % {
  709                     'prefix' : prefix,
  710                     'jsid'   : t2nm.asjavascriptid(item),
  711                     'width'  : width,
  712                     'height' : height,
  713                     'fname'  : urllib.quote(t2nm.asfilename(item, 'png',
  714                                                             prefix))})
  715         jsfile = open(os.path.join(dirname, 'imgobjs.js'), 'w')
  716         jsfile.write("\n".join(buf))
  717         jsfile.close()
  718 
  719     def writecss(self, dirname, bgcolor):
  720         buf = [
  721         "html, body { background-color:%s; }" % (self.gimp2html_color(bgcolor)),
  722         "a img { border-width: 0; }"
  723         ]
  724         cssfile = open(os.path.join(dirname, 'format.css'), 'w')
  725         cssfile.write("\n".join(buf))
  726         cssfile.close()
  727 
  728     def writehtml(self, dirname, strings, width, height, t2nm):
  729         buf = [
  730         '<?xml version="1.0" encoding="UTF-8"?>',
  731         '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"',
  732         ' "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">',
  733         '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">',
  734         '<head>',
  735         ' <title>A JavaScript MouseOver Example</title>',
  736         ' <script src="imgobjs.js" type="text/javascript"></script>',
  737         ' <link rel="stylesheet" type="text/css" href="format.css"/>',
  738         '</head>',
  739         '<body>',
  740         ' <div>'
  741         ]
  742         for item in strings:
  743             buf.append(
  744             '<a href="%(target)s"'
  745             ' onmouseover="return hilite(%(imgid)s, \'a_%(jsid)s\');"'
  746             ' onmouseout="return hilite(%(imgid)s, \'i_%(jsid)s\');"'
  747             ' onmousedown="return hilite(%(imgid)s, \'p_%(jsid)s\');"'
  748             ' onmouseup="return hilite(%(imgid)s, \'a_%(jsid)s\');">'
  749             '<img src="%(fname)s" class="nav" id="%(imgid)s" width="%(width)d" height="%(height)d"'
  750             ' alt="%(text)s" /></a><br />' % {
  751                 'target' : t2nm.aslinktarget(item),
  752                 'imgid'  : t2nm.asitemid(item),
  753                 'jsid'   : t2nm.asjavascriptid(item),
  754                 'fname'  : urllib.quote(t2nm.asfilename(item, 'png', 'i_')),
  755                 'width'  : width,
  756                 'height' : height,
  757                 'text'   : item})
  758         buf.extend([
  759         ' </div>',
  760         ' <p><a href="http://validator.w3.org/check/referer">'
  761         '<img src="http://www.w3.org/Icons/valid-xhtml11" alt="Valid XHTML 1.1!" height="31"'
  762         'width="88" /></a></p>',
  763         '</html>',
  764         ''
  765         ])            
  766         htmlfile = open(os.path.join(dirname, 'example.html'), 'w')
  767         htmlfile.write("\n".join(buf))
  768         htmlfile.close()
  769 
  770     def saveaspng(self, fname, image, transparency):
  771         imgcopy = pdb['gimp_image_duplicate'](image)
  772         if transparency:
  773             imgcopy.merge_visible_layers(CLIP_TO_BOTTOM_LAYER)
  774         else:
  775             imgcopy.flatten()
  776         pdb['file_png_save'](imgcopy, imgcopy.active_layer, fname, fname,
  777                              False, 9, False, False, False, False, True)
  778         gimp.delete(imgcopy)
  779 
  780     def __init__(self):
  781         self.data = {}
  782         self.inputdata = {}
  783         self.datafile = os.path.join(gimp.directory, "btn4wsrc")
  784 
  785     def checkdata(self, data):
  786         logging.debug("checkdata " + str(data))
  787         valid = True
  788         if data["filename"] is None:
  789             logging.error("filename is None")
  790             valid = False
  791         else:
  792             try:
  793                 if not os.path.isfile(data["filename"]):
  794                     logging.error("%s is not a file.", data["filename"])
  795                     valid = False
  796             except OSError, e:
  797                 logging.error(e)
  798                 valid = False
  799         if data["outdir"] is None:
  800             logging.error("outdir is None")
  801         else:
  802             try:
  803                 if not os.path.isdir(data["outdir"]):
  804                     logging.error("%s is not a directory.", data["outdir"])
  805                     valid = False
  806             except OSError, e:
  807                 logging.error(e)
  808                 valid = False
  809         # simple None checks
  810         for key in ("font", "strcolor", "roundradius", "bevelwidth",
  811                     "padding", "makejscript", "makeinactive", "makeactive",
  812                     "makepressed", "writexcf"):
  813             if data[key] is None:
  814                 logging.error("%s is None" % (key))
  815                 valid = False
  816         if data["usepattern"]:
  817             if data["pattern"] is None:
  818                 logging.error("usepattern is True and pattern is None")
  819                 valid = False
  820         elif data["buttoncolor"] is None:
  821             logging.error("usepattern is False and buttoncolor is None")
  822             valid = False
  823         if not data["transparency"] and data["bgcolor"] is None:
  824             logging.error("transparency is not enabled and bgcolor is None")
  825             valid = False
  826         if data["nova"]:
  827             if data["novacolor"] is None:
  828                 logging.error("nova is enabled and novacolor is None")
  829                 valid = False
  830             if data["novaradius"] is None:
  831                 logging.error("nova is enabled and novaradius is None")
  832                 valid = False
  833             if data["novasparkles"] is None:
  834                 logging.error("nova is enabled and novasparkles is None")
  835                 valid = False
  836         if data["glow"]:
  837             if data["glowcolor"] is None:
  838                 logging.error("glow is enabled and glowcolor is None")
  839                 valid = False
  840             if data["glowsize"] is None:
  841                 logging.error("glow is enabled and glowsize is None")
  842         return valid
  843 
  844     def makebuttons(self, filename = None, outdir = None, font = None,
  845                strcolor = None, transparency = False, bgcolor = None,
  846                glow = False, glowcolor = None, usepattern = False,
  847                pattern = None, buttoncolor = None, roundradius = None,
  848                padding = None, glowsize = None, bevelwidth = None,
  849                nova = False, novasparkles = None, novaradius = None,
  850                novacolor = None, writexcf = False, makeinactive = True,
  851                makeactive = True, makepressed = True, makejscript = True):
  852         # import used gimp pdb functions
  853         createtext = pdb['gimp_text_fontname']
  854         selectionlayeralpha = pdb['gimp_selection_layer_alpha']
  855         selectionfeather = pdb['gimp_selection_feather']
  856         bucketfill = pdb['gimp_edit_bucket_fill']
  857         selectionall = pdb['gimp_selection_all']
  858         editclear = pdb['gimp_edit_clear']
  859         rectselect = pdb['gimp_rect_select']
  860         ellipseselect = pdb['gimp_ellipse_select']
  861         selectionshrink = pdb['gimp_selection_shrink']
  862         selectionnone = pdb['gimp_selection_none']
  863         fill = pdb['gimp_edit_fill']
  864         bumpmap = pdb['plug_in_bump_map']
  865         novaplugin = pdb['plug_in_nova']
  866         xcfsave = pdb['gimp_xcf_save']
  867         
  868         gimp.progress_init()
  869         stringfile = open(filename)
  870         strings = [line.strip()
  871                    for line in stringfile.readlines()
  872                    if self.toprocess(line)]
  873         stringfile.close()
  874         t2nm = text_to_name_mapper(strings)
  875         (fontname, fontsize) = self.parsefont(font)
  876         (maxx, maxy) = self.getmaxextents(strings, fontsize, fontname)
  877         logging.debug("fontname: %s, fontsize: %d, maxx: %d, maxy: %d",
  878                       fontname, int(fontsize), maxx, maxy)
  879         width = maxx + (padding*4)
  880         height = maxy + (padding*4)
  881         logging.debug("width: %d, height: %d", width, height)
  882         
  883         if roundradius > height/2:
  884             roundradius = height/2 - 1
  885         if roundradius > width/2:
  886             roundradius = width/2 - 1
  887         logging.debug("roundradius: %d", roundradius)
  888 
  889         for text in strings:
  890             image = gimp.Image(width, height, RGB)
  891             image.disable_undo()
  892             gimp.set_foreground(strcolor)
  893             textlayer = createtext(image, None, padding*2, padding*2, text,
  894                                    0, 1, fontsize, 1, fontname)
  895             # center the text
  896             textlayer.set_offsets((image.width - textlayer.width)/2 - 1,
  897                                   (image.height - textlayer.height)/2 - 1)
  898             textlayer.lock_alpha = True
  899             textlayer.name = text
  900             if glow:
  901                 texteffect = textlayer.copy(True)
  902                 image.add_layer(texteffect, len(image.layers))
  903                 offs = texteffect.offsets
  904                 texteffect.resize(image.width, image.height, offs[0], offs[1])
  905                 texteffect.lock_alpha = False
  906                 image.active_layer = texteffect
  907                 selectionlayeralpha(texteffect)
  908                 selectionfeather(image, glowsize)
  909                 gimp.set_foreground(glowcolor)
  910                 bucketfill(texteffect, FG_BUCKET_FILL, NORMAL_MODE, 100, 0,
  911                            True, 0, 0)
  912             btnlayer0 = gimp.Layer(image, "Background", width, height,
  913                                    RGBA_IMAGE, 100, NORMAL_MODE)
  914             image.add_layer(btnlayer0, len(image.layers))
  915             selectionall(image)
  916             editclear(btnlayer0)
  917             offs = btnlayer0.offsets
  918             rectselect(image, offs[0] + roundradius, offs[1],
  919                        btnlayer0.width - roundradius*2, btnlayer0.height,
  920                        CHANNEL_OP_REPLACE, 0, 0)
  921             rectselect(image, offs[0], offs[1] + roundradius,
  922                        btnlayer0.width, btnlayer0.height - roundradius*2,
  923                        CHANNEL_OP_ADD, 0, 0)
  924             ellipseselect(image, offs[0], offs[1],
  925                           roundradius*2, roundradius*2,
  926                           CHANNEL_OP_ADD, False, 0, 0)
  927             ellipseselect(image, offs[0] + btnlayer0.width - roundradius*2,
  928                           offs[1],
  929                           roundradius*2, roundradius*2,
  930                           CHANNEL_OP_ADD, False, 0, 0)
  931             ellipseselect(image, offs[0],
  932                           offs[1] + btnlayer0.height - roundradius*2,
  933                           roundradius*2, roundradius*2,
  934                           CHANNEL_OP_ADD, False, 0, 0)
  935             ellipseselect(image, offs[0] + btnlayer0.width - roundradius*2,
  936                           offs[1] + btnlayer0.height - roundradius*2,
  937                           roundradius*2, roundradius*2,
  938                           CHANNEL_OP_ADD, False, 0, 0)
  939             selectionshrink(image, 1)
  940             selectionfeather(image, 2)
  941             if usepattern:
  942                 pdb['gimp_context_set_pattern'](pattern)
  943                 bucketfill(btnlayer0, PATTERN_BUCKET_FILL, NORMAL_MODE, 100, 0,
  944                            True, 0, 0)
  945             else:
  946                 gimp.set_background(buttoncolor)
  947                 bucketfill(btnlayer0, BG_BUCKET_FILL, NORMAL_MODE, 100, 0,
  948                            True, 0, 0)
  949             selectionnone(image)
  950             selectionlayeralpha(btnlayer0)
  951             selectionfeather(image, 2)
  952             bumplayer = gimp.Layer(image, "Bumpmap", width, height, RGBA_IMAGE,
  953                                    100, NORMAL_MODE)
  954             gimp.set_background(0, 0, 0)
  955             image.add_layer(bumplayer, 0)
  956             fill(bumplayer, BACKGROUND_FILL)
  957             for index in range(1, bevelwidth -1):
  958                 greyness = index*255/bevelwidth;
  959                 gimp.set_background(greyness, greyness, greyness)
  960                 bucketfill(bumplayer, BG_BUCKET_FILL, NORMAL_MODE, 100, 0,
  961                            False, 0, 0)
  962                 selectionshrink(image, 1)
  963             gimp.set_background(255, 255, 255)
  964             bucketfill(bumplayer, BG_BUCKET_FILL, NORMAL_MODE, 100, 0, False,
  965                        0, 0)
  966             selectionnone(image)
  967             btnlayer1 = btnlayer0.copy(True)
  968             btnlayer2 = btnlayer0.copy(True)
  969             image.add_layer(btnlayer1, len(image.layers))
  970             image.add_layer(btnlayer2, len(image.layers))
  971             bumpmap(image, btnlayer1, bumplayer, 125, 45, 3, 0, 0, 0, 0, 0,
  972                     0, 1)
  973             bumpmap(image, btnlayer2, bumplayer, 125, 45, 3, 0, 0, 0, 0, 0,
  974                     1, 1)
  975             image.remove_layer(bumplayer)
  976             #gimp.delete(bumplayer)
  977             if nova:
  978                 novalayer = gimp.Layer(image, "Nova", width, height,
  979                                        RGBA_IMAGE, 75, NORMAL_MODE)
  980                 image.add_layer(novalayer, 0)
  981                 selectionall(image)
  982                 image.active_layer = novalayer
  983                 editclear(novalayer)
  984                 selectionnone(image)
  985                 novaplugin(image, novalayer, width/4, height/4,
  986                            novacolor, novaradius, novasparkles, 0)
  987             blackboard = gimp.Layer(image, "Blackboard", width, height,
  988                                     RGBA_IMAGE, 100, NORMAL_MODE)
  989             image.add_layer(blackboard, len(image.layers))
  990             selectionall(image)
  991             if transparency:
  992                 blackboard.preserve_trans = True
  993                 editclear(blackboard)
  994             else:
  995                 gimp.set_background(bgcolor)
  996                 bucketfill(blackboard, BG_BUCKET_FILL, NORMAL_MODE, 100, 0,
  997                            False, 0, 0)
  998             selectionnone(image)
  999             if writexcf:
 1000                 fname = t2nm.asfilename(text, 'xcf', dirname = outdir)
 1001                 xcfsave(0, image, textlayer, fname, fname)
 1002             if makepressed:
 1003                 btnlayer0.visible = False
 1004                 btnlayer1.visible = False
 1005                 btnlayer2.visible = True
 1006                 if nova: novalayer.visible = True
 1007                 self.saveaspng(t2nm.asfilename(text, 'png', 'p_', outdir),
 1008                                image, transparency)
 1009             if makeactive:
 1010                 btnlayer0.visible = False
 1011                 btnlayer1.visible = True
 1012                 btnlayer2.visible = False
 1013                 if nova: novalayer.visible = True
 1014                 self.saveaspng(t2nm.asfilename(text, 'png', 'a_', outdir),
 1015                                image, transparency)
 1016             if makeinactive:
 1017                 btnlayer0.visible = True
 1018                 btnlayer1.visible = False
 1019                 btnlayer2.visible = False
 1020                 if nova: novalayer.visible = False
 1021                 self.saveaspng(t2nm.asfilename(text, 'png', 'i_', outdir),
 1022                                image, transparency)
 1023             image.enable_undo()
 1024             #gimp.Display(image)
 1025             gimp.progress_update((strings.index(text)+1)/len(strings))
 1026             gimp.delete(image)
 1027         if makejscript:
 1028             self.writejs(outdir, strings, width, height, t2nm)
 1029             self.writecss(outdir, bgcolor)
 1030             self.writehtml(outdir, strings, width, height, t2nm)
 1031         #gimp.displays_flush()
 1032 
 1033     def _cb_destroy(self, widget, data = None):
 1034         logging.debug("destroy")
 1035         gtk.main_quit()
 1036 
 1037     def _loaddata(self, data):
 1038         try:
 1039             if os.path.exists(self.datafile):
 1040                 return pickle.load(open(self.datafile))
 1041         except OSError, e:
 1042             pass
 1043         return data
 1044 
 1045     def _storedata(self, data):
 1046         try:
 1047             pickle.dump(data, open(self.datafile, 'w'))
 1048         except OSError, e:
 1049             pass
 1050 
 1051     def _cb_apply(self, widget):
 1052         self.data = widget.data
 1053         logging.debug(str(self.data))
 1054         if self.checkdata(self.data):            
 1055             self.makebuttons(**self.data)
 1056             shelf["btn4ws"] = self.data
 1057             self._storedata(self.data)
 1058         else:
 1059             logging.error("checking data failed")
 1060 
 1061     def btn4ws(self, runmode, filename = None, outdir = None, font = None,
 1062                strcolor = None, transparency = False, bgcolor = None,
 1063                glow = False, glowcolor = None, usepattern = False,
 1064                pattern = None, buttoncolor = None, roundradius = None,
 1065                padding = None, glowsize = None, bevelwidth = None,
 1066                nova = False, novasparkles = None, novaradius = None,
 1067                novacolor = None, writexcf = False, makeinactive = True,
 1068                makeactive = True, makepressed = True, makejscript = True):
 1069         """
 1070         This function controls the creation of the buttons and is
 1071         registered as gimp plugin.
 1072         """
 1073         self.inputdata = {
 1074             "filename" : filename, "outdir" : outdir, "font" : font,
 1075             "strcolor" : strcolor, "transparency" : transparency,
 1076             "bgcolor" : bgcolor, "glow" : glow, "glowcolor" : glowcolor,
 1077             "usepattern" : usepattern, "pattern" : pattern,
 1078             "buttoncolor" : buttoncolor, "roundradius" : roundradius,
 1079             "padding" : padding, "glowsize" : glowsize,
 1080             "bevelwidth" : bevelwidth, "nova" : nova,
 1081             "novasparkles" : novasparkles, "novaradius" : novaradius,
 1082             "novacolor" : novacolor, "writexcf" : writexcf,
 1083             "makeinactive" : makeinactive, "makeactive" : makeactive,
 1084             "makepressed" : makepressed, "makejscript" : makejscript
 1085             }
 1086         if runmode in (RUN_INTERACTIVE, RUN_WITH_LAST_VALS):
 1087             if shelf.has_key("btn4ws"):
 1088                 self.inputdata = shelf["btn4ws"]
 1089             else:
 1090                 self.inputdata = self._loaddata(self.inputdata)
 1091             dialog = Btn4wsDialog(self.inputdata)
 1092             dialog.connect("close", self._cb_destroy)
 1093             dialog.connect("cancel", self._cb_destroy)
 1094             dialog.connect("destroy", self._cb_destroy)
 1095             dialog.connect("apply", self._cb_apply)
 1096             gtk.main()
 1097         elif runmode == RUN_NONINTERACTIVE:
 1098             logging.debug("runmode noninteractive")
 1099             if self.checkdata(self.inputdata):
 1100                 self.makebuttons(**self.inputdata)
 1101             else:
 1102                 logging.error("checking data failed")
 1103         else:
 1104             logging.error("unknown runmode %d" % runmode)
 1105             return
 1106 
 1107     def start(self):
 1108         gimp.main(self.init, self.quit, self.query, self._run)
 1109 
 1110     def init(self):
 1111         logging.debug("init")
 1112 
 1113     def quit(self):
 1114         logging.debug("quit")
 1115 
 1116     def query(self):
 1117         logging.debug("query")
 1118         gimp.install_procedure(
 1119             "btn4ws",
 1120             "Buttons for website", """Creates buttons for a website. Which have the same size, layout, effects on it. It's possible to create JavaScript code, CSS and XHTML examples for MouseOver effects also.""",
 1121             "Jan Dittberner",
 1122             "Jan Dittberner <jan@dittberner.info>",
 1123             "%s, %s" % (btn4ws_version,
 1124                         "$Date: 2008-01-05 23:19:03 +0100 (Sa, 05 Jan 2008) $"),
 1125             "<Toolbox>/Xtns/Render/Buttons for website ...",
 1126             "", PLUGIN,
 1127             [(PDB_INT32, "run_mode", "Run mode"),
 1128              (PDB_STRING, "string_filename", "File containing the strings"),
 1129              (PDB_STRING, "output_directory", "Directory for the output files"),
 1130              (PDB_STRING, "font", "Font for the strings"), # "Sans 18"),
 1131              (PDB_COLOR, "string_color", "Color of the strings"), #, (255, 255, 0)),
 1132              (PDB_INT8, "transparent_background", "Keep the background transparent (This doesn't work in MS Internet Explorer <= 6.0)"), #, 0),
 1133              (PDB_COLOR, "background_color", "Color of the background"), #, (7, 135, 255)),
 1134              (PDB_INT8, "apply_glow", "Enable glow effect"), #, 1),
 1135              (PDB_COLOR, "glow_color", "Color of the Glow effect"), #, (255, 180, 0)),
 1136              (PDB_INT8, "use_pattern", "Use a pattern for the button"), #, 1),
 1137              (PDB_STRING, "button_pattern", "Fill pattern of the button"), #, "Rain"),
 1138              (PDB_COLOR, "button_color", "Button color (if you don't use a pattern)"), #, (0, 0, 255)),
 1139              (PDB_INT32, "round_radius", "Radius of the round corners"), #, 20),
 1140              (PDB_INT32, "padding", "Space around the text"), #, 3),
 1141              (PDB_INT32, "glow_size", "Size of the Glow effect"), #, 10),
 1142              (PDB_INT32, "bevel_width", "Width of the bevel"), #, 5),
 1143              (PDB_INT8, "apply_nova", "Nova or not Nova?"), #, 1),
 1144              (PDB_INT32, "nova_sparkles", "Sparkles of the Nova"), #, 5),
 1145              (PDB_INT32, "nova_radius", "Radius of the Nova"), #, 2),
 1146              (PDB_COLOR, "nova_color", "Color of the Nova effect"), #, (255, 238, 0)),
 1147              (PDB_INT8, "write_xcf", "Write a GIMP xcf file"), #, 0),
 1148              (PDB_INT8, "create_inactive", "Create Inactive Button"), #, 1),
 1149              (PDB_INT8, "create_active", "Create Active Button"), #, 1),
 1150              (PDB_INT8, "create_pressed", "Create Pressed Button"), #, 1),
 1151              (PDB_INT8, "create_jscript", "Create JavaScript, HTML and CSS"), #, 1)
 1152              ],
 1153             [])
 1154 
 1155 if __name__ == '__main__':
 1156     btn4wsplugin().start()