#
# Copyright (c) 2002, 2003, 2004 Art Haas
#
# This file is part of PythonCAD.
#
# PythonCAD 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 2 of the License, or
# (at your option) any later version.
#
# PythonCAD 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 PythonCAD; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
#
# code for setting the preferences of an image
#

import pygtk
pygtk.require('2.0')
import gtk
import gobject

import sys

import Generic.text
import Generic.units
import Generic.image
import Generic.color

def set_current_prefs(gtkimage, prefdict):
    assert prefdict.has_key('THICKNESS_ENTRY'), "Missing THICKNESS_ENTRY"
    _text = prefdict['THICKNESS_ENTRY'].get_chars(0, -1)
    if len(_text) and _text != '+':
        _thickness = float(_text)
        if _thickness > 0.0:
            gtkimage.setOption('LINE_THICKNESS', _thickness)
    assert prefdict.has_key('LEADER_ARROW_ENTRY'), "Missing LEADER_ARROW_ENTRY"
    _text = prefdict['LEADER_ARROW_ENTRY'].get_chars(0, -1)
    if len(_text) and _text != '+':
        _size = float(_text)
        gtkimage.setOption('LEADER_ARROW_SIZE', _size)
    assert prefdict.has_key('FONT_SEL'), "Missing FONT_SEL"
    fn = prefdict['FONT_SEL'].get_font_name()
    family, style, weight, stretch, size = Generic.text.parse_font(fn)
    gtkimage.setOption('FONT_FAMILY', family)
    gtkimage.setOption('FONT_SIZE', size)
    gtkimage.setOption('FONT_STYLE', style)
    gtkimage.setOption('FONT_WEIGHT', weight)
    assert prefdict.has_key('CHAMFER_ENTRY'), "Missing CHAMFER_ENTRY"
    _text = prefdict['CHAMFER_ENTRY'].get_chars(0, -1)
    if len(_text) and _text != '+':
        _length = float(_text)
        if _length > 0.0:
            gtkimage.setOption('CHAMFER_LENGTH', _length)
    assert prefdict.has_key('FILLET_ENTRY'), "Missing FILLET_ENTRY"
    _text = prefdict['FILLET_ENTRY'].get_chars(0, -1)
    if len(_text) and _text != '+':
        _radius = float(_text)
        if _radius > 0.0:
            gtkimage.setOption('FILLET_RADIUS', _radius)
    assert prefdict.has_key('UNIT_MENU'), "Missing UNIT_MENU"
    gtkimage.setUnits(prefdict['UNIT_MENU'].get_history())
    assert prefdict.has_key('HIGHLIGHT_CB'), "Missing HIGHLIGHT_CB"
    gtkimage.setOption('HIGHLIGHT_POINTS', prefdict['HIGHLIGHT_CB'].get_active())

#
# common routines for entry box validation
#

def _entry_move_cursor(entry):
    entry.set_position(-1)
    return gtk.FALSE

def _entry_activate(entry): # this probably isn't a good choice ...
    entry.stop_emission("activate")

def _entry_focus_out(entry, event):
    _text = entry.get_chars(0, -1)
    if _text == '-' or _text == '+':
        entry.delete_text(0, -1)
    return gtk.FALSE

def _entry_insert_text(entry, new_text, new_text_length, position):
    if (new_text.isdigit() or
        new_text == '.' or
        new_text == '+'):
        _string = entry.get_chars(0, -1) + new_text
        _hid = entry.get_data('handlerid')
        entry.handler_block(_hid)
        _pos = entry.get_position()
        _move = True
        if _string == '+':
            _pos = entry.insert_text(new_text, _pos)
        else:
            try:
                _val = float(_string)
                _pos = entry.insert_text(new_text, _pos)
            except StandardError, e:
                _move = False
        entry.handler_unblock(_hid)
        gtk.idle_add(_entry_move_cursor, entry)
    entry.stop_emission("insert-text")

#

def add_misc_page(gtkimage, pd, nb):
    _vbox = gtk.VBox(gtk.FALSE, 2)

    _cb = gtk.CheckButton("Highlight Points")
    _state = gtkimage.getOption('HIGHLIGHT_POINTS')
    _cb.set_active(_state)
    pd['HIGHLIGHT_CB'] = _cb
    _vbox.pack_start(_cb, gtk.FALSE, gtk.FALSE)
    #
    _hbox = gtk.HBox(gtk.TRUE, 5)
    _lb = gtk.Label("Line Thickness:")
    _hbox.pack_start(_lb, gtk.FALSE, gtk.FALSE)
    _thickness = "%g" % gtkimage.getOption('LINE_THICKNESS')
    _entry = gtk.Entry()
    _entry.set_text(_thickness)
    _entry.connect("focus_out_event", _entry_focus_out)
    _entry.connect("activate", _entry_activate)
    _handlerid = _entry.connect("insert_text", _entry_insert_text)
    _entry.set_data('handlerid', _handlerid)
    pd['THICKNESS_ENTRY'] = _entry
    _hbox.pack_start(_entry, gtk.TRUE, gtk.TRUE, 0)
    _vbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 0)
    #
    _hbox = gtk.HBox(gtk.TRUE, 10)
    _lb = gtk.Label("Leader Arrow Size:")
    _hbox.pack_start(_lb, gtk.FALSE, gtk.FALSE)
    _arrowsize = "%g" % gtkimage.getOption('LEADER_ARROW_SIZE')
    _entry = gtk.Entry()
    _entry.set_text(_arrowsize)
    _entry.connect("focus_out_event", _entry_focus_out)
    _entry.connect("activate", _entry_activate)
    _handlerid = _entry.connect("insert_text", _entry_insert_text)
    _entry.set_data('handlerid', _handlerid)
    pd['LEADER_ARROW_ENTRY'] = _entry
    _hbox.pack_start(_entry, gtk.TRUE, gtk.TRUE, 0)
    _vbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 0)
    #
    _vbox.show_all()
    #
    _label = gtk.Label("Miscellaneous")
    nb.append_page(_vbox, _label)

def add_font_page(gtkimage, pd, nb):
    vbox = gtk.VBox(gtk.FALSE, 2)
    frame = gtk.Frame("Font Properties")
    vbox.pack_start(frame, gtk.FALSE, gtk.FALSE)

    fw = gtk.FontSelection()
    fontlist = []
    fontlist.append(gtkimage.getOption('FONT_FAMILY'))
    weight = gtkimage.getOption('FONT_WEIGHT')
    if weight != Generic.text.NORMAL:
        if weight == 1:
            fontlist.append('Light')
        elif weight == 2:
            fontlist.append('Bold')
        elif weight == 3:
            fontlist.append('Heavy')
    style = gtkimage.getOption('FONT_STYLE')
    if style != Generic.text.NORMAL:
        if style == 1:
            fontlist.append('Oblique')
        elif style == 2:
            fontlist.append('Italic')
    fontlist.append(str(gtkimage.getOption('FONT_SIZE')))
    fw.set_font_name(' '.join(fontlist))
    pd['FONT_SEL'] = fw
    frame.add(fw)
    vbox.show_all()

    lb = gtk.Label("Fonts")
    nb.append_page(vbox, lb)

def add_fillets_page(gtkimage, pd, nb):
    _vbox = gtk.VBox(gtk.FALSE, 2)
    _frame = gtk.Frame("Fillets")
    _vbox.pack_start(_frame, gtk.FALSE, gtk.FALSE, 0)

    _hbox = gtk.HBox(gtk.TRUE, 5)
    _label = gtk.Label("Default radius:")
    _hbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 0)
    _radius = "%g" % gtkimage.getOption('FILLET_RADIUS')
    _entry = gtk.Entry()
    _entry.set_text(_radius)
    _entry.connect("focus_out_event", _entry_focus_out)
    _entry.connect("activate", _entry_activate)
    _handlerid = _entry.connect("insert_text", _entry_insert_text)
    _entry.set_data('handlerid', _handlerid)
    pd['FILLET_ENTRY'] = _entry
    _hbox.pack_start(_entry, gtk.TRUE, gtk.TRUE, 5)
    _frame.add(_hbox)

    _vbox.show_all()

    _label = gtk.Label("Fillets")
    nb.append_page(_vbox, _label)

def add_chamfers_page(gtkimage, pd, nb):
    _vbox = gtk.VBox(gtk.FALSE, 2)
    _frame = gtk.Frame("Chamfers")
    _vbox.pack_start(_frame, gtk.FALSE, gtk.FALSE, 0)

    _hbox = gtk.HBox(gtk.FALSE, 2)
    _label = gtk.Label("Default length:")
    _hbox.pack_start(_label, gtk.FALSE, gtk.FALSE)
    _length = "%g" % gtkimage.getOption('CHAMFER_LENGTH')
    _entry = gtk.Entry()
    _entry.set_text(_length)
    _entry.connect("focus_out_event", _entry_focus_out)
    _entry.connect("activate", _entry_activate)
    _handlerid = _entry.connect("insert_text", _entry_insert_text)
    _entry.set_data('handlerid', _handlerid)
    pd['CHAMFER_ENTRY'] = _entry
    _hbox.pack_start(_entry, gtk.TRUE, gtk.TRUE, 0)
    _frame.add(_hbox)

    _label = gtk.Label("Chamfers")
    nb.append_page(_vbox, _label)

def add_units_page(gtkimage, pd, nb):
    vbox = gtk.VBox(gtk.FALSE, 2)
    frame = gtk.Frame("Units")
    vbox.pack_start(frame, gtk.FALSE, gtk.FALSE)

    hbox = gtk.HBox(gtk.FALSE, 2)
    ml = gtk.Label("Units:")
    hbox.pack_start(ml, gtk.FALSE, gtk.FALSE)
    menu = gtk.Menu()
    idx = 0
    unit_list = Generic.units.get_all_units()
    cur_unit = gtkimage.getUnits()
    for i in range(len(unit_list)):
        if i == cur_unit:
            idx = i
        item = gtk.MenuItem(unit_list[i])
        menu.append(item)
    opt_menu = gtk.OptionMenu()
    opt_menu.set_menu(menu)
    opt_menu.set_history(idx)
    pd['UNIT_MENU'] = opt_menu
    hbox.pack_start(opt_menu, gtk.FALSE, gtk.FALSE)
    frame.add(hbox)
    vbox.show_all()

    tl = gtk.Label("Units")
    nb.append_page(vbox, tl)

def check_prefs(gtkimage):
    window = gtkimage.getWindow()
    dialog = gtk.Dialog("Preference", window,
                        gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
                        (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
                         gtk.STOCK_APPLY, gtk.RESPONSE_APPLY,
                         gtk.STOCK_OK, gtk.RESPONSE_OK))
    notebook = gtk.Notebook()
    pref_dict = {}
    dialog.vbox.pack_start(notebook, expand=gtk.TRUE)
    add_units_page(gtkimage, pref_dict, notebook)
    add_chamfers_page(gtkimage, pref_dict, notebook)
    add_fillets_page(gtkimage, pref_dict, notebook)
    add_font_page(gtkimage, pref_dict, notebook)
    add_misc_page(gtkimage, pref_dict, notebook)
    dialog.show_all()
    response = dialog.run()
    if response == gtk.RESPONSE_OK or response == gtk.RESPONSE_APPLY:
        set_current_prefs(gtkimage, pref_dict)
        gtkimage.redraw()
    dialog.destroy()

################################################################
#
# New and improved preferences code ...
#
################################################################

