#!/usr/bin/env python
# -*- coding: utf-8 -*-

# GIMP Layer Effects
# Copyright (c) 2008 Jonathan Stipe
# JonStipe@prodigy.net

# ---------------------------------------------------------------------

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import gimp, gimpplugin, math
from gimpenums import *
pdb = gimp.pdb
import gtk, gimpui, gimpcolor
from gimpshelf import shelf

class layerfx_base(object):
  mode_list = (NORMAL_MODE, DISSOLVE_MODE, MULTIPLY_MODE, DIVIDE_MODE, SCREEN_MODE, OVERLAY_MODE, DODGE_MODE, BURN_MODE, HARDLIGHT_MODE, SOFTLIGHT_MODE, GRAIN_EXTRACT_MODE, GRAIN_MERGE_MODE, DIFFERENCE_MODE, ADDITION_MODE, SUBTRACT_MODE, DARKEN_ONLY_MODE, LIGHTEN_ONLY_MODE, HUE_MODE, SATURATION_MODE, COLOR_MODE, VALUE_MODE)
  previewLayer = None
  hiddenLayer = None

  def get_layer_pos(self, layer):
    i = 0
    while i < len(self.img.layers):
      if layer == self.img.layers[i]:
        return i
      else:
        i += 1
    return -1

  def add_under_layer(self, newlayer, oldlayer):
    self.img.add_layer(newlayer, self.get_layer_pos(oldlayer) + 1)

  def add_over_layer(self, newlayer, oldlayer):
    self.img.add_layer(newlayer, self.get_layer_pos(oldlayer))

  def layer_exists(self, layer):
    return layer != None and layer in self.img.layers

  def set_hidden_layer(self, layer):
    if self.hiddenLayer == None:
      self.hiddenLayer = layer
    elif type(self.hiddenLayer) == gimp.Layer and self.hiddenLayer != layer:
      self.hiddenLayer = [self.hiddenLayer, layer]
    elif type(self.hiddenLayer) == list and layer not in self.hiddenLayer:
      self.hiddenLayer.append(layer)
    layer.visible = 0

  def unset_hidden_layer(self):
    if self.hiddenLayer != None:
      if type(self.hiddenLayer) == gimp.Layer and self.layer_exists(self.hiddenLayer):
        self.hiddenLayer.visible = 1
      elif type(self.hiddenLayer) == list:
        for i in self.hiddenLayer:
          if self.layer_exists(i):
            i.visible = 1
      self.hiddenLayer = None

  def draw_blurshape(self, drawable, size, initgrowth, sel, invert):
    k = initgrowth
    currshade = 0
    i = 0
    while i < size:
      if k > 0:
        pdb.gimp_selection_grow(drawable.image, k)
      elif k < 0:
        pdb.gimp_selection_shrink(drawable.image, abs(k))
      if invert:
        currshade = int(round((float(size - (i + 1)) / float(size)) * 255))
      else:
        currshade = int(round((float(i + 1) / float(size)) * 255))
      gimp.set_foreground(currshade, currshade, currshade)
      if pdb.gimp_selection_is_empty(drawable.image) == 0:
        pdb.gimp_edit_fill(drawable, FOREGROUND_FILL)
      pdb.gimp_selection_load(sel)
      k -= 1
      i += 1

  def apply_contour(self, drawable, channel, contour):
    contourtypes = (0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1)
    contours = ((0, 0, 127, 255, 255, 0),
                (0, 255, 127, 0, 255, 255),
                (0, 64, 94, 74, 150, 115, 179, 179, 191, 255),
                (0, 0, 5, 125, 6, 125, 48, 148, 79, 179, 107, 217, 130, 255),
                (0, 0, 33, 8, 64, 38, 97, 102, 128, 166, 158, 209, 191, 235, 222, 247, 255, 255),
                (0, 0, 28, 71, 87, 166, 194, 240, 255, 255),
                (0, 0, 33, 110, 64, 237, 97, 240, 128, 138, 158, 33, 191, 5, 222, 99, 255, 255),
                (0, 0, 33, 74, 64, 219, 97, 186, 128, 0, 158, 176, 191, 201, 222, 3, 255, 255),
                (3, 255, 54, 99, 97, 107, 179, 153, 252, 0),
                (0, 5, 9, 13, 16, 19, 22, 25, 27, 29, 30, 32, 33, 34, 35, 36, 38, 39, 40, 41, 43, 44, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 55, 56, 56, 57, 57, 58, 58, 59, 59, 59, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 62, 63, 63, 63, 63, 63, 63, 64, 64, 64, 64, 64, 71, 75, 78, 81, 84, 86, 89, 91, 93, 95, 96, 98, 99, 101, 102, 103, 104, 105, 107, 107, 108, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 119, 120, 121, 121, 122, 123, 123, 123, 124, 124, 124, 125, 125, 125, 125, 125, 125, 125, 126, 126, 126, 126, 126, 126, 126, 125, 125, 125, 125, 125, 125, 125, 125, 130, 134, 137, 141, 145, 148, 151, 153, 156, 158, 160, 162, 163, 165, 166, 167, 168, 170, 171, 171, 172, 173, 174, 175, 176, 177, 178, 178, 179, 180, 181, 181, 182, 183, 183, 184, 184, 185, 185, 186, 186, 187, 187, 188, 188, 189, 189, 189, 189, 190, 190, 190, 190, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 193, 194, 196, 197, 198, 200, 201, 203, 204, 205, 207, 208, 209, 211, 212, 213, 214, 215, 217, 218, 219, 220, 220, 221, 222, 222, 223, 223, 224, 224, 224, 224, 224, 223, 223, 222, 222, 221, 221, 220, 219, 218, 217, 216, 215, 214, 213, 212, 211, 210, 209, 208, 206, 205, 204, 203, 202, 200, 199, 198, 197, 196, 194, 194),
                (0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 127, 125, 123, 121, 119, 117, 115, 113, 111, 109, 107, 105, 103, 101, 99, 97, 95, 93, 91, 89, 87, 85, 83, 81, 79, 77, 75, 73, 71, 69, 67, 65, 63, 61, 59, 57, 55, 53, 51, 49, 47, 45, 43, 41, 39, 37, 35, 33, 31, 29, 27, 25, 23, 21, 19, 17, 15, 13, 11, 9, 7, 5, 3, 1, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99, 101, 103, 105, 107, 109, 111, 113, 115, 117, 119, 121, 123, 125, 127, 128, 126, 124, 122, 120, 118, 116, 114, 112, 110, 108, 106, 104, 102, 100, 98, 96, 94, 92, 90, 88, 86, 84, 82, 80, 78, 76, 74, 72, 70, 68, 66, 64, 62, 60, 58, 56, 54, 52, 50, 48, 46, 44, 42, 40, 38, 36, 34, 32, 30, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2))
    if contourtypes[contour-1] == 0:
      pdb.gimp_curves_spline(drawable, channel, len(contours[contour-1]), contours[contour-1])
    else:
      pdb.gimp_curves_explicit(drawable, channel, len(contours[contour-1]), contours[contour-1])

  def apply_noise(self, drawable, srclayer, noise, uselayer):
    noiselayer = gimp.Layer(drawable.image, "%s-noise" % (drawable.name), srclayer.width, srclayer.height, (RGBA_IMAGE, GRAYA_IMAGE)[drawable.image.base_type], 100.0, NORMAL_MODE)
    blanklayer = gimp.Layer(drawable.image, "%s-blank" % (drawable.name), srclayer.width, srclayer.height, (RGBA_IMAGE, GRAYA_IMAGE)[drawable.image.base_type], 100.0, NORMAL_MODE)
    self.add_over_layer(blanklayer, srclayer)
    self.add_over_layer(noiselayer, blanklayer)
    noiselayer.set_offsets(srclayer.offsets[0], srclayer.offsets[1])
    blanklayer.set_offsets(srclayer.offsets[0], srclayer.offsets[1])
    pdb.gimp_selection_none(drawable.image)
    gimp.set_foreground(0, 0, 0)
    pdb.gimp_edit_fill(noiselayer, FOREGROUND_FILL)
    pdb.gimp_edit_fill(blanklayer, FOREGROUND_FILL)
    gimp.set_foreground(255, 255, 255)
    if uselayer:
      srclayer.add_mask(srclayer.create_mask(ADD_WHITE_MASK))
      pdb.gimp_selection_none(drawable.image)
      pdb.gimp_edit_fill(blanklayer, FOREGROUND_FILL)
      pdb.plug_in_hsv_noise(drawable.image, noiselayer, 1, 0, 0, 255)
    else:
      pdb.gimp_selection_load(srclayer.mask)
      pdb.gimp_edit_fill(blanklayer, FOREGROUND_FILL)
      pdb.gimp_selection_none(drawable.image)
      pdb.plug_in_hsv_noise(drawable.image, noiselayer, 1, 0, 0, 255)
      noiselayer.mode = OVERLAY_MODE
    noiselayer.opacity = noise
    noiselayer = pdb.gimp_image_merge_down(drawable.image, noiselayer, EXPAND_AS_NECESSARY)
    blanklayer = noiselayer.create_mask(ADD_COPY_MASK)
    noiselayer.add_mask(blanklayer)
    pdb.gimp_selection_none(drawable.image)
    gimp.set_foreground(0, 0, 0)
    pdb.gimp_edit_fill(srclayer.mask, FOREGROUND_FILL)
    pdb.gimp_channel_combine_masks(srclayer.mask, blanklayer, CHANNEL_OP_REPLACE, 0, 0)
    drawable.image.remove_layer(noiselayer)

  def removePreviews(self):
    if self.layer_exists(self.previewLayer):
      self.img.remove_layer(self.previewLayer)
      self.previewLayer = None
    self.unset_hidden_layer()
    gimp.displays_flush()

  def make_label(self, text):
    label = gtk.Label(text)
    label.set_use_underline(True)
    label.set_alignment(1.0, 0.5)
    label.show()
    return label

  def make_blend_mode_box(self):
    mode_box = gtk.combo_box_new_text()
    mode_box.append_text("Normal")
    mode_box.append_text("Dissolve")
    mode_box.append_text("Multiply")
    mode_box.append_text("Divide")
    mode_box.append_text("Screen")
    mode_box.append_text("Overlay")
    mode_box.append_text("Dodge")
    mode_box.append_text("Burn")
    mode_box.append_text("Hard Light")
    mode_box.append_text("Soft Light")
    mode_box.append_text("Grain Extract")
    mode_box.append_text("Grain Merge")
    mode_box.append_text("Difference")
    mode_box.append_text("Addition")
    mode_box.append_text("Subtract")
    mode_box.append_text("Darken Only")
    mode_box.append_text("Lighten Only")
    mode_box.append_text("Hue")
    mode_box.append_text("Saturation")
    mode_box.append_text("Color")
    mode_box.append_text("Value")
    return mode_box

  def blend_mode_box_set(self, mode_box, mode):
    i = 0
    while i < len(self.mode_list):
      if self.mode_list[i] == mode:
        mode_box.set_active(i)
        i = len(self.mode_list)
      else:
        i += 1

  def make_contour_box(self):
    cbox = gtk.combo_box_new_text()
    cbox.append_text("Linear")
    cbox.append_text("Cone")
    cbox.append_text("Cone - Inverted")
    cbox.append_text("Cove - Deep")
    cbox.append_text("Cove-Shallow")
    cbox.append_text("Gaussian")
    cbox.append_text("Half Round")
    cbox.append_text("Ring")
    cbox.append_text("Ring - Double")
    cbox.append_text("Rolling Slope - Descending")
    cbox.append_text("Rounded Steps")
    cbox.append_text("Sawtooth 1")
    return cbox

  def make_spinner(self, init, min, max, step, page, digits):
    controls = {"adj":gtk.Adjustment(init, min, max, step, page), "spinner":gtk.SpinButton()}
    controls["spinner"].set_adjustment(controls["adj"])
    controls["spinner"].set_digits(digits)
    controls["spinner"].show()
    return controls

  def make_slider_and_spinner(self, init, min, max, step, page, digits):
    controls = {"adj":gtk.Adjustment(init, min, max, step, page), "slider":gtk.HScale(), "spinner":gtk.SpinButton()}
    controls["slider"].set_adjustment(controls["adj"])
    controls["slider"].set_draw_value(False)
    controls["spinner"].set_adjustment(controls["adj"])
    controls["spinner"].set_digits(digits)
    controls["slider"].show()
    controls["spinner"].show()
    return controls

  def show_error_msg(self, msg):
    origMsgHandler = pdb.gimp_message_get_handler()
    pdb.gimp_message_set_handler(ERROR_CONSOLE)
    pdb.gimp_message(msg)
    pdb.gimp_message_set_handler(origMsgHandler)

  def validatedata(self, img, drawable, params):
    if type(img) != gimp.Image:
      self.show_error_msg("Error: Argument 1 is not an image.")
      return False
    elif not img.base_type in (RGB, GRAY):
      self.show_error_msg("Error: Argument 1 must be of type RGB or GRAY.")
      return False
    elif type(drawable) != gimp.Layer:
      self.show_error_msg("Error: Argument 2 is not a layer.")
      return False
    elif drawable not in img.layers:
      self.show_error_msg("Error: Layer is not part of image.")
      return False
    else:
      i = 0
      while i < len(params):
        if params[i][0] == "color":
          if type(params[i][1]) != gimpcolor.RGB:
            self.show_error_msg("Error: Argument %s must be of type gimpcolor.RGB." % (i))
            return False
        elif params[i][0] == "gradient":
          if type(params[i][1]) != str:
            self.show_error_msg("Error: Argument %s must be of type string." % (i))
            return False
          elif params[i][1] not in pdb.gimp_gradients_get_list("")[1]:
            self.show_error_msg("Error: Argument %s not found in gradient list." % (i))
            return False
        elif params[i][0] == "color/gradient":
          if type(params[i][1]) != gimpcolor.RGB and type(params[i][1]) != str:
            self.show_error_msg("Error: Argument %s must be of type gimpcolor.RGB or string." % (i))
            return False
          elif type(params[i][1]) == str and params[i][1] not in pdb.gimp_gradients_get_list("")[1]:
            self.show_error_msg("Error: Argument %s not found in gradient list." % (i))
            return False
        elif params[i][0] == "pattern":
          if type(params[i][1]) != str:
            self.show_error_msg("Error: Argument %s must be of type string." % (i))
            return False
          elif params[i][1] not in pdb.gimp_patterns_get_list("")[1]:
            self.show_error_msg("Error: Argument %s not found in pattern list." % (i))
            return False
        elif params[i][0] == "percent":
          if type(params[i][1]) != float:
            self.show_error_msg("Error: Argument %s must be of type float." % (i))
            return False
          elif params[i][1] < 0.0 or params[i][1] > 100.0:
            self.show_error_msg("Error: Argument %s is out of range (must be between 0 and 100)." % (i))
            return False
        elif params[i][0] == "contour":
          if type(params[i][1]) != int:
            self.show_error_msg("Error: Argument %s must be of type int." % (i))
            return False
          elif params[i][1] < 0 or params[i][1] > 11:
            self.show_error_msg("Error: Argument %s is out of range (must be between 0 and 11)." % (i))
            return False
        elif params[i][0] == "mode":
          if type(params[i][1]) != int:
            self.show_error_msg("Error: Argument %s must be of type int." % (i))
            return False
          elif params[i][1] not in self.mode_list:
            self.show_error_msg("Error: Illegal value for argument %s." % (i))
            return False
        elif params[i][0] == "size":
          if type(params[i][1]) != int:
            self.show_error_msg("Error: Argument %s must be of type int." % (i))
            return False
          elif params[i][1] < 0 or params[i][1] > 250:
            self.show_error_msg("Error: Argument %s is out of range (must be between 0 and 250)." % (i))
            return False
        elif params[i][0] == "angle":
          if type(params[i][1]) != float:
            self.show_error_msg("Error: Argument %s must be of type float." % (i))
            return False
          elif params[i][1] < -180.0 or params[i][1] > 180.0:
            self.show_error_msg("Error: Argument %s is out of range (must be between -180 and 180)." % (i))
            return False
        elif params[i][0] == "boolean":
          if type(params[i][1]) != int:
            self.show_error_msg("Error: Argument %s must be of type int." % (i))
            return False
          elif params[i][1] < 0 or params[i][1] > 1:
            self.show_error_msg("Error: Argument %s is out of range (must be between 0 and 1)." % (i))
            return False
        elif params[i][0] == "intrange":
          if type(params[i][1]) != int:
            self.show_error_msg("Error: Argument %s must be of type int." % (i))
            return False
          elif params[i][1] < params[i][2] or params[i][1] > params[i][3]:
            self.show_error_msg("Error: Argument %s is out of range (must be between %s and %s)." % (i, params[i][2], params[i][3]))
            return False
        elif params[i][0] == "floatrange":
          if type(params[i][1]) != float:
            self.show_error_msg("Error: Argument %s must be of type float." % (i))
            return False
          elif params[i][1] < params[i][2] or params[i][1] > params[i][3]:
            self.show_error_msg("Error: Argument %s is out of range (must be between %s and %s)." % (i, params[i][2], params[i][3]))
            return False
        i += 1
      return True

  def stringToColor(self, string):
    colorlist = string[5:-1].split(", ")
    return gimpcolor.RGB(float(colorlist[0]), float(colorlist[1]), float(colorlist[2]), float(colorlist[3]))

  def writeParasite(self, drawable, fxlayer, controls):
    dataList = []
    for i in controls:
      if i[0] == "color":
        dataList.append(str(i[1].get_color()))
      elif i[0] == "gradient":
        dataList.append(i[1].get_gradient().encode("string_escape").replace("|", "\\x7c"))
      elif i[0] == "pattern":
        dataList.append(i[1].get_pattern().encode("string_escape").replace("|", "\\x7c"))
      elif i[0] == "intadj":
        dataList.append(str(int(round(i[1].get_value()))))
      elif i[0] == "floatadj":
        dataList.append(str(i[1].get_value()))
      elif i[0] == "combobox":
        dataList.append(str(i[1].get_active()))
      elif i[0] == "modebox":
        dataList.append(str(self.mode_list[i[1].get_active()]))
      elif i[0] == "check":
        if i[1].get_active():
          dataList.append("1")
        else:
          dataList.append("0")
      elif i[0] == "radio":
        j = 0
        while j < len(i[1]):
          if i[1][j].get_active():
            dataList.append(str(j))
            break
          else:
            j += 1
    data = "|".join(dataList)
    fxlayer.attach_new_parasite(self.shelfkey, 0, data)
    drawable.attach_new_parasite("%s-fxlayer" % (self.shelfkey), 0, fxlayer.name)

  def writeParasiteRaw(self, drawable, fxlayer, values):
    dataList = []
    for i in values:
      if type(i) == str:
        dataList.append(i.encode("string_escape").replace("|", "\\x7c"))
      else:
        dataList.append(str(i))
    data = "|".join(dataList)
    fxlayer.attach_new_parasite(self.shelfkey, 0, data)
    drawable.attach_new_parasite("%s-fxlayer" % (self.shelfkey), 0, fxlayer.name)

  def readParasite(self, img, drawable, keysntypes, keyname):
    fxlayername = "%s-fxlayer" % (keyname)
    if fxlayername in pdb.gimp_drawable_parasite_list(drawable)[1]:
      fxlayername = pdb.gimp_drawable_parasite_find(drawable, fxlayername).data
      for i in img.layers:
        if i.name == fxlayername:
          if keyname in pdb.gimp_drawable_parasite_list(i)[1]:
            datalist = pdb.gimp_drawable_parasite_find(i, keyname).data.split("|")
            keys = []
            vals = []
            j = 0
            while j < len(datalist):
              keys.append(keysntypes[j][0])
              if keysntypes[j][1] == "color":
                vals.append(self.stringToColor(datalist[j]))
              elif keysntypes[j][1] == "int":
                vals.append(int(datalist[j]))
              elif keysntypes[j][1] == "float":
                vals.append(float(datalist[j]))
              elif keysntypes[j][1] == "string":
                vals.append(datalist[j].decode("string_escape"))
              j += 1
            keys.append("oldid")
            vals.append(i)
            data = dict(zip(keys, vals))
            return data
          else:
            return False
    else:
      return False

  def removeOldLayer(self):
    if not hasattr(self, "parasitedata"):
      self.parasitedata = self.readParasite(self.img, self.drawable)
    if self.parasitedata:
      self.img.remove_layer(self.parasitedata["oldid"])

