#!/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)