class Prefstate(object):
    """A class for storing and retriving preference values.

The Prefstate class stores references to the widgets used in
making the preference dialog screens. When the dialog is closed
the widgets stored in the Prefstate class are examined for their
values if the user wants to set new preference values.

The Prefstate class has the following methods:

{set/get}TreeView(): Set/Get a gtk.TreeView for the Prefstate instance.
{set/get}HBox(): Set/Get a gtk.HBox for the Prefstate instance.
{set/get}Container(): Set/Get a reference to a gtk.Container instance.
{set/get}PrefKey(): Set/Get a key used for storing preference widget sets.
{set/get}Widget(): Set/Get a keyed reference to a widget.
hasWidgetKey(): Test if a key is used to store a widget reference.
getWidgetKeys(): Return the keys used to refer to stored widgets.
{set/get}Image(): Set/Get the Image used for preference adjustment.
{set/get}Window(): Set/Get the gtk.Window displaying the preference dialog.
    """
    def __init__(self):
        self.__tree_view = None
        self.__hbox = None
        self.__prefkeys = {}
        self.__prefkey = None
        self.__widgets = {}
        self.__image = None
        self.__window = None

    def setTreeView(self, treeview):
        """Store a reference to a TreeView widget.

setTreeView(treeview)

The argument "treeview" must be a gtk.TreeView instance.
        """
        if not isinstance(treeview, gtk.TreeView):
            raise TypeError, "Invalid TreeView: " + `treeview`
        self.__tree_view = treeview

    def getTreeView(self):
        """Return the stored TreeView widget.

getTreeView()

If no gtk.TreeView has been stored this method returns None.
        """
        return self.__tree_view

    def setHBox(self, hbox):
        """Store a reference to a gtk.HBox widget.

setHBox(hbox)

The argument "hbox" must be a gtk.HBox instance.
        """
        if not isinstance(hbox, gtk.HBox):
            raise TypeError, "Invalid HBox: " + `hbox`
        self.__hbox = hbox

    def getHBox(self):
        """Return the stored gtk.HBox.

getHBox()

If no gtk.HBox has been stored this method returns None.
        """
        return self.__hbox

    def setContainer(self, key, container):
        """Store a keyed reference to a gtk.Container instance.

setContainer(key, container)

Argument "key" is a text string, and the container must be
an instance of gtk.Container.
        """
        if not isinstance(container, gtk.Container):
            raise TypeError, "Invalid container: " + `container`
        self.__prefkeys[key] = container

    def getContainer(self, key):
        """Retrieve the gtk.Container referenced by a key.

getContainer(key)

If the key has been used to store a gtk.Container instance, the
stored container is returned. If not, None is returned.
        """
        if key in self.__prefkeys:
            _container = self.__prefkeys[key]
        else:
            _container = None
        return _container

    def setPrefKey(self, key):
        """Store a key representing a screenful of preference widgets.

setPrefKey(key)

Argument "key" should be a string.
        """
        if key not in self.__prefkeys:
            raise ValueError, "No container stored for key."
        self.__prefkey = key

    def getPrefKey(self):
        """Return the current key giving the preference widget screen.

getPrefKey()

This method returns the key last set by setPrefKey(). If that method
has not been invoked None is returned.
        """
        return self.__prefkey

    def delPrefKey(self):
        self.__prefkey = None

    def setWidget(self, key, widget):
        """Store a widget reference in the Prefstate.

setWidget(key, widget)

Argument "key" should be a string. Argument "widget" must be an
instance of gtk.Widget. Trying to use the same key twice will
raise a ValueError exception.
        """
        if not isinstance(widget, gtk.Widget):
            raise TypeError, "Invalid widget: " + `widget`
        if key in self.__widgets:
            raise ValueError, "Duplicate key: " + key
        self.__widgets[key] = widget

    def getWidget(self, key):
        """Return the widget associated with a key

getWidget(key)

Argument "key" should be a string. Using a key that has not
been used with setWidget() results in a KeyError exception.
        """
        return self.__widgets[key]

    def hasWidgetKey(self, key):
        """Test if a key is used for widget association.

hasWidgetKey(key)

This method returns True if the key has already been used to
store a widget.
        """
        return key in self.__widgets

    def getWidgetKeys(self):
        """Return all the keys used to store widgets.

getWidgetKeys()

This method returns a list of strings.
        """
        return self.__widgets.keys()

    def setImage(self, image):
        """Store a reference to the image used for preference adjustment.

setImage(image)

Argument "image" must be an instance of image.Image.
        """
        if not isinstance(image, Generic.image.Image):
            raise TypeError, "Invalid image: " + `image`
        self.__image = image

    def getImage(self):
        """Retrieve the image used for this Prefstate instance.

getImage()

This method raises a ValueError exception if it is called before
setImage().
        """
        if self.__image is None:
            raise ValueError, "Image not set."
        return self.__image

    def setWindow(self, window):
        """Store a reference to a gtk.Window.

setWindow(window)

Argument "window" must be an instance of gtk.Window.
        """
        if not isinstance(window, gtk.Window):
            raise TypeError, "Invalid window: " + `window`
        self.__window = window

    def getWindow(self):
        """Return the stored window for the Prefstate instance.

getWindow()

This method raises a ValueError exception if it is invoked before
setWindow() has been called.
        """
        if self.__window is None:
            raise ValueError, "Window not set."
        return self.__window
    
def entry_activate(entry):
    _text = entry.get_chars(0, -1)
    entry.delete_text(0, -1)
    if len(_text):
        if _text == '-' or _text == '+':
            sys.stderr.write("Incomplete value: '%s'\n" % _text)
        else:
            try:
                _value = float(_text)
                print "value: %g" % _value
            except:
                sys.stderr.write("Invalid float: '%s'\n" % _text)
    else:
        sys.stderr.write("Empty entry box.")

#
# use focus-out events to reset the value in entry boxes
# to their previous value if the entry box text is invalid
#

def _leader_entry_focus_out(entry, event, prefstate):
    _text = entry.get_chars(0, -1)
    if _text == '' or _text == '+':
        entry.delete_text(0, -1)
        _image = prefstate.getImage()
        _size = "%f" % _image.getOption('LEADER_ARROW_SIZE')
        entry.set_text(_size)
    return gtk.FALSE

def _dim_offset_entry_focus_out(entry, event, prefstate):
    _text = entry.get_chars(0, -1)
    if _text == '' or _text == '+':
        entry.delete_text(0, -1)
        _image = prefstate.getImage()
        _size = "%f" % _image.getOption('DIM_OFFSET')
        entry.set_text(_size)
    return gtk.FALSE

def _dim_marker_entry_focus_out(entry, event, prefstate):
    _text = entry.get_chars(0, -1)
    if _text == '' or _text == '+':
        entry.delete_text(0, -1)
        _image = prefstate.getImage()
        _size = "%f" % _image.getOption('DIM_ENDPOINT_SIZE')
        entry.set_text(_size)
    return gtk.FALSE

def _dim_extlen_entry_focus_out(entry, event, prefstate):
    _text = entry.get_chars(0, -1)
    if _text == '' or _text == '+':
        entry.delete_text(0, -1)
        _image = prefstate.getImage()
        _size = "%f" % _image.getOption('DIM_EXTENSION')
        entry.set_text(_size)
    return gtk.FALSE

def _thickness_entry_focus_out(entry, event, prefstate):
    _text = entry.get_chars(0, -1)
    if _text == '' or _text == '+':
        entry.delete_text(0, -1)
        _image = prefstate.getImage()
        _size = "%f" % _image.getOption('LINE_THICKNESS')
        entry.set_text(_size)
    return gtk.FALSE

def _chamfer_entry_focus_out(entry, event, prefstate):
    _text = entry.get_chars(0, -1)
    if _text == '' or _text == '+':
        entry.delete_text(0, -1)
        _image = prefstate.getImage()
        _size = "%f" % _image.getOption('CHAMFER_LENGTH')
        entry.set_text(_size)
    return gtk.FALSE

def _fillet_entry_focus_out(entry, event, prefstate):
    _text = entry.get_chars(0, -1)
    if _text == '' or _text == '+':
        entry.delete_text(0, -1)
        _image = prefstate.getImage()
        _size = "%f" % _image.getOption('FILLET_RADIUS')
        entry.set_text(_size)
    return gtk.FALSE

def entry_focus_out(entry, event):
    _text = entry.get_chars(0, -1)
    if _text == '-' or _text == '+':
        entry.delete_text(0, -1)
    return gtk.FALSE

#
# color change button handlers
#

def _select_background_color(button):
    _da = button.get_child().get_child()
    _color = _da.get_style().bg[gtk.STATE_NORMAL]
    _dialog = gtk.ColorSelectionDialog("Set Background Color")
    _colorsel = _dialog.colorsel
    _colorsel.set_previous_color(_color)
    _colorsel.set_current_color(_color)
    _colorsel.set_has_palette(gtk.TRUE)
    _response = _dialog.run()
    if _response == gtk.RESPONSE_OK:
        _gtk_color = _colorsel.get_current_color()
        _r = int((_gtk_color.red/65535.0) * 255.0)
        _g = int((_gtk_color.green/65535.0) * 255.0)
        _b = int((_gtk_color.blue/65535.0) * 255.0)
        _str = "#%02x%02x%02x" % (_r, _g, _b)
        _color = gtk.gdk.color_parse(_str)
        _da.modify_bg(gtk.STATE_NORMAL, _color)
    _dialog.destroy()

def _select_dimbar_color(button):
    _da = button.get_child().get_child()
    _color = _da.get_style().bg[gtk.STATE_NORMAL]
    _dialog = gtk.ColorSelectionDialog("Set Dimension Bar Color")
    _colorsel = _dialog.colorsel
    _colorsel.set_previous_color(_color)
    _colorsel.set_current_color(_color)
    _colorsel.set_has_palette(gtk.TRUE)
    _response = _dialog.run()
    if _response == gtk.RESPONSE_OK:
        _gtk_color = _colorsel.get_current_color()
        _r = int((_gtk_color.red/65535.0) * 255.0)
        _g = int((_gtk_color.green/65535.0) * 255.0)
        _b = int((_gtk_color.blue/65535.0) * 255.0)
        _str = "#%02x%02x%02x" % (_r, _g, _b)
        _color = gtk.gdk.color_parse(_str)
        _da.modify_bg(gtk.STATE_NORMAL, _color)
    _dialog.destroy()

def _select_font_color(button):
    _da = button.get_child().get_child()
    _color = _da.get_style().bg[gtk.STATE_NORMAL]
    _dialog = gtk.ColorSelectionDialog("Set Font Color")
    _colorsel = _dialog.colorsel
    _colorsel.set_previous_color(_color)
    _colorsel.set_current_color(_color)
    _colorsel.set_has_palette(gtk.TRUE)
    _response = _dialog.run()
    if _response == gtk.RESPONSE_OK:
        _gtk_color = _colorsel.get_current_color()
        _r = int((_gtk_color.red/65535.0) * 255.0)
        _g = int((_gtk_color.green/65535.0) * 255.0)
        _b = int((_gtk_color.blue/65535.0) * 255.0)
        _str = "#%02x%02x%02x" % (_r, _g, _b)
        _color = gtk.gdk.color_parse(_str)
        _da.modify_bg(gtk.STATE_NORMAL, _color)
    _dialog.destroy()

#

def _toggle_widgets_on(widget, checkbox):
    if widget is not checkbox:
        widget.set_sensitive(gtk.TRUE)

def _toggle_widgets_off(widget, checkbox):
    if widget is not checkbox:
        widget.set_sensitive(gtk.FALSE)

def _toggle_secondary_dim_opts(checkbox, vbox):
    if checkbox.get_active():
        vbox.foreach(_toggle_widgets_on, checkbox)
    else:
        vbox.foreach(_toggle_widgets_off, checkbox)

def move_cursor(entry):
    entry.set_position(-1)
    return gtk.FALSE

def entry_insert_text(entry, new_text, new_text_length, position):
    if (new_text.isdigit() or
        new_text == '.' or
        new_text == '+'):
        _string = entry.get_chars(0, -1) + new_text
        _hid = entry.get_data('handlerid')
        entry.handler_block(_hid)
        _pos = entry.get_position()
        _move = True
        if _string == '+':
            _pos = entry.insert_text(new_text, _pos)
        else:
            try:
                _val = float(_string)
                _pos = entry.insert_text(new_text, _pos)
            except StandardError, e:
                _move = False
                sys.stdout.write("exception: '%s'\n" % e)
        entry.handler_unblock(_hid)
        if _move:
            gtk.idle_add(move_cursor, entry)
    entry.stop_emission("insert-text")