class layerfx_drop_shadow(layerfx_base):
  shelfkey = "layerfx-drop-shadow"

  def __init__(self, runmode, img, drawable, color, opacity, contour, noise, mode, spread, size, offsetangle, offsetdist, knockout, merge):
    self.origMsgHandler = pdb.gimp_message_get_handler()
    pdb.gimp_message_set_handler(ERROR_CONSOLE)
    self.img = img
    self.drawable = drawable
    if runmode == RUN_INTERACTIVE:
      self.showDialog()
    elif runmode == RUN_NONINTERACTIVE:
      if self.validatedata(img, drawable, [
        ["color", color],
        ["percent", opacity],
        ["contour", contour],
        ["percent", noise],
        ["mode", mode],
        ["percent", spread],
        ["size", size],
        ["angle", offsetangle],
        ["floatrange", offsetdist, 0.0, 30000.0],
        ["boolean", knockout],
        ["boolean", merge]
      ]):
        self.removeOldLayer()
        fxlayer = self.makeShadow(img, drawable, color, opacity, contour, noise, mode, spread, size, offsetangle, offsetdist, knockout, merge)
        if merge == 0:
          self.writeParasiteRaw(drawable, fxlayer, [color, opacity, contour, noise, mode, spread, size, offsetangle, offsetdist, knockout, merge])
        shelf[self.shelfkey] = {"color":color,
          "opacity":opacity,
          "contour":contour,
          "noise":noise,
          "mode":mode,
          "spread":spread,
          "size":size,
          "offsetangle":offsetangle,
          "offsetdist":offsetdist,
          "knockout":knockout,
          "merge":merge}
    elif runmode == RUN_WITH_LAST_VALS and shelf.has_key(self.shelfkey) == 1:
      self.removeOldLayer()
      fxlayer = self.makeShadow(img,
        drawable,
        shelf[self.shelfkey]["color"],
        shelf[self.shelfkey]["opacity"],
        shelf[self.shelfkey]["contour"],
        shelf[self.shelfkey]["noise"],
        shelf[self.shelfkey]["mode"],
        shelf[self.shelfkey]["spread"],
        shelf[self.shelfkey]["size"],
        shelf[self.shelfkey]["offsetangle"],
        shelf[self.shelfkey]["offsetdist"],
        shelf[self.shelfkey]["knockout"],
        shelf[self.shelfkey]["merge"])
      if shelf[self.shelfkey]["merge"] == 0:
        self.writeParasiteRaw(drawable, fxlayer, [
          shelf[self.shelfkey]["color"],
          shelf[self.shelfkey]["opacity"],
          shelf[self.shelfkey]["contour"],
          shelf[self.shelfkey]["noise"],
          shelf[self.shelfkey]["mode"],
          shelf[self.shelfkey]["spread"],
          shelf[self.shelfkey]["size"],
          shelf[self.shelfkey]["offsetangle"],
          shelf[self.shelfkey]["offsetdist"],
          shelf[self.shelfkey]["knockout"],
          shelf[self.shelfkey]["merge"]
        ])
    else:
      pdb.gimp_message("unknown runmode")
    pdb.gimp_message_set_handler(self.origMsgHandler)

  def showDialog(self):
    self.dialog = gimpui.Dialog("Drop Shadow", "dropshadowdialog")

    self.parasitedata = self.readParasite(self.img, self.drawable)

    self.table = gtk.Table(9, 5, True)
    self.table.set_homogeneous(True)
    self.table.set_row_spacings(3)
    self.table.set_col_spacings(3)
    self.table.show()

    self.color_label = self.make_label("_Color:")
    self.table.attach(self.color_label, 0, 1, 0, 1)

    self.color_button = gimpui.ColorButton("Shadow Color", 10, 10, gimpcolor.RGB(0, 0, 0, 255))
    if self.parasitedata:
      self.color_button.set_color(self.parasitedata["color"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.color_button.set_color(shelf[self.shelfkey]["color"])
    self.color_label.set_mnemonic_widget(self.color_button)
    self.color_button.show()
    self.table.attach(self.color_button, 1, 2, 0, 1)
    self.color_button.connect("color-changed", self.preview)

    self.mode_label = self.make_label("_Blend Mode:")
    self.table.attach(self.mode_label, 0, 1, 1, 2)

    self.mode_box = self.make_blend_mode_box()
    if self.parasitedata:
      self.blend_mode_box_set(self.mode_box, self.parasitedata["mode"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.blend_mode_box_set(self.mode_box, shelf[self.shelfkey]["mode"])
    else:
      self.mode_box.set_active(2)
    self.mode_label.set_mnemonic_widget(self.mode_box)
    self.mode_box.show()
    self.table.attach(self.mode_box, 1, 5, 1, 2)
    self.mode_box.connect("changed", self.preview)

    self.opacity_label = self.make_label("_Opacity:")
    self.table.attach(self.opacity_label, 0, 1, 2, 3)

    self.opacity_slider = self.make_slider_and_spinner(75.0, 0.0, 100.0, 1.0, 10.0, 1)
    if self.parasitedata:
      self.opacity_slider["adj"].set_value(self.parasitedata["opacity"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.opacity_slider["adj"].set_value(shelf[self.shelfkey]["opacity"])
    self.opacity_label.set_mnemonic_widget(self.opacity_slider["spinner"])
    self.table.attach(self.opacity_slider["slider"], 1, 4, 2, 3)
    self.table.attach(self.opacity_slider["spinner"], 4, 5, 2, 3)
    self.opacity_slider["adj"].connect("value-changed", self.preview)

    self.angle_label = self.make_label("_Angle:")
    self.table.attach(self.angle_label, 0, 1, 3, 4)

    self.angle_slider = self.make_slider_and_spinner(120.0, -180.0, 180.0, 1.0, 10.0, 1)
    if self.parasitedata:
      self.angle_slider["adj"].set_value(self.parasitedata["offsetangle"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.angle_slider["adj"].set_value(shelf[self.shelfkey]["offsetangle"])
    self.angle_label.set_mnemonic_widget(self.angle_slider["spinner"])
    self.table.attach(self.angle_slider["slider"], 1, 4, 3, 4)
    self.table.attach(self.angle_slider["spinner"], 4, 5, 3, 4)
    self.angle_slider["adj"].connect("value-changed", self.preview)

    self.distance_label = self.make_label("_Distance:")
    self.table.attach(self.distance_label, 0, 1, 4, 5)

    self.distance_spinner = self.make_spinner(5.0, 0.0, 30000.0, 1.0, 10.0, 1)
    if self.parasitedata:
      self.distance_spinner["adj"].set_value(self.parasitedata["offsetdist"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.distance_spinner["adj"].set_value(shelf[self.shelfkey]["offsetdist"])
    self.distance_label.set_mnemonic_widget(self.distance_spinner["spinner"])
    self.table.attach(self.distance_spinner["spinner"], 1, 2, 4, 5)
    self.distance_spinner["adj"].connect("value-changed", self.preview)

    self.spread_label = self.make_label("_Spread:")
    self.table.attach(self.spread_label, 0, 1, 5, 6)

    self.spread_slider = self.make_slider_and_spinner(0.0, 0.0, 100.0, 1.0, 10.0, 1)
    if self.parasitedata:
      self.spread_slider["adj"].set_value(self.parasitedata["spread"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.spread_slider["adj"].set_value(shelf[self.shelfkey]["spread"])
    self.spread_label.set_mnemonic_widget(self.spread_slider["spinner"])
    self.table.attach(self.spread_slider["slider"], 1, 4, 5, 6)
    self.table.attach(self.spread_slider["spinner"], 4, 5, 5, 6)
    self.spread_slider["adj"].connect("value-changed", self.preview)

    self.size_label = self.make_label("S_ize:")
    self.table.attach(self.size_label, 0, 1, 6, 7)

    self.size_slider = self.make_slider_and_spinner(5, 0, 250, 1, 10, 0)
    if self.parasitedata:
      self.size_slider["adj"].set_value(self.parasitedata["size"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.size_slider["adj"].set_value(shelf[self.shelfkey]["size"])
    self.size_label.set_mnemonic_widget(self.size_slider["spinner"])
    self.table.attach(self.size_slider["slider"], 1, 4, 6, 7)
    self.table.attach(self.size_slider["spinner"], 4, 5, 6, 7)
    self.size_slider["adj"].connect("value-changed", self.preview)

    self.contour_label = self.make_label("Con_tour:")
    self.table.attach(self.contour_label, 0, 1, 7, 8)

    self.contour_box = self.make_contour_box()
    if self.parasitedata:
      self.contour_box.set_active(self.parasitedata["contour"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.contour_box.set_active(shelf[self.shelfkey]["contour"])
    else:
      self.contour_box.set_active(0)
    self.contour_label.set_mnemonic_widget(self.contour_box)
    self.contour_box.show()
    self.table.attach(self.contour_box, 1, 5, 7, 8)
    self.contour_box.connect("changed", self.preview)

    self.noise_label = self.make_label("_Noise:")
    self.table.attach(self.noise_label, 0, 1, 8, 9)

    self.noise_slider = self.make_slider_and_spinner(0.0, 0.0, 100.0, 1.0, 10.0, 1)
    if self.parasitedata:
      self.noise_slider["adj"].set_value(self.parasitedata["noise"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.noise_slider["adj"].set_value(shelf[self.shelfkey]["noise"])
    self.noise_label.set_mnemonic_widget(self.noise_slider["spinner"])
    self.table.attach(self.noise_slider["slider"], 1, 4, 8, 9)
    self.table.attach(self.noise_slider["spinner"], 4, 5, 8, 9)
    self.noise_slider["adj"].connect("value-changed", self.preview)

    self.knockout_check = gtk.CheckButton("Layer _knocks out Drop Shadow")
    if (self.parasitedata and self.parasitedata["knockout"] == 1) or (shelf.has_key(self.shelfkey) == 1 and shelf[self.shelfkey]["knockout"] == 1):
      self.knockout_check.set_active(True)
    self.knockout_check.show()
    self.knockout_check.connect("toggled", self.preview)

    self.merge_check = gtk.CheckButton("_Merge with layer")
    if (self.parasitedata and self.parasitedata["merge"] == 1) or (shelf.has_key(self.shelfkey) == 1 and shelf[self.shelfkey]["merge"] == 1):
      self.merge_check.set_active(True)
    self.merge_check.show()
    self.merge_check.connect("toggled", self.preview)

    self.preview_check = gtk.CheckButton("_Preview")
    self.preview_check.show()
    self.preview_check.connect("toggled", self.preview)

    self.dialog.vbox.hbox1 = gtk.HBox(False, 7)
    self.dialog.vbox.hbox1.show()
    self.dialog.vbox.pack_start(self.dialog.vbox.hbox1, True, True, 7)
    self.dialog.vbox.hbox1.pack_start(self.table, True, True, 7)
    self.dialog.vbox.hbox2 = gtk.HBox(False, 7)
    self.dialog.vbox.hbox2.show()
    self.dialog.vbox.add(self.dialog.vbox.hbox2)
    self.dialog.vbox.hbox2.pack_start(self.knockout_check, True, True, 10)
    self.dialog.vbox.hbox3 = gtk.HBox(False, 7)
    self.dialog.vbox.hbox3.show()
    self.dialog.vbox.add(self.dialog.vbox.hbox3)
    self.dialog.vbox.hbox3.pack_start(self.merge_check, True, True, 10)
    self.dialog.vbox.hbox4 = gtk.HBox(False, 7)
    self.dialog.vbox.hbox4.show()
    self.dialog.vbox.add(self.dialog.vbox.hbox4)
    self.dialog.vbox.hbox4.pack_start(self.preview_check, True, True, 10)

    reset_button = gtk.Button("_Reset")
    reset_button.connect("clicked", self.resetbutton)
    reset_button.show()

    if gtk.alternative_dialog_button_order():
      ok_button = self.dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
      cancel_button = self.dialog.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
      self.dialog.action_area.add(reset_button)
    else:
      self.dialog.action_area.add(reset_button)
      cancel_button = self.dialog.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
      ok_button = self.dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
    ok_button.connect("clicked", self.okbutton)

    self.dialog.show()
    self.dialog.run()
    self.removePreviews()

  def okbutton(self, widget):
    if self.layer_exists(self.previewLayer):
      self.img.remove_layer(self.previewLayer)
      self.previewLayer = None
    if self.knockout_check.get_active():
      knockout = 1
    else:
      knockout = 0
    if self.merge_check.get_active():
      merge = 1
    else:
      merge = 0
    shelf[self.shelfkey] = {"color":self.color_button.get_color(),
      "opacity":self.opacity_slider["adj"].get_value(),
      "contour":self.contour_box.get_active(),
      "noise":self.noise_slider["adj"].get_value(),
      "mode":self.mode_list[self.mode_box.get_active()],
      "spread":self.spread_slider["adj"].get_value(),
      "size":int(round(self.size_slider["adj"].get_value())),
      "offsetangle":self.angle_slider["adj"].get_value(),
      "offsetdist":self.distance_spinner["adj"].get_value(),
      "knockout":knockout,
      "merge":merge}
    self.removeOldLayer()
    fxlayer = self.makeShadow(self.img,
      self.drawable,
      shelf[self.shelfkey]["color"],
      shelf[self.shelfkey]["opacity"],
      shelf[self.shelfkey]["contour"],
      shelf[self.shelfkey]["noise"],
      shelf[self.shelfkey]["mode"],
      shelf[self.shelfkey]["spread"],
      shelf[self.shelfkey]["size"],
      shelf[self.shelfkey]["offsetangle"],
      shelf[self.shelfkey]["offsetdist"],
      shelf[self.shelfkey]["knockout"],
      shelf[self.shelfkey]["merge"])
    if merge == 0:
      self.writeParasite(self.drawable, fxlayer, [
        ["color", self.color_button],
        ["floatadj", self.opacity_slider["adj"]],
        ["combobox", self.contour_box],
        ["floatadj", self.noise_slider["adj"]],
        ["modebox", self.mode_box],
        ["floatadj", self.spread_slider["adj"]],
        ["intadj", self.size_slider["adj"]],
        ["floatadj", self.angle_slider["adj"]],
        ["floatadj", self.distance_spinner["adj"]],
        ["check", self.knockout_check],
        ["check", self.merge_check]
      ])

  def readParasite(self, img, drawable):
    return layerfx_base.readParasite(self, img, drawable, [
      ["color", "color"],
      ["opacity", "float"],
      ["contour", "int"],
      ["noise", "float"],
      ["mode", "int"],
      ["spread", "float"],
      ["size", "int"],
      ["offsetangle", "float"],
      ["offsetdist", "float"],
      ["knockout", "int"],
      ["merge", "int"]
    ], layerfx_drop_shadow.shelfkey)

  def resetbutton(self, widget):
    self.color_button.set_color(gimpcolor.RGB(0, 0, 0, 255))
    self.mode_box.set_active(2)
    self.opacity_slider["adj"].set_value(75.0)
    self.angle_slider["adj"].set_value(120.0)
    self.distance_spinner["adj"].set_value(5.0)
    self.spread_slider["adj"].set_value(0.0)
    self.size_slider["adj"].set_value(5)
    self.contour_box.set_active(0)
    self.noise_slider["adj"].set_value(0.0)
    self.knockout_check.set_active(False)
    self.merge_check.set_active(False)

  def preview(self, widget):
    if self.preview_check.get_active():
      if self.layer_exists(self.previewLayer):
        self.img.remove_layer(self.previewLayer)
      if self.parasitedata:
        self.set_hidden_layer(self.parasitedata["oldid"])
      if self.knockout_check.get_active():
        knockout = 1
      else:
        knockout = 0
      self.previewLayer = self.makeShadow(self.img,
        self.drawable,
        self.color_button.get_color(),
        self.opacity_slider["adj"].get_value(),
        self.contour_box.get_active(),
        self.noise_slider["adj"].get_value(),
        self.mode_list[self.mode_box.get_active()],
        self.spread_slider["adj"].get_value(),
        int(round(self.size_slider["adj"].get_value())),
        self.angle_slider["adj"].get_value(),
        self.distance_spinner["adj"].get_value(),
        knockout,
        0)

  def makeShadow(self, img, drawable, color, opacity, contour, noise, mode, spread, size, offsetangle, offsetdist, knockout, merge):
    pdb.gimp_image_undo_group_start(img)
    origfgcolor = gimp.get_foreground()
    origselection = pdb.gimp_selection_save(img)
    growamt = int(math.ceil(size / 2.0))
    steps = int(round(size - ((spread / 100.0) * size)))
    lyrgrowamt = int(round(growamt * 1.2))
    shadowlayer = gimp.Layer(img, "%s-dropshadow" % (drawable.name), drawable.width + (lyrgrowamt * 2), drawable.height + (lyrgrowamt * 2), (RGBA_IMAGE, GRAYA_IMAGE)[img.base_type], opacity, mode)
    ang = ((offsetangle + 180) * -1) * (math.pi / 180.0)
    offset = (int(round(offsetdist * math.cos(ang))), int(round(offsetdist * math.sin(ang))))
    self.add_under_layer(shadowlayer, drawable)
    shadowlayer.set_offsets(drawable.offsets[0] + offset[0] - lyrgrowamt, drawable.offsets[1] + offset[1] - lyrgrowamt)
    pdb.gimp_selection_none(img)
    gimp.set_foreground(color)
    pdb.gimp_edit_fill(shadowlayer, FOREGROUND_FILL)
    shadowmask = shadowlayer.create_mask(ADD_BLACK_MASK)
    shadowlayer.add_mask(shadowmask)
    pdb.gimp_selection_layer_alpha(drawable)
    if drawable.mask != None:
      pdb.gimp_selection_combine(drawable.mask, CHANNEL_OP_INTERSECT)
    pdb.gimp_selection_translate(img, offset[0], offset[1])
    alphaSel = pdb.gimp_selection_save(img)
    if (steps > 0):
      self.draw_blurshape(shadowmask, steps, growamt, alphaSel, False)
    else:
      pdb.gimp_selection_grow(img, growamt)
      gimp.set_foreground(255, 255, 255)
      pdb.gimp_edit_fill(shadowmask, FOREGROUND_FILL)
    pdb.gimp_selection_none(img)
    if contour > 0:
      self.apply_contour(shadowmask, HISTOGRAM_VALUE, contour)
      pdb.gimp_selection_load(alphaSel)
      pdb.gimp_selection_grow(img, growamt)
      pdb.gimp_selection_invert(img)
      gimp.set_foreground(0, 0, 0)
      pdb.gimp_edit_fill(shadowmask, FOREGROUND_FILL)
      pdb.gimp_selection_none(img)
    if noise > 0:
      self.apply_noise(drawable, shadowlayer, noise, False)
    if knockout == 1:
      gimp.set_foreground(0, 0, 0)
      pdb.gimp_selection_layer_alpha(drawable)
      pdb.gimp_edit_fill(shadowmask, FOREGROUND_FILL)
    shadowlayer.remove_mask(MASK_APPLY)
    pdb.gimp_selection_none(img)
    if merge == 1:
      origmask = drawable.mask
      layername = drawable.name
      if origmask != None:
        drawable.remove_mask(MASK_APPLY)
      shadowlayer = pdb.gimp_image_merge_down(img, drawable, EXPAND_AS_NECESSARY)
      shadowlayer.name = layername
    else:
      pdb.gimp_image_set_active_layer(img, drawable)
    gimp.set_foreground(origfgcolor)
    pdb.gimp_selection_load(origselection)
    img.remove_channel(alphaSel)
    img.remove_channel(origselection)
    gimp.displays_flush()
    pdb.gimp_image_undo_group_end(img)
    return shadowlayer

class layerfx_inner_shadow(layerfx_base):
  shelfkey = "layerfx-inner-shadow"

  def __init__(self, runmode, img, drawable, color, opacity, contour, noise, mode, source, choke, size, offsetangle, offsetdist, merge):
    self.origMsgHandler = pdb.gimp_message_get_handler()
    pdb.gimp_message_set_handler(ERROR_CONSOLE)
    self.img = img
    self.drawable = drawable
    if runmode == RUN_INTERACTIVE:
      self.showDialog()
    elif runmode == RUN_NONINTERACTIVE:
      if self.validatedata(img, drawable, [
        ["color", color],
        ["percent", opacity],
        ["contour", contour],
        ["percent", noise],
        ["mode", mode],
        ["boolean", source],
        ["percent", choke],
        ["size", size],
        ["angle", offsetangle],
        ["floatrange", offsetdist, 0.0, 30000.0],
        ["boolean", merge]
      ]):
        self.removeOldLayer()
        fxlayer = self.makeShadow(img, drawable, color, opacity, contour, noise, mode, source, choke, size, offsetangle, offsetdist, merge)
        if merge == 0:
          self.writeParasiteRaw(drawable, fxlayer, [color, opacity, contour, noise, mode, source, choke, size, offsetangle, offsetdist, merge])
        shelf[self.shelfkey] = {"color":color,
          "opacity":opacity,
          "contour":contour,
          "noise":noise,
          "mode":mode,
          "source":source,
          "choke":choke,
          "size":size,
          "offsetangle":offsetangle,
          "offsetdist":offsetdist,
          "merge":merge}
    elif runmode == RUN_WITH_LAST_VALS and shelf.has_key(self.shelfkey) == 1:
      self.removeOldLayer()
      fxlayer = self.makeShadow(img,
        drawable,
        shelf[self.shelfkey]["color"],
        shelf[self.shelfkey]["opacity"],
        shelf[self.shelfkey]["contour"],
        shelf[self.shelfkey]["noise"],
        shelf[self.shelfkey]["mode"],
        shelf[self.shelfkey]["source"],
        shelf[self.shelfkey]["choke"],
        shelf[self.shelfkey]["size"],
        shelf[self.shelfkey]["offsetangle"],
        shelf[self.shelfkey]["offsetdist"],
        shelf[self.shelfkey]["merge"])
      if shelf[self.shelfkey]["merge"] == 0:
        self.writeParasiteRaw(drawable, fxlayer, [
          shelf[self.shelfkey]["color"],
          shelf[self.shelfkey]["opacity"],
          shelf[self.shelfkey]["contour"],
          shelf[self.shelfkey]["noise"],
          shelf[self.shelfkey]["mode"],
          shelf[self.shelfkey]["source"],
          shelf[self.shelfkey]["choke"],
          shelf[self.shelfkey]["size"],
          shelf[self.shelfkey]["offsetangle"],
          shelf[self.shelfkey]["offsetdist"],
          shelf[self.shelfkey]["merge"]
        ])
    else:
      pdb.gimp_message("unknown runmode")
    pdb.gimp_message_set_handler(self.origMsgHandler)

  def showDialog(self):
    self.dialog = gimpui.Dialog("Inner Shadow", "innershadowdialog")

    self.parasitedata = self.readParasite(self.img, self.drawable)

    self.table = gtk.Table(10, 5, True)
    self.table.set_homogeneous(True)
    self.table.set_row_spacings(3)
    self.table.set_col_spacings(3)
    self.table.show()

    self.color_label = self.make_label("_Color:")
    self.table.attach(self.color_label, 0, 1, 0, 1)

    self.color_button = gimpui.ColorButton("Shadow Color", 10, 10, gimpcolor.RGB(0, 0, 0, 255))
    if self.parasitedata:
      self.color_button.set_color(self.parasitedata["color"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.color_button.set_color(shelf[self.shelfkey]["color"])
    self.color_label.set_mnemonic_widget(self.color_button)
    self.color_button.show()
    self.table.attach(self.color_button, 1, 2, 0, 1)
    self.color_button.connect("color-changed", self.preview)

    self.mode_label = self.make_label("_Blend Mode:")
    self.table.attach(self.mode_label, 0, 1, 1, 2)

    self.mode_box = self.make_blend_mode_box()
    if self.parasitedata:
      self.blend_mode_box_set(self.mode_box, self.parasitedata["mode"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.blend_mode_box_set(self.mode_box, shelf[self.shelfkey]["mode"])
    else:
      self.mode_box.set_active(2)
    self.mode_label.set_mnemonic_widget(self.mode_box)
    self.mode_box.show()
    self.table.attach(self.mode_box, 1, 5, 1, 2)
    self.mode_box.connect("changed", self.preview)

    self.opacity_label = self.make_label("_Opacity:")
    self.table.attach(self.opacity_label, 0, 1, 2, 3)

    self.opacity_slider = self.make_slider_and_spinner(75.0, 0.0, 100.0, 1.0, 10.0, 1)
    if self.parasitedata:
      self.opacity_slider["adj"].set_value(self.parasitedata["opacity"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.opacity_slider["adj"].set_value(shelf[self.shelfkey]["opacity"])
    self.opacity_label.set_mnemonic_widget(self.opacity_slider["spinner"])
    self.table.attach(self.opacity_slider["slider"], 1, 4, 2, 3)
    self.table.attach(self.opacity_slider["spinner"], 4, 5, 2, 3)
    self.opacity_slider["adj"].connect("value-changed", self.preview)

    self.angle_label = self.make_label("_Angle:")
    self.table.attach(self.angle_label, 0, 1, 3, 4)

    self.angle_slider = self.make_slider_and_spinner(120.0, -180.0, 180.0, 1.0, 10.0, 1)
    if self.parasitedata:
      self.angle_slider["adj"].set_value(self.parasitedata["offsetangle"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.angle_slider["adj"].set_value(shelf[self.shelfkey]["offsetangle"])
    self.angle_label.set_mnemonic_widget(self.angle_slider["spinner"])
    self.table.attach(self.angle_slider["slider"], 1, 4, 3, 4)
    self.table.attach(self.angle_slider["spinner"], 4, 5, 3, 4)
    self.angle_slider["adj"].connect("value-changed", self.preview)

    self.distance_label = self.make_label("_Distance:")
    self.table.attach(self.distance_label, 0, 1, 4, 5)

    self.distance_spinner = self.make_spinner(5.0, 0.0, 30000.0, 1.0, 10.0, 1)
    if self.parasitedata:
      self.distance_spinner["adj"].set_value(self.parasitedata["offsetdist"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.distance_spinner["adj"].set_value(shelf[self.shelfkey]["offsetdist"])
    self.distance_label.set_mnemonic_widget(self.distance_spinner["spinner"])
    self.table.attach(self.distance_spinner["spinner"], 1, 2, 4, 5)
    self.distance_spinner["adj"].connect("value-changed", self.preview)

    self.source_label = self.make_label("Source:")
    self.table.attach(self.source_label, 0, 1, 5, 6)

    self.source_center_radio = gtk.RadioButton(None, "Cent_er", True)
    self.source_edge_radio = gtk.RadioButton(self.source_center_radio, "Ed_ge", True)
    if self.parasitedata:
      if self.parasitedata["source"] == 0:
        self.source_center_radio.set_active(True)
      elif self.parasitedata["source"] == 1:
        self.source_edge_radio.set_active(True)
    elif shelf.has_key(self.shelfkey) == 1:
      if shelf[self.shelfkey]["source"] == 0:
        self.source_center_radio.set_active(True)
      elif shelf[self.shelfkey]["source"] == 1:
        self.source_edge_radio.set_active(True)
    else:
      self.source_edge_radio.set_active(True)
    self.source_center_radio.show()
    self.table.attach(self.source_center_radio, 1, 2, 5, 6)
    self.source_edge_radio.show()
    self.table.attach(self.source_edge_radio, 2, 3, 5, 6)
    self.source_center_radio.connect("toggled", self.preview)
    self.source_edge_radio.connect("toggled", self.preview)

    self.choke_label = self.make_label("C_hoke:")
    self.table.attach(self.choke_label, 0, 1, 6, 7)

    self.choke_slider = self.make_slider_and_spinner(0.0, 0.0, 100.0, 1.0, 10.0, 1)
    if self.parasitedata:
      self.choke_slider["adj"].set_value(self.parasitedata["choke"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.choke_slider["adj"].set_value(shelf[self.shelfkey]["choke"])
    self.choke_label.set_mnemonic_widget(self.choke_slider["spinner"])
    self.table.attach(self.choke_slider["slider"], 1, 4, 6, 7)
    self.table.attach(self.choke_slider["spinner"], 4, 5, 6, 7)
    self.choke_slider["adj"].connect("value-changed", self.preview)

    self.size_label = self.make_label("S_ize:")
    self.table.attach(self.size_label, 0, 1, 7, 8)

    self.size_slider = self.make_slider_and_spinner(5, 0, 250, 1, 10, 0)
    if self.parasitedata:
      self.size_slider["adj"].set_value(self.parasitedata["size"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.size_slider["adj"].set_value(shelf[self.shelfkey]["size"])
    self.size_label.set_mnemonic_widget(self.size_slider["spinner"])
    self.table.attach(self.size_slider["slider"], 1, 4, 7, 8)
    self.table.attach(self.size_slider["spinner"], 4, 5, 7, 8)
    self.size_slider["adj"].connect("value-changed", self.preview)

    self.contour_label = self.make_label("Con_tour:")
    self.table.attach(self.contour_label, 0, 1, 8, 9)

    self.contour_box = self.make_contour_box()
    if self.parasitedata:
      self.contour_box.set_active(self.parasitedata["contour"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.contour_box.set_active(shelf[self.shelfkey]["contour"])
    else:
      self.contour_box.set_active(0)
    self.contour_label.set_mnemonic_widget(self.contour_box)
    self.contour_box.show()
    self.table.attach(self.contour_box, 1, 5, 8, 9)
    self.contour_box.connect("changed", self.preview)

    self.noise_label = self.make_label("_Noise:")
    self.table.attach(self.noise_label, 0, 1, 9, 10)

    self.noise_slider = self.make_slider_and_spinner(0.0, 0.0, 100.0, 1.0, 10.0, 1)
    if self.parasitedata:
      self.noise_slider["adj"].set_value(self.parasitedata["noise"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.noise_slider["adj"].set_value(shelf[self.shelfkey]["noise"])
    self.noise_label.set_mnemonic_widget(self.noise_slider["spinner"])
    self.table.attach(self.noise_slider["slider"], 1, 4, 9, 10)
    self.table.attach(self.noise_slider["spinner"], 4, 5, 9, 10)
    self.noise_slider["adj"].connect("value-changed", self.preview)

    self.merge_check = gtk.CheckButton("_Merge with layer")
    if (self.parasitedata and self.parasitedata["merge"] == 1) or (shelf.has_key(self.shelfkey) == 1 and shelf[self.shelfkey]["merge"] == 1):
      self.merge_check.set_active(True)
    self.merge_check.show()
    self.merge_check.connect("toggled", self.preview)

    self.preview_check = gtk.CheckButton("_Preview")
    self.preview_check.show()
    self.preview_check.connect("toggled", self.preview)

    self.dialog.vbox.hbox1 = gtk.HBox(False, 7)
    self.dialog.vbox.hbox1.show()
    self.dialog.vbox.pack_start(self.dialog.vbox.hbox1, True, True, 7)
    self.dialog.vbox.hbox1.pack_start(self.table, True, True, 7)
    self.dialog.vbox.hbox2 = gtk.HBox(False, 7)
    self.dialog.vbox.hbox2.show()
    self.dialog.vbox.add(self.dialog.vbox.hbox2)
    self.dialog.vbox.hbox2.pack_start(self.merge_check, True, True, 10)
    self.dialog.vbox.hbox3 = gtk.HBox(False, 7)
    self.dialog.vbox.hbox3.show()
    self.dialog.vbox.add(self.dialog.vbox.hbox3)
    self.dialog.vbox.hbox3.pack_start(self.preview_check, True, True, 10)

    reset_button = gtk.Button("_Reset")
    reset_button.connect("clicked", self.resetbutton)
    reset_button.show()

    if gtk.alternative_dialog_button_order():
      ok_button = self.dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
      cancel_button = self.dialog.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
      self.dialog.action_area.add(reset_button)
    else:
      self.dialog.action_area.add(reset_button)
      cancel_button = self.dialog.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
      ok_button = self.dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
    ok_button.connect("clicked", self.okbutton)

    self.dialog.show()
    self.dialog.run()
    self.removePreviews()

  def okbutton(self, widget):
    if self.layer_exists(self.previewLayer):
      self.img.remove_layer(self.previewLayer)
      self.previewLayer = None
    self.unset_hidden_layer()
    if self.source_center_radio.get_active():
      source = 0
    elif self.source_edge_radio.get_active():
      source = 1
    if self.merge_check.get_active():
      merge = 1
    else:
      merge = 0
    shelf[self.shelfkey] = {"color":self.color_button.get_color(),
      "opacity":self.opacity_slider["adj"].get_value(),
      "contour":self.contour_box.get_active(),
      "noise":self.noise_slider["adj"].get_value(),
      "mode":self.mode_list[self.mode_box.get_active()],
      "source":source,
      "choke":self.choke_slider["adj"].get_value(),
      "size":int(round(self.size_slider["adj"].get_value())),
      "offsetangle":self.angle_slider["adj"].get_value(),
      "offsetdist":self.distance_spinner["adj"].get_value(),
      "merge":merge}
    self.removeOldLayer()
    fxlayer = self.makeShadow(self.img,
      self.drawable,
      shelf[self.shelfkey]["color"],
      shelf[self.shelfkey]["opacity"],
      shelf[self.shelfkey]["contour"],
      shelf[self.shelfkey]["noise"],
      shelf[self.shelfkey]["mode"],
      shelf[self.shelfkey]["source"],
      shelf[self.shelfkey]["choke"],
      shelf[self.shelfkey]["size"],
      shelf[self.shelfkey]["offsetangle"],
      shelf[self.shelfkey]["offsetdist"],
      shelf[self.shelfkey]["merge"])
    if merge == 0:
      self.writeParasite(self.drawable, fxlayer, [
        ["color", self.color_button],
        ["floatadj", self.opacity_slider["adj"]],
        ["combobox", self.contour_box],
        ["floatadj", self.noise_slider["adj"]],
        ["modebox", self.mode_box],
        ["radio", (self.source_center_radio, self.source_edge_radio)],
        ["floatadj", self.choke_slider["adj"]],
        ["intadj", self.size_slider["adj"]],
        ["floatadj", self.angle_slider["adj"]],
        ["floatadj", self.distance_spinner["adj"]],
        ["check", self.merge_check],
      ])

  def resetbutton(self, widget):
    self.color_button.set_color(gimpcolor.RGB(0, 0, 0, 255))
    self.mode_box.set_active(2)
    self.opacity_slider["adj"].set_value(75.0)
    self.angle_slider["adj"].set_value(120.0)
    self.distance_spinner["adj"].set_value(5.0)
    self.source_edge_radio.set_active(True)
    self.choke_slider["adj"].set_value(0.0)
    self.size_slider["adj"].set_value(5)
    self.contour_box.set_active(0)
    self.noise_slider["adj"].set_value(0.0)
    self.merge_check.set_active(False)

  def readParasite(self, img, drawable):
    return layerfx_base.readParasite(self, img, drawable, [
      ["color", "color"],
      ["opacity", "float"],
      ["contour", "int"],
      ["noise", "float"],
      ["mode", "int"],
      ["source", "int"],
      ["choke", "float"],
      ["size", "int"],
      ["offsetangle", "float"],
      ["offsetdist", "float"],
      ["merge", "int"]
    ], layerfx_inner_shadow.shelfkey)

  def preview(self, widget):
    if self.preview_check.get_active():
      if self.layer_exists(self.previewLayer):
        self.img.remove_layer(self.previewLayer)
      self.unset_hidden_layer()
      if self.parasitedata:
        self.set_hidden_layer(self.parasitedata["oldid"])
      if self.source_center_radio.get_active():
        source = 0
      elif self.source_edge_radio.get_active():
        source = 1
      if self.merge_check.get_active():
        self.previewLayer = self.drawable.copy()
        self.add_over_layer(self.previewLayer, self.drawable)
        self.set_hidden_layer(self.drawable)
        self.previewLayer = self.makeShadow(self.img,
          self.previewLayer,
          self.color_button.get_color(),
          self.opacity_slider["adj"].get_value(),
          self.contour_box.get_active(),
          self.noise_slider["adj"].get_value(),
          self.mode_list[self.mode_box.get_active()],
          source,
          self.choke_slider["adj"].get_value(),
          int(round(self.size_slider["adj"].get_value())),
          self.angle_slider["adj"].get_value(),
          self.distance_spinner["adj"].get_value(),
          1)
      else:
        self.previewLayer = self.makeShadow(self.img,
          self.drawable,
          self.color_button.get_color(),
          self.opacity_slider["adj"].get_value(),
          self.contour_box.get_active(),
          self.noise_slider["adj"].get_value(),
          self.mode_list[self.mode_box.get_active()],
          source,
          self.choke_slider["adj"].get_value(),
          int(round(self.size_slider["adj"].get_value())),
          self.angle_slider["adj"].get_value(),
          self.distance_spinner["adj"].get_value(),
          0)

  def makeShadow(self, img, drawable, color, opacity, contour, noise, mode, source, choke, size, offsetangle, offsetdist, merge):
    pdb.gimp_image_undo_group_start(img)
    origfgcolor = gimp.get_foreground()
    origselection = pdb.gimp_selection_save(img)
    growamt = int(math.ceil(size / 2.0))
    chokeamt = (choke / 100.0) * size
    steps = int(round(size - chokeamt))
    shadowlayer = gimp.Layer(img, "%s-innershadow" % (drawable.name), drawable.width, drawable.height, (RGBA_IMAGE, GRAYA_IMAGE)[img.base_type], opacity, mode)
    ang = ((offsetangle + 180) * -1) * (math.pi / 180.0)
    offset = (int(round(offsetdist * math.cos(ang))), int(round(offsetdist * math.sin(ang))))
    self.add_over_layer(shadowlayer, drawable)
    shadowlayer.set_offsets(drawable.offsets[0], drawable.offsets[1])
    pdb.gimp_selection_none(img)
    gimp.set_foreground(color)
    pdb.gimp_edit_fill(shadowlayer, FOREGROUND_FILL)
    shadowmask = shadowlayer.create_mask(ADD_BLACK_MASK)
    shadowlayer.add_mask(shadowmask)
    pdb.gimp_selection_layer_alpha(drawable)
    if drawable.mask != None:
      pdb.gimp_selection_combine(drawable.mask, CHANNEL_OP_INTERSECT)
    pdb.gimp_selection_translate(img, offset[0], offset[1])
    alphaSel = pdb.gimp_selection_save(img)
    if source == 1:
      pdb.gimp_selection_none(img)
      gimp.set_foreground(255, 255, 255)
      pdb.gimp_edit_fill(shadowmask, FOREGROUND_FILL)
      pdb.gimp_selection_load(alphaSel)
      if steps > 0:
        self.draw_blurshape(shadowmask, steps, growamt - chokeamt, alphaSel, True)
      else:
        pdb.gimp_selection_shrink(img, growamt)
        gimp.set_foreground(0, 0, 0)
        pdb.gimp_edit_fill(shadowmask, FOREGROUND_FILL)
    else:
      if steps > 0:
        self.draw_blurshape(shadowmask, steps, growamt - chokeamt, alphaSel, False)
      else:
        pdb.gimp_selection_shrink(img, growamt)
        gimp.set_foreground(255, 255, 255)
        pdb.gimp_edit_fill(shadowmask, FOREGROUND_FILL)
    pdb.gimp_selection_none(img)
    if contour > 0:
      self.apply_contour(shadowmask, HISTOGRAM_VALUE, contour)
    if merge == 0:
      pdb.gimp_selection_layer_alpha(drawable)
      pdb.gimp_selection_invert(img)
      gimp.set_foreground(0, 0, 0)
      pdb.gimp_edit_fill(shadowmask, FOREGROUND_FILL)
    if noise > 0:
      self.apply_noise(drawable, shadowlayer, noise, False)
    shadowlayer.remove_mask(MASK_APPLY)
    if merge == 1:
      if source == 1:
        origmask = drawable.mask
        layername = drawable.name
        if origmask != None:
          origmask = drawable.mask.copy()
          drawable.remove_mask(MASK_DISCARD)
        alphamask = drawable.create_mask(ADD_ALPHA_TRANSFER_MASK)
        shadowlayer = pdb.gimp_image_merge_down(img, shadowlayer, EXPAND_AS_NECESSARY)
        shadowlayer.name = layername
        shadowlayer.add_mask(alphamask)
        shadowlayer.remove_mask(MASK_APPLY)
        if origmask != None:
          shadowlayer.add_mask(origmask)
      else:
        origmask = drawable.mask
        layername = drawable.name
        if origmask != None:
          origmask = drawable.mask.copy()
          drawable.remove_mask(MASK_DISCARD)
        shadowlayer = pdb.gimp_image_merge_down(img, shadowlayer, EXPAND_AS_NECESSARY)
        shadowlayer.name = layername
        if origmask != None:
          shadowlayer.add_mask(origmask)
    else:
      pdb.gimp_image_set_active_layer(img, drawable)
    gimp.set_foreground(origfgcolor)
    pdb.gimp_selection_load(origselection)
    img.remove_channel(alphaSel)
    img.remove_channel(origselection)
    gimp.displays_flush()
    pdb.gimp_image_undo_group_end(img)
    return shadowlayer

class layerfx_outer_glow(layerfx_base):
  shelfkey = "layerfx-outer-glow"

  def __init__(self, runmode, img, drawable, color, opacity, contour, noise, mode, spread, size, knockout, merge):
    self.origMsgHandler = pdb.gimp_message_get_handler()
    pdb.gimp_message_set_handler(ERROR_CONSOLE)
    self.img = img
    self.drawable = drawable
    if runmode == RUN_INTERACTIVE:
      self.showDialog()
    elif runmode == RUN_NONINTERACTIVE:
      if self.validatedata(img, drawable, [
        ["color/gradient", color],
        ["percent", opacity],
        ["contour", contour],
        ["percent", noise],
        ["mode", mode],
        ["percent", spread],
        ["size", size],
        ["boolean", knockout],
        ["boolean", merge]
      ]):
        self.removeOldLayer()
        fxlayer = self.makeGlow(img, drawable, color, opacity, contour, noise, mode, spread, size, knockout, merge)
        if merge == 0:
          if type(color) == gimpcolor.RGB:
            self.writeParasiteRaw(drawable, fxlayer, [0, color, "FG to BG (RGB)", opacity, contour, noise, mode, spread, size, knockout, merge])
          else:
            self.writeParasiteRaw(drawable, fxlayer, [1, gimpcolor.RGB(255, 255, 190, 255), color, opacity, contour, noise, mode, spread, size, knockout, merge])
        if type(color) != gimpcolor.RGB:
          shelf[self.shelfkey] = {"filltype":0,
            "color":color,
            "gradient":"FG to BG (RGB)",
            "opacity":opacity,
            "contour":contour,
            "noise":noise,
            "mode":mode,
            "spread":spread,
            "size":size,
            "knockout":knockout,
            "merge":merge}
        else:
          shelf[self.shelfkey] = {"filltype":1,
            "color":gimpcolor.RGB(255, 255, 190, 255),
            "gradient":color,
            "opacity":opacity,
            "contour":contour,
            "noise":noise,
            "mode":mode,
            "spread":spread,
            "size":size,
            "knockout":knockout,
            "merge":merge}
    elif runmode == RUN_WITH_LAST_VALS and shelf.has_key(self.shelfkey) == 1:
      self.removeOldLayer()
      if shelf[self.shelfkey]["filltype"] == 0:
        fxlayer = self.makeGlow(img,
          drawable,
          shelf[self.shelfkey]["color"],
          shelf[self.shelfkey]["opacity"],
          shelf[self.shelfkey]["contour"],
          shelf[self.shelfkey]["noise"],
          shelf[self.shelfkey]["mode"],
          shelf[self.shelfkey]["spread"],
          shelf[self.shelfkey]["size"],
          shelf[self.shelfkey]["knockout"],
          shelf[self.shelfkey]["merge"])
        if shelf[self.shelfkey]["merge"] == 0:
          self.writeParasiteRaw(drawable, fxlayer, [
            shelf[self.shelfkey]["filltype"],
            shelf[self.shelfkey]["color"],
            shelf[self.shelfkey]["gradient"],
            shelf[self.shelfkey]["opacity"],
            shelf[self.shelfkey]["contour"],
            shelf[self.shelfkey]["noise"],
            shelf[self.shelfkey]["mode"],
            shelf[self.shelfkey]["spread"],
            shelf[self.shelfkey]["size"],
            shelf[self.shelfkey]["knockout"],
            shelf[self.shelfkey]["merge"]
          ])
      else:
        fxlayer = self.makeGlow(img,
          drawable,
          shelf[self.shelfkey]["gradient"],
          shelf[self.shelfkey]["opacity"],
          shelf[self.shelfkey]["contour"],
          shelf[self.shelfkey]["noise"],
          shelf[self.shelfkey]["mode"],
          shelf[self.shelfkey]["spread"],
          shelf[self.shelfkey]["size"],
          shelf[self.shelfkey]["knockout"],
          shelf[self.shelfkey]["merge"])
        if shelf[self.shelfkey]["merge"] == 0:
          self.writeParasiteRaw(drawable, fxlayer, [
            shelf[self.shelfkey]["filltype"],
            shelf[self.shelfkey]["color"],
            shelf[self.shelfkey]["gradient"],
            shelf[self.shelfkey]["opacity"],
            shelf[self.shelfkey]["contour"],
            shelf[self.shelfkey]["noise"],
            shelf[self.shelfkey]["mode"],
            shelf[self.shelfkey]["spread"],
            shelf[self.shelfkey]["size"],
            shelf[self.shelfkey]["knockout"],
            shelf[self.shelfkey]["merge"]
          ])
    else:
      pdb.gimp_message("unknown runmode")
    pdb.gimp_message_set_handler(self.origMsgHandler)

  def showDialog(self):
    self.dialog = gimpui.Dialog("Outer Glow", "outerglowdialog")

    self.parasitedata = self.readParasite(self.img, self.drawable)

    self.table = gtk.Table(7, 5, True)
    self.table.set_homogeneous(True)
    self.table.set_row_spacings(3)
    self.table.set_col_spacings(3)
    self.table.show()

    self.color_label = self.make_label("_Color:")
    self.table.attach(self.color_label, 0, 1, 0, 1)

    self.color_radio = gtk.RadioButton(None, None)
    self.color_radio.set_alignment(1.0, 0.5)
    self.gradient_radio = gtk.RadioButton(self.color_radio, None)
    self.gradient_radio.set_alignment(1.0, 0.5)
    if self.parasitedata:
      if self.parasitedata["filltype"] == 1:
        self.gradient_radio.set_active(True)
      else:
        self.color_radio.set_active(True)
    elif shelf.has_key(self.shelfkey) == 1:
      if shelf[self.shelfkey]["filltype"] == 1:
        self.gradient_radio.set_active(True)
      else:
        self.color_radio.set_active(True)
    else:
      self.color_radio.set_active(True)
    self.color_radio.show()
    self.gradient_radio.show()
    self.color_radio.connect("toggled", self.preview)
    self.gradient_radio.connect("toggled", self.preview)

    self.color_button = gimpui.ColorButton("Glow Color", 80, 0, gimpcolor.RGB(255, 255, 190, 255))
    if self.parasitedata:
      self.color_button.set_color(self.parasitedata["color"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.color_button.set_color(shelf[self.shelfkey]["color"])
    self.color_label.set_mnemonic_widget(self.color_button)
    self.color_button.show()
    self.color_button.connect("color-changed", self.preview)

    self.gradient_button = gimpui.GradientSelector()
    if self.parasitedata:
      self.gradient_button.set_gradient(self.parasitedata["gradient"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.gradient_button.set_gradient(shelf[self.shelfkey]["gradient"])
    self.gradient_button.show()
    self.gradient_button.connect("gradient-set", self.preview)

    self.color_hbox = gtk.HBox(False, 3)
    self.color_hbox.add(self.color_radio)
    self.color_hbox.add(self.color_button)
    self.color_hbox.show()

    self.gradient_hbox = gtk.HBox(False, 3)
    self.gradient_hbox.add(self.gradient_radio)
    self.gradient_hbox.add(self.gradient_button)
    self.gradient_hbox.show()

    self.table.attach(self.color_hbox, 1, 3, 0, 1)
    self.table.attach(self.gradient_hbox, 3, 5, 0, 1)

    self.mode_label = self.make_label("_Blend Mode:")
    self.table.attach(self.mode_label, 0, 1, 1, 2)

    self.mode_box = self.make_blend_mode_box()
    if self.parasitedata:
      self.blend_mode_box_set(self.mode_box, self.parasitedata["mode"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.blend_mode_box_set(self.mode_box, shelf[self.shelfkey]["mode"])
    else:
      self.mode_box.set_active(4)
    self.mode_label.set_mnemonic_widget(self.mode_box)
    self.mode_box.show()
    self.table.attach(self.mode_box, 1, 5, 1, 2)
    self.mode_box.connect("changed", self.preview)

    self.opacity_label = self.make_label("_Opacity:")
    self.table.attach(self.opacity_label, 0, 1, 2, 3)

    self.opacity_slider = self.make_slider_and_spinner(75.0, 0.0, 100.0, 1.0, 10.0, 1)
    if self.parasitedata:
      self.opacity_slider["adj"].set_value(self.parasitedata["opacity"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.opacity_slider["adj"].set_value(shelf[self.shelfkey]["opacity"])
    self.opacity_label.set_mnemonic_widget(self.opacity_slider["spinner"])
    self.table.attach(self.opacity_slider["slider"], 1, 4, 2, 3)
    self.table.attach(self.opacity_slider["spinner"], 4, 5, 2, 3)
    self.opacity_slider["adj"].connect("value-changed", self.preview)

    self.spread_label = self.make_label("_Spread:")
    self.table.attach(self.spread_label, 0, 1, 3, 4)

    self.spread_slider = self.make_slider_and_spinner(0.0, 0.0, 100.0, 1.0, 10.0, 1)
    if self.parasitedata:
      self.spread_slider["adj"].set_value(self.parasitedata["spread"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.spread_slider["adj"].set_value(shelf[self.shelfkey]["spread"])
    self.spread_label.set_mnemonic_widget(self.spread_slider["spinner"])
    self.table.attach(self.spread_slider["slider"], 1, 4, 3, 4)
    self.table.attach(self.spread_slider["spinner"], 4, 5, 3, 4)
    self.spread_slider["adj"].connect("value-changed", self.preview)

    self.size_label = self.make_label("S_ize:")
    self.table.attach(self.size_label, 0, 1, 4, 5)

    self.size_slider = self.make_slider_and_spinner(5, 0, 250, 1, 10, 0)
    if self.parasitedata:
      self.size_slider["adj"].set_value(self.parasitedata["size"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.size_slider["adj"].set_value(shelf[self.shelfkey]["size"])
    self.size_label.set_mnemonic_widget(self.size_slider["spinner"])
    self.table.attach(self.size_slider["slider"], 1, 4, 4, 5)
    self.table.attach(self.size_slider["spinner"], 4, 5, 4, 5)
    self.size_slider["adj"].connect("value-changed", self.preview)

    self.contour_label = self.make_label("Con_tour:")
    self.table.attach(self.contour_label, 0, 1, 5, 6)

    self.contour_box = self.make_contour_box()
    if self.parasitedata:
      self.contour_box.set_active(self.parasitedata["contour"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.contour_box.set_active(shelf[self.shelfkey]["contour"])
    else:
      self.contour_box.set_active(0)
    self.contour_label.set_mnemonic_widget(self.contour_box)
    self.contour_box.show()
    self.table.attach(self.contour_box, 1, 5, 5, 6)
    self.contour_box.connect("changed", self.preview)

    self.noise_label = self.make_label("_Noise:")
    self.table.attach(self.noise_label, 0, 1, 6, 7)

    self.noise_slider = self.make_slider_and_spinner(0.0, 0.0, 100.0, 1.0, 10.0, 1)
    if self.parasitedata:
      self.noise_slider["adj"].set_value(self.parasitedata["noise"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.noise_slider["adj"].set_value(shelf[self.shelfkey]["noise"])
    self.noise_label.set_mnemonic_widget(self.noise_slider["spinner"])
    self.table.attach(self.noise_slider["slider"], 1, 4, 6, 7)
    self.table.attach(self.noise_slider["spinner"], 4, 5, 6, 7)
    self.noise_slider["adj"].connect("value-changed", self.preview)

    self.knockout_check = gtk.CheckButton("Layer _knocks out Outer Glow")
    if self.parasitedata:
      if self.parasitedata["knockout"] == 1:
        self.knockout_check.set_active(True)
    elif shelf.has_key(self.shelfkey) == 1 and shelf[self.shelfkey]["knockout"] == 1:
      self.knockout_check.set_active(True)
    self.knockout_check.show()
    self.knockout_check.connect("toggled", self.preview)

    self.merge_check = gtk.CheckButton("_Merge with layer")
    if self.parasitedata:
      if self.parasitedata["merge"] == 1:
        self.merge_check.set_active(True)
    elif shelf.has_key(self.shelfkey) == 1 and shelf[self.shelfkey]["merge"] == 1:
      self.merge_check.set_active(True)
    self.merge_check.show()
    self.merge_check.connect("toggled", self.preview)

    self.preview_check = gtk.CheckButton("_Preview")
    self.preview_check.show()
    self.preview_check.connect("toggled", self.preview)

    self.dialog.vbox.hbox1 = gtk.HBox(False, 7)
    self.dialog.vbox.hbox1.show()
    self.dialog.vbox.pack_start(self.dialog.vbox.hbox1, True, True, 7)
    self.dialog.vbox.hbox1.pack_start(self.table, True, True, 7)
    self.dialog.vbox.hbox2 = gtk.HBox(False, 7)
    self.dialog.vbox.hbox2.show()
    self.dialog.vbox.add(self.dialog.vbox.hbox2)
    self.dialog.vbox.hbox2.pack_start(self.knockout_check, True, True, 10)
    self.dialog.vbox.hbox3 = gtk.HBox(False, 7)
    self.dialog.vbox.hbox3.show()
    self.dialog.vbox.add(self.dialog.vbox.hbox3)
    self.dialog.vbox.hbox3.pack_start(self.merge_check, True, True, 10)
    self.dialog.vbox.hbox4 = gtk.HBox(False, 7)
    self.dialog.vbox.hbox4.show()
    self.dialog.vbox.add(self.dialog.vbox.hbox4)
    self.dialog.vbox.hbox4.pack_start(self.preview_check, True, True, 10)

    reset_button = gtk.Button("_Reset")
    reset_button.connect("clicked", self.resetbutton)
    reset_button.show()

    if gtk.alternative_dialog_button_order():
      ok_button = self.dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
      cancel_button = self.dialog.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
      self.dialog.action_area.add(reset_button)
    else:
      self.dialog.action_area.add(reset_button)
      cancel_button = self.dialog.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
      ok_button = self.dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
    ok_button.connect("clicked", self.okbutton)

    self.dialog.show()
    self.dialog.run()
    self.removePreviews()

  def okbutton(self, widget):
    if self.layer_exists(self.previewLayer):
      self.img.remove_layer(self.previewLayer)
      self.previewLayer = None
    if self.color_radio.get_active():
      filltype = 0
    elif self.gradient_radio.get_active():
      filltype = 1
    if self.knockout_check.get_active():
      knockout = 1
    else:
      knockout = 0
    if self.merge_check.get_active():
      merge = 1
    else:
      merge = 0
    shelf[self.shelfkey] = {"filltype":filltype,
      "color":self.color_button.get_color(),
      "gradient":self.gradient_button.get_gradient(),
      "opacity":self.opacity_slider["adj"].get_value(),
      "contour":self.contour_box.get_active(),
      "noise":self.noise_slider["adj"].get_value(),
      "mode":self.mode_list[self.mode_box.get_active()],
      "spread":self.spread_slider["adj"].get_value(),
      "size":int(round(self.size_slider["adj"].get_value())),
      "knockout":knockout,
      "merge":merge}
    self.removeOldLayer()
    if filltype == 0:
      fxlayer = self.makeGlow(self.img,
        self.drawable,
        shelf[self.shelfkey]["color"],
        shelf[self.shelfkey]["opacity"],
        shelf[self.shelfkey]["contour"],
        shelf[self.shelfkey]["noise"],
        shelf[self.shelfkey]["mode"],
        shelf[self.shelfkey]["spread"],
        shelf[self.shelfkey]["size"],
        shelf[self.shelfkey]["knockout"],
        shelf[self.shelfkey]["merge"])
    else:
      fxlayer = self.makeGlow(self.img,
        self.drawable,
        shelf[self.shelfkey]["gradient"],
        shelf[self.shelfkey]["opacity"],
        shelf[self.shelfkey]["contour"],
        shelf[self.shelfkey]["noise"],
        shelf[self.shelfkey]["mode"],
        shelf[self.shelfkey]["spread"],
        shelf[self.shelfkey]["size"],
        shelf[self.shelfkey]["knockout"],
        shelf[self.shelfkey]["merge"])
    if merge == 0:
      self.writeParasite(self.drawable, fxlayer, [
        ["radio", (self.color_radio, self.gradient_radio)],
        ["color", self.color_button],
        ["gradient", self.gradient_button],
        ["floatadj", self.opacity_slider["adj"]],
        ["combobox", self.contour_box],
        ["floatadj", self.noise_slider["adj"]],
        ["modebox", self.mode_box],
        ["floatadj", self.spread_slider["adj"]],
        ["intadj", self.size_slider["adj"]],
        ["check", self.knockout_check],
        ["check", self.merge_check]
      ])

  def resetbutton(self, widget):
    self.color_radio.set_active(True)
    self.color_button.set_color(gimpcolor.RGB(255, 255, 190, 255))
    self.gradient_button.set_gradient("FG to BG (RGB)")
    self.mode_box.set_active(4)
    self.opacity_slider["adj"].set_value(75.0)
    self.spread_slider["adj"].set_value(0.0)
    self.size_slider["adj"].set_value(5)
    self.contour_box.set_active(0)
    self.noise_slider["adj"].set_value(0.0)
    self.knockout_check.set_active(False)
    self.merge_check.set_active(False)

  def readParasite(self, img, drawable):
    return layerfx_base.readParasite(self, img, drawable, [
      ["filltype", "int"],
      ["color", "color"],
      ["gradient", "string"],
      ["opacity", "float"],
      ["contour", "int"],
      ["noise", "float"],
      ["mode", "int"],
      ["spread", "float"],
      ["size", "int"],
      ["knockout", "int"],
      ["merge", "int"]
    ], layerfx_outer_glow.shelfkey)

  def preview(self, widget, *extra):
    if self.preview_check.get_active():
      if self.layer_exists(self.previewLayer):
        self.img.remove_layer(self.previewLayer)
      if self.parasitedata:
        self.set_hidden_layer(self.parasitedata["oldid"])
      if self.color_radio.get_active():
        filltype = 0
      elif self.gradient_radio.get_active():
        filltype = 1
      if self.knockout_check.get_active():
        knockout = 1
      else:
        knockout = 0
      if filltype == 0:
        self.previewLayer = self.makeGlow(self.img,
          self.drawable,
          self.color_button.get_color(),
          self.opacity_slider["adj"].get_value(),
          self.contour_box.get_active(),
          self.noise_slider["adj"].get_value(),
          self.mode_list[self.mode_box.get_active()],
          self.spread_slider["adj"].get_value(),
          int(round(self.size_slider["adj"].get_value())),
          knockout,
          0)
      else:
        self.previewLayer = self.makeGlow(self.img,
          self.drawable,
          self.gradient_button.get_gradient(),
          self.opacity_slider["adj"].get_value(),
          self.contour_box.get_active(),
          self.noise_slider["adj"].get_value(),
          self.mode_list[self.mode_box.get_active()],
          self.spread_slider["adj"].get_value(),
          int(round(self.size_slider["adj"].get_value())),
          knockout,
          0)

  def makeGlow(self, img, drawable, color, opacity, contour, noise, mode, spread, size, knockout, merge):
    pdb.gimp_image_undo_group_start(img)
    origfgcolor = gimp.get_foreground()
    origgradient = pdb.gimp_context_get_gradient()
    origselection = pdb.gimp_selection_save(img)
    growamt = (spread / 100.0) * size
    steps = int(round(size - growamt))
    lyrgrowamt = int(round(size * 1.2))
    glowlayer = gimp.Layer(img, "%s-outerglow" % (drawable.name), drawable.width + (lyrgrowamt * 2), drawable.height + (lyrgrowamt * 2), (RGBA_IMAGE, GRAYA_IMAGE)[img.base_type], opacity, mode)
    self.add_under_layer(glowlayer, drawable)
    glowlayer.set_offsets(drawable.offsets[0] - lyrgrowamt, drawable.offsets[1] - lyrgrowamt)
    pdb.gimp_selection_none(img)
    if type(color) == gimpcolor.RGB:
      gimp.set_foreground(color)
      pdb.gimp_edit_fill(glowlayer, FOREGROUND_FILL)
      glowmask = glowlayer.create_mask(ADD_BLACK_MASK)
      glowlayer.add_mask(glowmask)
    else:
      gimp.set_foreground(0, 0, 0)
      pdb.gimp_edit_fill(glowlayer, FOREGROUND_FILL)
      glowmask = glowlayer
    pdb.gimp_selection_layer_alpha(drawable)
    if drawable.mask != None:
      pdb.gimp_selection_combine(drawable.mask, CHANNEL_OP_INTERSECT)
    alphaSel = pdb.gimp_selection_save(img)
    if steps > 0:
      self.draw_blurshape(glowmask, steps, size, alphaSel, False)
    else:
      pdb.gimp_selection_grow(img, growamt)
      gimp.set_foreground(255, 255, 255)
      pdb.gimp_edit_fill(glowmask, FOREGROUND_FILL)
    pdb.gimp_selection_none(img)
    if contour > 0:
      self.apply_contour(glowmask, HISTOGRAM_VALUE, contour)
      pdb.gimp_selection_load(alphaSel)
      pdb.gimp_selection_grow(img, size)
      pdb.gimp_selection_invert(img)
      gimp.set_foreground(0, 0, 0)
      pdb.gimp_edit_fill(glowmask, FOREGROUND_FILL)
      pdb.gimp_selection_none(img)
    if noise > 0:
      self.apply_noise(drawable, glowlayer, noise, type(color) != gimpcolor.RGB)
    if knockout == 1 and type(color) == gimpcolor.RGB:
      gimp.set_foreground(0, 0, 0)
      pdb.gimp_selection_load(alphaSel)
      pdb.gimp_edit_fill(glowmask, FOREGROUND_FILL)
    if type(color) != gimpcolor.RGB:
      gimp.set_foreground(origfgcolor)
      pdb.gimp_context_set_gradient(color)
      pdb.gimp_selection_none(img)
      pdb.gimp_invert(glowlayer)
      pdb.plug_in_gradmap(img, glowlayer)
      if glowlayer.mask != None:
        glowlayer.remove_mask(MASK_APPLY)
      glowlayer.add_mask(glowlayer.create_mask(ADD_BLACK_MASK))
      pdb.gimp_selection_all(img)
      gimp.set_foreground(255, 255, 255)
      pdb.gimp_edit_fill(glowlayer.mask, FOREGROUND_FILL)
      glowlayer.remove_mask(MASK_APPLY)
      pdb.gimp_context_set_gradient(origgradient)
      pdb.gimp_selection_load(alphaSel)
      if knockout == 1:
        pdb.gimp_edit_clear(glowlayer)
      pdb.gimp_selection_grow(img, size)
      pdb.gimp_selection_invert(img)
      pdb.gimp_edit_clear(glowlayer)
    else:
      glowlayer.remove_mask(MASK_APPLY)
    pdb.gimp_selection_none(img)
    if merge == 1:
      origmask = drawable.mask
      layername = drawable.name
      if origmask != None:
        drawable.remove_mask(MASK_APPLY)
      glowlayer = pdb.gimp_image_merge_down(img, drawable, EXPAND_AS_NECESSARY)
      glowlayer.name = layername
    else:
      pdb.gimp_image_set_active_layer(img, drawable)
    gimp.set_foreground(origfgcolor)
    pdb.gimp_selection_load(origselection)
    img.remove_channel(alphaSel)
    img.remove_channel(origselection)
    gimp.displays_flush()
    pdb.gimp_image_undo_group_end(img)
    return glowlayer

class layerfx_inner_glow(layerfx_base):
  shelfkey = "layerfx-inner-glow"

  def __init__(self, runmode, img, drawable, color, opacity, contour, noise, mode, source, choke, size, merge):
    self.origMsgHandler = pdb.gimp_message_get_handler()
    pdb.gimp_message_set_handler(ERROR_CONSOLE)
    self.img = img
    self.drawable = drawable
    if runmode == RUN_INTERACTIVE:
      self.showDialog()
    elif runmode == RUN_NONINTERACTIVE:
      if self.validatedata(img, drawable, [
        ["color/gradient", color],
        ["percent", opacity],
        ["contour", contour],
        ["percent", noise],
        ["mode", mode],
        ["boolean", source],
        ["percent", choke],
        ["size", size],
        ["boolean", merge]
      ]):
        self.removeOldLayer()
        fxlayer = self.makeGlow(img, drawable, color, opacity, contour, noise, mode, source, choke, size, merge)
        if merge == 0:
          if type(color) == gimpcolor.RGB:
            self.writeParasiteRaw(drawable, fxlayer, [0, color, "FG to BG (RGB)", opacity, contour, noise, mode, source, choke, size, merge])
          else:
            self.writeParasiteRaw(drawable, fxlayer, [1, gimpcolor.RGB(255, 255, 190, 255), color, opacity, contour, noise, mode, source, choke, size, merge])
        if type(color) != gimpcolor.RGB:
          shelf[self.shelfkey] = {"filltype":0,
            "color":color,
            "gradient":"FG to BG (RGB)",
            "opacity":opacity,
            "contour":contour,
            "noise":noise,
            "mode":mode,
            "source":source,
            "choke":choke,
            "size":size,
            "merge":merge}
        else:
          shelf[self.shelfkey] = {"filltype":1,
            "color":gimpcolor.RGB(255, 255, 190, 255),
            "gradient":color,
            "opacity":opacity,
            "contour":contour,
            "noise":noise,
            "mode":mode,
            "source":source,
            "choke":choke,
            "size":size,
            "merge":merge}
    elif runmode == RUN_WITH_LAST_VALS and shelf.has_key(self.shelfkey) == 1:
      self.removeOldLayer()
      if shelf[self.shelfkey]["filltype"] == 0:
        fxlayer = self.makeGlow(img,
          drawable,
          shelf[self.shelfkey]["color"],
          shelf[self.shelfkey]["opacity"],
          shelf[self.shelfkey]["contour"],
          shelf[self.shelfkey]["noise"],
          shelf[self.shelfkey]["mode"],
          shelf[self.shelfkey]["source"],
          shelf[self.shelfkey]["choke"],
          shelf[self.shelfkey]["size"],
          shelf[self.shelfkey]["merge"])
        if shelf[self.shelfkey]["merge"] == 0:
          self.writeParasiteRaw(drawable, fxlayer, [
            shelf[self.shelfkey]["filltype"],
            shelf[self.shelfkey]["color"],
            shelf[self.shelfkey]["gradient"],
            shelf[self.shelfkey]["opacity"],
            shelf[self.shelfkey]["contour"],
            shelf[self.shelfkey]["noise"],
            shelf[self.shelfkey]["mode"],
            shelf[self.shelfkey]["source"],
            shelf[self.shelfkey]["choke"],
            shelf[self.shelfkey]["size"],
            shelf[self.shelfkey]["merge"]
          ])
      else:
        fxlayer = self.makeGlow(img,
          drawable,
          shelf[self.shelfkey]["gradient"],
          shelf[self.shelfkey]["opacity"],
          shelf[self.shelfkey]["contour"],
          shelf[self.shelfkey]["noise"],
          shelf[self.shelfkey]["mode"],
          shelf[self.shelfkey]["source"],
          shelf[self.shelfkey]["choke"],
          shelf[self.shelfkey]["size"],
          shelf[self.shelfkey]["merge"])
        if shelf[self.shelfkey]["merge"] == 0:
          self.writeParasiteRaw(drawable, fxlayer, [
            shelf[self.shelfkey]["filltype"],
            shelf[self.shelfkey]["color"],
            shelf[self.shelfkey]["gradient"],
            shelf[self.shelfkey]["opacity"],
            shelf[self.shelfkey]["contour"],
            shelf[self.shelfkey]["noise"],
            shelf[self.shelfkey]["mode"],
            shelf[self.shelfkey]["source"],
            shelf[self.shelfkey]["choke"],
            shelf[self.shelfkey]["size"],
            shelf[self.shelfkey]["merge"]
          ])
    else:
      pdb.gimp_message("unknown runmode")
    pdb.gimp_message_set_handler(self.origMsgHandler)

  def showDialog(self):
    self.dialog = gimpui.Dialog("Inner Glow", "innerglowdialog")

    self.parasitedata = self.readParasite(self.img, self.drawable)

    self.table = gtk.Table(8, 5, True)
    self.table.set_homogeneous(True)
    self.table.set_row_spacings(3)
    self.table.set_col_spacings(3)
    self.table.show()

    self.color_label = self.make_label("_Color:")
    self.table.attach(self.color_label, 0, 1, 0, 1)

    self.color_radio = gtk.RadioButton(None, None)
    self.color_radio.set_alignment(1.0, 0.5)
    self.gradient_radio = gtk.RadioButton(self.color_radio, None)
    self.gradient_radio.set_alignment(1.0, 0.5)
    if self.parasitedata:
      if self.parasitedata["filltype"] == 1:
        self.gradient_radio.set_active(True)
      else:
        self.color_radio.set_active(True)
    elif shelf.has_key(self.shelfkey) == 1:
      if shelf[self.shelfkey]["filltype"] == 1:
        self.gradient_radio.set_active(True)
      else:
        self.color_radio.set_active(True)
    else:
      self.color_radio.set_active(True)
    self.color_radio.show()
    self.gradient_radio.show()
    self.color_radio.connect("toggled", self.preview)
    self.gradient_radio.connect("toggled", self.preview)

    self.color_button = gimpui.ColorButton("Glow Color", 80, 0, gimpcolor.RGB(255, 255, 190, 255))
    if self.parasitedata:
      self.color_button.set_color(self.parasitedata["color"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.color_button.set_color(shelf[self.shelfkey]["color"])
    self.color_label.set_mnemonic_widget(self.color_button)
    self.color_button.show()
    self.color_button.connect("color-changed", self.preview)

    self.gradient_button = gimpui.GradientSelector()
    if self.parasitedata:
      self.gradient_button.set_gradient(self.parasitedata["gradient"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.gradient_button.set_gradient(shelf[self.shelfkey]["gradient"])
    self.gradient_button.show()
    self.gradient_button.connect("gradient-set", self.preview)

    self.color_hbox = gtk.HBox(False, 3)
    self.color_hbox.add(self.color_radio)
    self.color_hbox.add(self.color_button)
    self.color_hbox.show()

    self.gradient_hbox = gtk.HBox(False, 3)
    self.gradient_hbox.add(self.gradient_radio)
    self.gradient_hbox.add(self.gradient_button)
    self.gradient_hbox.show()

    self.table.attach(self.color_hbox, 1, 3, 0, 1)
    self.table.attach(self.gradient_hbox, 3, 5, 0, 1)

    self.mode_label = self.make_label("_Blend Mode:")
    self.table.attach(self.mode_label, 0, 1, 1, 2)

    self.mode_box = self.make_blend_mode_box()
    if self.parasitedata:
      self.blend_mode_box_set(self.mode_box, self.parasitedata["mode"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.blend_mode_box_set(self.mode_box, shelf[self.shelfkey]["mode"])
    else:
      self.mode_box.set_active(4)
    self.mode_label.set_mnemonic_widget(self.mode_box)
    self.mode_box.show()
    self.table.attach(self.mode_box, 1, 5, 1, 2)
    self.mode_box.connect("changed", self.preview)

    self.opacity_label = self.make_label("_Opacity:")
    self.table.attach(self.opacity_label, 0, 1, 2, 3)

    self.opacity_slider = self.make_slider_and_spinner(75.0, 0.0, 100.0, 1.0, 10.0, 1)
    if self.parasitedata:
      self.opacity_slider["adj"].set_value(self.parasitedata["opacity"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.opacity_slider["adj"].set_value(shelf[self.shelfkey]["opacity"])
    self.opacity_label.set_mnemonic_widget(self.opacity_slider["spinner"])
    self.table.attach(self.opacity_slider["slider"], 1, 4, 2, 3)
    self.table.attach(self.opacity_slider["spinner"], 4, 5, 2, 3)
    self.opacity_slider["adj"].connect("value-changed", self.preview)

    self.source_label = self.make_label("Source:")
    self.table.attach(self.source_label, 0, 1, 3, 4)

    self.source_center_radio = gtk.RadioButton(None, "Cent_er", True)
    self.source_edge_radio = gtk.RadioButton(self.source_center_radio, "Ed_ge", True)
    if self.parasitedata:
      if self.parasitedata["source"] == 0:
        self.source_center_radio.set_active(True)
      elif self.parasitedata["source"] == 1:
        self.source_edge_radio.set_active(True)
    elif shelf.has_key(self.shelfkey) == 1:
      if shelf[self.shelfkey]["source"] == 0:
        self.source_center_radio.set_active(True)
      elif shelf[self.shelfkey]["source"] == 1:
        self.source_edge_radio.set_active(True)
    else:
      self.source_edge_radio.set_active(True)
    self.source_center_radio.show()
    self.table.attach(self.source_center_radio, 1, 2, 3, 4)
    self.source_edge_radio.show()
    self.table.attach(self.source_edge_radio, 2, 3, 3, 4)
    self.source_center_radio.connect("toggled", self.preview)
    self.source_edge_radio.connect("toggled", self.preview)

    self.choke_label = self.make_label("C_hoke:")
    self.table.attach(self.choke_label, 0, 1, 4, 5)

    self.choke_slider = self.make_slider_and_spinner(0.0, 0.0, 100.0, 1.0, 10.0, 1)
    if self.parasitedata:
      self.choke_slider["adj"].set_value(self.parasitedata["choke"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.choke_slider["adj"].set_value(shelf[self.shelfkey]["choke"])
    self.choke_label.set_mnemonic_widget(self.choke_slider["spinner"])
    self.table.attach(self.choke_slider["slider"], 1, 4, 4, 5)
    self.table.attach(self.choke_slider["spinner"], 4, 5, 4, 5)
    self.choke_slider["adj"].connect("value-changed", self.preview)

    self.size_label = self.make_label("S_ize:")
    self.table.attach(self.size_label, 0, 1, 5, 6)

    self.size_slider = self.make_slider_and_spinner(5, 0, 250, 1, 10, 0)
    if self.parasitedata:
      self.size_slider["adj"].set_value(self.parasitedata["size"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.size_slider["adj"].set_value(shelf[self.shelfkey]["size"])
    self.size_label.set_mnemonic_widget(self.size_slider["spinner"])
    self.table.attach(self.size_slider["slider"], 1, 4, 5, 6)
    self.table.attach(self.size_slider["spinner"], 4, 5, 5, 6)
    self.size_slider["adj"].connect("value-changed", self.preview)

    self.contour_label = self.make_label("Con_tour:")
    self.table.attach(self.contour_label, 0, 1, 6, 7)

    self.contour_box = self.make_contour_box()
    if self.parasitedata:
      self.contour_box.set_active(self.parasitedata["contour"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.contour_box.set_active(shelf[self.shelfkey]["contour"])
    else:
      self.contour_box.set_active(0)
    self.contour_label.set_mnemonic_widget(self.contour_box)
    self.contour_box.show()
    self.table.attach(self.contour_box, 1, 5, 6, 7)
    self.contour_box.connect("changed", self.preview)

    self.noise_label = self.make_label("_Noise:")
    self.table.attach(self.noise_label, 0, 1, 7, 8)

    self.noise_slider = self.make_slider_and_spinner(0.0, 0.0, 100.0, 1.0, 10.0, 1)
    if self.parasitedata:
      self.noise_slider["adj"].set_value(self.parasitedata["noise"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.noise_slider["adj"].set_value(shelf[self.shelfkey]["noise"])
    self.noise_label.set_mnemonic_widget(self.noise_slider["spinner"])
    self.table.attach(self.noise_slider["slider"], 1, 4, 7, 8)
    self.table.attach(self.noise_slider["spinner"], 4, 5, 7, 8)
    self.noise_slider["adj"].connect("value-changed", self.preview)

    self.merge_check = gtk.CheckButton("_Merge with layer")
    if self.parasitedata:
      if self.parasitedata["merge"] == 1:
        self.merge_check.set_active(True)
    elif shelf.has_key(self.shelfkey) == 1 and shelf[self.shelfkey]["merge"] == 1:
      self.merge_check.set_active(True)
    self.merge_check.show()
    self.merge_check.connect("toggled", self.preview)

    self.preview_check = gtk.CheckButton("_Preview")
    self.preview_check.show()
    self.preview_check.connect("toggled", self.preview)

    self.dialog.vbox.hbox1 = gtk.HBox(False, 7)
    self.dialog.vbox.hbox1.show()
    self.dialog.vbox.pack_start(self.dialog.vbox.hbox1, True, True, 7)
    self.dialog.vbox.hbox1.pack_start(self.table, True, True, 7)
    self.dialog.vbox.hbox2 = gtk.HBox(False, 7)
    self.dialog.vbox.hbox2.show()
    self.dialog.vbox.add(self.dialog.vbox.hbox2)
    self.dialog.vbox.hbox2.pack_start(self.merge_check, True, True, 10)
    self.dialog.vbox.hbox3 = gtk.HBox(False, 7)
    self.dialog.vbox.hbox3.show()
    self.dialog.vbox.add(self.dialog.vbox.hbox3)
    self.dialog.vbox.hbox3.pack_start(self.preview_check, True, True, 10)

    reset_button = gtk.Button("_Reset")
    reset_button.connect("clicked", self.resetbutton)
    reset_button.show()

    if gtk.alternative_dialog_button_order():
      ok_button = self.dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
      cancel_button = self.dialog.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
      self.dialog.action_area.add(reset_button)
    else:
      self.dialog.action_area.add(reset_button)
      cancel_button = self.dialog.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
      ok_button = self.dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
    ok_button.connect("clicked", self.okbutton)

    self.dialog.show()
    self.dialog.run()
    self.removePreviews()

  def okbutton(self, widget):
    if self.layer_exists(self.previewLayer):
      self.img.remove_layer(self.previewLayer)
      self.previewLayer = None
    self.unset_hidden_layer()
    if self.color_radio.get_active():
      filltype = 0
    elif self.gradient_radio.get_active():
      filltype = 1
    if self.source_center_radio.get_active():
      source = 0
    elif self.source_edge_radio.get_active():
      source = 1
    if self.merge_check.get_active():
      merge = 1
    else:
      merge = 0
    shelf[self.shelfkey] = {"filltype":filltype,
      "color":self.color_button.get_color(),
      "gradient":self.gradient_button.get_gradient(),
      "opacity":self.opacity_slider["adj"].get_value(),
      "contour":self.contour_box.get_active(),
      "noise":self.noise_slider["adj"].get_value(),
      "mode":self.mode_list[self.mode_box.get_active()],
      "source":source,
      "choke":self.choke_slider["adj"].get_value(),
      "size":int(round(self.size_slider["adj"].get_value())),
      "merge":merge}
    if self.parasitedata:
      self.img.remove_layer(self.parasitedata["oldid"])
    if filltype == 0:
      fxlayer = self.makeGlow(self.img,
        self.drawable,
        shelf[self.shelfkey]["color"],
        shelf[self.shelfkey]["opacity"],
        shelf[self.shelfkey]["contour"],
        shelf[self.shelfkey]["noise"],
        shelf[self.shelfkey]["mode"],
        shelf[self.shelfkey]["source"],
        shelf[self.shelfkey]["choke"],
        shelf[self.shelfkey]["size"],
        shelf[self.shelfkey]["merge"])
    else:
      fxlayer = self.makeGlow(self.img,
        self.drawable,
        shelf[self.shelfkey]["gradient"],
        shelf[self.shelfkey]["opacity"],
        shelf[self.shelfkey]["contour"],
        shelf[self.shelfkey]["noise"],
        shelf[self.shelfkey]["mode"],
        shelf[self.shelfkey]["source"],
        shelf[self.shelfkey]["choke"],
        shelf[self.shelfkey]["size"],
        shelf[self.shelfkey]["merge"])
    if merge == 0:
      self.writeParasite(self.drawable, fxlayer, [
        ["radio", (self.color_radio, self.gradient_radio)],
        ["color", self.color_button],
        ["gradient", self.gradient_button],
        ["floatadj", self.opacity_slider["adj"]],
        ["combobox", self.contour_box],
        ["floatadj", self.noise_slider["adj"]],
        ["modebox", self.mode_box],
        ["radio", (self.source_center_radio, self.source_edge_radio)],
        ["floatadj", self.choke_slider["adj"]],
        ["intadj", self.size_slider["adj"]],
        ["check", self.merge_check],
      ])

  def resetbutton(self, widget):
    self.color_radio.set_active(True)
    self.color_button.set_color(gimpcolor.RGB(255, 255, 190, 255))
    self.gradient_button.set_gradient("FG to BG (RGB)")
    self.mode_box.set_active(4)
    self.opacity_slider["adj"].set_value(75.0)
    self.source_edge_radio.set_active(True)
    self.choke_slider["adj"].set_value(0.0)
    self.size_slider["adj"].set_value(5)
    self.contour_box.set_active(0)
    self.noise_slider["adj"].set_value(0.0)
    self.merge_check.set_active(False)

  def readParasite(self, img, drawable):
    return layerfx_base.readParasite(self, img, drawable, [
      ["filltype", "int"],
      ["color", "color"],
      ["gradient", "string"],
      ["opacity", "float"],
      ["contour", "int"],
      ["noise", "float"],
      ["mode", "int"],
      ["source", "int"],
      ["choke", "float"],
      ["size", "int"],
      ["merge", "int"]
    ], layerfx_inner_glow.shelfkey)

  def preview(self, widget, *extra):
    if self.preview_check.get_active():
      if self.layer_exists(self.previewLayer):
        self.img.remove_layer(self.previewLayer)
      self.unset_hidden_layer()
      if self.parasitedata:
        self.set_hidden_layer(self.parasitedata["oldid"])
      if self.color_radio.get_active():
        filltype = 0
      elif self.gradient_radio.get_active():
        filltype = 1
      if self.source_center_radio.get_active():
        source = 0
      elif self.source_edge_radio.get_active():
        source = 1
      if self.merge_check.get_active():
        self.previewLayer = self.drawable.copy()
        self.add_over_layer(self.previewLayer, self.drawable)
        self.set_hidden_layer(self.drawable)
        if filltype == 0:
          self.previewLayer = self.makeGlow(self.img,
            self.previewLayer,
            self.color_button.get_color(),
            self.opacity_slider["adj"].get_value(),
            self.contour_box.get_active(),
            self.noise_slider["adj"].get_value(),
            self.mode_list[self.mode_box.get_active()],
            source,
            self.choke_slider["adj"].get_value(),
            int(round(self.size_slider["adj"].get_value())),
            1)
        else:
          self.previewLayer = self.makeGlow(self.img,
            self.previewLayer,
            self.gradient_button.get_gradient(),
            self.opacity_slider["adj"].get_value(),
            self.contour_box.get_active(),
            self.noise_slider["adj"].get_value(),
            self.mode_list[self.mode_box.get_active()],
            source,
            self.choke_slider["adj"].get_value(),
            int(round(self.size_slider["adj"].get_value())),
            1)
      else:
        if filltype == 0:
          self.previewLayer = self.makeGlow(self.img,
            self.drawable,
            self.color_button.get_color(),
            self.opacity_slider["adj"].get_value(),
            self.contour_box.get_active(),
            self.noise_slider["adj"].get_value(),
            self.mode_list[self.mode_box.get_active()],
            source,
            self.choke_slider["adj"].get_value(),
            int(round(self.size_slider["adj"].get_value())),
            0)
        else:
          self.previewLayer = self.makeGlow(self.img,
            self.drawable,
            self.gradient_button.get_gradient(),
            self.opacity_slider["adj"].get_value(),
            self.contour_box.get_active(),
            self.noise_slider["adj"].get_value(),
            self.mode_list[self.mode_box.get_active()],
            source,
            self.choke_slider["adj"].get_value(),
            int(round(self.size_slider["adj"].get_value())),
            0)

  def makeGlow(self, img, drawable, color, opacity, contour, noise, mode, source, choke, size, merge):
    pdb.gimp_image_undo_group_start(img)
    origfgcolor = gimp.get_foreground()
    origgradient = pdb.gimp_context_get_gradient()
    origselection = pdb.gimp_selection_save(img)
    chokeamt = (choke / 100.0) * size
    steps = int(round(size - chokeamt))
    glowlayer = gimp.Layer(img, "%s-innerglow" % (drawable.name), drawable.width, drawable.height, (RGBA_IMAGE, GRAYA_IMAGE)[img.base_type], opacity, mode)
    self.add_over_layer(glowlayer, drawable)
    glowlayer.set_offsets(drawable.offsets[0], drawable.offsets[1])
    pdb.gimp_selection_none(img)
    if type(color) == gimpcolor.RGB:
      gimp.set_foreground(color)
      pdb.gimp_edit_fill(glowlayer, FOREGROUND_FILL)
      glowmask = glowlayer.create_mask(ADD_BLACK_MASK)
      glowlayer.add_mask(glowmask)
    else:
      if source == 0:
        gimp.set_foreground(0, 0, 0)
      else:
        gimp.set_foreground(255, 255, 255)
      pdb.gimp_edit_fill(glowlayer, FOREGROUND_FILL)
      glowmask = glowlayer
    pdb.gimp_selection_layer_alpha(drawable)
    if drawable.mask != None:
      pdb.gimp_selection_combine(drawable.mask, CHANNEL_OP_INTERSECT)
    alphaSel = pdb.gimp_selection_save(img)
    if source == 1:
      pdb.gimp_selection_none(img)
      gimp.set_foreground(255, 255, 255)
      pdb.gimp_edit_fill(glowmask, FOREGROUND_FILL)
      pdb.gimp_selection_load(alphaSel)
      if steps > 0:
        self.draw_blurshape(glowmask, steps, (chokeamt * -1) - 1, alphaSel, True)
      else:
        pdb.gimp_selection_shrink(img, chokeamt)
        gimp.set_foreground(0, 0, 0)
        pdb.gimp_edit_fill(glowmask, FOREGROUND_FILL)
    else:
      if steps > 0:
        self.draw_blurshape(glowmask, steps, chokeamt * -1, alphaSel, False)
      else:
        pdb.gimp_selection_shrink(img, chokeamt)
        gimp.set_foreground(255, 255, 255)
        pdb.gimp_edit_fill(glowmask, FOREGROUND_FILL)
    pdb.gimp_selection_none(img)
    if contour > 0:
      self.apply_contour(glowmask, HISTOGRAM_VALUE, contour)
    if type(color) == gimpcolor.RGB and source == 1 and merge == 0:
      pdb.gimp_selection_load(alphaSel)
      pdb.gimp_selection_invert(img)
      gimp.set_foreground(0, 0, 0)
      pdb.gimp_edit_fill(glowmask, FOREGROUND_FILL)
    if noise > 0:
      self.apply_noise(drawable, glowlayer, noise, type(color) != gimpcolor.RGB)
    if type(color) != gimpcolor.RGB:
      gimp.set_foreground(origfgcolor)
      pdb.gimp_context_set_gradient(color)
      pdb.gimp_selection_none(img)
      pdb.gimp_invert(glowlayer)
      pdb.plug_in_gradmap(img, glowlayer)
      pdb.gimp_context_set_gradient(origgradient)
      pdb.gimp_selection_load(alphaSel)
      if merge == 0:
        pdb.gimp_selection_invert(img)
        pdb.gimp_edit_clear(glowlayer)
        pdb.gimp_selection_invert(img)
      pdb.gimp_selection_shrink(img, size)
      pdb.gimp_edit_clear(glowlayer)
      if glowlayer.mask != None:
        glowlayer.remove_mask(MASK_APPLY)
    else:
      glowlayer.remove_mask(MASK_APPLY)
    if merge == 1:
      origmask = drawable.mask
      layername = drawable.name
      if origmask != None:
        origmask = drawable.mask.copy()
        drawable.remove_mask(MASK_DISCARD)
      if source == 1 or type(color) != gimpcolor.RGB:
        alphamask = drawable.create_mask(ADD_ALPHA_TRANSFER_MASK)
      glowlayer = pdb.gimp_image_merge_down(img, glowlayer, EXPAND_AS_NECESSARY)
      glowlayer.name = layername
      if source == 1 or type(color) != gimpcolor.RGB:
        glowlayer.add_mask(alphamask)
        glowlayer.remove_mask(MASK_APPLY)
      if origmask != None:
        glowlayer.add_mask(origmask)
    else:
      pdb.gimp_image_set_active_layer(img, drawable)
    gimp.set_foreground(origfgcolor)
    pdb.gimp_selection_load(origselection)
    img.remove_channel(alphaSel)
    img.remove_channel(origselection)
    gimp.displays_flush()
    pdb.gimp_image_undo_group_end(img)
    return glowlayer

class layerfx_bevel_emboss(layerfx_base):
  shelfkey = "layerfx-bevel-emboss"

  def __init__(self, runmode, img, drawable, style, depth, direction, size, soften, angle, altitude, glosscontour, highlightcolor, highlightmode, highlightopacity, shadowcolor, shadowmode, shadowopacity, surfacecontour, use_texture, pattern, scale, tex_depth, invert, merge):
    self.origMsgHandler = pdb.gimp_message_get_handler()
    pdb.gimp_message_set_handler(ERROR_CONSOLE)
    self.img = img
    self.drawable = drawable
    if runmode == RUN_INTERACTIVE:
      self.showDialog()
    elif runmode == RUN_NONINTERACTIVE:
      if self.validatedata(img, drawable, [
        ["intrange", style, 0, 3],
        ["intrange", depth, 1, 65],
        ["boolean", direction],
        ["size", size],
        ["intrange", soften, 0, 16],
        ["angle", angle],
        ["floatrange", altitude, 0.0, 90.0],
        ["contour", glosscontour],
        ["color", highlightcolor],
        ["mode", highlightmode],
        ["percent", highlightopacity],
        ["color", shadowcolor],
        ["mode", shadowmode],
        ["percent", shadowopacity],
        ["contour", surfacecontour],
        ["boolean", use_texture],
        ["pattern", pattern],
        ["floatrange", scale, 1.0, 1000.0],
        ["floatrange", tex_depth, -1000.0, 1000.0],
        ["boolean", invert],
        ["boolean", merge]
      ]):
        self.removeOldLayer()
        fxlayer = self.makeBevel(img, drawable, style, depth, direction, size, soften, angle, altitude, glosscontour, highlightcolor, highlightmode, highlightopacity, shadowcolor, shadowmode, shadowopacity, surfacecontour, use_texture, pattern, scale, tex_depth, invert, merge)
        if merge == 0:
          self.writeParasiteRaw(drawable, fxlayer, [style, depth, direction, size, soften, angle, altitude, glosscontour, highlightcolor, highlightmode, highlightopacity, shadowcolor, shadowmode, shadowopacity, surfacecontour, use_texture, pattern, scale, tex_depth, invert, merge])
        shelf[self.shelfkey] = {"style":style,
          "depth":depth,
          "direction":direction,
          "size":size,
          "soften":soften,
          "angle":angle,
          "altitude":altitude,
          "glosscontour":glosscontour,
          "highlightcolor":highlightcolor,
          "highlightmode":highlightmode,
          "highlightopacity":highlightopacity,
          "shadowcolor":shadowcolor,
          "shadowmode":shadowmode,
          "shadowopacity":shadowopacity,
          "surfacecontour":surfacecontour,
          "use_texture":use_texture,
          "pattern":pattern,
          "scale":scale,
          "tex_depth":tex_depth,
          "invert":invert,
          "merge":merge}
    elif runmode == RUN_WITH_LAST_VALS and shelf.has_key(self.shelfkey) == 1:
      self.removeOldLayer()
      fxlayer = self.makeBevel(img,
        drawable,
        shelf[self.shelfkey]["style"],
        shelf[self.shelfkey]["depth"],
        shelf[self.shelfkey]["direction"],
        shelf[self.shelfkey]["size"],
        shelf[self.shelfkey]["soften"],
        shelf[self.shelfkey]["angle"],
        shelf[self.shelfkey]["altitude"],
        shelf[self.shelfkey]["glosscontour"],
        shelf[self.shelfkey]["highlightcolor"],
        shelf[self.shelfkey]["highlightmode"],
        shelf[self.shelfkey]["highlightopacity"],
        shelf[self.shelfkey]["shadowcolor"],
        shelf[self.shelfkey]["shadowmode"],
        shelf[self.shelfkey]["shadowopacity"],
        shelf[self.shelfkey]["surfacecontour"],
        shelf[self.shelfkey]["use_texture"],
        shelf[self.shelfkey]["pattern"],
        shelf[self.shelfkey]["scale"],
        shelf[self.shelfkey]["tex_depth"],
        shelf[self.shelfkey]["invert"],
        shelf[self.shelfkey]["merge"])
      if shelf[self.shelfkey]["merge"] == 0:
        self.writeParasiteRaw(drawable, fxlayer, [
        shelf[self.shelfkey]["style"],
        shelf[self.shelfkey]["depth"],
        shelf[self.shelfkey]["direction"],
        shelf[self.shelfkey]["size"],
        shelf[self.shelfkey]["soften"],
        shelf[self.shelfkey]["angle"],
        shelf[self.shelfkey]["altitude"],
        shelf[self.shelfkey]["glosscontour"],
        shelf[self.shelfkey]["highlightcolor"],
        shelf[self.shelfkey]["highlightmode"],
        shelf[self.shelfkey]["highlightopacity"],
        shelf[self.shelfkey]["shadowcolor"],
        shelf[self.shelfkey]["shadowmode"],
        shelf[self.shelfkey]["shadowopacity"],
        shelf[self.shelfkey]["surfacecontour"],
        shelf[self.shelfkey]["use_texture"],
        shelf[self.shelfkey]["pattern"],
        shelf[self.shelfkey]["scale"],
        shelf[self.shelfkey]["tex_depth"],
        shelf[self.shelfkey]["invert"],
        shelf[self.shelfkey]["merge"]
      ])
    else:
      pdb.gimp_message("unknown runmode")
    pdb.gimp_message_set_handler(self.origMsgHandler)

  def showDialog(self):
    self.dialog = gimpui.Dialog("Bevel and Emboss", "bevelembossdialog")

    self.parasitedata = self.readParasite(self.img, self.drawable)

    self.structframe = gimpui.Frame("Structure")
    self.structframe.show()

    self.structtable = gtk.Table(6, 6, True)
    self.structtable.set_homogeneous(True)
    self.structtable.set_row_spacings(3)
    self.structtable.set_col_spacings(3)
    self.structtable.show()
    self.structframe.add(self.structtable)

    self.style_label = self.make_label("S_tyle:")
    self.structtable.attach(self.style_label, 0, 2, 0, 1)

    self.style_box = gtk.combo_box_new_text()
    self.style_box.append_text("Outer Bevel")
    self.style_box.append_text("Inner Bevel")
    self.style_box.append_text("Emboss")
    self.style_box.append_text("Pillow Emboss")
    if self.parasitedata:
      self.style_box.set_active(self.parasitedata["style"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.style_box.set_active(shelf[self.shelfkey]["style"])
    else:
      self.style_box.set_active(0)
    self.style_box.show()
    self.style_label.set_mnemonic_widget(self.style_box)
    self.structtable.attach(self.style_box, 2, 6, 0, 1)
    self.style_box.connect("changed", self.preview)

    self.depth_label = self.make_label("_Depth:")
    self.structtable.attach(self.depth_label, 0, 2, 1, 2)

    self.depth_slider = self.make_slider_and_spinner(3, 1, 65, 1, 10, 0)
    if self.parasitedata:
      self.depth_slider["adj"].set_value(self.parasitedata["depth"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.depth_slider["adj"].set_value(shelf[self.shelfkey]["depth"])
    self.depth_label.set_mnemonic_widget(self.depth_slider["spinner"])
    self.structtable.attach(self.depth_slider["slider"], 2, 5, 1, 2)
    self.structtable.attach(self.depth_slider["spinner"], 5, 6, 1, 2)
    self.depth_slider["adj"].connect("value-changed", self.preview)

    self.direction_label = self.make_label("Direction:")
    self.structtable.attach(self.direction_label, 0, 2, 2, 3)

    self.direction_up_radio = gtk.RadioButton(None, "Up", True)
    self.direction_down_radio = gtk.RadioButton(self.direction_up_radio, "Down", True)
    if self.parasitedata:
      if self.parasitedata["direction"] == 0:
        self.direction_up_radio.set_active(True)
      elif self.parasitedata["direction"] == 1:
        self.direction_down_radio.set_active(True)
    elif shelf.has_key(self.shelfkey) == 1:
      if shelf[self.shelfkey]["direction"] == 0:
        self.direction_up_radio.set_active(True)
      elif shelf[self.shelfkey]["direction"] == 1:
        self.direction_down_radio.set_active(True)
    else:
      self.direction_up_radio.set_active(True)
    self.direction_up_radio.show()
    self.structtable.attach(self.direction_up_radio, 2, 3, 2, 3)
    self.direction_down_radio.show()
    self.structtable.attach(self.direction_down_radio, 3, 4, 2, 3)
    self.direction_up_radio.connect("toggled", self.preview)
    self.direction_down_radio.connect("toggled", self.preview)

    self.size_label = self.make_label("S_ize:")
    self.structtable.attach(self.size_label, 0, 2, 3, 4)

    self.size_slider = self.make_slider_and_spinner(5, 0, 250, 1, 10, 0)
    if self.parasitedata:
      self.size_slider["adj"].set_value(self.parasitedata["size"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.size_slider["adj"].set_value(shelf[self.shelfkey]["size"])
    self.size_label.set_mnemonic_widget(self.size_slider["spinner"])
    self.structtable.attach(self.size_slider["slider"], 2, 5, 3, 4)
    self.structtable.attach(self.size_slider["spinner"], 5, 6, 3, 4)
    self.size_slider["adj"].connect("value-changed", self.preview)

    self.soften_label = self.make_label("So_ften:")
    self.structtable.attach(self.soften_label, 0, 2, 4, 5)

    self.soften_slider = self.make_slider_and_spinner(0, 0, 16, 1, 2, 0)
    if self.parasitedata:
      self.soften_slider["adj"].set_value(self.parasitedata["soften"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.soften_slider["adj"].set_value(shelf[self.shelfkey]["soften"])
    self.soften_label.set_mnemonic_widget(self.soften_slider["spinner"])
    self.structtable.attach(self.soften_slider["slider"], 2, 5, 4, 5)
    self.structtable.attach(self.soften_slider["spinner"], 5, 6, 4, 5)
    self.soften_slider["adj"].connect("value-changed", self.preview)

    self.surfacecontour_label = self.make_label("Surface Con_tour:")
    self.structtable.attach(self.surfacecontour_label, 0, 2, 5, 6)

    self.surfacecontour_box = self.make_contour_box()
    if self.parasitedata:
      self.surfacecontour_box.set_active(self.parasitedata["surfacecontour"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.surfacecontour_box.set_active(shelf[self.shelfkey]["surfacecontour"])
    else:
      self.surfacecontour_box.set_active(0)
    self.surfacecontour_label.set_mnemonic_widget(self.surfacecontour_box)
    self.surfacecontour_box.show()
    self.structtable.attach(self.surfacecontour_box, 2, 6, 5, 6)
    self.surfacecontour_box.connect("changed", self.preview)

    self.shadeframe = gimpui.Frame("Shading")
    self.shadeframe.show()

    self.shadetable = gtk.Table(7, 6, True)
    self.shadetable.set_homogeneous(True)
    self.shadetable.set_row_spacings(3)
    self.shadetable.set_col_spacings(3)
    self.shadetable.show()
    self.shadeframe.add(self.shadetable)

    self.angle_label = self.make_label("_Angle:")
    self.shadetable.attach(self.angle_label, 0, 2, 0, 1)

    self.angle_slider = self.make_slider_and_spinner(120.0, -180.0, 180.0, 1.0, 10.0, 1)
    if self.parasitedata:
      self.angle_slider["adj"].set_value(self.parasitedata["angle"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.angle_slider["adj"].set_value(shelf[self.shelfkey]["angle"])
    self.angle_label.set_mnemonic_widget(self.angle_slider["spinner"])
    self.shadetable.attach(self.angle_slider["slider"], 2, 5, 0, 1)
    self.shadetable.attach(self.angle_slider["spinner"], 5, 6, 0, 1)
    self.angle_slider["adj"].connect("value-changed", self.preview)

    self.altitude_label = self.make_label("_Altitude:")
    self.shadetable.attach(self.altitude_label, 0, 2, 1, 2)

    self.altitude_slider = self.make_slider_and_spinner(30.0, 0.0, 90.0, 1.0, 10.0, 1)
    if self.parasitedata:
      self.altitude_slider["adj"].set_value(self.parasitedata["altitude"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.altitude_slider["adj"].set_value(shelf[self.shelfkey]["altitude"])
    self.altitude_label.set_mnemonic_widget(self.altitude_slider["spinner"])
    self.shadetable.attach(self.altitude_slider["slider"], 2, 5, 1, 2)
    self.shadetable.attach(self.altitude_slider["spinner"], 5, 6, 1, 2)
    self.altitude_slider["adj"].connect("value-changed", self.preview)

    self.glosscontour_label = self.make_label("Gloss Con_tour:")
    self.shadetable.attach(self.glosscontour_label, 0, 2, 2, 3)

    self.glosscontour_box = self.make_contour_box()
    if self.parasitedata:
      self.glosscontour_box.set_active(self.parasitedata["glosscontour"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.glosscontour_box.set_active(shelf[self.shelfkey]["glosscontour"])
    else:
      self.glosscontour_box.set_active(0)
    self.glosscontour_label.set_mnemonic_widget(self.glosscontour_box)
    self.glosscontour_box.show()
    self.shadetable.attach(self.glosscontour_box, 2, 6, 2, 3)
    self.glosscontour_box.connect("changed", self.preview)

    self.highlightmode_label = self.make_label("Highlight Mode:")
    self.shadetable.attach(self.highlightmode_label, 0, 2, 3, 4)

    self.highlightmode_box = self.make_blend_mode_box()
    if self.parasitedata:
      self.blend_mode_box_set(self.highlightmode_box, self.parasitedata["highlightmode"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.blend_mode_box_set(self.highlightmode_box, shelf[self.shelfkey]["highlightmode"])
    else:
      self.blend_mode_box_set(self.highlightmode_box, SCREEN_MODE)
    self.highlightmode_label.set_mnemonic_widget(self.highlightmode_box)
    self.highlightmode_box.show()
    self.shadetable.attach(self.highlightmode_box, 2, 4, 3, 4)
    self.highlightmode_box.connect("changed", self.preview)

    self.highlightcolor_label = self.make_label("Color:")
    self.shadetable.attach(self.highlightcolor_label, 4, 5, 3, 4)

    self.highlightcolor_button = gimpui.ColorButton("Highlight Color", 10, 10, gimpcolor.RGB(255, 255, 255, 255))
    if self.parasitedata:
      self.highlightcolor_button.set_color(self.parasitedata["highlightcolor"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.highlightcolor_button.set_color(shelf[self.shelfkey]["highlightcolor"])
    self.highlightcolor_label.set_mnemonic_widget(self.highlightcolor_button)
    self.highlightcolor_button.show()
    self.shadetable.attach(self.highlightcolor_button, 5, 6, 3, 4)
    self.highlightcolor_button.connect("color-changed", self.preview)

    self.highlightopacity_label = self.make_label("Highlight Opacity:")
    self.shadetable.attach(self.highlightopacity_label, 0, 2, 4, 5)

    self.highlightopacity_slider = self.make_slider_and_spinner(75.0, 0.0, 100.0, 1.0, 10.0, 1)
    if self.parasitedata:
      self.highlightopacity_slider["adj"].set_value(self.parasitedata["highlightopacity"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.highlightopacity_slider["adj"].set_value(shelf[self.shelfkey]["highlightopacity"])
    self.highlightopacity_label.set_mnemonic_widget(self.highlightopacity_slider["spinner"])
    self.shadetable.attach(self.highlightopacity_slider["slider"], 2, 5, 4, 5)
    self.shadetable.attach(self.highlightopacity_slider["spinner"], 5, 6, 4, 5)
    self.highlightopacity_slider["adj"].connect("value-changed", self.preview)

    self.shadowmode_label = self.make_label("Shadow Mode:")
    self.shadetable.attach(self.shadowmode_label, 0, 2, 5, 6)

    self.shadowmode_box = self.make_blend_mode_box()
    if self.parasitedata:
      self.blend_mode_box_set(self.shadowmode_box, self.parasitedata["shadowmode"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.blend_mode_box_set(self.shadowmode_box, shelf[self.shelfkey]["shadowmode"])
    else:
      self.blend_mode_box_set(self.shadowmode_box, MULTIPLY_MODE)
    self.shadowmode_label.set_mnemonic_widget(self.shadowmode_box)
    self.shadowmode_box.show()
    self.shadetable.attach(self.shadowmode_box, 2, 4, 5, 6)
    self.shadowmode_box.connect("changed", self.preview)

    self.shadowcolor_label = self.make_label("Color:")
    self.shadetable.attach(self.shadowcolor_label, 4, 5, 5, 6)

    self.shadowcolor_button = gimpui.ColorButton("Shadow Color", 10, 10, gimpcolor.RGB(0, 0, 0, 255))
    if self.parasitedata:
      self.shadowcolor_button.set_color(self.parasitedata["shadowcolor"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.shadowcolor_button.set_color(shelf[self.shelfkey]["shadowcolor"])
    self.shadowcolor_label.set_mnemonic_widget(self.shadowcolor_button)
    self.shadowcolor_button.show()
    self.shadetable.attach(self.shadowcolor_button, 5, 6, 5, 6)
    self.shadowcolor_button.connect("color-changed", self.preview)

    self.shadowopacity_label = self.make_label("Shadow Opacity:")
    self.shadetable.attach(self.shadowopacity_label, 0, 2, 6, 7)

    self.shadowopacity_slider = self.make_slider_and_spinner(75.0, 0.0, 100.0, 1.0, 10.0, 1)
    if self.parasitedata:
      self.shadowopacity_slider["adj"].set_value(self.parasitedata["shadowopacity"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.shadowopacity_slider["adj"].set_value(shelf[self.shelfkey]["shadowopacity"])
    self.shadowopacity_label.set_mnemonic_widget(self.shadowopacity_slider["spinner"])
    self.shadetable.attach(self.shadowopacity_slider["slider"], 2, 5, 6, 7)
    self.shadetable.attach(self.shadowopacity_slider["spinner"], 5, 6, 6, 7)
    self.shadowopacity_slider["adj"].connect("value-changed", self.preview)

    self.textureframe = gimpui.Frame("Texture")
    self.textureframe.show()

    self.texturetable = gtk.Table(4, 6, True)
    self.texturetable.set_homogeneous(True)
    self.texturetable.set_row_spacings(3)
    self.texturetable.set_col_spacings(3)
    self.texturetable.show()
    self.textureframe.add(self.texturetable)

    self.use_texture_check = gtk.CheckButton("Use Texture")
    if self.parasitedata:
      if self.parasitedata["use_texture"] == 1:
        self.use_texture_check.set_active(True)
    elif shelf.has_key(self.shelfkey) == 1 and shelf[self.shelfkey]["use_texture"] == 1:
      self.use_texture_check.set_active(True)
    self.use_texture_check.show()
    self.texturetable.attach(self.use_texture_check, 1, 3, 0, 1)
    self.use_texture_check.connect("toggled", self.preview)

    self.pattern_label = self.make_label("_Pattern:")
    self.texturetable.attach(self.pattern_label, 0, 1, 1, 2)

    self.pattern_hbox = gtk.HBox(False, 15)
    self.pattern_hbox.show()
    self.texturetable.attach(self.pattern_hbox, 1, 4, 1, 2)

    self.pattern_button = gimpui.PatternSelector()
    if self.parasitedata:
      self.pattern_button.set_pattern(self.parasitedata["pattern"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.pattern_button.set_pattern(shelf[self.shelfkey]["pattern"])
    self.pattern_label.set_mnemonic_widget(self.pattern_button)
    self.pattern_button.show()
    self.pattern_hbox.add(self.pattern_button)
    self.pattern_button.connect("pattern-set", self.preview)

    self.invert_check = gtk.CheckButton("_Invert")
    if self.parasitedata:
      if self.parasitedata["invert"] == 1:
        self.invert_check.set_active(True)
    elif shelf.has_key(self.shelfkey) == 1 and shelf[self.shelfkey]["invert"] == 1:
      self.invert_check.set_active(True)
    self.invert_check.show()
    self.pattern_hbox.add(self.invert_check)
    self.invert_check.connect("toggled", self.preview)

    self.scale_label = self.make_label("Scale:")
    self.texturetable.attach(self.scale_label, 0, 1, 2, 3)

    self.scale_slider = self.make_slider_and_spinner(100.0, 1.0, 1000.0, 1.0, 10.0, 1)
    if self.parasitedata:
      self.scale_slider["adj"].set_value(self.parasitedata["scale"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.scale_slider["adj"].set_value(shelf[self.shelfkey]["scale"])
    self.scale_label.set_mnemonic_widget(self.scale_slider["spinner"])
    self.texturetable.attach(self.scale_slider["slider"], 1, 5, 2, 3)
    self.texturetable.attach(self.scale_slider["spinner"], 5, 6, 2, 3)
    self.scale_slider["adj"].connect("value-changed", self.preview)

    self.tex_depth_label = self.make_label("Depth:")
    self.texturetable.attach(self.tex_depth_label, 0, 1, 3, 4)

    self.tex_depth_slider = self.make_slider_and_spinner(100.0, -1000.0, 1000.0, 1.0, 10.0, 1)
    if self.parasitedata:
      self.tex_depth_slider["adj"].set_value(self.parasitedata["tex_depth"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.tex_depth_slider["adj"].set_value(shelf[self.shelfkey]["tex_depth"])
    self.tex_depth_label.set_mnemonic_widget(self.tex_depth_slider["spinner"])
    self.texturetable.attach(self.tex_depth_slider["slider"], 1, 5, 3, 4)
    self.texturetable.attach(self.tex_depth_slider["spinner"], 5, 6, 3, 4)
    self.tex_depth_slider["adj"].connect("value-changed", self.preview)

    self.merge_check = gtk.CheckButton("_Merge with layer")
    if self.parasitedata:
      if self.parasitedata["merge"] == 1:
        self.merge_check.set_active(True)
    elif shelf.has_key(self.shelfkey) == 1 and shelf[self.shelfkey]["merge"] == 1:
      self.merge_check.set_active(True)
    self.merge_check.show()
    self.merge_check.connect("toggled", self.preview)

    self.preview_check = gtk.CheckButton("_Preview")
    self.preview_check.show()
    self.preview_check.connect("toggled", self.preview)

    self.dialog.vbox.hbox1 = gtk.HBox(False, 7)
    self.dialog.vbox.hbox1.show()
    self.dialog.vbox.pack_start(self.dialog.vbox.hbox1, True, True, 7)
    self.dialog.vbox.hbox1.pack_start(self.structframe, True, True, 7)
    self.dialog.vbox.hbox2 = gtk.HBox(False, 7)
    self.dialog.vbox.hbox2.show()
    self.dialog.vbox.add(self.dialog.vbox.hbox2)
    self.dialog.vbox.hbox2.pack_start(self.shadeframe, True, True, 7)
    self.dialog.vbox.hbox3 = gtk.HBox(False, 7)
    self.dialog.vbox.hbox3.show()
    self.dialog.vbox.add(self.dialog.vbox.hbox3)
    self.dialog.vbox.hbox3.pack_start(self.textureframe, True, True, 7)
    self.dialog.vbox.hbox4 = gtk.HBox(False, 7)
    self.dialog.vbox.hbox4.show()
    self.dialog.vbox.add(self.dialog.vbox.hbox4)
    self.dialog.vbox.hbox4.pack_start(self.merge_check, True, True, 10)
    self.dialog.vbox.hbox5 = gtk.HBox(False, 7)
    self.dialog.vbox.hbox5.show()
    self.dialog.vbox.add(self.dialog.vbox.hbox5)
    self.dialog.vbox.hbox5.pack_start(self.preview_check, True, True, 10)

    reset_button = gtk.Button("_Reset")
    reset_button.connect("clicked", self.resetbutton)
    reset_button.show()

    if gtk.alternative_dialog_button_order():
      ok_button = self.dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
      cancel_button = self.dialog.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
      self.dialog.action_area.add(reset_button)
    else:
      self.dialog.action_area.add(reset_button)
      cancel_button = self.dialog.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
      ok_button = self.dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
    ok_button.connect("clicked", self.okbutton)

    self.dialog.show()
    self.dialog.run()
    self.removePreviews()

  def okbutton(self, widget):
    if self.previewLayer != None:
      if type(self.previewLayer) == tuple:
        if self.layer_exists(self.previewLayer[0]):
          self.img.remove_layer(self.previewLayer[0])
        if self.layer_exists(self.previewLayer[1]):
          self.img.remove_layer(self.previewLayer[1])
      else:
        if self.layer_exists(self.previewLayer):
          self.img.remove_layer(self.previewLayer)
      self.previewLayer = None
    self.unset_hidden_layer()
    if self.direction_up_radio.get_active():
      direction = 0
    elif self.direction_down_radio.get_active():
      direction = 1
    if self.use_texture_check.get_active():
      use_texture = 1
    else:
      use_texture = 0
    if self.invert_check.get_active():
      invert = 1
    else:
      invert = 0
    if self.merge_check.get_active():
      merge = 1
    else:
      merge = 0
    shelf[self.shelfkey] = {"style":self.style_box.get_active(),
      "depth":int(round(self.depth_slider["adj"].get_value())),
      "direction":direction,
      "size":int(round(self.size_slider["adj"].get_value())),
      "soften":int(round(self.soften_slider["adj"].get_value())),
      "angle":self.angle_slider["adj"].get_value(),
      "altitude":self.altitude_slider["adj"].get_value(),
      "glosscontour":self.glosscontour_box.get_active(),
      "highlightcolor":self.highlightcolor_button.get_color(),
      "highlightmode":self.mode_list[self.highlightmode_box.get_active()],
      "highlightopacity":self.highlightopacity_slider["adj"].get_value(),
      "shadowcolor":self.shadowcolor_button.get_color(),
      "shadowmode":self.mode_list[self.shadowmode_box.get_active()],
      "shadowopacity":self.shadowopacity_slider["adj"].get_value(),
      "surfacecontour":self.surfacecontour_box.get_active(),
      "use_texture":use_texture,
      "pattern":self.pattern_button.get_pattern(),
      "scale":self.scale_slider["adj"].get_value(),
      "tex_depth":self.tex_depth_slider["adj"].get_value(),
      "invert":invert,
      "merge":merge}
    if self.parasitedata:
      self.img.remove_layer(self.parasitedata["oldid"])
      self.img.remove_layer(self.parasitedata["oldid2"])
    fxlayer = self.makeBevel(self.img,
      self.drawable,
      shelf[self.shelfkey]["style"],
      shelf[self.shelfkey]["depth"],
      shelf[self.shelfkey]["direction"],
      shelf[self.shelfkey]["size"],
      shelf[self.shelfkey]["soften"],
      shelf[self.shelfkey]["angle"],
      shelf[self.shelfkey]["altitude"],
      shelf[self.shelfkey]["glosscontour"],
      shelf[self.shelfkey]["highlightcolor"],
      shelf[self.shelfkey]["highlightmode"],
      shelf[self.shelfkey]["highlightopacity"],
      shelf[self.shelfkey]["shadowcolor"],
      shelf[self.shelfkey]["shadowmode"],
      shelf[self.shelfkey]["shadowopacity"],
      shelf[self.shelfkey]["surfacecontour"],
      shelf[self.shelfkey]["use_texture"],
      shelf[self.shelfkey]["pattern"],
      shelf[self.shelfkey]["scale"],
      shelf[self.shelfkey]["tex_depth"],
      shelf[self.shelfkey]["invert"],
      shelf[self.shelfkey]["merge"])
    if merge == 0:
      self.writeParasite(self.drawable, fxlayer, [
        ["combobox", self.style_box],
        ["intadj", self.depth_slider["adj"]],
        ["radio", (self.direction_up_radio, self.direction_down_radio)],
        ["intadj", self.size_slider["adj"]],
        ["intadj", self.soften_slider["adj"]],
        ["floatadj", self.angle_slider["adj"]],
        ["floatadj", self.altitude_slider["adj"]],
        ["combobox", self.glosscontour_box],
        ["color", self.highlightcolor_button],
        ["modebox", self.highlightmode_box],
        ["floatadj", self.highlightopacity_slider["adj"]],
        ["color", self.shadowcolor_button],
        ["modebox", self.shadowmode_box],
        ["floatadj", self.shadowopacity_slider["adj"]],
        ["combobox", self.surfacecontour_box],
        ["check", self.use_texture_check],
        ["pattern", self.pattern_button],
        ["floatadj", self.scale_slider["adj"]],
        ["floatadj", self.tex_depth_slider["adj"]],
        ["check", self.invert_check],
        ["check", self.merge_check]
      ])

  def resetbutton(self, widget):
    self.style_box.set_active(0)
    self.depth_slider["adj"].set_value(3)
    self.direction_up_radio.set_active(True)
    self.size_slider["adj"].set_value(5)
    self.soften_slider["adj"].set_value(0)
    self.surfacecontour_box.set_active(0)
    self.angle_slider["adj"].set_value(120.0)
    self.altitude_slider["adj"].set_value(30.0)
    self.glosscontour_box.set_active(0)
    self.highlightcolor_button.set_color(gimpcolor.RGB(255, 255, 255, 255))
    self.blend_mode_box_set(self.highlightmode_box, SCREEN_MODE)
    self.highlightopacity_slider["adj"].set_value(75.0)
    self.shadowcolor_button.set_color(gimpcolor.RGB(0, 0, 0, 255))
    self.blend_mode_box_set(self.shadowmode_box, MULTIPLY_MODE)
    self.shadowopacity_slider["adj"].set_value(75.0)
    self.use_texture_check.set_active(False)
    self.pattern_button.set_pattern(pdb.gimp_context_get_pattern())
    self.invert_check.set_active(False)
    self.scale_slider["adj"].set_value(100.0)
    self.tex_depth_slider["adj"].set_value(100.0)
    self.merge_check.set_active(False)

  def removeOldLayer(self):
    if not hasattr(self, "parasitedata"):
      self.parasitedata = self.readParasite(self.img, self.drawable)
    if self.parasitedata:
      self.img.remove_layer(self.parasitedata["oldid"])
      self.img.remove_layer(self.parasitedata["oldid2"])

  def preview(self, widget, *extra):
    if self.preview_check.get_active():
      if self.previewLayer != None:
        if type(self.previewLayer) == tuple:
          if self.layer_exists(self.previewLayer[0]):
            self.img.remove_layer(self.previewLayer[0])
          if self.layer_exists(self.previewLayer[1]):
            self.img.remove_layer(self.previewLayer[1])
        else:
          if self.layer_exists(self.previewLayer):
            self.img.remove_layer(self.previewLayer)
      self.unset_hidden_layer()
      if self.parasitedata:
        self.set_hidden_layer(self.parasitedata["oldid"])
        self.set_hidden_layer(self.parasitedata["oldid2"])
      if self.direction_up_radio.get_active():
        direction = 0
      elif self.direction_down_radio.get_active():
        direction = 1
      if self.use_texture_check.get_active():
        use_texture = 1
      else:
        use_texture = 0
      if self.invert_check.get_active():
        invert = 1
      else:
        invert = 0
      if self.merge_check.get_active():
        self.previewLayer = self.drawable.copy()
        self.add_over_layer(self.previewLayer, self.drawable)
        self.set_hidden_layer(self.drawable)
        self.previewLayer = self.makeBevel(self.img,
          self.previewLayer,
          self.style_box.get_active(),
          int(round(self.depth_slider["adj"].get_value())),
          direction,
          int(round(self.size_slider["adj"].get_value())),
          int(round(self.soften_slider["adj"].get_value())),
          self.angle_slider["adj"].get_value(),
          self.altitude_slider["adj"].get_value(),
          self.glosscontour_box.get_active(),
          self.highlightcolor_button.get_color(),
          self.mode_list[self.highlightmode_box.get_active()],
          self.highlightopacity_slider["adj"].get_value(),
          self.shadowcolor_button.get_color(),
          self.mode_list[self.shadowmode_box.get_active()],
          self.shadowopacity_slider["adj"].get_value(),
          self.surfacecontour_box.get_active(),
          use_texture,
          self.pattern_button.get_pattern(),
          self.scale_slider["adj"].get_value(),
          self.tex_depth_slider["adj"].get_value(),
          invert,
          1)
      else:
        self.previewLayer = self.makeBevel(self.img,
          self.drawable,
          self.style_box.get_active(),
          int(round(self.depth_slider["adj"].get_value())),
          direction,
          int(round(self.size_slider["adj"].get_value())),
          int(round(self.soften_slider["adj"].get_value())),
          self.angle_slider["adj"].get_value(),
          self.altitude_slider["adj"].get_value(),
          self.glosscontour_box.get_active(),
          self.highlightcolor_button.get_color(),
          self.mode_list[self.highlightmode_box.get_active()],
          self.highlightopacity_slider["adj"].get_value(),
          self.shadowcolor_button.get_color(),
          self.mode_list[self.shadowmode_box.get_active()],
          self.shadowopacity_slider["adj"].get_value(),
          self.surfacecontour_box.get_active(),
          use_texture,
          self.pattern_button.get_pattern(),
          self.scale_slider["adj"].get_value(),
          self.tex_depth_slider["adj"].get_value(),
          invert,
          0)

  def removePreviews(self):
    if self.previewLayer != None:
      if type(self.previewLayer) == tuple:
        if self.layer_exists(self.previewLayer[0]):
          self.img.remove_layer(self.previewLayer[0])
        if self.layer_exists(self.previewLayer[1]):
          self.img.remove_layer(self.previewLayer[1])
      else:
        if self.layer_exists(self.previewLayer):
          self.img.remove_layer(self.previewLayer)
      self.previewLayer = None
    self.unset_hidden_layer()
    gimp.displays_flush()

  def writeParasite(self, drawable, fxlayer, controls):
    layerfx_base.writeParasite(self, drawable, fxlayer[0], controls)
    drawable.attach_new_parasite("%s-fxlayer-s" % (self.shelfkey), 0, fxlayer[1].name)

  def writeParasiteRaw(self, drawable, fxlayer, values):
    layerfx_base.writeParasiteRaw(self, drawable, fxlayer[0], values)
    drawable.attach_new_parasite("%s-fxlayer-s" % (self.shelfkey), 0, fxlayer[1].name)

  def readParasite(self, img, drawable):
    parasitedata = layerfx_base.readParasite(self, img, drawable, [
      ["style", "int"],
      ["depth", "int"],
      ["direction", "int"],
      ["size", "int"],
      ["soften", "int"],
      ["angle", "float"],
      ["altitude", "float"],
      ["glosscontour", "int"],
      ["highlightcolor", "color"],
      ["highlightmode", "int"],
      ["highlightopacity", "float"],
      ["shadowcolor", "color"],
      ["shadowmode", "int"],
      ["shadowopacity", "float"],
      ["surfacecontour", "int"],
      ["use_texture", "int"],
      ["pattern", "string"],
      ["scale", "float"],
      ["tex_depth", "float"],
      ["invert", "int"],
      ["merge", "int"]
    ], layerfx_bevel_emboss.shelfkey)
    if parasitedata:
      fxlayername = "%s-fxlayer-s" % (self.shelfkey)
      if fxlayername in pdb.gimp_drawable_parasite_list(drawable)[1]:
        fxlayername = pdb.gimp_drawable_parasite_find(drawable, fxlayername).data
        for i in img.layers:
          if i.name == fxlayername:
            parasitedata.update({"oldid2": i})
            break
    return parasitedata

  def makeBevel(self, img, drawable, style, depth, direction, size, soften, angle, altitude, glosscontour, highlightcolor, highlightmode, highlightopacity, shadowcolor, shadowmode, shadowopacity, surfacecontour, use_texture, pattern, scale, tex_depth, invert, merge):
    pdb.gimp_image_undo_group_start(img)
    origfgcolor = gimp.get_foreground()
    origselection = pdb.gimp_selection_save(img)
    imgtype = (RGBA_IMAGE, GRAYA_IMAGE)[img.base_type]
    lyrgrowamt = int(round(size * 1.2))
    if style == 0:
      layersize = {"width":drawable.width + (lyrgrowamt * 2),
                   "height":drawable.height + (lyrgrowamt * 2),
                   "offsetx":drawable.offsets[0] - lyrgrowamt,
                   "offsety":drawable.offsets[1] - lyrgrowamt}
    elif style == 1:
      layersize = {"width":drawable.width,
                   "height":drawable.height,
                   "offsetx":drawable.offsets[0],
                   "offsety":drawable.offsets[1]}
    elif style == 2 or style == 3:
      layersize = {"width":drawable.width + lyrgrowamt,
                   "height":drawable.height + lyrgrowamt,
                   "offsetx":drawable.offsets[0] - int(lyrgrowamt/2),
                   "offsety":drawable.offsets[1] - int(lyrgrowamt/2)}
    bumpmaplayer = gimp.Layer(img, "%s-bumpmap" % (drawable.name), layersize["width"], layersize["height"], imgtype, 100.0, NORMAL_MODE)
    highlightlayer = gimp.Layer(img, "%s-highlight" % (drawable.name), layersize["width"], layersize["height"], imgtype, highlightopacity, highlightmode)
    shadowlayer = gimp.Layer(img, "%s-shadow" % (drawable.name), layersize["width"], layersize["height"], imgtype, shadowopacity, shadowmode)
    self.add_over_layer(bumpmaplayer, drawable)
    self.add_over_layer(shadowlayer, bumpmaplayer)
    self.add_over_layer(highlightlayer, shadowlayer)
    bumpmaplayer.set_offsets(layersize["offsetx"], layersize["offsety"])
    shadowlayer.set_offsets(layersize["offsetx"], layersize["offsety"])
    highlightlayer.set_offsets(layersize["offsetx"], layersize["offsety"])
    pdb.gimp_selection_none(img)
    gimp.set_foreground(highlightcolor)
    pdb.gimp_edit_fill(highlightlayer, FOREGROUND_FILL)
    gimp.set_foreground(shadowcolor)
    pdb.gimp_edit_fill(shadowlayer, FOREGROUND_FILL)
    gimp.set_foreground(0, 0, 0)
    pdb.gimp_edit_fill(bumpmaplayer, FOREGROUND_FILL)
    highlightmask = highlightlayer.create_mask(ADD_BLACK_MASK)
    shadowmask = shadowlayer.create_mask(ADD_BLACK_MASK)
    highlightlayer.add_mask(highlightmask)
    shadowlayer.add_mask(shadowmask)
    pdb.gimp_selection_layer_alpha(drawable)
    if drawable.mask != None:
      pdb.gimp_selection_combine(drawable.mask, CHANNEL_OP_INTERSECT)
    alphaSel = pdb.gimp_selection_save(img)
    if style == 0:
      self.draw_blurshape(bumpmaplayer, size, size, alphaSel, False)
    elif style == 1:
      self.draw_blurshape(bumpmaplayer, size, 0, alphaSel, False)
    elif style == 2:
      halfsizef = int(math.floor(size/2.0))
      halfsizec = size - halfsizef
      self.draw_blurshape(bumpmaplayer, size, int(math.ceil(size/2.0)), alphaSel, False)
    elif style == 3:
      halfsizef = int(math.floor(size/2.0))
      halfsizec = size - halfsizef
      pdb.gimp_selection_none(img)
      gimp.set_foreground(255, 255, 255)
      pdb.gimp_edit_fill(bumpmaplayer, FOREGROUND_FILL)
      self.draw_blurshape(bumpmaplayer, halfsizec, halfsizec, alphaSel, True)
      self.draw_blurshape(bumpmaplayer, halfsizef, 0, alphaSel, False)
    pdb.gimp_selection_none(img)
    if use_texture == 1:
      texturelayer = gimp.Layer(img, "%s-texture" % (drawable.name), int(round(layersize["width"]/(scale/100.0))), int(round(layersize["height"]/(scale/100.0))), imgtype, 100.0, MULTIPLY_MODE)
      self.add_over_layer(texturelayer, bumpmaplayer)
      texturelayer.set_offsets(bumpmaplayer.offsets[0], bumpmaplayer.offsets[1])
      origpattern = pdb.gimp_context_get_pattern()
      pdb.gimp_context_set_pattern(pattern)
      texturelayer.fill(PATTERN_FILL)
      pdb.gimp_context_set_pattern(origpattern)
      if img.base_type == RGB:
        pdb.gimp_desaturate_full(texturelayer, DESATURATE_LUMINOSITY)
      if tex_depth >= 0.0:
        if tex_depth <= 100.0:
          contrastadj = int(round((1-(tex_depth/100.0)) * -127))
        else:
          contrastadj = int(round(((tex_depth-100.0)/900.0) * 127))
      else:
        pdb.gimp_invert(texturelayer)
        if tex_depth >= -100.0:
          contrastadj = int(round((1-(abs(tex_depth)/100.0)) * -127))
        else:
          contrastadj = int(round(((abs(tex_depth)-100.0)/900.0) * 127))
      pdb.gimp_brightness_contrast(texturelayer, 0, contrastadj)
      if scale != 100.0:
        pdb.gimp_drawable_transform_scale(texturelayer, bumpmaplayer.offsets[0], bumpmaplayer.offsets[1], bumpmaplayer.offsets[0] + layersize["width"], bumpmaplayer.offsets[1] + layersize["height"], TRANSFORM_FORWARD, INTERPOLATION_LANCZOS, 1, 3, TRANSFORM_RESIZE_ADJUST)
      bumpmaplayer = pdb.gimp_image_merge_down(img, texturelayer, EXPAND_AS_NECESSARY)
    gimp.set_foreground(127, 127, 127)
    pdb.gimp_edit_fill(highlightmask, FOREGROUND_FILL)
    if surfacecontour > 0:
      self.apply_contour(bumpmaplayer, HISTOGRAM_VALUE, surfacecontour)
    if angle < 0:
      angle += 360.0
    pdb.plug_in_bump_map(img, highlightmask, bumpmaplayer, angle, altitude, depth, 0, 0, 0, 0, 1, direction, 0)
    if glosscontour > 0:
      self.apply_contour(highlightmask, HISTOGRAM_VALUE, glosscontour)
    if soften > 0:
      pdb.plug_in_gauss_rle(img, highlightmask, soften, 1, 1)
    if use_texture == 1 and invert > 0:
      pdb.gimp_invert(highlightmask)
    pdb.gimp_channel_combine_masks(shadowmask, highlightmask, CHANNEL_OP_REPLACE, 0, 0)
    pdb.gimp_levels(highlightmask, HISTOGRAM_VALUE, 127, 255, 1.0, 0, 255)
    pdb.gimp_levels(shadowmask, HISTOGRAM_VALUE, 0, 127, 1.0, 255, 0)
    pdb.gimp_selection_load(alphaSel)
    if style == 0:
      pdb.gimp_selection_grow(img, size)
    elif style == 2 or style == 3:
      pdb.gimp_selection_grow(img, halfsizec)
    pdb.gimp_selection_invert(img)
    gimp.set_foreground(0, 0, 0)
    pdb.gimp_edit_fill(shadowmask, FOREGROUND_FILL)
    pdb.gimp_selection_none(img)
    img.remove_layer(bumpmaplayer)
    if merge == 1:
      if style == 1:
        origmask = drawable.mask
        layername = drawable.name
        if origmask != None:
          origmask = drawable.mask.copy()
          drawable.remove_mask(MASK_DISCARD)
        alphamask = drawable.create_mask(ADD_ALPHA_TRANSFER_MASK)
        shadowlayer = pdb.gimp_image_merge_down(img, shadowlayer, EXPAND_AS_NECESSARY)
        highlightlayer = pdb.gimp_image_merge_down(img, highlightlayer, EXPAND_AS_NECESSARY)
        highlightlayer.name = layername
        highlightlayer.add_mask(alphamask)
        highlightlayer.remove_mask(MASK_APPLY)
        if origmask != None:
          highlightlayer.add_mask(origmask)
      else:
        origmask = drawable.mask
        layername = drawable.name
        if origmask != None:
          drawable.remove_mask(MASK_APPLY)
        shadowlayer = pdb.gimp_image_merge_down(img, shadowlayer, EXPAND_AS_NECESSARY)
        highlightlayer = pdb.gimp_image_merge_down(img, highlightlayer, EXPAND_AS_NECESSARY)
        highlightlayer.name = layername
    else:
      highlightlayer.remove_mask(MASK_APPLY)
      shadowlayer.remove_mask(MASK_APPLY)
      pdb.gimp_image_set_active_layer(img, drawable)
    gimp.set_foreground(origfgcolor)
    pdb.gimp_selection_load(origselection)
    img.remove_channel(alphaSel)
    img.remove_channel(origselection)
    gimp.displays_flush()
    pdb.gimp_image_undo_group_end(img)
    if merge == 0:
      return (highlightlayer, shadowlayer)
    else:
      return highlightlayer

class layerfx_satin(layerfx_base):
  shelfkey = "layerfx-satin"

  def __init__(self, runmode, img, drawable, color, opacity, mode, offsetangle, offsetdist, size, contour, invert, merge):
    self.origMsgHandler = pdb.gimp_message_get_handler()
    pdb.gimp_message_set_handler(ERROR_CONSOLE)
    self.img = img
    self.drawable = drawable
    if runmode == RUN_INTERACTIVE:
      self.showDialog()
    elif runmode == RUN_NONINTERACTIVE:
      if self.validatedata(img, drawable, [
        ["color", color],
        ["percent", opacity],
        ["mode", mode],
        ["angle", offsetangle],
        ["floatrange", offsetdist, 0.0, 30000.0],
        ["size", size],
        ["contour", contour],
        ["boolean", invert],
        ["boolean", merge]
      ]):
        self.removeOldLayer()
        fxlayer = self.makeSatin(img, drawable, color, opacity, mode, offsetangle, offsetdist, size, contour, invert, merge)
        if merge == 0:
          self.writeParasiteRaw(drawable, fxlayer, [color, opacity, mode, offsetangle, offsetdist, size, contour, invert, merge])
        shelf[self.shelfkey] = {"color":color,
          "opacity":opacity,
          "mode":mode,
          "offsetangle":offsetangle,
          "offsetdist":offsetdist,
          "size":size,
          "contour":contour,
          "invert":invert,
          "merge":merge}
    elif runmode == RUN_WITH_LAST_VALS and shelf.has_key(self.shelfkey) == 1:
      self.removeOldLayer()
      fxlayer = self.makeSatin(img,
        drawable,
        shelf[self.shelfkey]["color"],
        shelf[self.shelfkey]["opacity"],
        shelf[self.shelfkey]["mode"],
        shelf[self.shelfkey]["offsetangle"],
        shelf[self.shelfkey]["offsetdist"],
        shelf[self.shelfkey]["size"],
        shelf[self.shelfkey]["contour"],
        shelf[self.shelfkey]["invert"],
        shelf[self.shelfkey]["merge"])
      if shelf[self.shelfkey]["merge"] == 0:
        self.writeParasiteRaw(drawable, fxlayer, [
          shelf[self.shelfkey]["color"],
          shelf[self.shelfkey]["opacity"],
          shelf[self.shelfkey]["mode"],
          shelf[self.shelfkey]["offsetangle"],
          shelf[self.shelfkey]["offsetdist"],
          shelf[self.shelfkey]["size"],
          shelf[self.shelfkey]["contour"],
          shelf[self.shelfkey]["invert"],
          shelf[self.shelfkey]["merge"]
        ])
    else:
      pdb.gimp_message("unknown runmode")
    pdb.gimp_message_set_handler(self.origMsgHandler)

  def showDialog(self):
    self.dialog = gimpui.Dialog("Satin", "satindialog")

    self.parasitedata = self.readParasite(self.img, self.drawable)

    self.table = gtk.Table(7, 5, True)
    self.table.set_homogeneous(True)
    self.table.set_row_spacings(3)
    self.table.set_col_spacings(3)
    self.table.show()

    self.color_label = self.make_label("_Color:")
    self.table.attach(self.color_label, 0, 1, 0, 1)

    self.color_button = gimpui.ColorButton("Satin Color", 10, 10, gimpcolor.RGB(0, 0, 0, 255))
    if self.parasitedata:
      self.color_button.set_color(self.parasitedata["color"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.color_button.set_color(shelf[self.shelfkey]["color"])
    self.color_label.set_mnemonic_widget(self.color_button)
    self.color_button.show()
    self.table.attach(self.color_button, 1, 2, 0, 1)
    self.color_button.connect("color-changed", self.preview)

    self.mode_label = self.make_label("_Blend Mode:")
    self.table.attach(self.mode_label, 0, 1, 1, 2)

    self.mode_box = self.make_blend_mode_box()
    if self.parasitedata:
      self.blend_mode_box_set(self.mode_box, self.parasitedata["mode"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.blend_mode_box_set(self.mode_box, shelf[self.shelfkey]["mode"])
    else:
      self.mode_box.set_active(2)
    self.mode_label.set_mnemonic_widget(self.mode_box)
    self.mode_box.show()
    self.table.attach(self.mode_box, 1, 5, 1, 2)
    self.mode_box.connect("changed", self.preview)

    self.opacity_label = self.make_label("_Opacity:")
    self.table.attach(self.opacity_label, 0, 1, 2, 3)

    self.opacity_slider = self.make_slider_and_spinner(75.0, 0.0, 100.0, 1.0, 10.0, 1)
    if self.parasitedata:
      self.opacity_slider["adj"].set_value(self.parasitedata["opacity"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.opacity_slider["adj"].set_value(shelf[self.shelfkey]["opacity"])
    self.opacity_label.set_mnemonic_widget(self.opacity_slider["spinner"])
    self.table.attach(self.opacity_slider["slider"], 1, 4, 2, 3)
    self.table.attach(self.opacity_slider["spinner"], 4, 5, 2, 3)
    self.opacity_slider["adj"].connect("value-changed", self.preview)

    self.angle_label = self.make_label("_Angle:")
    self.table.attach(self.angle_label, 0, 1, 3, 4)

    self.angle_slider = self.make_slider_and_spinner(19.0, -180.0, 180.0, 1.0, 10.0, 1)
    if self.parasitedata:
      self.angle_slider["adj"].set_value(self.parasitedata["offsetangle"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.angle_slider["adj"].set_value(shelf[self.shelfkey]["offsetangle"])
    self.angle_label.set_mnemonic_widget(self.angle_slider["spinner"])
    self.table.attach(self.angle_slider["slider"], 1, 4, 3, 4)
    self.table.attach(self.angle_slider["spinner"], 4, 5, 3, 4)
    self.angle_slider["adj"].connect("value-changed", self.preview)

    self.distance_label = self.make_label("_Distance:")
    self.table.attach(self.distance_label, 0, 1, 4, 5)

    self.distance_spinner = self.make_spinner(11.0, 0.0, 30000.0, 1.0, 10.0, 1)
    if self.parasitedata:
      self.distance_spinner["adj"].set_value(self.parasitedata["offsetdist"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.distance_spinner["adj"].set_value(shelf[self.shelfkey]["offsetdist"])
    self.distance_label.set_mnemonic_widget(self.distance_spinner["spinner"])
    self.table.attach(self.distance_spinner["spinner"], 1, 2, 4, 5)
    self.distance_spinner["adj"].connect("value-changed", self.preview)

    self.size_label = self.make_label("S_ize:")
    self.table.attach(self.size_label, 0, 1, 5, 6)

    self.size_slider = self.make_slider_and_spinner(14, 0, 250, 1, 10, 0)
    if self.parasitedata:
      self.size_slider["adj"].set_value(self.parasitedata["size"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.size_slider["adj"].set_value(shelf[self.shelfkey]["size"])
    self.size_label.set_mnemonic_widget(self.size_slider["spinner"])
    self.table.attach(self.size_slider["slider"], 1, 4, 5, 6)
    self.table.attach(self.size_slider["spinner"], 4, 5, 5, 6)
    self.size_slider["adj"].connect("value-changed", self.preview)

    self.contour_label = self.make_label("Con_tour:")
    self.table.attach(self.contour_label, 0, 1, 6, 7)

    self.contour_box = self.make_contour_box()
    if self.parasitedata:
      self.contour_box.set_active(self.parasitedata["contour"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.contour_box.set_active(shelf[self.shelfkey]["contour"])
    else:
      self.contour_box.set_active(5)
    self.contour_label.set_mnemonic_widget(self.contour_box)
    self.contour_box.show()
    self.table.attach(self.contour_box, 1, 5, 6, 7)
    self.contour_box.connect("changed", self.preview)

    self.invert_check = gtk.CheckButton("Invert")
    if self.parasitedata:
      if self.parasitedata["contour"] == 0:
        self.invert_check.set_active(False)
    elif shelf.has_key(self.shelfkey) == 1 and shelf[self.shelfkey]["invert"] == 0:
      self.invert_check.set_active(False)
    else:
      self.invert_check.set_active(True)
    self.invert_check.show()
    self.invert_check.connect("toggled", self.preview)

    self.merge_check = gtk.CheckButton("_Merge with layer")
    if self.parasitedata:
      if self.parasitedata["merge"] == 1:
        self.merge_check.set_active(True)
    elif shelf.has_key(self.shelfkey) == 1 and shelf[self.shelfkey]["merge"] == 1:
      self.merge_check.set_active(True)
    self.merge_check.show()
    self.merge_check.connect("toggled", self.preview)

    self.preview_check = gtk.CheckButton("_Preview")
    self.preview_check.show()
    self.preview_check.connect("toggled", self.preview)

    self.dialog.vbox.hbox1 = gtk.HBox(False, 7)
    self.dialog.vbox.hbox1.show()
    self.dialog.vbox.pack_start(self.dialog.vbox.hbox1, True, True, 7)
    self.dialog.vbox.hbox1.pack_start(self.table, True, True, 7)
    self.dialog.vbox.hbox2 = gtk.HBox(False, 7)
    self.dialog.vbox.hbox2.show()
    self.dialog.vbox.add(self.dialog.vbox.hbox2)
    self.dialog.vbox.hbox2.pack_start(self.invert_check, True, True, 10)
    self.dialog.vbox.hbox3 = gtk.HBox(False, 7)
    self.dialog.vbox.hbox3.show()
    self.dialog.vbox.add(self.dialog.vbox.hbox3)
    self.dialog.vbox.hbox3.pack_start(self.merge_check, True, True, 10)
    self.dialog.vbox.hbox4 = gtk.HBox(False, 7)
    self.dialog.vbox.hbox4.show()
    self.dialog.vbox.add(self.dialog.vbox.hbox4)
    self.dialog.vbox.hbox4.pack_start(self.preview_check, True, True, 10)

    reset_button = gtk.Button("_Reset")
    reset_button.connect("clicked", self.resetbutton)
    reset_button.show()

    if gtk.alternative_dialog_button_order():
      ok_button = self.dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
      cancel_button = self.dialog.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
      self.dialog.action_area.add(reset_button)
    else:
      self.dialog.action_area.add(reset_button)
      cancel_button = self.dialog.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
      ok_button = self.dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
    ok_button.connect("clicked", self.okbutton)

    self.dialog.show()
    self.dialog.run()
    self.removePreviews()

  def okbutton(self, widget):
    if self.layer_exists(self.previewLayer):
      self.img.remove_layer(self.previewLayer)
      self.previewLayer = None
    self.unset_hidden_layer()
    if self.invert_check.get_active():
      invert = 1
    else:
      invert = 0
    if self.merge_check.get_active():
      merge = 1
    else:
      merge = 0
    shelf[self.shelfkey] = {"color":self.color_button.get_color(),
      "opacity":self.opacity_slider["adj"].get_value(),
      "mode":self.mode_list[self.mode_box.get_active()],
      "offsetangle":self.angle_slider["adj"].get_value(),
      "offsetdist":self.distance_spinner["adj"].get_value(),
      "size":int(round(self.size_slider["adj"].get_value())),
      "contour":self.contour_box.get_active(),
      "invert":invert,
      "merge":merge}
    if self.parasitedata:
      self.img.remove_layer(self.parasitedata["oldid"])
    fxlayer = self.makeSatin(self.img,
      self.drawable,
      shelf[self.shelfkey]["color"],
      shelf[self.shelfkey]["opacity"],
      shelf[self.shelfkey]["mode"],
      shelf[self.shelfkey]["offsetangle"],
      shelf[self.shelfkey]["offsetdist"],
      shelf[self.shelfkey]["size"],
      shelf[self.shelfkey]["contour"],
      shelf[self.shelfkey]["invert"],
      shelf[self.shelfkey]["merge"])
    if merge == 0:
      self.writeParasite(self.drawable, fxlayer, [
        ["color", self.color_button],
        ["floatadj", self.opacity_slider["adj"]],
        ["modebox", self.mode_box],
        ["floatadj", self.angle_slider["adj"]],
        ["floatadj", self.distance_spinner["adj"]],
        ["intadj", self.size_slider["adj"]],
        ["combobox", self.contour_box],
        ["check", self.invert_check],
        ["check", self.merge_check]
      ])

  def resetbutton(self, widget):
    self.color_button.set_color(gimpcolor.RGB(0, 0, 0, 255))
    self.mode_box.set_active(2)
    self.opacity_slider["adj"].set_value(75.0)
    self.angle_slider["adj"].set_value(19.0)
    self.distance_spinner["adj"].set_value(11.0)
    self.size_slider["adj"].set_value(14)
    self.contour_box.set_active(5)
    self.invert_check.set_active(True)
    self.merge_check.set_active(False)

  def readParasite(self, img, drawable):
    return layerfx_base.readParasite(self, img, drawable, [
      ["color", "color"],
      ["opacity", "float"],
      ["mode", "int"],
      ["offsetangle", "float"],
      ["offsetdist", "float"],
      ["size", "int"],
      ["contour", "int"],
      ["invert", "int"],
      ["merge", "int"]
    ], layerfx_satin.shelfkey)

  def preview(self, widget):
    if self.preview_check.get_active():
      if self.layer_exists(self.previewLayer):
        self.img.remove_layer(self.previewLayer)
      self.unset_hidden_layer()
      if self.parasitedata:
        self.set_hidden_layer(self.parasitedata["oldid"])
      if self.invert_check.get_active():
        invert = 1
      else:
        invert = 0
      if self.merge_check.get_active():
        self.previewLayer = self.drawable.copy()
        self.add_over_layer(self.previewLayer, self.drawable)
        self.set_hidden_layer(self.drawable)
        self.previewLayer = self.makeSatin(self.img,
          self.previewLayer,
          self.color_button.get_color(),
          self.opacity_slider["adj"].get_value(),
          self.mode_list[self.mode_box.get_active()],
          self.angle_slider["adj"].get_value(),
          self.distance_spinner["adj"].get_value(),
          int(round(self.size_slider["adj"].get_value())),
          self.contour_box.get_active(),
          invert,
          1)
      else:
        self.previewLayer = self.makeSatin(self.img,
          self.drawable,
          self.color_button.get_color(),
          self.opacity_slider["adj"].get_value(),
          self.mode_list[self.mode_box.get_active()],
          self.angle_slider["adj"].get_value(),
          self.distance_spinner["adj"].get_value(),
          int(round(self.size_slider["adj"].get_value())),
          self.contour_box.get_active(),
          invert,
          0)

  def makeSatin(self, img, drawable, color, opacity, mode, offsetangle, offsetdist, size, contour, invert, merge):
    pdb.gimp_image_undo_group_start(img)
    origfgcolor = gimp.get_foreground()
    origselection = pdb.gimp_selection_save(img)
    growamt = int(math.ceil(size / 2.0))
    lyrgrowamt = int(round(growamt * 1.2))
    satinlayer = gimp.Layer(img, "%s-satin" % (drawable.name), drawable.width + (lyrgrowamt * 2), drawable.height + (lyrgrowamt * 2), (RGBA_IMAGE, GRAYA_IMAGE)[img.base_type], 100, NORMAL_MODE)
    ang = ((offsetangle + 180) * -1) * (math.pi / 180.0)
    offset = (int(round(offsetdist * math.cos(ang))), int(round(offsetdist * math.sin(ang))))
    self.add_over_layer(satinlayer, drawable)
    satinlayer.set_offsets(drawable.offsets[0] - lyrgrowamt, drawable.offsets[1] - lyrgrowamt)
    pdb.gimp_selection_none(img)
    gimp.set_foreground(0, 0, 0)
    pdb.gimp_edit_fill(satinlayer, FOREGROUND_FILL)
    pdb.gimp_selection_layer_alpha(drawable)
    if drawable.mask != None:
      pdb.gimp_selection_combine(drawable.mask, CHANNEL_OP_INTERSECT)
    alphaSel = pdb.gimp_selection_save(img)
    self.draw_blurshape(satinlayer, size, growamt, alphaSel, False)
    pdb.plug_in_autocrop_layer(img, satinlayer)
    satinmask = satinlayer.copy(0)
    self.add_over_layer(satinmask, satinlayer)
    satinlayer.translate(offset[0], offset[1])
    satinmask.translate(offset[0] * -1, offset[1] * -1)
    dx = max(satinlayer.offsets[0], satinmask.offsets[0]) - min(satinlayer.offsets[0], satinmask.offsets[0])
    dy = max(satinlayer.offsets[1], satinmask.offsets[1]) - min(satinlayer.offsets[1], satinmask.offsets[1])
    blacklayer = gimp.Layer(img, "%s-satinblank" % (drawable.name), satinlayer.width + dx, satinlayer.height + dy, (RGBA_IMAGE, GRAYA_IMAGE)[img.base_type], 100, NORMAL_MODE)
    self.add_under_layer(blacklayer, satinlayer)
    blacklayer.set_offsets(min(satinlayer.offsets[0], satinmask.offsets[0]), min(satinlayer.offsets[1], satinmask.offsets[1]))
    pdb.gimp_selection_none(img)
    gimp.set_foreground(0, 0, 0)
    pdb.gimp_edit_fill(blacklayer, FOREGROUND_FILL)
    satinmask.mode = DIFFERENCE_MODE
    satinlayer = pdb.gimp_image_merge_down(img, satinlayer, EXPAND_AS_NECESSARY)
    satinlayer = pdb.gimp_image_merge_down(img, satinmask, EXPAND_AS_NECESSARY)
    satinlayer.name = "%s-satin" % (drawable.name)
    if contour > 0:
      self.apply_contour(satinlayer, HISTOGRAM_VALUE, contour)
      pdb.gimp_selection_load(alphaSel)
      pdb.gimp_selection_grow(img, size)
      pdb.gimp_selection_invert(img)
      gimp.set_foreground(0, 0, 0)
      pdb.gimp_edit_fill(satinlayer, FOREGROUND_FILL)
      pdb.gimp_selection_none(img)
    if invert == 1:
      pdb.gimp_invert(satinlayer)
    satinmask = satinlayer.create_mask(ADD_COPY_MASK)
    satinlayer.add_mask(satinmask)
    pdb.gimp_selection_none(img)
    gimp.set_foreground(color)
    pdb.gimp_edit_fill(satinlayer, FOREGROUND_FILL)
    satinlayer.opacity = opacity
    satinlayer.mode = mode
    satinlayer.resize(drawable.width, drawable.height, satinlayer.offsets[0] - drawable.offsets[0], satinlayer.offsets[1] - drawable.offsets[1])
    if merge == 1:
      origmask = drawable.mask
      layername = drawable.name
      if origmask != None:
        origmask = drawable.mask.copy()
        drawable.remove_mask(MASK_DISCARD)
      alphamask = drawable.create_mask(ADD_ALPHA_TRANSFER_MASK)
      satinlayer = pdb.gimp_image_merge_down(img, satinlayer, EXPAND_AS_NECESSARY)
      satinlayer.name = layername
      satinlayer.add_mask(alphamask)
      satinlayer.remove_mask(MASK_APPLY)
      if origmask != None:
        satinlayer.add_mask(origmask)
    else:
      pdb.gimp_selection_load(alphaSel)
      pdb.gimp_selection_invert(img)
      gimp.set_foreground(0, 0, 0)
      pdb.gimp_edit_fill(satinmask, FOREGROUND_FILL)
      satinlayer.remove_mask(MASK_APPLY)
      pdb.gimp_image_set_active_layer(img, drawable)
    gimp.set_foreground(origfgcolor)
    pdb.gimp_selection_load(origselection)
    img.remove_channel(alphaSel)
    img.remove_channel(origselection)
    gimp.displays_flush()
    pdb.gimp_image_undo_group_end(img)
    return satinlayer

class layerfx_stroke(layerfx_base):
  shelfkey = "layerfx-stroke"

  def __init__(self, runmode, img, drawable, color, opacity, mode, size, position, merge):
    self.origMsgHandler = pdb.gimp_message_get_handler()
    pdb.gimp_message_set_handler(ERROR_CONSOLE)
    self.img = img
    self.drawable = drawable
    if runmode == RUN_INTERACTIVE:
      self.showDialog()
    elif runmode == RUN_NONINTERACTIVE:
      if self.validatedata(img, drawable, [
        ["color", color],
        ["percent", opacity],
        ["mode", mode],
        ["size", size],
        ["percent", position],
        ["boolean", merge]
      ]):
        self.removeOldLayer()
        fxlayer = self.makeStroke(img, drawable, color, opacity, mode, size, position, merge)
        if merge == 0:
          self.writeParasiteRaw(drawable, fxlayer, [color, opacity, mode, size, position, merge])
        shelf[self.shelfkey] = {"color":color,
          "opacity":opacity,
          "mode":mode,
          "size":size,
          "position":position,
          "merge":merge}
    elif runmode == RUN_WITH_LAST_VALS and shelf.has_key(self.shelfkey) == 1:
      self.removeOldLayer()
      fxlayer = self.makeStroke(img,
        drawable,
        shelf[self.shelfkey]["color"],
        shelf[self.shelfkey]["opacity"],
        shelf[self.shelfkey]["mode"],
        shelf[self.shelfkey]["size"],
        shelf[self.shelfkey]["position"],
        shelf[self.shelfkey]["merge"])
      if shelf[self.shelfkey]["merge"] == 0:
        self.writeParasiteRaw(drawable, fxlayer, [
          shelf[self.shelfkey]["color"],
          shelf[self.shelfkey]["opacity"],
          shelf[self.shelfkey]["mode"],
          shelf[self.shelfkey]["size"],
          shelf[self.shelfkey]["position"],
          shelf[self.shelfkey]["merge"]
        ])
    else:
      pdb.gimp_message("unknown runmode")
    pdb.gimp_message_set_handler(self.origMsgHandler)

  def showDialog(self):
    self.dialog = gimpui.Dialog("Stroke", "strokedialog")

    self.parasitedata = self.readParasite(self.img, self.drawable)

    self.table = gtk.Table(6, 5, True)
    self.table.set_homogeneous(True)
    self.table.set_row_spacings(3)
    self.table.set_col_spacings(3)
    self.table.show()

    self.color_label = self.make_label("_Color:")
    self.table.attach(self.color_label, 0, 1, 0, 1)

    self.color_button = gimpui.ColorButton("Stroke Color", 10, 10, gimpcolor.RGB(255, 0, 0, 255))
    if self.parasitedata:
      self.color_button.set_color(self.parasitedata["color"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.color_button.set_color(shelf[self.shelfkey]["color"])
    self.color_label.set_mnemonic_widget(self.color_button)
    self.color_button.show()
    self.table.attach(self.color_button, 1, 2, 0, 1)
    self.color_button.connect("color-changed", self.preview)

    self.size_label = self.make_label("S_ize:")
    self.table.attach(self.size_label, 0, 1, 1, 2)

    self.size_slider = self.make_slider_and_spinner(3, 1, 250, 1, 10, 0)
    if self.parasitedata:
      self.size_slider["adj"].set_value(self.parasitedata["size"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.size_slider["adj"].set_value(shelf[self.shelfkey]["size"])
    self.size_label.set_mnemonic_widget(self.size_slider["spinner"])
    self.table.attach(self.size_slider["slider"], 1, 4, 1, 2)
    self.table.attach(self.size_slider["spinner"], 4, 5, 1, 2)
    self.size_slider["adj"].connect("value-changed", self.preview)

    self.position_label = self.make_label("Position:")
    self.table.attach(self.position_label, 0, 1, 2, 3)

    self.position_slider = self.make_slider_and_spinner(50.0, 0.0, 100.0, 1, 10, 1)
    if self.parasitedata:
      self.position_slider["adj"].set_value(self.parasitedata["position"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.position_slider["adj"].set_value(shelf[self.shelfkey]["position"])
    self.position_label.set_mnemonic_widget(self.position_slider["spinner"])
    self.table.attach(self.position_slider["slider"], 1, 4, 2, 3)
    self.table.attach(self.position_slider["spinner"], 4, 5, 2, 3)
    self.position_slider["adj"].connect("value-changed", self.preview)

    self.position_label2 = gtk.Label("0 = inside, 100 = outside")
    self.position_label2.set_alignment(0.5, 0.5)
    self.position_label2.show()
    self.table.attach(self.position_label2, 1, 5, 3, 4)

    self.mode_label = self.make_label("_Blend Mode:")
    self.table.attach(self.mode_label, 0, 1, 4, 5)

    self.mode_box = self.make_blend_mode_box()
    if self.parasitedata:
      self.blend_mode_box_set(self.mode_box, self.parasitedata["mode"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.blend_mode_box_set(self.mode_box, shelf[self.shelfkey]["mode"])
    else:
      self.mode_box.set_active(0)
    self.mode_label.set_mnemonic_widget(self.mode_box)
    self.mode_box.show()
    self.table.attach(self.mode_box, 1, 5, 4, 5)
    self.mode_box.connect("changed", self.preview)

    self.opacity_label = self.make_label("_Opacity:")
    self.table.attach(self.opacity_label, 0, 1, 5, 6)

    self.opacity_slider = self.make_slider_and_spinner(75.0, 0.0, 100.0, 1.0, 10.0, 1)
    if self.parasitedata:
      self.opacity_slider["adj"].set_value(self.parasitedata["opacity"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.opacity_slider["adj"].set_value(shelf[self.shelfkey]["opacity"])
    else:
      self.opacity_slider["adj"].set_value(100.0)
    self.opacity_label.set_mnemonic_widget(self.opacity_slider["spinner"])
    self.table.attach(self.opacity_slider["slider"], 1, 4, 5, 6)
    self.table.attach(self.opacity_slider["spinner"], 4, 5, 5, 6)
    self.opacity_slider["adj"].connect("value-changed", self.preview)

    self.merge_check = gtk.CheckButton("_Merge with layer")
    if self.parasitedata:
      if self.parasitedata["merge"] == 1:
        self.merge_check.set_active(True)
    elif shelf.has_key(self.shelfkey) == 1 and shelf[self.shelfkey]["merge"] == 1:
      self.merge_check.set_active(True)
    self.merge_check.show()
    self.merge_check.connect("toggled", self.preview)

    self.preview_check = gtk.CheckButton("_Preview")
    self.preview_check.show()
    self.preview_check.connect("toggled", self.preview)

    self.dialog.vbox.hbox1 = gtk.HBox(False, 7)
    self.dialog.vbox.hbox1.show()
    self.dialog.vbox.pack_start(self.dialog.vbox.hbox1, True, True, 7)
    self.dialog.vbox.hbox1.pack_start(self.table, True, True, 7)
    self.dialog.vbox.hbox2 = gtk.HBox(False, 7)
    self.dialog.vbox.hbox2.show()
    self.dialog.vbox.add(self.dialog.vbox.hbox2)
    self.dialog.vbox.hbox2.pack_start(self.merge_check, True, True, 10)
    self.dialog.vbox.hbox3 = gtk.HBox(False, 7)
    self.dialog.vbox.hbox3.show()
    self.dialog.vbox.add(self.dialog.vbox.hbox3)
    self.dialog.vbox.hbox3.pack_start(self.preview_check, True, True, 10)

    reset_button = gtk.Button("_Reset")
    reset_button.connect("clicked", self.resetbutton)
    reset_button.show()

    if gtk.alternative_dialog_button_order():
      ok_button = self.dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
      cancel_button = self.dialog.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
      self.dialog.action_area.add(reset_button)
    else:
      self.dialog.action_area.add(reset_button)
      cancel_button = self.dialog.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
      ok_button = self.dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
    ok_button.connect("clicked", self.okbutton)

    self.dialog.show()
    self.dialog.run()
    self.removePreviews()

  def okbutton(self, widget):
    if self.layer_exists(self.previewLayer):
      self.img.remove_layer(self.previewLayer)
      self.previewLayer = None
    self.unset_hidden_layer()
    if self.merge_check.get_active():
      merge = 1
    else:
      merge = 0
    shelf[self.shelfkey] = {"color":self.color_button.get_color(),
      "opacity":self.opacity_slider["adj"].get_value(),
      "mode":self.mode_list[self.mode_box.get_active()],
      "size":int(round(self.size_slider["adj"].get_value())),
      "position":self.position_slider["adj"].get_value(),
      "merge":merge}
    if self.parasitedata:
      self.img.remove_layer(self.parasitedata["oldid"])
    fxlayer = self.makeStroke(self.img,
      self.drawable,
      shelf[self.shelfkey]["color"],
      shelf[self.shelfkey]["opacity"],
      shelf[self.shelfkey]["mode"],
      shelf[self.shelfkey]["size"],
      shelf[self.shelfkey]["position"],
      shelf[self.shelfkey]["merge"])
    if merge == 0:
      self.writeParasite(self.drawable, fxlayer, [
        ["color", self.color_button],
        ["floatadj", self.opacity_slider["adj"]],
        ["modebox", self.mode_box],
        ["intadj", self.size_slider["adj"]],
        ["floatadj", self.position_slider["adj"]],
        ["check", self.merge_check]
      ])

  def resetbutton(self, widget):
    self.color_button.set_color(gimpcolor.RGB(255, 0, 0, 255))
    self.size_slider["adj"].set_value(3)
    self.position_slider["adj"].set_value(50.0)
    self.mode_box.set_active(0)
    self.opacity_slider["adj"].set_value(100.0)
    self.merge_check.set_active(False)

  def readParasite(self, img, drawable):
    return layerfx_base.readParasite(self, img, drawable, [
      ["color", "color"],
      ["opacity", "float"],
      ["mode", "int"],
      ["size", "int"],
      ["position", "float"],
      ["merge", "int"]
    ], layerfx_stroke.shelfkey)

  def preview(self, widget):
    if self.preview_check.get_active():
      if self.layer_exists(self.previewLayer):
        self.img.remove_layer(self.previewLayer)
      self.unset_hidden_layer()
      if self.parasitedata:
        self.set_hidden_layer(self.parasitedata["oldid"])
      if self.merge_check.get_active():
        self.previewLayer = self.drawable.copy()
        self.add_over_layer(self.previewLayer, self.drawable)
        self.set_hidden_layer(self.drawable)
        self.previewLayer = self.makeStroke(self.img,
          self.previewLayer,
          self.color_button.get_color(),
          self.opacity_slider["adj"].get_value(),
          self.mode_list[self.mode_box.get_active()],
          int(round(self.size_slider["adj"].get_value())),
          self.position_slider["adj"].get_value(),
          1)
      else:
        self.previewLayer = self.makeStroke(self.img,
          self.drawable,
          self.color_button.get_color(),
          self.opacity_slider["adj"].get_value(),
          self.mode_list[self.mode_box.get_active()],
          int(round(self.size_slider["adj"].get_value())),
          self.position_slider["adj"].get_value(),
          0)

  def makeStroke(self, img, drawable, color, opacity, mode, size, position, merge):
    pdb.gimp_image_undo_group_start(img)
    origfgcolor = gimp.get_foreground()
    origselection = pdb.gimp_selection_save(img)
    if position == 0:
      strokelayer = gimp.Layer(img, "%s-stroke" % (drawable.name), drawable.width, drawable.height, (RGBA_IMAGE, GRAYA_IMAGE)[img.base_type], opacity, mode)
      self.add_over_layer(strokelayer, drawable)
      strokelayer.set_offsets(drawable.offsets[0], drawable.offsets[1])
      pdb.gimp_selection_none(img)
      pdb.gimp_edit_clear(strokelayer)
      pdb.gimp_selection_layer_alpha(drawable)
      if drawable.mask != None:
        pdb.gimp_selection_combine(drawable.mask, CHANNEL_OP_INTERSECT)
      alphaSel = pdb.gimp_selection_save(img)
      pdb.gimp_selection_shrink(img, size)
      innerSel = pdb.gimp_selection_save(img)
      if merge == 1:
        origmask = drawable.mask
        layername = drawable.name
        if origmask != None:
          origmask = drawable.mask.copy()
          drawable.remove_mask(MASK_DISCARD)
        alphamask = drawable.create_mask(ADD_ALPHA_TRANSFER_MASK)
        pdb.gimp_selection_none(img)
        pdb.gimp_threshold(alphaSel, 1, 255)
      pdb.gimp_selection_load(alphaSel)
      pdb.gimp_selection_combine(innerSel, CHANNEL_OP_SUBTRACT)
      gimp.set_foreground(color)
      pdb.gimp_edit_fill(strokelayer, FOREGROUND_FILL)
      if merge == 1:
        strokelayer = pdb.gimp_image_merge_down(img, strokelayer, EXPAND_AS_NECESSARY)
        strokelayer.name = layername
        strokelayer.add_mask(alphamask)
        strokelayer.remove_mask(MASK_APPLY)
        if origmask != None:
          strokelayer.add_mask(origmask)
      else:
        pdb.gimp_image_set_active_layer(img, drawable)
    elif position == 100:
      growamt = int(round(size * 1.2))
      strokelayer = gimp.Layer(img, "%s-stroke" % (drawable.name), drawable.width + (growamt * 2), drawable.height + (growamt * 2), (RGBA_IMAGE, GRAYA_IMAGE)[img.base_type], opacity, mode)
      self.add_under_layer(strokelayer, drawable)
      strokelayer.set_offsets(drawable.offsets[0] - growamt, drawable.offsets[1] - growamt)
      pdb.gimp_selection_none(img)
      pdb.gimp_edit_clear(strokelayer)
      pdb.gimp_selection_layer_alpha(drawable)
      if drawable.mask != None:
        pdb.gimp_selection_combine(drawable.mask, CHANNEL_OP_INTERSECT)
      alphaSel = pdb.gimp_selection_save(img)
      innerSel = pdb.gimp_selection_save(img)
      pdb.gimp_selection_none(img)
      pdb.gimp_threshold(innerSel, 255, 255)
      pdb.gimp_selection_load(alphaSel)
      pdb.gimp_selection_grow(img, size)
      pdb.gimp_selection_combine(innerSel, CHANNEL_OP_SUBTRACT)
      gimp.set_foreground(color)
      pdb.gimp_edit_fill(strokelayer, FOREGROUND_FILL)
      if merge == 1:
        origmask = drawable.mask
        layername = drawable.name
        if origmask != None:
          drawable.remove_mask(MASK_APPLY)
        strokelayer = pdb.gimp_image_merge_down(img, drawable, EXPAND_AS_NECESSARY)
        strokelayer.name = layername
      else:
        pdb.gimp_image_set_active_layer(img, drawable)
    else:
      outerwidth = int(round((position / 100.0) * size))
      innerwidth = size - outerwidth
      growamt = int(round(outerwidth * 1.2))
      strokelayer = gimp.Layer(img, "%s-stroke" % (drawable.name), drawable.width + (growamt * 2), drawable.height + (growamt * 2), (RGBA_IMAGE, GRAYA_IMAGE)[img.base_type], opacity, mode)
      self.add_over_layer(strokelayer, drawable)
      strokelayer.set_offsets(drawable.offsets[0] - growamt, drawable.offsets[1] - growamt)
      pdb.gimp_selection_none(img)
      pdb.gimp_edit_clear(strokelayer)
      pdb.gimp_selection_layer_alpha(drawable)
      if drawable.mask != None:
        pdb.gimp_selection_combine(drawable.mask, CHANNEL_OP_INTERSECT)
      alphaSel = pdb.gimp_selection_save(img)
      pdb.gimp_selection_shrink(img, innerwidth)
      innerSel = pdb.gimp_selection_save(img)
      pdb.gimp_selection_load(alphaSel)
      pdb.gimp_selection_grow(img, outerwidth)
      pdb.gimp_selection_combine(innerSel, CHANNEL_OP_SUBTRACT)
      gimp.set_foreground(color)
      pdb.gimp_edit_fill(strokelayer, FOREGROUND_FILL)
      if merge == 1:
        origmask = drawable.mask
        layername = drawable.name
        if origmask != None:
          drawable.remove_mask(MASK_APPLY)
        strokelayer = pdb.gimp_image_merge_down(img, strokelayer, EXPAND_AS_NECESSARY)
        strokelayer.name = layername
      else:
        pdb.gimp_image_set_active_layer(img, drawable)
    gimp.set_foreground(origfgcolor)
    pdb.gimp_selection_load(origselection)
    img.remove_channel(alphaSel)
    img.remove_channel(innerSel)
    img.remove_channel(origselection)
    gimp.displays_flush()
    pdb.gimp_image_undo_group_end(img)
    return strokelayer

class layerfx_color_overlay(layerfx_base):
  shelfkey = "layerfx-color-overlay"

  def __init__(self, runmode, img, drawable, color, opacity, mode, merge):
    self.origMsgHandler = pdb.gimp_message_get_handler()
    pdb.gimp_message_set_handler(ERROR_CONSOLE)
    self.img = img
    self.drawable = drawable
    if runmode == RUN_INTERACTIVE:
      self.showDialog()
    elif runmode == RUN_NONINTERACTIVE:
      if self.validatedata(img, drawable, [
        ["color", color],
        ["percent", opacity],
        ["mode", mode],
        ["boolean", merge]
      ]):
        self.removeOldLayer()
        fxlayer = self.makeOverlay(img, drawable, color, opacity, mode, merge)
        if merge == 0:
          self.writeParasiteRaw(drawable, fxlayer, [color, opacity, mode, merge])
        shelf[self.shelfkey] = {"color":color,
          "opacity":opacity,
          "mode":mode,
          "merge":merge}
    elif runmode == RUN_WITH_LAST_VALS and shelf.has_key(self.shelfkey) == 1:
      self.removeOldLayer()
      fxlayer = self.makeOverlay(img,
        drawable,
        shelf[self.shelfkey]["color"],
        shelf[self.shelfkey]["opacity"],
        shelf[self.shelfkey]["mode"],
        shelf[self.shelfkey]["merge"])
      if shelf[self.shelfkey]["merge"] == 0:
        self.writeParasiteRaw(drawable, fxlayer, [
          shelf[self.shelfkey]["color"],
          shelf[self.shelfkey]["opacity"],
          shelf[self.shelfkey]["mode"],
          shelf[self.shelfkey]["merge"]
        ])
    else:
      pdb.gimp_message("unknown runmode")
    pdb.gimp_message_set_handler(self.origMsgHandler)

  def showDialog(self):
    self.dialog = gimpui.Dialog("Color Overlay", "coloroverlaydialog")

    self.parasitedata = self.readParasite(self.img, self.drawable)

    self.table = gtk.Table(3, 5, True)
    self.table.set_homogeneous(True)
    self.table.set_row_spacings(3)
    self.table.set_col_spacings(3)
    self.table.show()

    self.color_label = self.make_label("_Color:")
    self.table.attach(self.color_label, 0, 1, 0, 1)

    self.color_button = gimpui.ColorButton("Overlay Color", 10, 10, gimpcolor.RGB(255, 255, 255, 255))
    if self.parasitedata:
      self.color_button.set_color(self.parasitedata["color"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.color_button.set_color(shelf[self.shelfkey]["color"])
    self.color_label.set_mnemonic_widget(self.color_button)
    self.color_button.show()
    self.table.attach(self.color_button, 1, 2, 0, 1)
    self.color_button.connect("color-changed", self.preview)

    self.mode_label = self.make_label("_Blend Mode:")
    self.table.attach(self.mode_label, 0, 1, 1, 2)

    self.mode_box = self.make_blend_mode_box()
    if self.parasitedata:
      self.blend_mode_box_set(self.mode_box, self.parasitedata["mode"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.blend_mode_box_set(self.mode_box, shelf[self.shelfkey]["mode"])
    else:
      self.mode_box.set_active(0)
    self.mode_label.set_mnemonic_widget(self.mode_box)
    self.mode_box.show()
    self.table.attach(self.mode_box, 1, 5, 1, 2)
    self.mode_box.connect("changed", self.preview)

    self.opacity_label = self.make_label("_Opacity:")
    self.table.attach(self.opacity_label, 0, 1, 2, 3)

    self.opacity_slider = self.make_slider_and_spinner(75.0, 0.0, 100.0, 1.0, 10.0, 1)
    if self.parasitedata:
      self.opacity_slider["adj"].set_value(self.parasitedata["opacity"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.opacity_slider["adj"].set_value(shelf[self.shelfkey]["opacity"])
    else:
      self.opacity_slider["adj"].set_value(100.0)
    self.opacity_label.set_mnemonic_widget(self.opacity_slider["spinner"])
    self.table.attach(self.opacity_slider["slider"], 1, 4, 2, 3)
    self.table.attach(self.opacity_slider["spinner"], 4, 5, 2, 3)
    self.opacity_slider["adj"].connect("value-changed", self.preview)

    self.merge_check = gtk.CheckButton("_Merge with layer")
    if self.parasitedata:
      if self.parasitedata["merge"] == 1:
        self.merge_check.set_active(True)
    elif shelf.has_key(self.shelfkey) == 1 and shelf[self.shelfkey]["merge"] == 1:
      self.merge_check.set_active(True)
    self.merge_check.show()
    self.merge_check.connect("toggled", self.preview)

    self.preview_check = gtk.CheckButton("_Preview")
    self.preview_check.show()
    self.preview_check.connect("toggled", self.preview)

    self.dialog.vbox.hbox1 = gtk.HBox(False, 7)
    self.dialog.vbox.hbox1.show()
    self.dialog.vbox.pack_start(self.dialog.vbox.hbox1, True, True, 7)
    self.dialog.vbox.hbox1.pack_start(self.table, True, True, 7)
    self.dialog.vbox.hbox2 = gtk.HBox(False, 7)
    self.dialog.vbox.hbox2.show()
    self.dialog.vbox.add(self.dialog.vbox.hbox2)
    self.dialog.vbox.hbox2.pack_start(self.merge_check, True, True, 10)
    self.dialog.vbox.hbox3 = gtk.HBox(False, 7)
    self.dialog.vbox.hbox3.show()
    self.dialog.vbox.add(self.dialog.vbox.hbox3)
    self.dialog.vbox.hbox3.pack_start(self.preview_check, True, True, 10)

    reset_button = gtk.Button("_Reset")
    reset_button.connect("clicked", self.resetbutton)
    reset_button.show()

    if gtk.alternative_dialog_button_order():
      ok_button = self.dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
      cancel_button = self.dialog.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
      self.dialog.action_area.add(reset_button)
    else:
      self.dialog.action_area.add(reset_button)
      cancel_button = self.dialog.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
      ok_button = self.dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
    ok_button.connect("clicked", self.okbutton)

    self.dialog.show()
    self.dialog.run()
    self.removePreviews()

  def okbutton(self, widget):
    if self.layer_exists(self.previewLayer):
      self.img.remove_layer(self.previewLayer)
      self.previewLayer = None
    self.unset_hidden_layer()
    if self.merge_check.get_active():
      merge = 1
    else:
      merge = 0
    shelf[self.shelfkey] = {"color":self.color_button.get_color(),
      "opacity":self.opacity_slider["adj"].get_value(),
      "mode":self.mode_list[self.mode_box.get_active()],
      "merge":merge}
    if self.parasitedata:
      self.img.remove_layer(self.parasitedata["oldid"])
    fxlayer = self.makeOverlay(self.img,
      self.drawable,
      shelf[self.shelfkey]["color"],
      shelf[self.shelfkey]["opacity"],
      shelf[self.shelfkey]["mode"],
      shelf[self.shelfkey]["merge"])
    if merge == 0:
      self.writeParasite(self.drawable, fxlayer, [
        ["color", self.color_button],
        ["floatadj", self.opacity_slider["adj"]],
        ["modebox", self.mode_box],
        ["check", self.merge_check]
      ])

  def resetbutton(self, widget):
    self.color_button.set_color(gimpcolor.RGB(255, 255, 255, 255))
    self.mode_box.set_active(0)
    self.opacity_slider["adj"].set_value(100.0)
    self.merge_check.set_active(False)

  def readParasite(self, img, drawable):
    return layerfx_base.readParasite(self, img, drawable, [
      ["color", "color"],
      ["opacity", "float"],
      ["mode", "int"],
      ["merge", "int"]
    ], layerfx_color_overlay.shelfkey)

  def preview(self, widget):
    if self.preview_check.get_active():
      if self.layer_exists(self.previewLayer):
        self.img.remove_layer(self.previewLayer)
      self.unset_hidden_layer()
      if self.parasitedata:
        self.set_hidden_layer(self.parasitedata["oldid"])
      if self.merge_check.get_active():
        self.previewLayer = self.drawable.copy()
        self.add_over_layer(self.previewLayer, self.drawable)
        self.set_hidden_layer(self.drawable)
        self.previewLayer = self.makeOverlay(self.img,
          self.previewLayer,
          self.color_button.get_color(),
          self.opacity_slider["adj"].get_value(),
          self.mode_list[self.mode_box.get_active()],
          1)
      else:
        self.previewLayer = self.makeOverlay(self.img,
          self.drawable,
          self.color_button.get_color(),
          self.opacity_slider["adj"].get_value(),
          self.mode_list[self.mode_box.get_active()],
          0)

  def makeOverlay(self, img, drawable, color, opacity, mode, merge):
    pdb.gimp_image_undo_group_start(img)
    origfgcolor = gimp.get_foreground()
    origselection = pdb.gimp_selection_save(img)
    colorlayer = gimp.Layer(img, "%s-color" % (drawable.name), drawable.width, drawable.height, (RGBA_IMAGE, GRAYA_IMAGE)[img.base_type], opacity, mode)
    self.add_over_layer(colorlayer, drawable)
    colorlayer.set_offsets(drawable.offsets[0], drawable.offsets[1])
    pdb.gimp_selection_none(img)
    gimp.set_foreground(color)
    pdb.gimp_edit_fill(colorlayer, FOREGROUND_FILL)
    if merge == 1:
      origmask = drawable.mask
      layername = drawable.name
      if origmask != None:
        origmask = drawable.mask.copy()
        drawable.remove_mask(MASK_DISCARD)
      alphamask = drawable.create_mask(ADD_ALPHA_TRANSFER_MASK)
      colorlayer = pdb.gimp_image_merge_down(img, colorlayer, EXPAND_AS_NECESSARY)
      colorlayer.name = layername
      colorlayer.add_mask(alphamask)
      colorlayer.remove_mask(MASK_APPLY)
      if origmask != None:
        colorlayer.add_mask(origmask)
    else:
      pdb.gimp_selection_layer_alpha(drawable)
      if drawable.mask != None:
        pdb.gimp_selection_combine(drawable.mask, CHANNEL_OP_INTERSECT)
      alphamask = colorlayer.create_mask(ADD_SELECTION_MASK)
      colorlayer.add_mask(alphamask)
      colorlayer.remove_mask(MASK_APPLY)
      pdb.gimp_image_set_active_layer(img, drawable)
    gimp.set_foreground(origfgcolor)
    pdb.gimp_selection_load(origselection)
    img.remove_channel(origselection)
    gimp.displays_flush()
    pdb.gimp_image_undo_group_end(img)
    return colorlayer

class layerfx_gradient_overlay(layerfx_base):
  shelfkey = "layerfx-gradient-overlay"

  def __init__(self, runmode, img, drawable, gradient, gradienttype, repeat, reverse, opacity, mode, centerx, centery, angle, width, merge):
    self.origMsgHandler = pdb.gimp_message_get_handler()
    pdb.gimp_message_set_handler(ERROR_CONSOLE)
    self.img = img
    self.drawable = drawable
    if runmode == RUN_INTERACTIVE:
      self.showDialog()
    elif runmode == RUN_NONINTERACTIVE:
      if self.validatedata(img, drawable, [
        ["gradient", gradient],
        ["intrange", gradienttype, 0, 10],
        ["intrange", repeat, 0, 2],
        ["boolean", reverse],
        ["percent", opacity],
        ["mode", mode],
        ["floatrange", centerx, 0.0, img.width],
        ["floatrange", centery, 0.0, img.height],
        ["angle", angle],
        ["floatrange", width, 0.0, 262144.0],
        ["boolean", merge]
      ]):
        self.removeOldLayer()
        fxlayer = self.makeOverlay(img, drawable, gradient, gradienttype, repeat, reverse, opacity, mode, centerx, centery, angle, width, merge)
        if merge == 0:
          self.writeParasiteRaw(drawable, fxlayer, [gradient, gradienttype, repeat, reverse, opacity, mode, centerx, centery, angle, width, merge])
        shelf[self.shelfkey] = {"gradient":gradient,
          "gradienttype":gradienttype,
          "repeat":repeat,
          "reverse":reverse,
          "opacity":opacity,
          "mode":mode,
          "centerx":centerx,
          "centery":centery,
          "angle":angle,
          "width":width,
          "merge":merge}
    elif runmode == RUN_WITH_LAST_VALS and shelf.has_key(self.shelfkey) == 1:
      self.removeOldLayer()
      fxlayer = self.makeOverlay(img,
        drawable,
        shelf[self.shelfkey]["gradient"],
        shelf[self.shelfkey]["gradienttype"],
        shelf[self.shelfkey]["repeat"],
        shelf[self.shelfkey]["reverse"],
        shelf[self.shelfkey]["opacity"],
        shelf[self.shelfkey]["mode"],
        shelf[self.shelfkey]["centerx"],
        shelf[self.shelfkey]["centery"],
        shelf[self.shelfkey]["angle"],
        shelf[self.shelfkey]["width"],
        shelf[self.shelfkey]["merge"])
      if shelf[self.shelfkey]["merge"] == 0:
        self.writeParasiteRaw(drawable, fxlayer, [
          shelf[self.shelfkey]["gradient"],
          shelf[self.shelfkey]["gradienttype"],
          shelf[self.shelfkey]["repeat"],
          shelf[self.shelfkey]["reverse"],
          shelf[self.shelfkey]["opacity"],
          shelf[self.shelfkey]["mode"],
          shelf[self.shelfkey]["centerx"],
          shelf[self.shelfkey]["centery"],
          shelf[self.shelfkey]["angle"],
          shelf[self.shelfkey]["width"],
          shelf[self.shelfkey]["merge"]
        ])
    else:
      pdb.gimp_message("unknown runmode")
    pdb.gimp_message_set_handler(self.origMsgHandler)

  def showDialog(self):
    self.dialog = gimpui.Dialog("Gradient Overlay", "gradientoverlaydialog")

    self.parasitedata = self.readParasite(self.img, self.drawable)

    self.table = gtk.Table(8, 4, True)
    self.table.set_homogeneous(True)
    self.table.set_row_spacings(3)
    self.table.set_col_spacings(3)
    self.table.show()

    self.gradient_label = self.make_label("_Gradient:")
    self.table.attach(self.gradient_label, 0, 1, 0, 1)

    self.gradient_button = gimpui.GradientSelector()
    if self.parasitedata:
      self.gradient_button.set_gradient(self.parasitedata["gradient"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.gradient_button.set_gradient(shelf[self.shelfkey]["gradient"])
    self.gradient_label.set_mnemonic_widget(self.gradient_button)
    self.gradient_button.show()
    self.table.attach(self.gradient_button, 1, 2, 0, 1)
    self.gradient_button.connect("gradient-set", self.preview)

    self.gradienttype_label = self.make_label("Gradient _Type:")
    self.table.attach(self.gradienttype_label, 0, 1, 1, 2)

    self.gradienttype_box = gtk.combo_box_new_text()
    self.gradienttype_box.append_text("Linear")
    self.gradienttype_box.append_text("Bi-linear")
    self.gradienttype_box.append_text("Radial")
    self.gradienttype_box.append_text("Square")
    self.gradienttype_box.append_text("Conical (sym)")
    self.gradienttype_box.append_text("Conical (asym)")
    self.gradienttype_box.append_text("Shaped (angular)")
    self.gradienttype_box.append_text("Shaped (spherical)")
    self.gradienttype_box.append_text("Shaped (dimpled)")
    self.gradienttype_box.append_text("Spiral (cw)")
    self.gradienttype_box.append_text("Spiral (ccw)")
    if self.parasitedata:
      self.gradienttype_box.set_active(self.parasitedata["gradienttype"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.gradienttype_box.set_active(shelf[self.shelfkey]["gradienttype"])
    else:
      self.gradienttype_box.set_active(0)
    self.gradienttype_box.show()
    self.gradienttype_label.set_mnemonic_widget(self.gradienttype_box)
    self.table.attach(self.gradienttype_box, 1, 4, 1, 2)
    self.gradienttype_box.connect("changed", self.preview)

    self.repeat_label = self.make_label("Repeat:")
    self.table.attach(self.repeat_label, 0, 1, 2, 3)

    self.repeat_box = gtk.combo_box_new_text()
    self.repeat_box.append_text("None")
    self.repeat_box.append_text("Sawtooth Wave")
    self.repeat_box.append_text("Triangular Wave")
    if self.parasitedata:
      self.repeat_box.set_active(self.parasitedata["repeat"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.repeat_box.set_active(shelf[self.shelfkey]["repeat"])
    else:
      self.repeat_box.set_active(0)
    self.repeat_box.show()
    self.repeat_label.set_mnemonic_widget(self.repeat_box)
    self.table.attach(self.repeat_box, 1, 4, 2, 3)
    self.repeat_box.connect("changed", self.preview)

    self.reverse_check = gtk.CheckButton("_Reverse")
    if self.parasitedata:
      if self.parasitedata["reverse"] == 1:
        self.reverse_check.set_active(True)
    elif shelf.has_key(self.shelfkey) == 1 and shelf[self.shelfkey]["reverse"] == 1:
      self.reverse_check.set_active(True)
    self.reverse_check.show()
    self.table.attach(self.reverse_check, 2, 3, 0, 1)
    self.reverse_check.connect("toggled", self.preview)

    self.mode_label = self.make_label("_Blend Mode:")
    self.table.attach(self.mode_label, 0, 1, 3, 4)

    self.mode_box = self.make_blend_mode_box()
    if self.parasitedata:
      self.blend_mode_box_set(self.mode_box, self.parasitedata["mode"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.blend_mode_box_set(self.mode_box, shelf[self.shelfkey]["mode"])
    else:
      self.mode_box.set_active(0)
    self.mode_label.set_mnemonic_widget(self.mode_box)
    self.mode_box.show()
    self.table.attach(self.mode_box, 1, 4, 3, 4)
    self.mode_box.connect("changed", self.preview)

    self.opacity_label = self.make_label("_Opacity:")
    self.table.attach(self.opacity_label, 0, 1, 4, 5)

    self.opacity_slider = self.make_slider_and_spinner(100.0, 0.0, 100.0, 1.0, 10.0, 1)
    if self.parasitedata:
      self.opacity_slider["adj"].set_value(self.parasitedata["opacity"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.opacity_slider["adj"].set_value(shelf[self.shelfkey]["opacity"])
    self.opacity_label.set_mnemonic_widget(self.opacity_slider["spinner"])
    self.table.attach(self.opacity_slider["slider"], 1, 3, 4, 5)
    self.table.attach(self.opacity_slider["spinner"], 3, 4, 4, 5)
    self.opacity_slider["adj"].connect("value-changed", self.preview)

    self.center_label = self.make_label("_Center:")
    self.table.attach(self.center_label, 0, 1, 5, 6)

    self.centerx_spinner = self.make_spinner(0.0, 0.0, self.img.width, 1.0, 10.0, 1)
    if self.parasitedata:
      self.centerx_spinner["adj"].set_value(self.parasitedata["centerx"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.centerx_spinner["adj"].set_value(shelf[self.shelfkey]["centerx"])
    self.center_label.set_mnemonic_widget(self.centerx_spinner["spinner"])
    self.table.attach(self.centerx_spinner["spinner"], 1, 2, 5, 6)
    self.centerx_spinner["adj"].connect("value-changed", self.preview)

    self.centery_spinner = self.make_spinner(0.0, 0.0, self.img.height, 1.0, 10.0, 1)
    if self.parasitedata:
      self.centery_spinner["adj"].set_value(self.parasitedata["centery"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.centery_spinner["adj"].set_value(shelf[self.shelfkey]["centery"])
    self.table.attach(self.centery_spinner["spinner"], 2, 3, 5, 6)
    self.centery_spinner["adj"].connect("value-changed", self.preview)

    self.angle_label = self.make_label("_Gradient Angle:")
    self.table.attach(self.angle_label, 0, 1, 6, 7)

    self.angle_slider = self.make_slider_and_spinner(90.0, -180.0, 180.0, 1.0, 10.0, 1)
    if self.parasitedata:
      self.angle_slider["adj"].set_value(self.parasitedata["angle"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.angle_slider["adj"].set_value(shelf[self.shelfkey]["angle"])
    self.angle_label.set_mnemonic_widget(self.angle_slider["spinner"])
    self.table.attach(self.angle_slider["slider"], 1, 3, 6, 7)
    self.table.attach(self.angle_slider["spinner"], 3, 4, 6, 7)
    self.angle_slider["adj"].connect("value-changed", self.preview)

    self.width_label = self.make_label("_Gradient Width:")
    self.table.attach(self.width_label, 0, 1, 7, 8)

    self.width_spinner = self.make_spinner(0.0, 0.0, 262144.0, 1.0, 10.0, 1)
    if self.parasitedata:
      self.width_spinner["adj"].set_value(self.parasitedata["width"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.width_spinner["adj"].set_value(shelf[self.shelfkey]["width"])
    self.width_label.set_mnemonic_widget(self.width_spinner["spinner"])
    self.table.attach(self.width_spinner["spinner"], 1, 2, 7, 8)
    self.width_spinner["adj"].connect("value-changed", self.preview)

    self.merge_check = gtk.CheckButton("_Merge with layer")
    if self.parasitedata:
      if self.parasitedata["merge"] == 1:
        self.merge_check.set_active(True)
    elif shelf.has_key(self.shelfkey) == 1 and shelf[self.shelfkey]["merge"] == 1:
      self.merge_check.set_active(True)
    self.merge_check.show()
    self.merge_check.connect("toggled", self.preview)

    self.preview_check = gtk.CheckButton("_Preview")
    self.preview_check.show()
    self.preview_check.connect("toggled", self.preview)

    self.dialog.vbox.hbox1 = gtk.HBox(False, 7)
    self.dialog.vbox.hbox1.show()
    self.dialog.vbox.pack_start(self.dialog.vbox.hbox1, True, True, 7)
    self.dialog.vbox.hbox1.pack_start(self.table, True, True, 7)
    self.dialog.vbox.hbox2 = gtk.HBox(False, 7)
    self.dialog.vbox.hbox2.show()
    self.dialog.vbox.add(self.dialog.vbox.hbox2)
    self.dialog.vbox.hbox2.pack_start(self.merge_check, True, True, 10)
    self.dialog.vbox.hbox3 = gtk.HBox(False, 7)
    self.dialog.vbox.hbox3.show()
    self.dialog.vbox.add(self.dialog.vbox.hbox3)
    self.dialog.vbox.hbox3.pack_start(self.preview_check, True, True, 10)

    reset_button = gtk.Button("_Reset")
    reset_button.connect("clicked", self.resetbutton)
    reset_button.show()

    if gtk.alternative_dialog_button_order():
      ok_button = self.dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
      cancel_button = self.dialog.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
      self.dialog.action_area.add(reset_button)
    else:
      self.dialog.action_area.add(reset_button)
      cancel_button = self.dialog.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
      ok_button = self.dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
    ok_button.connect("clicked", self.okbutton)

    self.dialog.show()
    self.dialog.run()
    self.removePreviews()

  def okbutton(self, widget):
    if self.layer_exists(self.previewLayer):
      self.img.remove_layer(self.previewLayer)
      self.previewLayer = None
    self.unset_hidden_layer()
    if self.reverse_check.get_active():
      reverse = 1
    else:
      reverse = 0
    if self.merge_check.get_active():
      merge = 1
    else:
      merge = 0
    shelf[self.shelfkey] = {"gradient":self.gradient_button.get_gradient(),
      "gradienttype":self.gradienttype_box.get_active(),
      "repeat":self.repeat_box.get_active(),
      "reverse":reverse,
      "opacity":self.opacity_slider["adj"].get_value(),
      "mode":self.mode_list[self.mode_box.get_active()],
      "centerx":self.centerx_spinner["adj"].get_value(),
      "centery":self.centery_spinner["adj"].get_value(),
      "angle":self.angle_slider["adj"].get_value(),
      "width":self.width_spinner["adj"].get_value(),
      "merge":merge}
    if self.parasitedata:
      self.img.remove_layer(self.parasitedata["oldid"])
    fxlayer = self.makeOverlay(self.img,
      self.drawable,
      shelf[self.shelfkey]["gradient"],
      shelf[self.shelfkey]["gradienttype"],
      shelf[self.shelfkey]["repeat"],
      shelf[self.shelfkey]["reverse"],
      shelf[self.shelfkey]["opacity"],
      shelf[self.shelfkey]["mode"],
      shelf[self.shelfkey]["centerx"],
      shelf[self.shelfkey]["centery"],
      shelf[self.shelfkey]["angle"],
      shelf[self.shelfkey]["width"],
      shelf[self.shelfkey]["merge"])
    if merge == 0:
      self.writeParasite(self.drawable, fxlayer, [
        ["gradient", self.gradient_button],
        ["combobox", self.gradienttype_box],
        ["combobox", self.repeat_box],
        ["check", self.reverse_check],
        ["floatadj", self.opacity_slider["adj"]],
        ["modebox", self.mode_box],
        ["floatadj", self.centerx_spinner["adj"]],
        ["floatadj", self.centery_spinner["adj"]],
        ["floatadj", self.angle_slider["adj"]],
        ["floatadj", self.width_spinner["adj"]],
        ["check", self.merge_check]
      ])

  def resetbutton(self, widget):
    self.gradient_button.set_gradient("FG to BG (RGB)")
    self.gradienttype_box.set_active(0)
    self.repeat_box.set_active(0)
    self.reverse_check.set_active(False)
    self.mode_box.set_active(0)
    self.opacity_slider["adj"].set_value(100.0)
    self.centerx_spinner["adj"].set_value(0.0)
    self.centery_spinner["adj"].set_value(0.0)
    self.angle_slider["adj"].set_value(90.0)
    self.width_spinner["adj"].set_value(0.0)
    self.merge_check.set_active(False)

  def readParasite(self, img, drawable):
    return layerfx_base.readParasite(self, img, drawable, [
      ["gradient", "string"],
      ["gradienttype", "int"],
      ["repeat", "int"],
      ["reverse", "int"],
      ["opacity", "float"],
      ["mode", "int"],
      ["centerx", "float"],
      ["centery", "float"],
      ["angle", "float"],
      ["width", "float"],
      ["merge", "int"]
    ], layerfx_gradient_overlay.shelfkey)

  def preview(self, widget, *extra):
    if self.preview_check.get_active():
      if self.layer_exists(self.previewLayer):
        self.img.remove_layer(self.previewLayer)
      self.unset_hidden_layer()
      if self.parasitedata:
        self.set_hidden_layer(self.parasitedata["oldid"])
      if self.reverse_check.get_active():
        reverse = 1
      else:
        reverse = 0
      if self.merge_check.get_active():
        self.previewLayer = self.drawable.copy()
        self.add_over_layer(self.previewLayer, self.drawable)
        self.set_hidden_layer(self.drawable)
        self.previewLayer = self.makeOverlay(self.img,
          self.previewLayer,
          self.gradient_button.get_gradient(),
          self.gradienttype_box.get_active(),
          self.repeat_box.get_active(),
          reverse,
          self.opacity_slider["adj"].get_value(),
          self.mode_list[self.mode_box.get_active()],
          self.centerx_spinner["adj"].get_value(),
          self.centery_spinner["adj"].get_value(),
          self.angle_slider["adj"].get_value(),
          self.width_spinner["adj"].get_value(),
          1)
      else:
        self.previewLayer = self.makeOverlay(self.img,
          self.drawable,
          self.gradient_button.get_gradient(),
          self.gradienttype_box.get_active(),
          self.repeat_box.get_active(),
          reverse,
          self.opacity_slider["adj"].get_value(),
          self.mode_list[self.mode_box.get_active()],
          self.centerx_spinner["adj"].get_value(),
          self.centery_spinner["adj"].get_value(),
          self.angle_slider["adj"].get_value(),
          self.width_spinner["adj"].get_value(),
          0)

  def makeOverlay(self, img, drawable, gradient, gradienttype, repeat, reverse, opacity, mode, centerx, centery, angle, width, merge):
    pdb.gimp_image_undo_group_start(img)
    origgradient = pdb.gimp_context_get_gradient()
    origselection = pdb.gimp_selection_save(img)
    gradientlayer = gimp.Layer(img, "%s-gradient" % (drawable.name), drawable.width, drawable.height, (RGBA_IMAGE, GRAYA_IMAGE)[img.base_type], opacity, mode)
    self.add_over_layer(gradientlayer, drawable)
    gradientlayer.set_offsets(drawable.offsets[0], drawable.offsets[1])
    ang = (angle * -1) * (math.pi / 180.0)
    if gradienttype == 0:
      offset = ((width / 2.0) * math.cos(ang), (width / 2.0) * math.sin(ang))
      gradstart = (centerx - offset[0] - drawable.offsets[0], centery - offset[1] - drawable.offsets[1])
      gradend = (centerx + offset[0] - drawable.offsets[0], centery + offset[1] - drawable.offsets[1])
    elif gradienttype >= 1 and gradienttype <= 8:
      offset = ((width / 2.0) * math.cos(ang), (width / 2.0) * math.sin(ang))
      gradstart = (centerx - drawable.offsets[0], centery - drawable.offsets[1])
      gradend = (centerx + offset[0] - drawable.offsets[0], centery + offset[1] - drawable.offsets[1])
    else:
      offset = (width * math.cos(ang), width * math.sin(ang))
      gradstart = (centerx - drawable.offsets[0], centery - drawable.offsets[1])
      gradend = (centerx + offset[0] - drawable.offsets[0], centery + offset[1] - drawable.offsets[1])
    pdb.gimp_selection_none(img)
    pdb.gimp_edit_clear(gradientlayer)
    pdb.gimp_context_set_gradient(gradient)
    if gradienttype >= 6 and gradienttype <= 8:
      pdb.gimp_selection_layer_alpha(drawable)
    pdb.gimp_edit_blend(gradientlayer, CUSTOM_MODE, NORMAL_MODE, gradienttype, 100.0, 1.0, repeat, reverse, False, 1, 0.0, False, gradstart[0], gradstart[1], gradend[0], gradend[1])
    pdb.gimp_selection_none(img)
    if merge == 1:
      origmask = drawable.mask
      layername = drawable.name
      if origmask != None:
        origmask = drawable.mask.copy()
        drawable.remove_mask(MASK_DISCARD)
      alphamask = drawable.create_mask(ADD_ALPHA_TRANSFER_MASK)
      gradientlayer = pdb.gimp_image_merge_down(img, gradientlayer, EXPAND_AS_NECESSARY)
      gradientlayer.name = layername
      gradientlayer.add_mask(alphamask)
      gradientlayer.remove_mask(MASK_APPLY)
      if origmask != None:
        gradientlayer.add_mask(origmask)
    else:
      pdb.gimp_selection_layer_alpha(drawable)
      if drawable.mask != None:
        pdb.gimp_selection_combine(drawable.mask, CHANNEL_OP_INTERSECT)
      alphamask = gradientlayer.create_mask(ADD_SELECTION_MASK)
      gradientlayer.add_mask(alphamask)
      gradientlayer.remove_mask(MASK_APPLY)
      pdb.gimp_image_set_active_layer(img, drawable)
    pdb.gimp_context_set_gradient(origgradient)
    pdb.gimp_selection_load(origselection)
    img.remove_channel(origselection)
    gimp.displays_flush()
    pdb.gimp_image_undo_group_end(img)
    return gradientlayer

class layerfx_pattern_overlay(layerfx_base):
  shelfkey = "layerfx-pattern-overlay"

  def __init__(self, runmode, img, drawable, pattern, opacity, mode, scale, interpolation_type, merge):
    self.origMsgHandler = pdb.gimp_message_get_handler()
    pdb.gimp_message_set_handler(ERROR_CONSOLE)
    self.img = img
    self.drawable = drawable
    if runmode == RUN_INTERACTIVE:
      self.showDialog()
    elif runmode == RUN_NONINTERACTIVE:
      if self.validatedata(img, drawable, [
        ["pattern", pattern],
        ["percent", opacity],
        ["mode", mode],
        ["floatrange", scale, 1.0, 1000.0],
        ["intrange", interpolation_type, 0, 3],
        ["boolean", merge]
      ]):
        self.removeOldLayer()
        fxlayer = self.makeOverlay(img, drawable, pattern, opacity, mode, scale, interpolation_type, merge)
        if merge == 0:
          self.writeParasiteRaw(drawable, fxlayer, [pattern, opacity, mode, scale, interpolation_type, merge])
        shelf[self.shelfkey] = {"pattern":pattern,
          "opacity":opacity,
          "mode":mode,
          "scale":scale,
          "interpolation_type":interpolation_type,
          "merge":merge}
    elif runmode == RUN_WITH_LAST_VALS and shelf.has_key(self.shelfkey) == 1:
      self.removeOldLayer()
      fxlayer = self.makeOverlay(img,
        drawable,
        shelf[self.shelfkey]["pattern"],
        shelf[self.shelfkey]["opacity"],
        shelf[self.shelfkey]["mode"],
        shelf[self.shelfkey]["scale"],
        shelf[self.shelfkey]["interpolation_type"],
        shelf[self.shelfkey]["merge"])
      if shelf[self.shelfkey]["merge"] == 0:
        self.writeParasiteRaw(drawable, fxlayer, [
          shelf[self.shelfkey]["pattern"],
          shelf[self.shelfkey]["opacity"],
          shelf[self.shelfkey]["mode"],
          shelf[self.shelfkey]["scale"],
          shelf[self.shelfkey]["interpolation_type"],
          shelf[self.shelfkey]["merge"]
        ])
    else:
      pdb.gimp_message("unknown runmode")
    pdb.gimp_message_set_handler(self.origMsgHandler)

  def showDialog(self):
    self.dialog = gimpui.Dialog("Pattern Overlay", "patternoverlaydialog")

    self.parasitedata = self.readParasite(self.img, self.drawable)

    self.table = gtk.Table(5, 6, True)
    self.table.set_homogeneous(True)
    self.table.set_row_spacings(3)
    self.table.set_col_spacings(3)
    self.table.show()

    self.pattern_label = self.make_label("_Pattern:")
    self.table.attach(self.pattern_label, 0, 2, 0, 1)

    self.pattern_button = gimpui.PatternSelector()
    if self.parasitedata:
      self.pattern_button.set_pattern(self.parasitedata["pattern"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.pattern_button.set_pattern(shelf[self.shelfkey]["pattern"])
    self.pattern_label.set_mnemonic_widget(self.pattern_button)
    self.pattern_button.show()
    self.table.attach(self.pattern_button, 2, 4, 0, 1)
    self.pattern_button.connect("pattern-set", self.preview)

    self.mode_label = self.make_label("_Blend Mode:")
    self.table.attach(self.mode_label, 0, 2, 1, 2)

    self.mode_box = self.make_blend_mode_box()
    if self.parasitedata:
      self.blend_mode_box_set(self.mode_box, self.parasitedata["mode"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.blend_mode_box_set(self.mode_box, shelf[self.shelfkey]["mode"])
    else:
      self.mode_box.set_active(0)
    self.mode_label.set_mnemonic_widget(self.mode_box)
    self.mode_box.show()
    self.table.attach(self.mode_box, 2, 6, 1, 2)
    self.mode_box.connect("changed", self.preview)

    self.opacity_label = self.make_label("_Opacity:")
    self.table.attach(self.opacity_label, 0, 2, 2, 3)

    self.opacity_slider = self.make_slider_and_spinner(100.0, 0.0, 100.0, 1.0, 10.0, 1)
    if self.parasitedata:
      self.opacity_slider["adj"].set_value(self.parasitedata["opacity"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.opacity_slider["adj"].set_value(shelf[self.shelfkey]["opacity"])
    self.opacity_label.set_mnemonic_widget(self.opacity_slider["spinner"])
    self.table.attach(self.opacity_slider["slider"], 2, 5, 2, 3)
    self.table.attach(self.opacity_slider["spinner"], 5, 6, 2, 3)
    self.opacity_slider["adj"].connect("value-changed", self.preview)

    self.scale_label = self.make_label("Scale:")
    self.table.attach(self.scale_label, 0, 2, 3, 4)

    self.scale_slider = self.make_slider_and_spinner(100.0, 1.0, 1000.0, 1.0, 10.0, 1)
    if self.parasitedata:
      self.scale_slider["adj"].set_value(self.parasitedata["scale"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.scale_slider["adj"].set_value(shelf[self.shelfkey]["scale"])
    self.scale_label.set_mnemonic_widget(self.scale_slider["spinner"])
    self.table.attach(self.scale_slider["slider"], 2, 5, 3, 4)
    self.table.attach(self.scale_slider["spinner"], 5, 6, 3, 4)
    self.scale_slider["adj"].connect("value-changed", self.preview)

    self.interpolation_type_label = self.make_label("Interpolation:")
    self.table.attach(self.interpolation_type_label, 0, 2, 4, 5)

    self.interpolation_type_box = gtk.combo_box_new_text()
    self.interpolation_type_box.append_text("None")
    self.interpolation_type_box.append_text("Linear")
    self.interpolation_type_box.append_text("Cubic")
    self.interpolation_type_box.append_text("Sinc (Lanczos3)")
    if self.parasitedata:
      self.interpolation_type_box.set_active(self.parasitedata["interpolation_type"])
    elif shelf.has_key(self.shelfkey) == 1:
      self.interpolation_type_box.set_active(shelf[self.shelfkey]["interpolation_type"])
    else:
      self.interpolation_type_box.set_active(0)
    self.interpolation_type_box.show()
    self.interpolation_type_label.set_mnemonic_widget(self.interpolation_type_box)
    self.table.attach(self.interpolation_type_box, 2, 6, 4, 5)
    self.interpolation_type_box.connect("changed", self.preview)

    self.merge_check = gtk.CheckButton("_Merge with layer")
    if self.parasitedata:
      if self.parasitedata["merge"] == 1:
        self.merge_check.set_active(True)
    elif shelf.has_key(self.shelfkey) == 1 and shelf[self.shelfkey]["merge"] == 1:
      self.merge_check.set_active(True)
    self.merge_check.show()
    self.merge_check.connect("toggled", self.preview)

    self.preview_check = gtk.CheckButton("_Preview")
    self.preview_check.show()
    self.preview_check.connect("toggled", self.preview)

    self.dialog.vbox.hbox1 = gtk.HBox(False, 7)
    self.dialog.vbox.hbox1.show()
    self.dialog.vbox.pack_start(self.dialog.vbox.hbox1, True, True, 7)
    self.dialog.vbox.hbox1.pack_start(self.table, True, True, 7)
    self.dialog.vbox.hbox2 = gtk.HBox(False, 7)
    self.dialog.vbox.hbox2.show()
    self.dialog.vbox.add(self.dialog.vbox.hbox2)
    self.dialog.vbox.hbox2.pack_start(self.merge_check, True, True, 10)
    self.dialog.vbox.hbox3 = gtk.HBox(False, 7)
    self.dialog.vbox.hbox3.show()
    self.dialog.vbox.add(self.dialog.vbox.hbox3)
    self.dialog.vbox.hbox3.pack_start(self.preview_check, True, True, 10)

    reset_button = gtk.Button("_Reset")
    reset_button.connect("clicked", self.resetbutton)
    reset_button.show()

    if gtk.alternative_dialog_button_order():
      ok_button = self.dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
      cancel_button = self.dialog.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
      self.dialog.action_area.add(reset_button)
    else:
      self.dialog.action_area.add(reset_button)
      cancel_button = self.dialog.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
      ok_button = self.dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
    ok_button.connect("clicked", self.okbutton)

    self.dialog.show()
    self.dialog.run()
    self.removePreviews()

  def okbutton(self, widget):
    if self.layer_exists(self.previewLayer):
      self.img.remove_layer(self.previewLayer)
      self.previewLayer = None
    self.unset_hidden_layer()
    if self.merge_check.get_active():
      merge = 1
    else:
      merge = 0
    shelf[self.shelfkey] = {"pattern":self.pattern_button.get_pattern(),
      "opacity":self.opacity_slider["adj"].get_value(),
      "mode":self.mode_list[self.mode_box.get_active()],
      "scale":self.scale_slider["adj"].get_value(),
      "interpolation_type":self.interpolation_type_box.get_active(),
      "merge":merge}
    if self.parasitedata:
      self.img.remove_layer(self.parasitedata["oldid"])
    fxlayer = self.makeOverlay(self.img,
      self.drawable,
      shelf[self.shelfkey]["pattern"],
      shelf[self.shelfkey]["opacity"],
      shelf[self.shelfkey]["mode"],
      shelf[self.shelfkey]["scale"],
      shelf[self.shelfkey]["interpolation_type"],
      shelf[self.shelfkey]["merge"])
    if merge == 0:
      self.writeParasite(self.drawable, fxlayer, [
        ["pattern", self.pattern_button],
        ["floatadj", self.opacity_slider["adj"]],
        ["modebox", self.mode_box],
        ["floatadj", self.scale_slider["adj"]],
        ["combobox", self.interpolation_type_box],
        ["check", self.merge_check]
      ])

  def resetbutton(self, widget):
    self.pattern_button.set_pattern(pdb.gimp_context_get_pattern())
    self.mode_box.set_active(0)
    self.opacity_slider["adj"].set_value(100.0)
    self.scale_slider["adj"].set_value(100.0)
    self.interpolation_type_box.set_active(0)
    self.merge_check.set_active(False)

  def readParasite(self, img, drawable):
    return layerfx_base.readParasite(self, img, drawable, [
      ["pattern", "string"],
      ["opacity", "float"],
      ["mode", "int"],
      ["scale", "float"],
      ["interpolation_type", "int"],
      ["merge", "int"]
    ], layerfx_pattern_overlay.shelfkey)

  def preview(self, widget, *extra):
    if self.preview_check.get_active():
      if self.layer_exists(self.previewLayer):
        self.img.remove_layer(self.previewLayer)
      self.unset_hidden_layer()
      if self.parasitedata:
        self.set_hidden_layer(self.parasitedata["oldid"])
      if self.merge_check.get_active():
        self.previewLayer = self.drawable.copy()
        self.add_over_layer(self.previewLayer, self.drawable)
        self.unset_hidden_layer()
        self.previewLayer = self.makeOverlay(self.img,
          self.previewLayer,
          self.pattern_button.get_pattern(),
          self.opacity_slider["adj"].get_value(),
          self.mode_list[self.mode_box.get_active()],
          self.scale_slider["adj"].get_value(),
          self.interpolation_type_box.get_active(),
          1)
      else:
        self.previewLayer = self.makeOverlay(self.img,
          self.drawable,
          self.pattern_button.get_pattern(),
          self.opacity_slider["adj"].get_value(),
          self.mode_list[self.mode_box.get_active()],
          self.scale_slider["adj"].get_value(),
          self.interpolation_type_box.get_active(),
          0)

  def makeOverlay(self, img, drawable, pattern, opacity, mode, scale, interpolation_type, merge):
    pdb.gimp_image_undo_group_start(img)
    origpattern = pdb.gimp_context_get_pattern()
    origselection = pdb.gimp_selection_save(img)
    if scale == 100.0:
      layerwidth = drawable.width
      layerheight = drawable.height
    else:
      layerwidth = int(round(drawable.width/(scale/100.0)))
      layerheight = int(round(drawable.height/(scale/100.0)))
    patternlayer = gimp.Layer(img, "%s-pattern" % (drawable.name), layerwidth, layerheight, (RGBA_IMAGE, GRAYA_IMAGE)[img.base_type], opacity, mode)
    self.add_over_layer(patternlayer, drawable)
    patternlayer.set_offsets(drawable.offsets[0], drawable.offsets[1])
    pdb.gimp_selection_none(img)
    pdb.gimp_context_set_pattern(pattern)
    patternlayer.fill(PATTERN_FILL)
    if scale != 100.0:
      pdb.gimp_drawable_transform_scale(patternlayer, drawable.offsets[0], drawable.offsets[1], drawable.offsets[0] + drawable.width, drawable.offsets[1] + drawable.height, TRANSFORM_FORWARD, interpolation_type, 1, 3, TRANSFORM_RESIZE_ADJUST)
    if merge == 1:
      origmask = drawable.mask
      layername = drawable.name
      if origmask != None:
        origmask = drawable.mask.copy()
        drawable.remove_mask(MASK_DISCARD)
      alphamask = drawable.create_mask(ADD_ALPHA_TRANSFER_MASK)
      patternlayer = pdb.gimp_image_merge_down(img, patternlayer, EXPAND_AS_NECESSARY)
      patternlayer.name = layername
      patternlayer.add_mask(alphamask)
      patternlayer.remove_mask(MASK_APPLY)
      if origmask != None:
        patternlayer.add_mask(origmask)
    else:
      pdb.gimp_selection_layer_alpha(drawable)
      if drawable.mask != None:
        pdb.gimp_selection_combine(drawable.mask, CHANNEL_OP_INTERSECT)
      alphamask = patternlayer.create_mask(ADD_SELECTION_MASK)
      patternlayer.add_mask(alphamask)
      patternlayer.remove_mask(MASK_APPLY)
      pdb.gimp_image_set_active_layer(img, drawable)
    pdb.gimp_context_set_pattern(origpattern)
    pdb.gimp_selection_load(origselection)
    img.remove_channel(origselection)
    gimp.displays_flush()
    pdb.gimp_image_undo_group_end(img)
    return patternlayer

class layerfx_reapply_effects(layerfx_drop_shadow, layerfx_inner_shadow, layerfx_outer_glow, layerfx_inner_glow, layerfx_bevel_emboss, layerfx_satin, layerfx_stroke, layerfx_color_overlay, layerfx_gradient_overlay, layerfx_pattern_overlay):
  def __init__(self, runmode, img, drawable):
    self.origMsgHandler = pdb.gimp_message_get_handler()
    pdb.gimp_message_set_handler(ERROR_CONSOLE)
    self.img = img
    self.drawable = drawable
    if runmode == RUN_INTERACTIVE or runmode == RUN_WITH_LAST_VALS:
      self.reapplyEffects(img, drawable)
    elif runmode == RUN_NONINTERACTIVE:
      if self.validatedata(img, drawable):
        self.reapplyEffects(img, drawable)
    else:
      pdb.gimp_message("unknown runmode")
    pdb.gimp_message_set_handler(self.origMsgHandler)

  def reapplyEffects(self, img, drawable):
    pdb.gimp_image_undo_group_start(img)

    self.parasitedata = {
      "drop-shadow": layerfx_drop_shadow.readParasite(self, img, drawable),
      "inner-shadow": layerfx_inner_shadow.readParasite(self, img, drawable),
      "outer-glow": layerfx_outer_glow.readParasite(self, img, drawable),
      "inner-glow": layerfx_inner_glow.readParasite(self, img, drawable),
      "bevel-emboss": layerfx_bevel_emboss.readParasite(self, img, drawable),
      "satin": layerfx_satin.readParasite(self, img, drawable),
      "stroke": layerfx_stroke.readParasite(self, img, drawable),
      "color-overlay": layerfx_color_overlay.readParasite(self, img, drawable),
      "gradient-overlay": layerfx_gradient_overlay.readParasite(self, img, drawable),
      "pattern-overlay": layerfx_pattern_overlay.readParasite(self, img, drawable)}
    active_effects = []
    for i in self.parasitedata.keys():
      if self.parasitedata[i]:
        active_effects.append(i)
    active_effects.sort(cmp=lambda a, b: self.get_layer_pos(self.parasitedata[a]["oldid"]) - self.get_layer_pos(self.parasitedata[b]["oldid"]))
    fx_detected = False
    for j in active_effects:
      if j == "drop-shadow":
        fx_detected = True
        layerfx_drop_shadow(RUN_NONINTERACTIVE, img, drawable,
          self.parasitedata["drop-shadow"]["color"],
          self.parasitedata["drop-shadow"]["opacity"],
          self.parasitedata["drop-shadow"]["contour"],
          self.parasitedata["drop-shadow"]["noise"],
          self.parasitedata["drop-shadow"]["mode"],
          self.parasitedata["drop-shadow"]["spread"],
          self.parasitedata["drop-shadow"]["size"],
          self.parasitedata["drop-shadow"]["offsetangle"],
          self.parasitedata["drop-shadow"]["offsetdist"],
          self.parasitedata["drop-shadow"]["knockout"],
          self.parasitedata["drop-shadow"]["merge"])
      elif j == "inner-shadow":
        fx_detected = True
        layerfx_inner_shadow(RUN_NONINTERACTIVE, img, drawable,
          self.parasitedata["inner-shadow"]["color"],
          self.parasitedata["inner-shadow"]["opacity"],
          self.parasitedata["inner-shadow"]["contour"],
          self.parasitedata["inner-shadow"]["noise"],
          self.parasitedata["inner-shadow"]["mode"],
          self.parasitedata["inner-shadow"]["source"],
          self.parasitedata["inner-shadow"]["choke"],
          self.parasitedata["inner-shadow"]["size"],
          self.parasitedata["inner-shadow"]["offsetangle"],
          self.parasitedata["inner-shadow"]["offsetdist"],
          self.parasitedata["inner-shadow"]["merge"])
      elif j == "outer-glow":
        fx_detected = True
        if self.parasitedata["outer-glow"]["filltype"] == 0:
          fill = self.parasitedata["outer-glow"]["color"]
        elif self.parasitedata["outer-glow"]["filltype"] == 1:
          fill = self.parasitedata["outer-glow"]["gradient"]
        layerfx_outer_glow(RUN_NONINTERACTIVE, img, drawable,
          fill,
          self.parasitedata["outer-glow"]["opacity"],
          self.parasitedata["outer-glow"]["contour"],
          self.parasitedata["outer-glow"]["noise"],
          self.parasitedata["outer-glow"]["mode"],
          self.parasitedata["outer-glow"]["spread"],
          self.parasitedata["outer-glow"]["size"],
          self.parasitedata["outer-glow"]["knockout"],
          self.parasitedata["outer-glow"]["merge"])
      elif j == "inner-glow":
        fx_detected = True
        if self.parasitedata["inner-glow"]["filltype"] == 0:
          fill = self.parasitedata["inner-glow"]["color"]
        elif self.parasitedata["inner-glow"]["filltype"] == 1:
          fill = self.parasitedata["inner-glow"]["gradient"]
        layerfx_inner_glow(RUN_NONINTERACTIVE, img, drawable,
          fill,
          self.parasitedata["inner-glow"]["opacity"],
          self.parasitedata["inner-glow"]["contour"],
          self.parasitedata["inner-glow"]["noise"],
          self.parasitedata["inner-glow"]["mode"],
          self.parasitedata["inner-glow"]["source"],
          self.parasitedata["inner-glow"]["choke"],
          self.parasitedata["inner-glow"]["size"],
          self.parasitedata["inner-glow"]["merge"])
      elif j == "bevel-emboss":
        fx_detected = True
        layerfx_bevel_emboss(RUN_NONINTERACTIVE, img, drawable,
          self.parasitedata["bevel-emboss"]["style"],
          self.parasitedata["bevel-emboss"]["depth"],
          self.parasitedata["bevel-emboss"]["direction"],
          self.parasitedata["bevel-emboss"]["size"],
          self.parasitedata["bevel-emboss"]["soften"],
          self.parasitedata["bevel-emboss"]["angle"],
          self.parasitedata["bevel-emboss"]["altitude"],
          self.parasitedata["bevel-emboss"]["glosscontour"],
          self.parasitedata["bevel-emboss"]["highlightcolor"],
          self.parasitedata["bevel-emboss"]["highlightmode"],
          self.parasitedata["bevel-emboss"]["highlightopacity"],
          self.parasitedata["bevel-emboss"]["shadowcolor"],
          self.parasitedata["bevel-emboss"]["shadowmode"],
          self.parasitedata["bevel-emboss"]["shadowopacity"],
          self.parasitedata["bevel-emboss"]["surfacecontour"],
          self.parasitedata["bevel-emboss"]["use_texture"],
          self.parasitedata["bevel-emboss"]["pattern"],
          self.parasitedata["bevel-emboss"]["scale"],
          self.parasitedata["bevel-emboss"]["tex_depth"],
          self.parasitedata["bevel-emboss"]["invert"],
          self.parasitedata["bevel-emboss"]["merge"])
      elif j == "satin":
        fx_detected = True
        layerfx_satin(RUN_NONINTERACTIVE, img, drawable,
          self.parasitedata["satin"]["color"],
          self.parasitedata["satin"]["opacity"],
          self.parasitedata["satin"]["mode"],
          self.parasitedata["satin"]["offsetangle"],
          self.parasitedata["satin"]["offsetdist"],
          self.parasitedata["satin"]["size"],
          self.parasitedata["satin"]["contour"],
          self.parasitedata["satin"]["invert"],
          self.parasitedata["satin"]["merge"])
      elif j == "stroke":
        fx_detected = True
        layerfx_stroke(RUN_NONINTERACTIVE, img, drawable,
          self.parasitedata["stroke"]["color"],
          self.parasitedata["stroke"]["opacity"],
          self.parasitedata["stroke"]["mode"],
          self.parasitedata["stroke"]["size"],
          self.parasitedata["stroke"]["position"],
          self.parasitedata["stroke"]["merge"])
      elif j == "color-overlay":
        fx_detected = True
        layerfx_color_overlay(RUN_NONINTERACTIVE, img, drawable,
          self.parasitedata["color-overlay"]["color"],
          self.parasitedata["color-overlay"]["opacity"],
          self.parasitedata["color-overlay"]["mode"],
          self.parasitedata["color-overlay"]["merge"])
      elif j == "gradient-overlay":
        fx_detected = True
        layerfx_gradient_overlay(RUN_NONINTERACTIVE, img, drawable,
          self.parasitedata["gradient-overlay"]["gradient"],
          self.parasitedata["gradient-overlay"]["gradienttype"],
          self.parasitedata["gradient-overlay"]["repeat"],
          self.parasitedata["gradient-overlay"]["reverse"],
          self.parasitedata["gradient-overlay"]["opacity"],
          self.parasitedata["gradient-overlay"]["mode"],
          self.parasitedata["gradient-overlay"]["centerx"],
          self.parasitedata["gradient-overlay"]["centery"],
          self.parasitedata["gradient-overlay"]["angle"],
          self.parasitedata["gradient-overlay"]["width"],
          self.parasitedata["gradient-overlay"]["merge"])
      elif j == "pattern-overlay":
        fx_detected = True
        layerfx_pattern_overlay(RUN_NONINTERACTIVE, img, drawable,
          self.parasitedata["pattern-overlay"]["pattern"],
          self.parasitedata["pattern-overlay"]["opacity"],
          self.parasitedata["pattern-overlay"]["mode"],
          self.parasitedata["pattern-overlay"]["scale"],
          self.parasitedata["pattern-overlay"]["interpolation_type"],
          self.parasitedata["pattern-overlay"]["merge"])
    if fx_detected == False:
      self.show_error_msg("No effects found on this layer.")
    gimp.displays_flush()
    pdb.gimp_image_undo_group_end(img)

class layerfxplugin(gimpplugin.plugin):
  def start(self):
    gimp.main(self.init, self.quit, self.query, self._run)

  def init(self):
    pass

  def quit(self):
    pass

  def query(self):
    authorname = "Jonathan Stipe"
    copyrightname = "Jonathan Stipe"
    imgmenupath = "<Image>/Layer/La_yer Effects/"
    layersmenupath = "<Layers>/_Layer Effects/"
    date = "July 2008"
    modevals = "{ NORMAL-MODE (0), DISSOLVE-MODE (1), MULTIPLY-MODE (3), SCREEN-MODE (4), OVERLAY-MODE (5), DIFFERENCE-MODE (6), ADDITION-MODE (7), SUBTRACT-MODE (8), DARKEN-ONLY-MODE (9), LIGHTEN-ONLY-MODE (10), HUE-MODE (11), SATURATION-MODE (12), COLOR-MODE (13), VALUE-MODE (14), DIVIDE-MODE (15), DODGE-MODE (16), BURN-MODE (17), HARDLIGHT-MODE (18), SOFTLIGHT-MODE (19), GRAIN-EXTRACT-MODE (20), GRAIN-MERGE-MODE (21), COLOR-ERASE-MODE (22), ERASE-MODE (23), REPLACE-MODE (24), ANTI-ERASE-MODE (25) }"
    
    drop_shadow_description = "Adds a drop shadow to a layer."
    drop_shadow_help = "Adds a drop shadow to a layer."
    drop_shadow_params = [
                           (PDB_INT32, "run_mode", "Run mode"),
                           (PDB_IMAGE, "image", "Input image"),
                           (PDB_DRAWABLE, "drawable", "Input drawable"),
                           (PDB_COLOR, "color", "The shadow's color"),
                           (PDB_FLOAT, "opacity", "The shadow's opacity (0 <= opacity <= 100)"),
                           (PDB_INT32, "contour", "A contour used to modify the shadow's intensity curve (0 <= contour <= 11)"),
                           (PDB_FLOAT, "noise", "The amount of noise applied to the shadow (0 <= noise <= 100)"),
                           (PDB_INT32, "mode", "The shadow layer's combination mode %s" % (modevals)),
                           (PDB_FLOAT, "spread", "Spread (0 <= spread <= 100)"),
                           (PDB_INT32, "size", "The size of the shadow's blur (0 <= size <= 250)"),
                           (PDB_FLOAT, "offset_angle", "The angle the shadow is cast in (-180 <= offset_angle <= 180)"),
                           (PDB_FLOAT, "offset_distance", "The distance between the layer and the shadow (0 <= offset_distance <= 30000)"),
                           (PDB_INT32, "knockout", "Layer knocks out Drop Shadow (TRUE or FALSE)"),
                           (PDB_INT32, "merge", "Merge with layer (TRUE or FALSE)")
                         ]
    gimp.install_procedure("python_layerfx_drop_shadow",
                           drop_shadow_description,
                           drop_shadow_help,
                           authorname,
                           copyrightname,
                           date,
                           "%s_Drop Shadow..." % (imgmenupath),
                           "RGBA, GRAYA",
                           PLUGIN,
                           drop_shadow_params,
                           [])
    gimp.install_procedure("python_layer_fx_drop_shadow",
                           drop_shadow_description,
                           drop_shadow_help,
                           authorname,
                           copyrightname,
                           date,
                           "%s_Drop Shadow..." % (layersmenupath),
                           "RGBA, GRAYA",
                           PLUGIN,
                           drop_shadow_params,
                           [])
    inner_shadow_description = "Adds an inner shadow to a layer"
    inner_shadow_help = "Adds an inner shadow to a layer"
    inner_shadow_params = [
                            (PDB_INT32, "run_mode", "Run mode"),
                            (PDB_IMAGE, "image", "Input image"),
                            (PDB_DRAWABLE, "drawable", "Input drawable"),
                            (PDB_COLOR, "color", "The shadow's color"),
                            (PDB_FLOAT, "opacity", "The shadow's opacity (0 <= opacity <= 100)"),
                            (PDB_INT32, "contour", "A contour used to modify the shadow's intensity curve (0 <= contour <= 11)"),
                            (PDB_FLOAT, "noise", "The amount of noise applied to the shadow (0 <= noise <= 100)"),
                            (PDB_INT32, "mode", "The shadow layer's combination mode %s" % (modevals)),
                            (PDB_INT32, "source", "Source (0 = Center, 1 = Edge)"),
                            (PDB_FLOAT, "choke", "Choke (0 <= choke <= 100)"),
                            (PDB_INT32, "size", "The size of the shadow's blur (0 <= size <= 250)"),
                            (PDB_FLOAT, "offset_angle", "The angle the shadow is cast in (-180 <= offset_angle <= 180)"),
                            (PDB_FLOAT, "offset_distance", "The distance between the layer and the shadow (0 <= offset_distance <= 30000)"),
                            (PDB_INT32, "merge", "Merge with layer (TRUE or FALSE)")
                          ]
    gimp.install_procedure("python_layerfx_inner_shadow",
                           inner_shadow_description,
                           inner_shadow_help,
                           authorname,
                           copyrightname,
                           date,
                           "%sI_nner Shadow..." % (imgmenupath),
                           "RGB*, GRAY*",
                           PLUGIN,
                           inner_shadow_params,
                           [])
    gimp.install_procedure("python_layer_fx_inner_shadow",
                           inner_shadow_description,
                           inner_shadow_help,
                           authorname,
                           copyrightname,
                           date,
                           "%sI_nner Shadow..." % (layersmenupath),
                           "RGB*, GRAY*",
                           PLUGIN,
                           inner_shadow_params,
                           [])
    outer_glow_description = "Creates an outer glow effect around a layer."
    outer_glow_help = "Creates an outer glow effect around a layer."
    outer_glow_params = [
                          (PDB_INT32, "run_mode", "Run mode"),
                          (PDB_IMAGE, "image", "Input image"),
                          (PDB_DRAWABLE, "drawable", "Input drawable"),
                          (PDB_COLOR, "color", "The glow's color. You can also use a gradient name here."),
                          (PDB_FLOAT, "opacity", "The glow's opacity (0 <= opacity <= 100)"),
                          (PDB_INT32, "contour", "A contour used to modify the glow's intensity curve (0 <= contour <= 11)"),
                          (PDB_FLOAT, "noise", "The amount of noise applied to the glow (0 <= noise <= 100)"),
                          (PDB_INT32, "mode", "The glow layer's combination mode %s" % (modevals)),
                          (PDB_FLOAT, "spread", "Spread (0 <= spread <= 100)"),
                          (PDB_INT32, "size", "The size of the glow's blur (0 <= size <= 250)"),
                          (PDB_INT32, "knockout", "Layer knocks out Outer Glow (TRUE or FALSE)"),
                          (PDB_INT32, "merge", "Merge with layer (TRUE or FALSE)")
                        ]
    gimp.install_procedure("python_layerfx_outer_glow",
                           outer_glow_description,
                           outer_glow_help,
                           authorname,
                           copyrightname,
                           date,
                           "%s_Outer Glow..." % (imgmenupath),
                           "RGBA, GRAYA",
                           PLUGIN,
                           outer_glow_params,
                           [])
    gimp.install_procedure("python_layer_fx_outer_glow",
                           outer_glow_description,
                           outer_glow_help,
                           authorname,
                           copyrightname,
                           date,
                           "%s_Outer Glow..." % (layersmenupath),
                           "RGBA, GRAYA",
                           PLUGIN,
                           outer_glow_params,
                           [])
    inner_glow_description = "Creates an inner glow effect around a layer."
    inner_glow_help = "Creates an inner glow effect around a layer."
    inner_glow_params = [
                          (PDB_INT32, "run_mode", "Run mode"),
                          (PDB_IMAGE, "image", "Input image"),
                          (PDB_DRAWABLE, "drawable", "Input drawable"),
                          (PDB_COLOR, "color", "The glow's color. You can also use a gradient name here."),
                          (PDB_FLOAT, "opacity", "The glow's opacity (0 <= opacity <= 100)"),
                          (PDB_INT32, "contour", "A contour used to modify the glow's intensity curve (0 <= contour <= 11)"),
                          (PDB_FLOAT, "noise", "The amount of noise applied to the glow (0 <= noise <= 100)"),
                          (PDB_INT32, "mode", "The glow layer's combination mode %s" % (modevals)),
                          (PDB_INT32, "source", "Source (0 = Center, 1 = Edge)"),
                          (PDB_FLOAT, "choke", "Choke (0 <= choke <= 100)"),
                          (PDB_INT32, "size", "The size of the glow's blur (0 <= size <= 250)"),
                          (PDB_INT32, "merge", "Merge with layer (TRUE or FALSE)")
                        ]
    gimp.install_procedure("python_layerfx_inner_glow",
                           inner_glow_description,
                           inner_glow_help,
                           authorname,
                           copyrightname,
                           date,
                           "%s_Inner Glow..." % (imgmenupath),
                           "RGB*, GRAY*",
                           PLUGIN,
                           inner_glow_params,
                           [])
    gimp.install_procedure("python_layer_fx_inner_glow",
                           inner_glow_description,
                           inner_glow_help,
                           authorname,
                           copyrightname,
                           date,
                           "%s_Inner Glow..." % (layersmenupath),
                           "RGB*, GRAY*",
                           PLUGIN,
                           inner_glow_params,
                           [])
    bevel_emboss_description = "Creates beveling and embossing effects over a layer."
    bevel_emboss_help = "Creates beveling and embossing effects over a layer."
    bevel_emboss_params = [
                            (PDB_INT32, "run_mode", "Run mode"),
                            (PDB_IMAGE, "image", "Input image"),
                            (PDB_DRAWABLE, "drawable", "Input drawable"),
                            (PDB_INT32, "style", "Beveling Style (0 = Outer Bevel, 1 = Inner Bevel, 2 = Emboss, 3 = Pillow Emboss)"),
                            (PDB_INT32, "depth", "Depth (1 <= depth <= 65)"),
                            (PDB_INT32, "direction", "Direction (0 = Up, 1 = Down)"),
                            (PDB_INT32, "size", "The size of the bevel (0 <= size <= 250)"),
                            (PDB_INT32, "soften", "Soften (0 <= soften <= 16)"),
                            (PDB_FLOAT, "angle", "Angle of the light source (-180 <= angle <= 180)"),
                            (PDB_FLOAT, "altitude", "Altitude of the light source (0 <= altitude <= 90)"),
                            (PDB_INT32, "gloss_contour", "A contour used to modify the gloss's intensity curve (0 <= gloss_contour <= 11)"),
                            (PDB_COLOR, "highlight_color", "The highlight color"),
                            (PDB_INT32, "highlight_mode", "The highlight layer's combination mode %s" % (modevals)),
                            (PDB_FLOAT, "highlight_opacity", "The highlight's opacity (0 <= highlight_opacity <= 100)"),
                            (PDB_COLOR, "shadow_color", "The shadow color"),
                            (PDB_INT32, "shadow_mode", "The shadow layer's combination mode %s" % (modevals)),
                            (PDB_FLOAT, "shadow_opacity", "The shadow's opacity (0 <= shadow_opacity <= 100)"),
                            (PDB_INT32, "surface_contour", "A contour used to modify the surface shape (0 <= gloss_contour <= 11)"),
                            (PDB_INT32, "use_texture", "Apply a texture to the surface (TRUE or FALSE)"),
                            (PDB_STRING, "pattern", "The texture pattern"),
                            (PDB_FLOAT, "scale", "The texture scale (1 <= scale <= 1000)"),
                            (PDB_FLOAT, "tex_depth", "The texture depth (-1000 <= tex_depth <= 1000)"),
                            (PDB_INT32, "invert", "Invert (TRUE or FALSE)"),
                            (PDB_INT32, "merge", "Merge with layer (TRUE or FALSE)")
                          ]
    gimp.install_procedure("python_layerfx_bevel_emboss",
                           bevel_emboss_description,
                           bevel_emboss_help,
                           authorname,
                           copyrightname,
                           date,
                           "%s_Bevel and Emboss..." % (imgmenupath),
                           "RGBA, GRAYA",
                           PLUGIN,
                           bevel_emboss_params,
                           [])
    gimp.install_procedure("python_layer_fx_bevel_emboss",
                           bevel_emboss_description,
                           bevel_emboss_help,
                           authorname,
                           copyrightname,
                           date,
                           "%s_Bevel and Emboss..." % (layersmenupath),
                           "RGBA, GRAYA",
                           PLUGIN,
                           bevel_emboss_params,
                           [])
    satin_description = "Creates a satin effect over a layer."
    satin_help = "Creates a satin effect over a layer."
    satin_params = [
                     (PDB_INT32, "run_mode", "Run mode"),
                     (PDB_IMAGE, "image", "Input image"),
                     (PDB_DRAWABLE, "drawable", "Input drawable"),
                     (PDB_COLOR, "color", "The shadow color"),
                     (PDB_FLOAT, "opacity", "The shadow opacity (0 <= opacity <= 100)"),
                     (PDB_INT32, "mode", "The shadow layer's combination mode %s" % (modevals)),
                     (PDB_FLOAT, "offset_angle", "The angle the shadow is cast in (-180 <= offset_angle <= 180)"),
                     (PDB_FLOAT, "offset_distance", "The offset distance (0 <= offset_distance <= 30000)"),
                     (PDB_INT32, "size", "The size of the satin's blur (0 <= size <= 250)"),
                     (PDB_INT32, "contour", "A contour used to modify the shadow's intensity curve (0 <= contour <= 11)"),
                     (PDB_INT32, "invert", "Invert (TRUE or FALSE)"),
                     (PDB_INT32, "merge", "Merge with layer (TRUE or FALSE)")
                   ]
    gimp.install_procedure("python_layerfx_satin",
                           satin_description,
                           satin_help,
                           authorname,
                           copyrightname,
                           date,
                           "%s_Satin..." % (imgmenupath),
                           "RGBA, GRAYA",
                           PLUGIN,
                           satin_params,
                           [])
    gimp.install_procedure("python_layer_fx_satin",
                           satin_description,
                           satin_help,
                           authorname,
                           copyrightname,
                           date,
                           "%s_Satin..." % (layersmenupath),
                           "RGBA, GRAYA",
                           PLUGIN,
                           satin_params,
                           [])
    stroke_description = "Creates a stroke around a layer."
    stroke_help = "Creates a stroke around a layer."
    stroke_params = [
                      (PDB_INT32, "run_mode", "Run mode"),
                      (PDB_IMAGE, "image", "Input image"),
                      (PDB_DRAWABLE, "drawable", "Input drawable"),
                      (PDB_COLOR, "color", "The stroke color"),
                      (PDB_FLOAT, "opacity", "The stroke opacity (0 <= opacity <= 100)"),
                      (PDB_INT32, "mode", "The stroke layer's combination mode %s" % (modevals)),
                      (PDB_INT32, "size", "The stroke's width (1 <= size <= 250)"),
                      (PDB_FLOAT, "position", "The stroke's position; 0 = inside the layer borders, 100 = outside the layer border (0 <= position <= 100)"),
                      (PDB_INT32, "merge", "Merge with layer (TRUE or FALSE)")
                    ]
    gimp.install_procedure("python_layerfx_stroke",
                           stroke_description,
                           stroke_help,
                           authorname,
                           copyrightname,
                           date,
                           "%sS_troke..." % (imgmenupath),
                           "RGBA, GRAYA",
                           PLUGIN,
                           stroke_params,
                           [])
    gimp.install_procedure("python_layer_fx_stroke",
                           stroke_description,
                           stroke_help,
                           authorname,
                           copyrightname,
                           date,
                           "%sS_troke..." % (layersmenupath),
                           "RGBA, GRAYA",
                           PLUGIN,
                           stroke_params,
                           [])
    color_overlay_description = "Overlays a color over a layer."
    color_overlay_help = "Overlays a color over a layer."
    color_overlay_params = [
                             (PDB_INT32, "run_mode", "Run mode"),
                             (PDB_IMAGE, "image", "Input image"),
                             (PDB_DRAWABLE, "drawable", "Input drawable"),
                             (PDB_COLOR, "color", "The color to overlay"),
                             (PDB_FLOAT, "opacity", "The overlay opacity (0 <= opacity <= 100)"),
                             (PDB_INT32, "mode", "The overlay layer's combination mode %s" % (modevals)),
                             (PDB_INT32, "merge", "Merge with layer (TRUE or FALSE)")
                           ]
    gimp.install_procedure("python_layerfx_color_overlay",
                           color_overlay_description,
                           color_overlay_help,
                           authorname,
                           copyrightname,
                           date,
                           "%s_Color Overlay..." % (imgmenupath),
                           "RGB*, GRAY*",
                           PLUGIN,
                           color_overlay_params,
                           [])
    gimp.install_procedure("python_layer_fx_color_overlay",
                           color_overlay_description,
                           color_overlay_help,
                           authorname,
                           copyrightname,
                           date,
                           "%s_Color Overlay..." % (layersmenupath),
                           "RGB*, GRAY*",
                           PLUGIN,
                           color_overlay_params,
                           [])
    gradient_overlay_description = "Overlays a gradient over a layer."
    gradient_overlay_help = "Overlays a gradient over a layer."
    gradient_overlay_params = [
                                (PDB_INT32, "run_mode", "Run mode"),
                                (PDB_IMAGE, "image", "Input image"),
                                (PDB_DRAWABLE, "drawable", "Input drawable"),
                                (PDB_STRING, "gradient", "The gradient to overlay"),
                                (PDB_INT32, "gradient_type", "The type of gradient { GRADIENT-LINEAR (0), GRADIENT-BILINEAR (1), GRADIENT-RADIAL (2), GRADIENT-SQUARE (3), GRADIENT-CONICAL-SYMMETRIC (4), GRADIENT-CONICAL-ASYMMETRIC (5), GRADIENT-SHAPEBURST-ANGULAR (6), GRADIENT-SHAPEBURST-SPHERICAL (7), GRADIENT-SHAPEBURST-DIMPLED (8), GRADIENT-SPIRAL-CLOCKWISE (9), GRADIENT-SPIRAL-ANTICLOCKWISE (10) }"),
                                (PDB_INT32, "repeat", "Repeat mode { REPEAT-NONE (0), REPEAT-SAWTOOTH (1), REPEAT-TRIANGULAR (2) }"),
                                (PDB_INT32, "reverse", "Use the reverse gradient (TRUE or FALSE)"),
                                (PDB_FLOAT, "opacity", "The overlay opacity (0 <= opacity <= 100)"),
                                (PDB_INT32, "mode", "The overlay layer's combination mode %s" % (modevals)),
                                (PDB_FLOAT, "center_x", "X coordinate of center"),
                                (PDB_FLOAT, "center_y", "Y coordinate of center"),
                                (PDB_FLOAT, "angle", "Gradient angle (-180 <= angle <= 180)"),
                                (PDB_FLOAT, "width", "Gradient width (0 <= width <= 262144"),
                                (PDB_INT32, "merge", "Merge with layer (TRUE or FALSE)")
                              ]
    gimp.install_procedure("python_layerfx_gradient_overlay",
                           gradient_overlay_description,
                           gradient_overlay_help,
                           authorname,
                           copyrightname,
                           date,
                           "%s_Gradient Overlay..." % (imgmenupath),
                           "RGB*, GRAY*",
                           PLUGIN,
                           gradient_overlay_params,
                           [])
    gimp.install_procedure("python_layer_fx_gradient_overlay",
                           gradient_overlay_description,
                           gradient_overlay_help,
                           authorname,
                           copyrightname,
                           date,
                           "%s_Gradient Overlay..." % (layersmenupath),
                           "RGB*, GRAY*",
                           PLUGIN,
                           gradient_overlay_params,
                           [])
    pattern_overlay_description = "Overlays a pattern over a layer."
    pattern_overlay_help = "Overlays a pattern over a layer."
    pattern_overlay_params = [
                               (PDB_INT32, "run_mode", "Run mode"),
                               (PDB_IMAGE, "image", "Input image"),
                               (PDB_DRAWABLE, "drawable", "Input drawable"),
                               (PDB_STRING, "pattern", "The pattern to overlay"),
                               (PDB_FLOAT, "opacity", "The overlay opacity (0 <= opacity <= 100)"),
                               (PDB_INT32, "mode", "The overlay layer's combination mode %s" % (modevals)),
                               (PDB_FLOAT, "scale", "Amount to scale the pattern (1 <= scale <= 1000)"),
                               (PDB_INT32, "interpolation", "Type of interpolation { INTERPOLATION-NONE (0), INTERPOLATION-LINEAR (1), INTERPOLATION-CUBIC (2), INTERPOLATION-LANCZOS (3) }"),
                               (PDB_INT32, "merge", "Merge with layer (TRUE or FALSE)")
                             ]
    gimp.install_procedure("python_layerfx_pattern_overlay",
                           pattern_overlay_description,
                           pattern_overlay_help,
                           authorname,
                           copyrightname,
                           date,
                           "%s_Pattern Overlay..." % (imgmenupath),
                           "RGB*, GRAY*",
                           PLUGIN,
                           pattern_overlay_params,
                           [])
    gimp.install_procedure("python_layer_fx_pattern_overlay",
                           pattern_overlay_description,
                           pattern_overlay_help,
                           authorname,
                           copyrightname,
                           date,
                           "%s_Pattern Overlay..." % (layersmenupath),
                           "RGB*, GRAY*",
                           PLUGIN,
                           pattern_overlay_params,
                           [])
    reapply_effects_description = "Reapply all effects previously applied to a layer."
    reapply_effects_help = "Reapply all effects previously applied to a layer. NOTE: Does not work for effects that were applied with the \"Merge with layer\" option active."
    reapply_effects_params = [
                               (PDB_INT32, "run_mode", "Run mode"),
                               (PDB_IMAGE, "image", "Input image"),
                               (PDB_DRAWABLE, "drawable", "Input drawable")
                             ]
    gimp.install_procedure("python_layerfx_reapply_effects",
                           reapply_effects_description,
                           reapply_effects_help,
                           authorname,
                           copyrightname,
                           date,
                           "%s_Reapply Effects" % (imgmenupath),
                           "RGB*, GRAY*",
                           PLUGIN,
                           reapply_effects_params,
                           [])
    gimp.install_procedure("python_layer_fx_reapply_effects",
                           reapply_effects_description,
                           reapply_effects_help,
                           authorname,
                           copyrightname,
                           date,
                           "%s_Reapply Effects" % (layersmenupath),
                           "RGB*, GRAY*",
                           PLUGIN,
                           reapply_effects_params,
                           [])

  def python_layerfx_drop_shadow(self, runmode, img, drawable, color = gimpcolor.RGB(0, 0, 0, 255), opacity = 75.0, contour = 0, noise = 0.0, mode = MULTIPLY_MODE, spread = 0.0, size = 5, offsetangle = 120.0, offsetdist = 5.0, knockout = 0, merge = 0):
    layerfx_drop_shadow(runmode, img, drawable, color, opacity, contour, noise, mode, spread, size, offsetangle, offsetdist, knockout, merge)

  def python_layer_fx_drop_shadow(self, runmode, img, drawable, color = gimpcolor.RGB(0, 0, 0, 255), opacity = 75.0, contour = 0, noise = 0.0, mode = MULTIPLY_MODE, spread = 0.0, size = 5, offsetangle = 120.0, offsetdist = 5.0, knockout = 0, merge = 0):
    layerfx_drop_shadow(runmode, img, drawable, color, opacity, contour, noise, mode, spread, size, offsetangle, offsetdist, knockout, merge)

  def python_layerfx_inner_shadow(self, runmode, img, drawable, color = gimpcolor.RGB(0, 0, 0, 255), opacity = 75.0, contour = 0, noise = 0.0, mode = MULTIPLY_MODE, source = 1, choke = 0.0, size = 5, offsetangle = 120.0, offsetdist = 5.0, merge = 0):
    layerfx_inner_shadow(runmode, img, drawable, color, opacity, contour, noise, mode, source, choke, size, offsetangle, offsetdist, merge)

  def python_layer_fx_inner_shadow(self, runmode, img, drawable, color = gimpcolor.RGB(0, 0, 0, 255), opacity = 75.0, contour = 0, noise = 0.0, mode = MULTIPLY_MODE, source = 1, choke = 0.0, size = 5, offsetangle = 120.0, offsetdist = 5.0, merge = 0):
    layerfx_inner_shadow(runmode, img, drawable, color, opacity, contour, noise, mode, source, choke, size, offsetangle, offsetdist, merge)

  def python_layerfx_outer_glow(self, runmode, img, drawable, color = gimpcolor.RGB(255, 255, 190, 255), opacity = 75.0, contour = 0, noise = 0.0, mode = SCREEN_MODE, spread = 0.0, size = 5, knockout = 0, merge = 0):
    layerfx_outer_glow(runmode, img, drawable, color, opacity, contour, noise, mode, spread, size, knockout, merge)

  def python_layer_fx_outer_glow(self, runmode, img, drawable, color = gimpcolor.RGB(255, 255, 190, 255), opacity = 75.0, contour = 0, noise = 0.0, mode = SCREEN_MODE, spread = 0.0, size = 5, knockout = 0, merge = 0):
    layerfx_outer_glow(runmode, img, drawable, color, opacity, contour, noise, mode, spread, size, knockout, merge)

  def python_layerfx_inner_glow(self, runmode, img, drawable, color = gimpcolor.RGB(255, 255, 190, 255), opacity = 75.0, contour = 0, noise = 0.0, mode = SCREEN_MODE, source = 1, choke = 0.0, size = 5, merge = 0):
    layerfx_inner_glow(runmode, img, drawable, color, opacity, contour, noise, mode, source, choke, size, merge)

  def python_layer_fx_inner_glow(self, runmode, img, drawable, color = gimpcolor.RGB(255, 255, 190, 255), opacity = 75.0, contour = 0, noise = 0.0, mode = SCREEN_MODE, source = 1, choke = 0.0, size = 5, merge = 0):
    layerfx_inner_glow(runmode, img, drawable, color, opacity, contour, noise, mode, source, choke, size, merge)

  def python_layerfx_bevel_emboss(self, runmode, img, drawable, style = 0, depth = 3, direction = 0, size = 5, soften = 0, angle = 120.0, altitude = 30.0, glosscontour = 0, highlightcolor = gimpcolor.RGB(255, 255, 255, 255), highlightmode = SCREEN_MODE, highlightopacity = 75.0, shadowcolor = gimpcolor.RGB(0, 0, 0, 255), shadowmode = MULTIPLY_MODE, shadowopacity = 75.0, surfacecontour = 0, use_texture = 0, pattern = "", scale = 100.0, tex_depth = 100.0, invert = 0, merge = 0):
    layerfx_bevel_emboss(runmode, img, drawable, style, depth, direction, size, soften, angle, altitude, glosscontour, highlightcolor, highlightmode, highlightopacity, shadowcolor, shadowmode, shadowopacity, surfacecontour, use_texture, pattern, scale, tex_depth, invert, merge)

  def python_layer_fx_bevel_emboss(self, runmode, img, drawable, style = 0, depth = 3, direction = 0, size = 5, soften = 0, angle = 120.0, altitude = 30.0, glosscontour = 0, highlightcolor = gimpcolor.RGB(255, 255, 255, 255), highlightmode = SCREEN_MODE, highlightopacity = 75.0, shadowcolor = gimpcolor.RGB(0, 0, 0, 255), shadowmode = MULTIPLY_MODE, shadowopacity = 75.0, surfacecontour = 0, use_texture = 0, pattern = "", scale = 100.0, tex_depth = 100.0, invert = 0, merge = 0):
    layerfx_bevel_emboss(runmode, img, drawable, style, depth, direction, size, soften, angle, altitude, glosscontour, highlightcolor, highlightmode, highlightopacity, shadowcolor, shadowmode, shadowopacity, surfacecontour, use_texture, pattern, scale, tex_depth, invert, merge)

  def python_layerfx_satin(self, runmode, img, drawable, color = gimpcolor.RGB(0, 0, 0, 255), opacity = 75.0, mode = MULTIPLY_MODE, offsetangle = 19.0, offsetdist = 11.0, size = 14, contour = 5, invert = 1, merge = 0):
    layerfx_satin(runmode, img, drawable, color, opacity, mode, offsetangle, offsetdist, size, contour, invert, merge)

  def python_layer_fx_satin(self, runmode, img, drawable, color = gimpcolor.RGB(0, 0, 0, 255), opacity = 75.0, mode = MULTIPLY_MODE, offsetangle = 19.0, offsetdist = 11.0, size = 14, contour = 5, invert = 1, merge = 0):
    layerfx_satin(runmode, img, drawable, color, opacity, mode, offsetangle, offsetdist, size, contour, invert, merge)

  def python_layerfx_stroke(self, runmode, img, drawable, color = gimpcolor.RGB(255, 0, 0, 255), opacity = 100.0, mode = NORMAL_MODE, size = 3, position = 50.0, merge = 0):
    layerfx_stroke(runmode, img, drawable, color, opacity, mode, size, position, merge)

  def python_layer_fx_stroke(self, runmode, img, drawable, color = gimpcolor.RGB(255, 0, 0, 255), opacity = 100.0, mode = NORMAL_MODE, size = 3, position = 50.0, merge = 0):
    layerfx_stroke(runmode, img, drawable, color, opacity, mode, size, position, merge)

  def python_layerfx_color_overlay(self, runmode, img, drawable, color = gimpcolor.RGB(255, 255, 255, 255), opacity = 100.0, mode = NORMAL_MODE, merge = 0):
    layerfx_color_overlay(runmode, img, drawable, color, opacity, mode, merge)

  def python_layer_fx_color_overlay(self, runmode, img, drawable, color = gimpcolor.RGB(255, 255, 255, 255), opacity = 100.0, mode = NORMAL_MODE, merge = 0):
    layerfx_color_overlay(runmode, img, drawable, color, opacity, mode, merge)

  def python_layerfx_gradient_overlay(self, runmode, img, drawable, gradient = "FG to BG (RGB)", gradienttype = GRADIENT_LINEAR, repeat = REPEAT_NONE, reverse = 0, opacity = 100.0, mode = NORMAL_MODE, centerx = 0.0, centery = 0.0, angle = 90.0, width = 10.0, merge = 0):
    layerfx_gradient_overlay(runmode, img, drawable, gradient, gradienttype, repeat, reverse, opacity, mode, centerx, centery, angle, width, merge)

  def python_layer_fx_gradient_overlay(self, runmode, img, drawable, gradient = "FG to BG (RGB)", gradienttype = GRADIENT_LINEAR, repeat = REPEAT_NONE, reverse = 0, opacity = 100.0, mode = NORMAL_MODE, centerx = 0.0, centery = 0.0, angle = 90.0, width = 10.0, merge = 0):
    layerfx_gradient_overlay(runmode, img, drawable, gradient, gradienttype, repeat, reverse, opacity, mode, centerx, centery, angle, width, merge)

  def python_layerfx_pattern_overlay(self, runmode, img, drawable, pattern = "", opacity = 100.0, mode = NORMAL_MODE, scale = 100.0, interpolation_type = INTERPOLATION_NONE, merge = 0):
    layerfx_pattern_overlay(runmode, img, drawable, pattern, opacity, mode, scale, interpolation_type, merge)

  def python_layer_fx_pattern_overlay(self, runmode, img, drawable, pattern = "", opacity = 100.0, mode = NORMAL_MODE, scale = 100.0, interpolation_type = INTERPOLATION_NONE, merge = 0):
    layerfx_pattern_overlay(runmode, img, drawable, pattern, opacity, mode, scale, interpolation_type, merge)

  def python_layerfx_reapply_effects(self, runmode, img, drawable):
    layerfx_reapply_effects(runmode, img, drawable)

  def python_layer_fx_reapply_effects(self, runmode, img, drawable):
    layerfx_reapply_effects(runmode, img, drawable)

if __name__ == "__main__":
  layerfxplugin().start()