def tree_select_cb(selection, prefstate):
    if selection is not None:
        _model, _iter = selection.get_selected()
        if _iter is not None:
            _hbox = prefstate.getHBox()
            _prefkey = prefstate.getPrefKey()
            if _prefkey is not None:
                _old_container = prefstate.getContainer(_prefkey)
                assert _old_container is not None, "No container: " + _prefkey
            _pstring = _model.get_value(_iter, 1)
            # print "second field: '%s'" % _pstring
            _new_container = prefstate.getContainer(_pstring)
            if _new_container is None:
                if _pstring == 'dimensions':
                    _new_container = _make_dimension_opts(prefstate)
                elif _pstring == 'linear':
                    _new_container = _make_linear_opts(prefstate)
                elif _pstring == 'radial':
                    _new_container = _make_radial_opts(prefstate)
                elif _pstring == 'angular':
                    _new_container = _make_angular_opts(prefstate)
                elif _pstring == 'basic':
                    _new_container = _make_basic_opts(prefstate)
                elif _pstring == 'sizes':
                    _new_container = _make_size_opts(prefstate)
                elif _pstring == 'chamfers':
                    _new_container = None
                elif _pstring == 'fillets':
                    _new_container = None
                elif _pstring == 'text':
                    _new_container = _make_text_opts(prefstate)
                elif _pstring == 'primary':
                    _new_container = _make_primary_opts(prefstate)
                elif _pstring == 'secondary':
                    _new_container = _make_secondary_opts(prefstate)
                else:
                    print "unexpected string: '%s'" % _pstring
            if _new_container is not None:
                _frame = None
                if _pstring == 'linear':
                    _frame = prefstate.getWidget('LINEAR_SECONDARY_FRAME')
                elif _pstring == 'radial':
                    _frame = prefstate.getWidget('RADIAL_SECONDARY_FRAME')
                elif _pstring == 'angular':
                    _frame = prefstate.getWidget('ANGULAR_SECONDARY_FRAME')
                else:
                    pass
                if _frame is not None:
                    _flag = True
                    if prefstate.hasWidgetKey('DIM_DUAL_MODE'):
                        _cb = prefstate.getWidget('DIM_DUAL_MODE')
                        _flag = _cb.get_active()
                    if _flag:
                        _frame.foreach(_toggle_widgets_on, _frame)
                    else:
                        _frame.foreach(_toggle_widgets_off, _frame)
                if _prefkey is not None:
                    _old_container.hide_all()
                    _hbox.remove(_old_container)
                _new_container.show_all()
                prefstate.setContainer(_pstring, _new_container)
                prefstate.setPrefKey(_pstring)
                _hbox.pack_start(_new_container, gtk.TRUE, gtk.TRUE, 5)
                #
                # the second time a new container is shown it may not
                # redraw completely - why?
                #
                _hbox.show_all()

def _make_dimension_opts(prefstate):
    _vbox = gtk.VBox(gtk.FALSE, 5)
    _image = prefstate.getImage()

    _frame = gtk.Frame()
    _frame.set_shadow_type(gtk.SHADOW_IN)
    _text = "<span weight='bold' size='16000'>General Dimension Options</span>"
    _label = gtk.Label(_text)
    _label.set_use_markup(gtk.TRUE)
    _frame.add(_label)
    _vbox.pack_start(_frame, gtk.FALSE, gtk.FALSE, 5)

    _size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
    #
    # options for dimension bars
    #
    _frame = gtk.Frame("Dimension Bar Options")
    _table = gtk.Table(5, 2, gtk.FALSE)
    _table.set_border_width(5)
    _table.set_row_spacings(5)
    _table.set_col_spacings(5)
    _frame.add(_table)
    _label = gtk.Label("Offset length:")
    _table.attach(_label, 0, 1, 0, 1,
                  gtk.EXPAND,
                  gtk.EXPAND,
                  2, 2)
    _entry = gtk.Entry()
    _length = "%f" % _image.getOption('DIM_OFFSET')
    _entry.set_text(_length)
    if not prefstate.hasWidgetKey('DIM_OFFSET'):
        prefstate.setWidget('DIM_OFFSET', _entry)
    _entry.connect("activate", entry_activate)
    _entry.connect("focus-out-event", _dim_offset_entry_focus_out, prefstate)
    _handlerid = _entry.connect("insert-text", entry_insert_text)
    _entry.set_data('handlerid', _handlerid)
    _size_group.add_widget(_entry)
    _table.attach(_entry, 1, 2, 0, 1,
                  gtk.FILL | gtk.EXPAND,
                  gtk.FILL | gtk.EXPAND,
                  2, 2)
    _thbox = gtk.HBox(gtk.FALSE)
    _thbox.set_border_width(2)
    _label = gtk.Label("The offset length is the distance between the dimension point and the start of the dimension bar.")
    _thbox.pack_start(_label, gtk.FALSE, gtk.FALSE)
    _label.set_line_wrap(gtk.TRUE)
    _table.attach(_thbox, 0, 2, 1, 2,
                  gtk.FILL | gtk.EXPAND,
                  gtk.FILL | gtk.EXPAND,
                  2, 2)
    #
    _label = gtk.Label("Extension length:")
    _table.attach(_label, 0, 1, 2, 3,
                  gtk.EXPAND,
                  gtk.EXPAND,
                  2, 2)
    _entry = gtk.Entry()
    _length = "%f" % _image.getOption('DIM_EXTENSION')
    _entry.set_text(_length)
    if not prefstate.hasWidgetKey('DIM_EXTENSION'):
        prefstate.setWidget('DIM_EXTENSION', _entry)
    _entry.connect("activate", entry_activate)
    _entry.connect("focus-out-event", _dim_extlen_entry_focus_out, prefstate)
    _handlerid = _entry.connect("insert-text", entry_insert_text)
    _entry.set_data('handlerid', _handlerid)
    _size_group.add_widget(_entry)
    _table.attach(_entry, 1, 2, 2, 3,
                  gtk.FILL | gtk.EXPAND,
                  gtk.FILL | gtk.EXPAND,
                  2, 2)
    _thbox = gtk.HBox(gtk.FALSE)
    _thbox.set_border_width(2)
    _label = gtk.Label("The extension length is the distance the dimension bars extend beyond the dimension crossbar/crossarc.")
    _label.set_line_wrap(gtk.TRUE)
    _thbox.pack_start(_label, gtk.FALSE, gtk.FALSE)
    _table.attach(_thbox, 0, 2, 3, 4,
                  gtk.FILL | gtk.EXPAND,
                  gtk.FILL | gtk.EXPAND,
                  2, 2)
    _fhbox = gtk.HBox(gtk.FALSE, 5)
    _label = gtk.Label('Dimension bar color:')
    _fhbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 5)
    _button = gtk.Button()
    _bframe = gtk.Frame()
    _bframe.set_shadow_type(gtk.SHADOW_ETCHED_OUT)
    _bframe.set_border_width(5)
    _button.add(_bframe)
    _da = gtk.DrawingArea()
    _da.set_size_request(20, 10)
    _dimcolor = _image.getOption('DIM_COLOR')
    _color = gtk.gdk.color_parse(str(_dimcolor))
    _da.modify_bg(gtk.STATE_NORMAL, _color)
    if not prefstate.hasWidgetKey('DIM_COLOR'):
        prefstate.setWidget('DIM_COLOR', _da)
    _button.connect("clicked", _select_dimbar_color)
    _bframe.add(_da)
    _fhbox.pack_start(_button, gtk.FALSE, gtk.FALSE, 5)
    _table.attach(_fhbox, 0, 2, 4, 5,
                  gtk.FILL | gtk.EXPAND,
                  gtk.FILL | gtk.EXPAND,
                  2, 2)
    _vbox.pack_start(_frame, gtk.FALSE, gtk.FALSE, 5)
    #
    # options for dimension text position
    #
    _frame = gtk.Frame("Dimension Text Position")
    _fhbox = gtk.HBox(gtk.FALSE, 5)
    _fhbox.set_border_width(5)
    _frame.add(_fhbox)
    _label = gtk.Label("Text Location at crossbar:")
    _fhbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 5)
    _menu = gtk.Menu()
    _idx = 0
    _opts = ['Splitting', 'Above', 'Below']
    _cur_pos = _image.getOption('DIM_POSITION')
    for _i in range(len(_opts)):
        if _i == _cur_pos:
            _idx = _i
        _item = gtk.MenuItem(_opts[_i])
        _menu.append(_item)
    _opt_menu = gtk.OptionMenu()
    _opt_menu.set_menu(_menu)
    _opt_menu.set_history(_idx)
    if not prefstate.hasWidgetKey('DIM_POSITION'):
        prefstate.setWidget('DIM_POSITION', _opt_menu)
    _fhbox.pack_start(_opt_menu, gtk.FALSE, gtk.FALSE, 0)
    _vbox.pack_start(_frame, gtk.FALSE, gtk.FALSE, 5)
    #
    # options for dimension crossbar/crossarc markers
    #
    _frame = gtk.Frame("Dimension Crossbar Markers")
    _table = gtk.Table(2, 2, gtk.FALSE)
    _table.set_border_width(5)
    _table.set_row_spacings(5)
    _table.set_col_spacings(5)
    _frame.add(_table)
    _label = gtk.Label("Dimension marker:")
    _table.attach(_label, 0, 1, 0, 1,
                  gtk.FILL,
                  gtk.FILL,
                  2, 2)
    _menu = gtk.Menu()
    _idx = 0
    _opts = ['None', 'Arrow', 'Filled Arrow', 'Slash', 'Circle']
    _endpt = _image.getOption('DIM_ENDPOINT')
    for _i in range(len(_opts)):
        if _i == _endpt:
            _idx = _i
        _item = gtk.MenuItem(_opts[_i])
        _menu.append(_item)
    _opt_menu = gtk.OptionMenu()
    _opt_menu.set_menu(_menu)
    _opt_menu.set_history(_idx)
    if not prefstate.hasWidgetKey('DIM_ENDPOINT'):
        prefstate.setWidget('DIM_ENDPOINT', _opt_menu)
    _table.attach(_opt_menu, 1, 2, 0, 1,
                  gtk.FILL,
                  gtk.FILL,
                  2, 2)
    #
    _label = gtk.Label("Marker size:")
    _table.attach(_label, 0, 1, 1, 2,
                  gtk.FILL,
                  gtk.FILL,
                  2, 2)
    _entry = gtk.Entry()
    _size = "%f" % _image.getOption('DIM_ENDPOINT_SIZE')
    _entry.set_text(_size)
    if not prefstate.hasWidgetKey('DIM_ENDPOINT_SIZE'):
        prefstate.setWidget('DIM_ENDPOINT_SIZE', _entry)
    _entry.connect("activate", entry_activate)
    _entry.connect("focus-out-event", _dim_marker_entry_focus_out, prefstate)
    _handlerid = _entry.connect("insert-text", entry_insert_text)
    _entry.set_data('handlerid', _handlerid)
    _size_group.add_widget(_entry)
    _table.attach(_entry, 1, 2, 1, 2,
                  gtk.FILL,
                  gtk.FILL,
                  2, 2)
    _vbox.pack_start(_frame, gtk.FALSE, gtk.FALSE, 5)
    return _vbox

def _get_primary_dim_font(image):
    _fontlist = []
    _fontlist.append(image.getOption('DIM_PRIMARY_FONT_FAMILY'))
    _weight = image.getOption('DIM_PRIMARY_FONT_WEIGHT')
    if _weight != Generic.text.NORMAL:
        if _weight == 1:
            _fontlist.append('Light')
        elif _weight == 2:
            _fontlist.append('Bold')
        elif _weight == 3:
            _fontlist.append('Heavy')
    _style = image.getOption('DIM_PRIMARY_FONT_STYLE')
    if _style != Generic.text.NORMAL:
        if _style == 1:
            _fontlist.append('Oblique')
        elif _style == 2:
            _fontlist.append('Italic')
    _fontlist.append(str(image.getOption('DIM_PRIMARY_FONT_SIZE')))
    return ' '.join(_fontlist)

def _make_primary_opts(prefstate):
    _vbox = gtk.VBox(gtk.FALSE, 2)
    _image = prefstate.getImage()

    _frame = gtk.Frame()
    _frame.set_shadow_type(gtk.SHADOW_IN)
    _text = "<span weight='bold' size='16000'>Primary Dimension Options</span>"
    _label = gtk.Label(_text)
    _label.set_use_markup(gtk.TRUE)
    _frame.add(_label)
    _vbox.pack_start(_frame, gtk.FALSE, gtk.FALSE, 5)

    _frame = gtk.Frame("Units")
    _frame.set_border_width(2)
    _fhbox = gtk.HBox(gtk.FALSE, 5)
    _fhbox.set_border_width(2)
    _frame.add(_fhbox)
    _label = gtk.Label("Primary dimension units:")
    _fhbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 5)
    _menu = gtk.Menu()
    _idx = 0
    _units = Generic.units.get_all_units()
    _cur_unit = _image.getOption('DIM_PRIMARY_UNITS')
    for _i in range(len(_units)):
        if _i == _cur_unit:
            _idx = _i
        _item = gtk.MenuItem(_units[_i])
        _menu.append(_item)
    _opt_menu = gtk.OptionMenu()
    _opt_menu.set_menu(_menu)
    _opt_menu.set_history(_idx)
    if not prefstate.hasWidgetKey('DIM_PRIMARY_UNITS'):
        prefstate.setWidget('DIM_PRIMARY_UNITS', _opt_menu)
    _fhbox.pack_start(_opt_menu, gtk.FALSE, gtk.FALSE, 5)
    _vbox.pack_start(_frame, gtk.FALSE, gtk.FALSE, 5)

    _frame = gtk.Frame("Font Properties")
    _frame.set_border_width(2)
    _fvbox = gtk.VBox(gtk.FALSE, 5)
    _fvbox.set_border_width(2)
    _frame.add(_fvbox)
    _fontsel = gtk.FontSelection()
    _fontsel.set_font_name(_get_primary_dim_font(_image))
    if not prefstate.hasWidgetKey('DIM_PRIMARY_FONT'):
        prefstate.setWidget('DIM_PRIMARY_FONT', _fontsel)
    _fvbox.pack_start(_fontsel, gtk.TRUE, gtk.TRUE, 5)
    _fhbox = gtk.HBox(gtk.FALSE, 5)
    _fhbox.set_border_width(2)
    _label = gtk.Label('Font color:')
    _fhbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 5)
    _button = gtk.Button()
    _bframe = gtk.Frame()
    _bframe.set_shadow_type(gtk.SHADOW_ETCHED_OUT)
    _bframe.set_border_width(5)
    _button.add(_bframe)
    _da = gtk.DrawingArea()
    _da.set_size_request(20, 10)
    _fontcolor = _image.getOption('DIM_PRIMARY_FONT_COLOR')
    _color = gtk.gdk.color_parse(str(_fontcolor))
    _da.modify_bg(gtk.STATE_NORMAL, _color)
    if not prefstate.hasWidgetKey('DIM_PRIMARY_FONT_COLOR'):
        prefstate.setWidget('DIM_PRIMARY_FONT_COLOR', _da)
    _button.connect("clicked", _select_font_color)
    _bframe.add(_da)
    _fhbox.pack_start(_button, gtk.FALSE, gtk.FALSE, 5)
    _fvbox.pack_start(_fhbox, gtk.TRUE, gtk.TRUE, 5)
    _vbox.pack_start(_frame, gtk.FALSE, gtk.FALSE, 5)

    _frame = gtk.Frame("Format Options")
    _frame.set_border_width(2)
    _table = gtk.Table(3, 1, gtk.FALSE)
    _table.set_border_width(5)
    _table.set_row_spacings(5)
    _table.set_col_spacings(5)
    _frame.add(_table)
    _cb = gtk.CheckButton("Print leading 0")
    _state = _image.getOption('DIM_PRIMARY_LEADING_ZERO')
    _cb.set_active(_state)
    if not prefstate.hasWidgetKey('DIM_PRIMARY_LEADING_ZERO'):
        prefstate.setWidget('DIM_PRIMARY_LEADING_ZERO', _cb)
    _table.attach(_cb, 0, 1, 0, 1,
                  gtk.FILL | gtk.EXPAND,
                  gtk.FILL | gtk.EXPAND,
                  2, 2)

    _cb = gtk.CheckButton("Print trailing decimal point")
    _state = _image.getOption('DIM_PRIMARY_TRAILING_DECIMAL')
    _cb.set_active(_state)
    if not prefstate.hasWidgetKey('DIM_PRIMARY_TRAILING_DECIMAL'):
        prefstate.setWidget('DIM_PRIMARY_TRAILING_DECIMAL', _cb)
    _table.attach(_cb, 0, 1, 1, 2,
                  gtk.FILL | gtk.EXPAND,
                  gtk.FILL | gtk.EXPAND,
                  2, 2)

    _thbox = gtk.HBox(gtk.FALSE, 5)
    _label = gtk.Label("Display precision:")
    _thbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 5)
    _prec = _image.getOption('DIM_PRIMARY_PRECISION')
    _adj = gtk.Adjustment(_prec, 0, 15, 1, 1, 1)
    _sb = gtk.SpinButton(_adj)
    _sb.set_digits(0)
    _sb.set_numeric(gtk.TRUE)
    if not prefstate.hasWidgetKey('DIM_PRIMARY_PRECISION'):
        prefstate.setWidget('DIM_PRIMARY_PRECISION', _sb)
    _thbox.pack_start(_sb, gtk.FALSE, gtk.FALSE, 5)
    _table.attach(_thbox, 0, 1, 2, 3,
                  gtk.FILL | gtk.EXPAND,
                  gtk.FILL | gtk.EXPAND,
                  2, 2)
    _vbox.pack_start(_frame, gtk.FALSE, gtk.FALSE, 5)
    return _vbox

def _get_secondary_dim_font(image):
    _fontlist = []
    _fontlist.append(image.getOption('DIM_SECONDARY_FONT_FAMILY'))
    _weight = image.getOption('DIM_SECONDARY_FONT_WEIGHT')
    if _weight != Generic.text.NORMAL:
        if _weight == 1:
            _fontlist.append('Light')
        elif _weight == 2:
            _fontlist.append('Bold')
        elif _weight == 3:
            _fontlist.append('Heavy')
    _style = image.getOption('DIM_SECONDARY_FONT_STYLE')
    if _style != Generic.text.NORMAL:
        if _style == 1:
            _fontlist.append('Oblique')
        elif _style == 2:
            _fontlist.append('Italic')
    _fontlist.append(str(image.getOption('DIM_SECONDARY_FONT_SIZE')))
    return ' '.join(_fontlist)

def _make_secondary_opts(prefstate):
    _vbox = gtk.VBox(gtk.FALSE, 2)
    _image = prefstate.getImage()

    _frame = gtk.Frame()
    _frame.set_shadow_type(gtk.SHADOW_IN)
    _text = "<span weight='bold' size='16000'>Secondary Dimension Options</span>"
    _label = gtk.Label(_text)
    _label.set_use_markup(gtk.TRUE)
    _frame.add(_label)
    _vbox.pack_start(_frame, gtk.TRUE, gtk.TRUE, 5)
    #
    # it would be good to allow the widgets to be used if
    # the check box is active ...
    #
    _cb = gtk.CheckButton("Display secondary dimension text.")
    _state = _image.getOption('DIM_DUAL_MODE')
    _cb.set_active(_state)
    _cb.connect("toggled", _toggle_secondary_dim_opts, _vbox)
    if not prefstate.hasWidgetKey('DIM_DUAL_MODE'):
        prefstate.setWidget('DIM_DUAL_MODE', _cb)
    _vbox.pack_start(_cb, gtk.FALSE, gtk.FALSE, 5)

    _frame = gtk.Frame("Units")
    _frame.set_border_width(2)
    _fhbox = gtk.HBox(gtk.FALSE, 5)
    _fhbox.set_border_width(2)
    _frame.add(_fhbox)
    _label = gtk.Label("Secondary dimension units:")
    _fhbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 5)
    _menu = gtk.Menu()
    _idx = 0
    _units = Generic.units.get_all_units()
    _cur_unit = _image.getOption('DIM_SECONDARY_UNITS')
    for _i in range(len(_units)):
        if _i == _cur_unit:
            _idx = _i
        _item = gtk.MenuItem(_units[_i])
        _menu.append(_item)
    _opt_menu = gtk.OptionMenu()
    _opt_menu.set_menu(_menu)
    _opt_menu.set_history(_idx)
    if not prefstate.hasWidgetKey('DIM_SECONDARY_UNITS'):
        prefstate.setWidget('DIM_SECONDARY_UNITS', _opt_menu)
    _fhbox.pack_start(_opt_menu, gtk.FALSE, gtk.FALSE, 5)
    _vbox.pack_start(_frame, gtk.FALSE, gtk.FALSE, 5)

    _frame = gtk.Frame("Font Properties")
    _frame.set_border_width(2)
    _fvbox = gtk.VBox(gtk.FALSE, 5)
    _fvbox.set_border_width(2)
    _frame.add(_fvbox)
    _fontsel = gtk.FontSelection()
    _fontsel.set_font_name(_get_secondary_dim_font(_image))
    if not prefstate.hasWidgetKey('DIM_SECONDARY_FONT'):
        prefstate.setWidget('DIM_SECONDARY_FONT', _fontsel)
    _fvbox.pack_start(_fontsel, gtk.TRUE, gtk.TRUE, 5)
    _fhbox = gtk.HBox(gtk.FALSE, 5)
    _fhbox.set_border_width(2)
    _label = gtk.Label('Font color:')
    _fhbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 5)
    _button = gtk.Button()
    _bframe = gtk.Frame()
    _bframe.set_shadow_type(gtk.SHADOW_ETCHED_OUT)
    _bframe.set_border_width(5)
    _button.add(_bframe)
    _da = gtk.DrawingArea()
    _da.set_size_request(20, 10)
    _fontcolor = _image.getOption('DIM_SECONDARY_FONT_COLOR')
    _color = gtk.gdk.color_parse(str(_fontcolor))
    _da.modify_bg(gtk.STATE_NORMAL, _color)
    if not prefstate.hasWidgetKey('DIM_SECONDARY_FONT_COLOR'):
        prefstate.setWidget('DIM_SECONDARY_FONT_COLOR', _da)
    _button.connect("clicked", _select_font_color)
    _bframe.add(_da)
    _fhbox.pack_start(_button, gtk.FALSE, gtk.FALSE, 5)
    _fvbox.pack_start(_fhbox, gtk.TRUE, gtk.TRUE, 5)
    _vbox.pack_start(_frame, gtk.FALSE, gtk.FALSE, 5)

    _frame = gtk.Frame("Format Options")
    _frame.set_border_width(2)
    _table = gtk.Table(3, 1, gtk.FALSE)
    _table.set_border_width(5)
    _table.set_row_spacings(5)
    _table.set_col_spacings(5)
    _frame.add(_table)
    _cb = gtk.CheckButton("Print leading 0")
    _state = _image.getOption('DIM_SECONDARY_LEADING_ZERO')
    _cb.set_active(_state)
    if not prefstate.hasWidgetKey('DIM_SECONDARY_LEADING_ZERO'):
        prefstate.setWidget('DIM_SECONDARY_LEADING_ZERO', _cb)
    _table.attach(_cb, 0, 1, 0, 1,
                  gtk.FILL | gtk.EXPAND,
                  gtk.FILL | gtk.EXPAND,
                  2, 2)

    _cb = gtk.CheckButton("Print trailing decimal point")
    _state = _image.getOption('DIM_SECONDARY_TRAILING_DECIMAL')
    _cb.set_active(_state)
    if not prefstate.hasWidgetKey('DIM_SECONDARY_TRAILING_DECIMAL'):
        prefstate.setWidget('DIM_SECONDARY_TRAILING_DECIMAL', _cb)
    _table.attach(_cb, 0, 1, 1, 2,
                  gtk.FILL | gtk.EXPAND,
                  gtk.FILL | gtk.EXPAND,
                  2, 2)

    _thbox = gtk.HBox(gtk.FALSE, 5)
    _label = gtk.Label("Display precision:")
    _thbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 5)
    _prec = _image.getOption('DIM_SECONDARY_PRECISION')
    _adj = gtk.Adjustment(_prec, 0, 15, 1, 1, 1)
    _sb = gtk.SpinButton(_adj)
    _sb.set_digits(0)
    _sb.set_numeric(gtk.TRUE)
    if not prefstate.hasWidgetKey('DIM_SECONDARY_PRECISION'):
        prefstate.setWidget('DIM_SECONDARY_PRECISION', _sb)
    _thbox.pack_start(_sb, gtk.FALSE, gtk.FALSE, 5)
    _table.attach(_thbox, 0, 1, 2, 3,
                  gtk.FILL | gtk.EXPAND,
                  gtk.FILL | gtk.EXPAND,
                  2, 2)
    _vbox.pack_start(_frame, gtk.FALSE, gtk.FALSE, 5)
    _cb = prefstate.getWidget('DIM_DUAL_MODE')
    _cb.emit("toggled")
    return _vbox

def _make_linear_opts(prefstate):
    _vbox = gtk.VBox(gtk.FALSE, 5)
    _image = prefstate.getImage()

    _frame = gtk.Frame()
    _frame.set_shadow_type(gtk.SHADOW_IN)

    _text = "<span weight='bold' size='16000'>Linear Dimension Options</span>"
    _label = gtk.Label(_text)
    _label.set_use_markup(gtk.TRUE)
    _frame.add(_label)
    _vbox.pack_start(_frame, gtk.FALSE, gtk.FALSE, 5)

    _size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)

    _frame = gtk.Frame('Primary Dimension Text Options')
    _table = gtk.Table(2, 2, gtk.FALSE)
    _table.set_border_width(5)
    _table.set_row_spacings(5)
    _table.set_col_spacings(5)
    _frame.add(_table)
    _label = gtk.Label("Default prefix:")
    _table.attach(_label, 0, 1, 0, 1,
                  gtk.EXPAND,
                  gtk.EXPAND,
                  2, 2)
    _entry = gtk.Entry()
    _entry.set_text(_image.getOption('DIM_PRIMARY_PREFIX'))
    _size_group.add_widget(_entry)
    if not prefstate.hasWidgetKey('DIM_PRIMARY_PREFIX'):
        prefstate.setWidget('DIM_PRIMARY_PREFIX', _entry)
    _table.attach(_entry, 1, 2, 0, 1,
                  gtk.FILL | gtk.EXPAND,
                  gtk.FILL | gtk.EXPAND,
                  2, 2)
    _label = gtk.Label("Default suffix:")
    _table.attach(_label, 0, 1, 1, 2,
                  gtk.EXPAND,
                  gtk.EXPAND,
                  2, 2)
    _entry = gtk.Entry()
    _entry.set_text(_image.getOption('DIM_PRIMARY_SUFFIX'))
    _size_group.add_widget(_entry)
    if not prefstate.hasWidgetKey('DIM_PRIMARY_SUFFIX'):
        prefstate.setWidget('DIM_PRIMARY_SUFFIX', _entry)
    _table.attach(_entry, 1, 2, 1, 2,
                  gtk.FILL | gtk.EXPAND,
                  gtk.FILL | gtk.EXPAND,
                  2, 2)
    _vbox.pack_start(_frame, gtk.FALSE, gtk.FALSE, 5)

    _frame = gtk.Frame('Secondary Dimension Text Options')
    _table = gtk.Table(2, 2, gtk.FALSE)
    _table.set_border_width(5)
    _table.set_row_spacings(5)
    _table.set_col_spacings(5)
    _frame.add(_table)
    if not prefstate.hasWidgetKey('LINEAR_SECONDARY_FRAME'):
        prefstate.setWidget('LINEAR_SECONDARY_FRAME', _frame)
    _label = gtk.Label("Default prefix:")
    _table.attach(_label, 0, 1, 0, 1,
                  gtk.EXPAND,
                  gtk.EXPAND,
                  2, 2)
    _entry = gtk.Entry()
    _entry.set_text(_image.getOption('DIM_SECONDARY_PREFIX'))
    _size_group.add_widget(_entry)
    if not prefstate.hasWidgetKey('DIM_SECONDARY_PREFIX'):
        prefstate.setWidget('DIM_SECONDARY_PREFIX', _entry)
    _table.attach(_entry, 1, 2, 0, 1,
                  gtk.FILL | gtk.EXPAND,
                  gtk.FILL | gtk.EXPAND,
                  2, 2)
    _label = gtk.Label("Default suffix:")
    _table.attach(_label, 0, 1, 1, 2,
                  gtk.EXPAND,
                  gtk.EXPAND,
                  2, 2)
    _entry = gtk.Entry()
    _entry.set_text(_image.getOption('DIM_SECONDARY_SUFFIX'))
    _size_group.add_widget(_entry)
    if not prefstate.hasWidgetKey('DIM_SECONDARY_SUFFIX'):
        prefstate.setWidget('DIM_SECONDARY_SUFFIX', _entry)
    _table.attach(_entry, 1, 2, 1, 2,
                  gtk.FILL | gtk.EXPAND,
                  gtk.FILL | gtk.EXPAND,
                  2, 2)
    _vbox.pack_start(_frame, gtk.FALSE, gtk.FALSE, 5)
    return _vbox

def _make_radial_opts(prefstate):
    _vbox = gtk.VBox(gtk.FALSE, 5)
    _image = prefstate.getImage()

    _frame = gtk.Frame()
    _frame.set_shadow_type(gtk.SHADOW_IN)

    _text = "<span weight='bold' size='16000'>Radial Dimension Options</span>"
    _label = gtk.Label(_text)
    _label.set_use_markup(gtk.TRUE)
    _frame.add(_label)
    _vbox.pack_start(_frame, gtk.FALSE, gtk.FALSE, 5)

    _size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)

    _frame = gtk.Frame('Primary Dimension Text Options')
    _table = gtk.Table(2, 2, gtk.FALSE)
    _table.set_border_width(5)
    _table.set_row_spacings(5)
    _table.set_col_spacings(5)
    _frame.add(_table)
    _label = gtk.Label("Default prefix:")
    _table.attach(_label, 0, 1, 0, 1,
                  gtk.EXPAND,
                  gtk.EXPAND,
                  2, 2)
    _entry = gtk.Entry()
    _entry.set_text(_image.getOption('RADIAL_DIM_PRIMARY_PREFIX'))
    _size_group.add_widget(_entry)
    if not prefstate.hasWidgetKey('RADIAL_DIM_PRIMARY_PREFIX'):
        prefstate.setWidget('RADIAL_DIM_PRIMARY_PREFIX', _entry)
    _table.attach(_entry, 1, 2, 0, 1,
                  gtk.FILL | gtk.EXPAND,
                  gtk.FILL | gtk.EXPAND,
                  2, 2)
    _label = gtk.Label("Default suffix:")
    _table.attach(_label, 0, 1, 1, 2,
                  gtk.EXPAND,
                  gtk.EXPAND,
                  2, 2)
    _entry = gtk.Entry()
    _entry.set_text(_image.getOption('RADIAL_DIM_PRIMARY_SUFFIX'))
    _size_group.add_widget(_entry)
    if not prefstate.hasWidgetKey('RADIAL_DIM_PRIMARY_SUFFIX'):
        prefstate.setWidget('RADIAL_DIM_PRIMARY_SUFFIX', _entry)
    _table.attach(_entry, 1, 2, 1, 2,
                  gtk.FILL | gtk.EXPAND,
                  gtk.FILL | gtk.EXPAND,
                  2, 2)
    _vbox.pack_start(_frame, gtk.FALSE, gtk.FALSE, 5)

    _frame = gtk.Frame('Secondary Dimension Text Options')
    _table = gtk.Table(2, 2, gtk.FALSE)
    _table.set_border_width(5)
    _table.set_row_spacings(5)
    _table.set_col_spacings(5)
    _frame.add(_table)
    if not prefstate.hasWidgetKey('RADIAL_SECONDARY_FRAME'):
        prefstate.setWidget('RADIAL_SECONDARY_FRAME', _frame)
    _label = gtk.Label("Default prefix:")
    _table.attach(_label, 0, 1, 0, 1,
                  gtk.EXPAND,
                  gtk.EXPAND,
                  2, 2)
    _entry = gtk.Entry()
    _entry.set_text(_image.getOption('RADIAL_DIM_SECONDARY_PREFIX'))
    _size_group.add_widget(_entry)
    if not prefstate.hasWidgetKey('RADIAL_DIM_SECONDARY_PREFIX'):
        prefstate.setWidget('RADIAL_DIM_SECONDARY_PREFIX', _entry)
    _table.attach(_entry, 1, 2, 0, 1,
                  gtk.FILL | gtk.EXPAND,
                  gtk.FILL | gtk.EXPAND,
                  2, 2)
    _label = gtk.Label("Default suffix:")
    _table.attach(_label, 0, 1, 1, 2,
                  gtk.EXPAND,
                  gtk.EXPAND,
                  2, 2)
    _entry = gtk.Entry()
    _entry.set_text(_image.getOption('RADIAL_DIM_SECONDARY_SUFFIX'))
    _size_group.add_widget(_entry)
    if not prefstate.hasWidgetKey('RADIAL_DIM_SECONDARY_SUFFIX'):
        prefstate.setWidget('RADIAL_DIM_SECONDARY_SUFFIX', _entry)
    _table.attach(_entry, 1, 2, 1, 2,
                  gtk.FILL | gtk.EXPAND,
                  gtk.FILL | gtk.EXPAND,
                  2, 2)
    _vbox.pack_start(_frame, gtk.FALSE, gtk.FALSE, 5)

    _cb = gtk.CheckButton("Show diametrical dimension value")
    _state = _image.getOption('RADIAL_DIM_DIA_MODE')
    _cb.set_active(_state)
    if not prefstate.hasWidgetKey('RADIAL_DIM_DIA_MODE'):
        prefstate.setWidget('RADIAL_DIM_DIA_MODE', _cb)
    _vbox.pack_start(_cb, gtk.FALSE, gtk.FALSE, 5)
    return _vbox

def _make_angular_opts(prefstate):
    _vbox = gtk.VBox(gtk.FALSE, 5)
    _image = prefstate.getImage()

    _frame = gtk.Frame()
    _frame.set_shadow_type(gtk.SHADOW_IN)

    _text = "<span weight='bold' size='16000'>Angular Dimension Options</span>"
    _label = gtk.Label(_text)
    _label.set_use_markup(gtk.TRUE)
    _frame.add(_label)
    _vbox.pack_start(_frame, gtk.FALSE, gtk.FALSE, 5)

    _size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)

    _frame = gtk.Frame('Primary Dimension Text Options')
    _table = gtk.Table(2, 2, gtk.FALSE)
    _table.set_border_width(5)
    _table.set_row_spacings(5)
    _table.set_col_spacings(5)
    _frame.add(_table)
    _label = gtk.Label("Default prefix:")
    _table.attach(_label, 0, 1, 0, 1,
                  gtk.EXPAND,
                  gtk.EXPAND,
                  2, 2)
    _entry = gtk.Entry()
    _entry.set_text(_image.getOption('ANGULAR_DIM_PRIMARY_PREFIX'))
    _size_group.add_widget(_entry)
    if not prefstate.hasWidgetKey('ANGULAR_DIM_PRIMARY_PREFIX'):
        prefstate.setWidget('ANGULAR_DIM_PRIMARY_PREFIX', _entry)
    _table.attach(_entry, 1, 2, 0, 1,
                  gtk.FILL | gtk.EXPAND,
                  gtk.FILL | gtk.EXPAND,
                  2, 2)
    _label = gtk.Label("Default suffix:")
    _table.attach(_label, 0, 1, 1, 2,
                  gtk.EXPAND,
                  gtk.EXPAND,
                  2, 2)
    _entry = gtk.Entry()
    _entry.set_text(_image.getOption('ANGULAR_DIM_PRIMARY_SUFFIX'))
    _size_group.add_widget(_entry)
    if not prefstate.hasWidgetKey('ANGULAR_DIM_PRIMARY_SUFFIX'):
        prefstate.setWidget('ANGULAR_DIM_PRIMARY_SUFFIX', _entry)
    _table.attach(_entry, 1, 2, 1, 2,
                  gtk.FILL | gtk.EXPAND,
                  gtk.FILL | gtk.EXPAND,
                  2, 2)
    _vbox.pack_start(_frame, gtk.FALSE, gtk.FALSE, 5)

    _frame = gtk.Frame('Secondary Dimension Text Options')
    _table = gtk.Table(2, 2, gtk.FALSE)
    _table.set_border_width(5)
    _table.set_row_spacings(5)
    _table.set_col_spacings(5)
    _frame.add(_table)
    if not prefstate.hasWidgetKey('ANGULAR_SECONDARY_FRAME'):
        prefstate.setWidget('ANGULAR_SECONDARY_FRAME', _frame)
    _label = gtk.Label("Default prefix:")
    _table.attach(_label, 0, 1, 0, 1,
                  gtk.EXPAND,
                  gtk.EXPAND,
                  2, 2)
    _entry = gtk.Entry()
    _entry.set_text(_image.getOption('ANGULAR_DIM_SECONDARY_PREFIX'))
    _size_group.add_widget(_entry)
    if not prefstate.hasWidgetKey('ANGULAR_DIM_SECONDARY_PREFIX'):
        prefstate.setWidget('ANGULAR_DIM_SECONDARY_PREFIX', _entry)
    _table.attach(_entry, 1, 2, 0, 1,
                  gtk.FILL | gtk.EXPAND,
                  gtk.FILL | gtk.EXPAND,
                  2, 2)
    _label = gtk.Label("Default suffix:")
    _table.attach(_label, 0, 1, 1, 2,
                  gtk.EXPAND,
                  gtk.EXPAND,
                  2, 2)
    _entry = gtk.Entry()
    _entry.set_text(_image.getOption('ANGULAR_DIM_SECONDARY_SUFFIX'))
    _size_group.add_widget(_entry)
    if not prefstate.hasWidgetKey('ANGULAR_DIM_SECONDARY_SUFFIX'):
        prefstate.setWidget('ANGULAR_DIM_SECONDARY_SUFFIX', _entry)
    _table.attach(_entry, 1, 2, 1, 2,
                  gtk.FILL | gtk.EXPAND,
                  gtk.FILL | gtk.EXPAND,
                  2, 2)
    _vbox.pack_start(_frame, gtk.FALSE, gtk.FALSE, 5)
    return _vbox

def _make_basic_opts(prefstate):
    _vbox = gtk.VBox(gtk.FALSE, 5)
    _image = prefstate.getImage()

    _frame = gtk.Frame()
    _frame.set_shadow_type(gtk.SHADOW_IN)

    _text = "<span weight='bold' size='16000'>Basic Options</span>"
    _label = gtk.Label(_text)
    _label.set_use_markup(gtk.TRUE)
    _frame.add(_label)
    _vbox.pack_start(_frame, gtk.FALSE, gtk.FALSE, 5)

    _frame = gtk.Frame("Units")
    _fhbox = gtk.HBox(gtk.FALSE, 5)
    _fhbox.set_border_width(5)
    _frame.add(_fhbox)
    _label = gtk.Label("Drawing units:")
    _fhbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 5)
    _menu = gtk.Menu()
    _idx = 0
    _unit_list = Generic.units.get_all_units()
    _cur_unit = _image.getUnits()
    for _i in range(len(_unit_list)):
        if _i == _cur_unit:
            _idx = _i
        _item = gtk.MenuItem(_unit_list[_i])
        _menu.append(_item)
    _opt_menu = gtk.OptionMenu()
    _opt_menu.set_menu(_menu)
    _opt_menu.set_history(_idx)
    if not prefstate.hasWidgetKey('DRAWING_UNITS'):
        prefstate.setWidget('DRAWING_UNITS', _opt_menu)
    _fhbox.pack_start(_opt_menu, gtk.FALSE, gtk.FALSE, 5)
    _vbox.pack_start(_frame, gtk.FALSE, gtk.FALSE, 5)

    _frame = gtk.Frame("Highlight Points")
    _fhbox = gtk.HBox(gtk.FALSE, 5)
    _fhbox.set_border_width(5)
    _frame.add(_fhbox)
    _cb = gtk.CheckButton("Boxes are drawn around Point objects")
    _state = _image.getOption('HIGHLIGHT_POINTS')
    _cb.set_active(_state)
    if not prefstate.hasWidgetKey('HIGHLIGHT_POINTS'):
        prefstate.setWidget('HIGHLIGHT_POINTS', _cb)
    _fhbox.pack_start(_cb, gtk.FALSE, gtk.FALSE, 5)
    _vbox.pack_start(_frame, gtk.FALSE, gtk.FALSE, 5)

    _frame = gtk.Frame("Colors")
    _table = gtk.Table(4, 2, gtk.FALSE)
    _table.set_border_width(5)
    _table.set_row_spacings(5)
    _table.set_col_spacings(5)
    _frame.add(_table)
    _label = gtk.Label("Drawing area color:")
    _table.attach(_label, 0, 1, 0, 1,
                  gtk.FILL,
                  gtk.FILL,
                  2, 2)
    _button = gtk.Button()
    _bframe = gtk.Frame()
    _bframe.set_shadow_type(gtk.SHADOW_ETCHED_OUT)
    _bframe.set_border_width(5)
    _button.add(_bframe)
    _da = gtk.DrawingArea()
    _da.set_size_request(20, 10)
    _bgcolor = _image.getOption('BACKGROUND_COLOR')
    _color = gtk.gdk.color_parse(str(_bgcolor))
    _da.modify_bg(gtk.STATE_NORMAL, _color)
    if not prefstate.hasWidgetKey('BACKGROUND_COLOR'):
        prefstate.setWidget('BACKGROUND_COLOR', _da)
    _bframe.add(_da)
    _button.connect("clicked", _select_background_color)
    _table.attach(_button, 1, 2, 0, 1,
                  gtk.FILL,
                  gtk.FILL,
                  2, 2)
    #
    _label = gtk.Label("Inactive layer color:")
    _table.attach(_label, 0, 1, 1, 2,
                  gtk.FILL,
                  gtk.FILL,
                  2, 2)
    _button = gtk.Button()
    _bframe = gtk.Frame()
    _bframe.set_shadow_type(gtk.SHADOW_ETCHED_OUT)
    _bframe.set_border_width(5)
    _button.add(_bframe)
    _da = gtk.DrawingArea()
    _da.set_size_request(20, 10)
    _ilcolor = _image.getOption('INACTIVE_LAYER_COLOR')
    _color = gtk.gdk.color_parse(str(_ilcolor))
    _da.modify_bg(gtk.STATE_NORMAL, _color)
    if not prefstate.hasWidgetKey('INACTIVE_LAYER_COLOR'):
        prefstate.setWidget('INACTIVE_LAYER_COLOR', _da)
    _bframe.add(_da)
    _button.connect("clicked", _select_background_color)
    _table.attach(_button, 1, 2, 1, 2,
                  gtk.FILL,
                  gtk.FILL,
                  2, 2)
    #
    _label = gtk.Label("Single point color:")
    _table.attach(_label, 0, 1, 2, 3,
                  gtk.FILL,
                  gtk.FILL,
                  2, 2)
    _button = gtk.Button()
    _bframe = gtk.Frame()
    _bframe.set_shadow_type(gtk.SHADOW_ETCHED_OUT)
    _bframe.set_border_width(5)
    _button.add(_bframe)
    _da = gtk.DrawingArea()
    _da.set_size_request(20, 10)
    _spcolor = _image.getOption('SINGLE_POINT_COLOR')
    _color = gtk.gdk.color_parse(str(_spcolor))
    _da.modify_bg(gtk.STATE_NORMAL, _color)
    if not prefstate.hasWidgetKey('SINGLE_POINT_COLOR'):
        prefstate.setWidget('SINGLE_POINT_COLOR', _da)
    _bframe.add(_da)
    _button.connect("clicked", _select_background_color)
    _table.attach(_button, 1, 2, 2, 3,
                  gtk.FILL,
                  gtk.FILL,
                  2, 2)
    #
    _label = gtk.Label("Multi point color:")
    _table.attach(_label, 0, 1, 3, 4,
                  gtk.FILL,
                  gtk.FILL,
                  2, 2)
    _button = gtk.Button()
    _bframe = gtk.Frame()
    _bframe.set_shadow_type(gtk.SHADOW_ETCHED_OUT)
    _bframe.set_border_width(5)
    _button.add(_bframe)
    _da = gtk.DrawingArea()
    _da.set_size_request(20, 10)
    _mpcolor = _image.getOption('MULTI_POINT_COLOR')
    _color = gtk.gdk.color_parse(str(_mpcolor))
    _da.modify_bg(gtk.STATE_NORMAL, _color)
    if not prefstate.hasWidgetKey('MULTI_POINT_COLOR'):
        prefstate.setWidget('MULTI_POINT_COLOR', _da)
    _bframe.add(_da)
    _button.connect("clicked", _select_background_color)
    _table.attach(_button, 1, 2, 3, 4,
                  gtk.FILL,
                  gtk.FILL,
                  2, 2)
    
    _vbox.pack_start(_frame, gtk.FALSE, gtk.FALSE, 5)
    _size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)

    _frame = gtk.Frame("Line Thickness")
    _fhbox = gtk.HBox(gtk.FALSE, 5)
    _fhbox.set_border_width(5)
    _frame.add(_fhbox)
    _label = gtk.Label("Thickness:")
    _fhbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 5)
    _entry = gtk.Entry()
    _thickness = "%f" % _image.getOption('LINE_THICKNESS')
    _entry.set_text(_thickness)
    if not prefstate.hasWidgetKey('LINE_THICKNESS'):
        prefstate.setWidget('LINE_THICKNESS', _entry)
    _entry.connect("activate", entry_activate)
    _entry.connect("focus-out-event", _thickness_entry_focus_out, prefstate)
    _handlerid = _entry.connect("insert-text", entry_insert_text)
    _entry.set_data('handlerid', _handlerid)
    _size_group.add_widget(_entry)
    _fhbox.pack_start(_entry, gtk.FALSE, gtk.FALSE, 5)
    _vbox.pack_start(_frame, gtk.FALSE, gtk.FALSE, 5)
    return _vbox

def _make_size_opts(prefstate):
    _vbox = gtk.VBox(gtk.FALSE, 5)
    _image = prefstate.getImage()
    _frame = gtk.Frame()
    _frame.set_shadow_type(gtk.SHADOW_IN)

    _label_size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
    _entry_size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)

    _text = "<span weight='bold' size='16000'>Size Options</span>"
    _label = gtk.Label(_text)
    _label.set_use_markup(gtk.TRUE)
    _frame.add(_label)
    _vbox.pack_start(_frame, gtk.FALSE, gtk.FALSE, 5)
    #
    # leader line arrow size
    #
    _frame = gtk.Frame("Leader Arrow Size")
    _fhbox = gtk.HBox(gtk.FALSE, 5)
    _fhbox.set_border_width(5)
    _frame.add(_fhbox)
    _label = gtk.Label("Size:")
    _label_size_group.add_widget(_label)
    _fhbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 5)
    _entry = gtk.Entry()
    _arrowsize = "%f" % _image.getOption('LEADER_ARROW_SIZE')
    _entry.set_text(_arrowsize)
    if not prefstate.hasWidgetKey('LEADER_ARROW_SIZE'):
        prefstate.setWidget('LEADER_ARROW_SIZE', _entry)
    _entry.connect("activate", entry_activate)
    _entry.connect("focus-out-event", _leader_entry_focus_out, prefstate)
    _handlerid = _entry.connect("insert-text", entry_insert_text)
    _entry.set_data('handlerid', _handlerid)
    _entry_size_group.add_widget(_entry)
    _fhbox.pack_start(_entry, gtk.FALSE, gtk.FALSE, 5)
    _vbox.pack_start(_frame, gtk.FALSE, gtk.FALSE, 5)
    #
    # Chamfer length
    #
    _frame = gtk.Frame("Chamfer Length")
    _fhbox = gtk.HBox(gtk.FALSE, 5)
    _fhbox.set_border_width(5)
    _frame.add(_fhbox)

    _label = gtk.Label("Length:")
    _label_size_group.add_widget(_label)
    _fhbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 5)
    _entry = gtk.Entry()
    _length = "%f" % _image.getOption('CHAMFER_LENGTH')
    _entry.set_text(_length)
    if not prefstate.hasWidgetKey('CHAMFER_LENGTH'):
        prefstate.setWidget('CHAMFER_LENGTH', _entry)
    _entry.connect("activate", entry_activate)
    _entry.connect("focus-out-event", _chamfer_entry_focus_out, prefstate)
    _handlerid = _entry.connect("insert-text", entry_insert_text)
    _entry.set_data('handlerid', _handlerid)
    _entry_size_group.add_widget(_entry)
    _fhbox.pack_start(_entry, gtk.FALSE, gtk.FALSE, 5)
    _vbox.pack_start(_frame, gtk.FALSE, gtk.FALSE, 5)
    #
    # Fillet radius
    #
    _frame = gtk.Frame("Fillet Radius")
    _fhbox = gtk.HBox(gtk.FALSE, 5)
    _fhbox.set_border_width(5)
    _frame.add(_fhbox)

    _label = gtk.Label("Radius:")
    _label_size_group.add_widget(_label)
    _fhbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 5)
    _entry = gtk.Entry()
    _radius = "%f" % _image.getOption('FILLET_RADIUS')
    _entry.set_text(_radius)
    if not prefstate.hasWidgetKey('FILLET_RADIUS'):
        prefstate.setWidget('FILLET_RADIUS', _entry)
    _entry.connect("activate", entry_activate)
    _entry.connect("focus-out-event", _fillet_entry_focus_out, prefstate)
    _handlerid = _entry.connect("insert-text", entry_insert_text)
    _entry.set_data('handlerid', _handlerid)
    _entry_size_group.add_widget(_entry)
    _fhbox.pack_start(_entry, gtk.FALSE, gtk.FALSE, 5)
    _vbox.pack_start(_frame, gtk.FALSE, gtk.FALSE, 5)
    return _vbox

def _make_text_font(image):
    _fontlist = []
    _fontlist.append(image.getOption('FONT_FAMILY'))
    _weight = image.getOption('FONT_WEIGHT')
    if _weight != Generic.text.NORMAL:
        if _weight == 1:
            _fontlist.append('Light')
        elif _weight == 2:
            _fontlist.append('Bold')
        elif _weight == 3:
            _fontlist.append('Heavy')
    _style = image.getOption('FONT_STYLE')
    if _style != Generic.text.NORMAL:
        if _style == 1:
            _fontlist.append('Oblique')
        elif _style == 2:
            _fontlist.append('Italic')
    _fontlist.append(str(image.getOption('FONT_SIZE')))
    return ' '.join(_fontlist)

def _make_text_opts(prefstate):
    _vbox = gtk.VBox(gtk.FALSE, 5)
    _image = prefstate.getImage()

    _frame = gtk.Frame()
    _frame.set_shadow_type(gtk.SHADOW_IN)

    _text = "<span weight='bold' size='16000'>Text Options</span>"
    _label = gtk.Label(_text)
    _label.set_use_markup(gtk.TRUE)
    _frame.add(_label)
    _vbox.pack_start(_frame, gtk.FALSE, gtk.FALSE, 5)

    _frame = gtk.Frame("Font Properties")
    _frame.set_border_width(5)
    _fvbox = gtk.VBox(gtk.FALSE, 5)
    _frame.add(_fvbox)
    _fontsel = gtk.FontSelection()
    _fontsel.set_font_name(_make_text_font(_image))
    if not prefstate.hasWidgetKey('FONT_WIDGET'):
        prefstate.setWidget('FONT_WIDGET', _fontsel)
    _fvbox.pack_start(_fontsel, gtk.FALSE, gtk.FALSE, 5)
    _fhbox = gtk.HBox(gtk.FALSE, 5)
    _fhbox.set_border_width(2)
    _fvbox.pack_start(_fhbox, gtk.FALSE, gtk.FALSE, 5)
    _label = gtk.Label('Font color:')
    _fhbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 5)
    _button = gtk.Button()
    _bframe = gtk.Frame()
    _bframe.set_shadow_type(gtk.SHADOW_ETCHED_OUT)
    _bframe.set_border_width(5)
    _button.add(_bframe)
    _da = gtk.DrawingArea()
    _da.set_size_request(20, 10)
    _fontcolor = _image.getOption('FONT_COLOR')
    _color = gtk.gdk.color_parse(str(_fontcolor))
    _da.modify_bg(gtk.STATE_NORMAL, _color)
    if not prefstate.hasWidgetKey('FONT_COLOR'):
        prefstate.setWidget('FONT_COLOR', _da)
    _button.connect("clicked", _select_font_color)
    _bframe.add(_da)
    _fhbox.pack_start(_button, gtk.FALSE, gtk.FALSE, 5)
    _vbox.pack_start(_frame, gtk.FALSE, gtk.FALSE, 5)
    return _vbox

def _make_pref_tree(hbox, prefstate):
    _sw = gtk.ScrolledWindow()
    _sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
    _sw.set_size_request(120, 300)
    _tree_store = gtk.TreeStore(gobject.TYPE_STRING,
                                gobject.TYPE_STRING)
    _iter1 = _tree_store.append(None)
    _tree_store.set(_iter1, 0, 'Basic')
    _tree_store.set(_iter1, 1, 'basic')
    _iter1 = _tree_store.append(None)
    _tree_store.set(_iter1, 0, 'Sized Objects')
    _tree_store.set(_iter1, 1, 'sizes')
    _iter1 = _tree_store.append(None)
    _tree_store.set(_iter1, 0, 'Text')
    _tree_store.set(_iter1, 1, 'text')
    _tree_view = gtk.TreeView(_tree_store)
    _iter1 = _tree_store.append(None)
    _tree_store.set(_iter1, 0, 'Dimensions')
    _tree_store.set(_iter1, 1, 'dimensions')
    _iter2 = _tree_store.append(_iter1)
    _tree_store.set(_iter2, 0, 'Primary')
    _tree_store.set(_iter2, 1, 'primary')
    _iter2 = _tree_store.append(_iter1)
    _tree_store.set(_iter2, 0, 'Secondary')
    _tree_store.set(_iter2, 1, 'secondary')
    _iter2 = _tree_store.append(_iter1)
    _tree_store.set(_iter2, 0, 'Linear')
    _tree_store.set(_iter2, 1, 'linear')
    _iter2 = _tree_store.append(_iter1)
    _tree_store.set(_iter2, 0, 'Radial')
    _tree_store.set(_iter2, 1, 'radial')
    _iter2 = _tree_store.append(_iter1)
    _tree_store.set(_iter2, 0, 'Angular')
    _tree_store.set(_iter2, 1, 'angular')
    _tree_view.set_reorderable(gtk.FALSE) # no drag-and-drop
    _select = _tree_view.get_selection()
    _select.set_mode(gtk.SELECTION_SINGLE)
    _select.connect("changed", tree_select_cb, prefstate)
    _renderer = gtk.CellRendererText()
    _column = gtk.TreeViewColumn("Options", _renderer, text=0)
    _tree_view.append_column(_column)
    _sw.add(_tree_view)
    hbox.pack_start(_sw, gtk.FALSE, gtk.FALSE, 5)
    return _tree_view


def _set_dim_offset(prefstate):
    _image = prefstate.getImage()
    _entry = prefstate.getWidget('DIM_OFFSET')
    _text = _entry.get_chars(0, -1)
    if len(_text) and _text != '+':
        _offset = float(_text)
        _image.setOption('DIM_OFFSET', _offset)

def _set_dim_extension(prefstate):
    _image = prefstate.getImage()
    _entry = prefstate.getWidget('DIM_EXTENSION')
    _text = _entry.get_chars(0, -1)
    if len(_text) and _text != '+':
        _ext = float(_text)
        _image.setOption('DIM_EXTENSION', _ext)

def _set_dim_color(prefstate):
    _image = prefstate.getImage()
    _da = prefstate.getWidget('DIM_COLOR')
    _color= _da.get_style().bg[gtk.STATE_NORMAL]
    _r = int((_color.red/65535.0) * 255.0)
    _g = int((_color.green/65535.0) * 255.0)
    _b = int((_color.blue/65535.0) * 255.0)
    _dimcolor = Generic.color.get_color(_r, _g, _b)
    _image.setOption('DIM_COLOR', _dimcolor)

def _set_background_color(prefstate):
    _image = prefstate.getImage()
    _da = prefstate.getWidget('BACKGROUND_COLOR')
    _color= _da.get_style().bg[gtk.STATE_NORMAL]
    _r = int((_color.red/65535.0) * 255.0)
    _g = int((_color.green/65535.0) * 255.0)
    _b = int((_color.blue/65535.0) * 255.0)
    _bgcolor = Generic.color.get_color(_r, _g, _b)
    _image.setOption('BACKGROUND_COLOR', _bgcolor)

def _set_inactive_layer_color(prefstate):
    _image = prefstate.getImage()
    _da = prefstate.getWidget('INACTIVE_LAYER_COLOR')
    _color= _da.get_style().bg[gtk.STATE_NORMAL]
    _r = int((_color.red/65535.0) * 255.0)
    _g = int((_color.green/65535.0) * 255.0)
    _b = int((_color.blue/65535.0) * 255.0)
    _bgcolor = Generic.color.get_color(_r, _g, _b)
    _image.setOption('INACTIVE_LAYER_COLOR', _bgcolor)

def _set_single_point_color(prefstate):
    _image = prefstate.getImage()
    _da = prefstate.getWidget('SINGLE_POINT_COLOR')
    _color= _da.get_style().bg[gtk.STATE_NORMAL]
    _r = int((_color.red/65535.0) * 255.0)
    _g = int((_color.green/65535.0) * 255.0)
    _b = int((_color.blue/65535.0) * 255.0)
    _spcolor = Generic.color.get_color(_r, _g, _b)
    _image.setOption('SINGLE_POINT_COLOR', _spcolor)

def _set_multi_point_color(prefstate):
    _image = prefstate.getImage()
    _da = prefstate.getWidget('MULTI_POINT_COLOR')
    _color= _da.get_style().bg[gtk.STATE_NORMAL]
    _r = int((_color.red/65535.0) * 255.0)
    _g = int((_color.green/65535.0) * 255.0)
    _b = int((_color.blue/65535.0) * 255.0)
    _mpcolor = Generic.color.get_color(_r, _g, _b)
    _image.setOption('MULTI_POINT_COLOR', _mpcolor)

def _set_font_color(prefstate):
    _image = prefstate.getImage()
    _da = prefstate.getWidget('FONT_COLOR')
    _color= _da.get_style().bg[gtk.STATE_NORMAL]
    _r = int((_color.red/65535.0) * 255.0)
    _g = int((_color.green/65535.0) * 255.0)
    _b = int((_color.blue/65535.0) * 255.0)
    _fontcolor = Generic.color.get_color(_r, _g, _b)
    _image.setOption('FONT_COLOR', _fontcolor)

def _set_dim_primary_font_color(prefstate):
    _image = prefstate.getImage()
    _da = prefstate.getWidget('DIM_PRIMARY_FONT_COLOR')
    _color= _da.get_style().bg[gtk.STATE_NORMAL]
    _r = int((_color.red/65535.0) * 255.0)
    _g = int((_color.green/65535.0) * 255.0)
    _b = int((_color.blue/65535.0) * 255.0)
    _fontcolor = Generic.color.get_color(_r, _g, _b)
    _image.setOption('DIM_PRIMARY_FONT_COLOR', _fontcolor)

def _set_dim_secondary_font_color(prefstate):
    _image = prefstate.getImage()
    _da = prefstate.getWidget('DIM_SECONDARY_FONT_COLOR')
    _color= _da.get_style().bg[gtk.STATE_NORMAL]
    _r = int((_color.red/65535.0) * 255.0)
    _g = int((_color.green/65535.0) * 255.0)
    _b = int((_color.blue/65535.0) * 255.0)
    _fontcolor = Generic.color.get_color(_r, _g, _b)
    _image.setOption('DIM_SECONDARY_FONT_COLOR', _fontcolor)

def _set_line_thickness(prefstate):
    _image = prefstate.getImage()
    _entry = prefstate.getWidget('LINE_THICKNESS')
    _text = _entry.get_chars(0, -1)
    if len(_text) and _text != '+':
        _thickness = float(_text)
        _image.setOption('LINE_THICKNESS', _thickness)

def _set_leader_arrow_size(prefstate):
    _image = prefstate.getImage()
    _entry = prefstate.getWidget('LEADER_ARROW_SIZE')
    _text = _entry.get_chars(0, -1)
    if len(_text) and _text != '+':
        _size = float(_text)
        _image.setOption('LEADER_ARROW_SIZE', _size)

def _set_chamfer_length(prefstate):
    _image = prefstate.getImage()
    _entry = prefstate.getWidget('CHAMFER_LENGTH')
    _text = _entry.get_chars(0, -1)
    if len(_text) and _text != '+':
        _length = float(_text)
        _image.setOption('CHAMFER_LENGTH', _length)

def _set_fillet_radius(prefstate):
    _image = prefstate.getImage()
    _entry = prefstate.getWidget('FILLET_RADIUS')
    _text = _entry.get_chars(0, -1)
    if len(_text) and _text != '+':
        _radius = float(_text)
        _image.setOption('FILLET_RADIUS', _radius)

def _set_dim_endpoint_size(prefstate):
    _image = prefstate.getImage()
    _entry = prefstate.getWidget('DIM_ENDPOINT_SIZE')
    _text = _entry.get_chars(0, -1)
    if len(_text) and _text != '+':
        _size = float(_text)
        _image.setOption('DIM_ENDPOINT_SIZE', _size)

def _set_dim_dual_mode(prefstate):
    _image = prefstate.getImage()
    _cb = prefstate.getWidget('DIM_DUAL_MODE')
    _state = _cb.get_active()
    _image.setOption('DIM_DUAL_MODE', _state)

def _set_highlight_points(prefstate):
    _image = prefstate.getImage()
    _cb = prefstate.getWidget('HIGHLIGHT_POINTS')
    _state = _cb.get_active()
    _image.setOption('HIGHLIGHT_POINTS', _state)

def _set_dim_primary_leading_zero(prefstate):
    _image = prefstate.getImage()
    _cb = prefstate.getWidget('DIM_PRIMARY_LEADING_ZERO')
    _state = _cb.get_active()
    _image.setOption('DIM_PRIMARY_LEADING_ZERO', _state)

def _set_dim_primary_trailing_decimal(prefstate):
    _image = prefstate.getImage()
    _cb = prefstate.getWidget('DIM_PRIMARY_TRAILING_DECIMAL')
    _state = _cb.get_active()
    _image.setOption('DIM_PRIMARY_TRAILING_DECIMAL', _state)

def _set_dim_primary_precision(prefstate):
    _image = prefstate.getImage()
    _sb = prefstate.getWidget('DIM_PRIMARY_PRECISION')
    _prec = int(_sb.get_value())
    _image.setOption('DIM_PRIMARY_PRECISION', _prec)

def _set_dim_secondary_leading_zero(prefstate):
    _image = prefstate.getImage()
    _cb = prefstate.getWidget('DIM_SECONDARY_LEADING_ZERO')
    _state = _cb.get_active()
    _image.setOption('DIM_SECONDARY_LEADING_ZERO', _state)

def _set_dim_secondary_trailing_decimal(prefstate):
    _image = prefstate.getImage()
    _cb = prefstate.getWidget('DIM_SECONDARY_TRAILING_DECIMAL')
    _state = _cb.get_active()
    _image.setOption('DIM_SECONDARY_TRAILING_DECIMAL', _state)

def _set_dim_secondary_precision(prefstate):
    _image = prefstate.getImage()
    _sb = prefstate.getWidget('DIM_SECONDARY_PRECISION')
    _prec = int(_sb.get_value())
    _image.setOption('DIM_SECONDARY_PRECISION', _prec)

def _set_dim_primary_prefix(prefstate):
    _image = prefstate.getImage()
    _entry = prefstate.getWidget('DIM_PRIMARY_PREFIX')
    _text = _entry.get_chars(0, -1)
    _prefix = unicode(_text)
    _image.setOption('DIM_PRIMARY_PREFIX', _prefix)

def _set_dim_primary_suffix(prefstate):
    _image = prefstate.getImage()
    _entry = prefstate.getWidget('DIM_PRIMARY_SUFFIX')
    _text = _entry.get_chars(0, -1)
    _suffix = unicode(_text)
    _image.setOption('DIM_PRIMARY_SUFFIX', _suffix)

def _set_dim_secondary_prefix(prefstate):
    _image = prefstate.getImage()
    _entry = prefstate.getWidget('DIM_SECONDARY_PREFIX')
    _text = _entry.get_chars(0, -1)
    _prefix = unicode(_text)
    _image.setOption('DIM_SECONDARY_PREFIX', _prefix)

def _set_dim_secondary_suffix(prefstate):
    _image = prefstate.getImage()
    _entry = prefstate.getWidget('DIM_SECONDARY_SUFFIX')
    _text = _entry.get_chars(0, -1)
    _suffix = unicode(_text)
    _image.setOption('DIM_SECONDARY_SUFFIX', _suffix)

def _set_radial_dim_primary_prefix(prefstate):
    _image = prefstate.getImage()
    _entry = prefstate.getWidget('RADIAL_DIM_PRIMARY_PREFIX')
    _text = _entry.get_chars(0, -1)
    _prefix = unicode(_text)
    _image.setOption('RADIAL_DIM_PRIMARY_PREFIX', _prefix)

def _set_radial_dim_primary_suffix(prefstate):
    _image = prefstate.getImage()
    _entry = prefstate.getWidget('RADIAL_DIM_PRIMARY_SUFFIX')
    _text = _entry.get_chars(0, -1)
    _suffix = unicode(_text)
    _image.setOption('RADIAL_DIM_PRIMARY_SUFFIX', _suffix)

def _set_radial_dim_secondary_prefix(prefstate):
    _image = prefstate.getImage()
    _entry = prefstate.getWidget('RADIAL_DIM_SECONDARY_PREFIX')
    _text = _entry.get_chars(0, -1)
    _prefix = unicode(_text)
    _image.setOption('RADIAL_DIM_SECONDARY_PREFIX', _prefix)

def _set_radial_dim_secondary_suffix(prefstate):
    _image = prefstate.getImage()
    _entry = prefstate.getWidget('RADIAL_DIM_SECONDARY_SUFFIX')
    _text = _entry.get_chars(0, -1)
    _suffix = unicode(_text)
    _image.setOption('RADIAL_DIM_SECONDARY_SUFFIX', _suffix)

def _set_radial_dim_dia_mode(prefstate):
    _image = prefstate.getImage()
    _cb = prefstat.getWidget('RADIAL_DIM_DIA_MODE')
    _state = _cb.get_active()
    _image.setOption('RADIAL_DIM_DIA_MODE', _state)

def _set_angular_dim_primary_prefix(prefstate):
    _image = prefstate.getImage()
    _entry = prefstate.getWidget('ANGULAR_DIM_PRIMARY_PREFIX')
    _text = _entry.get_chars(0, -1)
    _prefix = unicode(_text)
    _image.setOption('ANGULAR_DIM_PRIMARY_PREFIX', _prefix)

def _set_angular_dim_primary_suffix(prefstate):
    _image = prefstate.getImage()
    _entry = prefstate.getWidget('ANGULAR_DIM_PRIMARY_SUFFIX')
    _text = _entry.get_chars(0, -1)
    _suffix = unicode(_text)
    _image.setOption('ANGULAR_DIM_PRIMARY_SUFFIX', _suffix)

def _set_angular_dim_secondary_prefix(prefstate):
    _image = prefstate.getImage()
    _entry = prefstate.getWidget('ANGULAR_DIM_SECONDARY_PREFIX')
    _text = _entry.get_chars(0, -1)
    _prefix = unicode(_text)
    _image.setOption('ANGULAR_DIM_SECONDARY_PREFIX', _prefix)

def _set_angular_dim_secondary_suffix(prefstate):
    _image = prefstate.getImage()
    _entry = prefstate.getWidget('ANGULAR_DIM_SECONDARY_SUFFIX')
    _text = _entry.get_chars(0, -1)
    _suffix = unicode(_text)
    _image.setOption('ANGULAR_DIM_SECONDARY_SUFFIX', _suffix)

def _set_drawing_units(prefstate):
    _image = prefstate.getImage()
    _opt_menu = prefstate.getWidget('DRAWING_UNITS')
    _unit = _opt_menu.get_history()
    _image.setUnits(_unit)

def _set_dim_primary_units(prefstate):
    _image = prefstate.getImage()
    _opt_menu = prefstate.getWidget('DIM_PRIMARY_UNITS')
    _unit = _opt_menu.get_history()
    _image.setOption('DIM_PRIMARY_UNITS', _unit)

def _set_dim_secondary_units(prefstate):
    _image = prefstate.getImage()
    _opt_menu = prefstate.getWidget('DIM_SECONDARY_UNITS')
    _unit = _opt_menu.get_history()
    _image.setOption('DIM_SECONDARY_UNITS', _unit)

def _set_dim_endpoint(prefstate):
    _image = prefstate.getImage()
    _opt_menu = prefstate.getWidget('DIM_ENDPOINT')
    _endpoint = _opt_menu.get_history()
    _image.setOption('DIM_ENDPOINT', _endpoint)

def _set_dim_position(prefstate):
    _image = prefstate.getImage()
    _opt_menu = prefstate.getWidget('DIM_POSITION')
    _endpoint = _opt_menu.get_history()
    _image.setOption('DIM_POSITION', _endpoint)

def _set_font(prefstate):
    _image = prefstate.getImage()
    _fontsel = prefstate.getWidget('FONT_WIDGET')
    _font = _fontsel.get_font_name()
    _family, _style, _weight, _stretch, _size = Generic.text.parse_font(_font)
    _image.setOption('FONT_FAMILY', _family)
    _image.setOption('FONT_SIZE', _size)
    _image.setOption('FONT_STYLE', _style)
    _image.setOption('FONT_WEIGHT', _weight)

def _set_dim_primary_font(prefstate):
    _image = prefstate.getImage()
    _fontsel = prefstate.getWidget('DIM_PRIMARY_FONT')
    _font = _fontsel.get_font_name()
    _family, _style, _weight, _stretch, _size = Generic.text.parse_font(_font)
    _image.setOption('DIM_PRIMARY_FONT_FAMILY', _family)
    _image.setOption('DIM_PRIMARY_FONT_SIZE', _size)
    _image.setOption('DIM_PRIMARY_FONT_STYLE', _style)
    _image.setOption('DIM_PRIMARY_FONT_WEIGHT', _weight)

def _set_dim_secondary_font(prefstate):
    _image = prefstate.getImage()
    _fontsel = prefstate.getWidget('DIM_SECONDARY_FONT')
    _font = _fontsel.get_font_name()
    _family, _style, _weight, _stretch, _size = Generic.text.parse_font(_font)
    _image.setOption('DIM_SECONDARY_FONT_FAMILY', _family)
    _image.setOption('DIM_SECONDARY_FONT_SIZE', _size)
    _image.setOption('DIM_SECONDARY_FONT_STYLE', _style)
    _image.setOption('DIM_SECONDARY_FONT_WEIGHT', _weight)
    
keymap = {
    'DIM_OFFSET' : _set_dim_offset,
    'DIM_EXTENSION' : _set_dim_extension,
    'DIM_COLOR' : _set_dim_color,
    'BACKGROUND_COLOR' : _set_background_color,
    'INACTIVE_LAYER_COLOR' : _set_inactive_layer_color,
    'SINGLE_POINT_COLOR' : _set_single_point_color,
    'MULTI_POINT_COLOR' : _set_multi_point_color,
    'FONT_COLOR' : _set_font_color,
    'DIM_PRIMARY_FONT_COLOR' : _set_dim_primary_font_color,
    'DIM_SECONDARY_FONT_COLOR' : _set_dim_secondary_font_color,
    'LINE_THICKNESS' : _set_line_thickness,
    'LEADER_ARROW_SIZE' : _set_leader_arrow_size,
    'CHAMFER_LENGTH' : _set_chamfer_length,
    'FILLET_RADIUS' : _set_fillet_radius,
    'HIGHLIGHT_POINTS' : _set_highlight_points,
    'DIM_PRIMARY_PRECISION' : _set_dim_primary_precision,
    'DIM_PRIMARY_LEADING_ZERO' : _set_dim_primary_leading_zero,
    'DIM_PRIMARY_TRAILING_DECIMAL' : _set_dim_primary_trailing_decimal,
    'DIM_SECONDARY_PRECISION' : _set_dim_secondary_precision,
    'DIM_SECONDARY_LEADING_ZERO' : _set_dim_secondary_leading_zero,
    'DIM_SECONDARY_TRAILING_DECIMAL' : _set_dim_secondary_trailing_decimal,
    'DIM_PRIMARY_PREFIX' : _set_dim_primary_prefix,
    'DIM_PRIMARY_SUFFIX' : _set_dim_primary_suffix,
    'DIM_SECONDARY_PREFIX' : _set_dim_secondary_prefix,
    'DIM_SECONDARY_SUFFIX' : _set_dim_secondary_suffix,
    'RADIAL_DIM_PRIMARY_PREFIX' : _set_radial_dim_primary_prefix,
    'RADIAL_DIM_PRIMARY_SUFFIX' : _set_radial_dim_primary_suffix,
    'RADIAL_DIM_SECONDARY_PREFIX' : _set_radial_dim_secondary_prefix,
    'RADIAL_DIM_SECONDARY_SUFFIX' : _set_radial_dim_secondary_suffix,
    'RADIAL_DIM_DIA_MODE' : _set_radial_dim_dia_mode,
    'ANGULAR_DIM_PRIMARY_PREFIX' : _set_angular_dim_primary_prefix,
    'ANGULAR_DIM_PRIMARY_SUFFIX' : _set_angular_dim_primary_suffix,
    'ANGULAR_DIM_SECONDARY_PREFIX' : _set_angular_dim_secondary_prefix,
    'ANGULAR_DIM_SECONDARY_SUFFIX' : _set_angular_dim_secondary_suffix,
    'DRAWING_UNITS' : _set_drawing_units,
    'DIM_PRIMARY_UNITS' : _set_dim_primary_units,
    'DIM_SECONDARY_UNITS' : _set_dim_secondary_units,
    'FONT_WIDGET' : _set_font,
    'DIM_PRIMARY_FONT' : _set_dim_primary_font,
    'DIM_SECONDARY_FONT' : _set_dim_secondary_font,
    'DIM_ENDPOINT' : _set_dim_endpoint,
    'DIM_ENDPOINT_SIZE' : _set_dim_endpoint_size,
    'DIM_DUAL_MODE' : _set_dim_dual_mode,
    'DIM_POSITION' : _set_dim_position,
    }

def apply_prefs(prefstate):
    for _key in prefstate.getWidgetKeys():
        # print "widget key: " + _key
        if _key in keymap:
            _optfunc = keymap[_key]
            _optfunc(prefstate)
        # else:
            # print "no function for " + _key

def prefs_dialog(gtkimage):
    _window = gtkimage.getWindow()
    _prefstate = Prefstate()
    _prefstate.setImage(gtkimage)
    _prefstate.setWindow(_window)
    _dialog = gtk.Dialog("Set Preferences", _window,
                         gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
                         (gtk.STOCK_OK, gtk.RESPONSE_OK,
                          gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
    _hbox = gtk.HBox(gtk.FALSE, 5)
    _prefstate.setHBox(_hbox)
    _hbox.set_border_width(5)
    _dialog.vbox.pack_start(_hbox, gtk.TRUE, gtk.TRUE)
    _tree_view = _make_pref_tree(_hbox, _prefstate)
    _dialog.show_all()
    _response = _dialog.run()
    if _response == gtk.RESPONSE_OK:
        apply_prefs(_prefstate)
    _dialog.destroy()
