#
# 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
#
#
# functions for doing modifications on drawing
# entities
#

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

from PythonCAD.Generic.dimension import Dimension
from PythonCAD.Generic.dimension import RadialDimension
from PythonCAD.Generic.dimension import AngularDimension
from PythonCAD.Generic.color import get_color
from PythonCAD.Generic.graphicobject import GraphicObject
from PythonCAD.Generic.segment import Segment
from PythonCAD.Generic.circle import Circle
from PythonCAD.Generic.arc import Arc
from PythonCAD.Generic.polyline import Polyline
from PythonCAD.Generic.text import TextStyle, TextBlock
import PythonCAD.Generic.units

import PythonCAD.Generic.move
import PythonCAD.Generic.transfer
import PythonCAD.Generic.split
import PythonCAD.Generic.delete

#
# common code
#

def select_motion_notify(gtkimage, widget, event, tool):
    _tx, _ty = tool.getLocation()
    _px, _py = gtkimage.coordToPixTransform(_tx, _ty)
    _gc = gtkimage.getGC()
    _x = int(event.x)
    _y = int(event.y)
    _cp = tool.getCurrentPoint()
    if _cp is not None:
        _xc, _yc = _cp
        _xmin = min(_xc, _px)
        _ymin = min(_yc, _py)
        _rw = abs(_xc - _px)
        _rh = abs(_yc - _py)
        widget.window.draw_rectangle(_gc, gtk.FALSE, _xmin, _ymin, _rw, _rh)
    tool.setCurrentPoint(_x, _y)
    _xmin = min(_x, _px)
    _ymin = min(_y, _py)
    _rw = abs(_x - _px)
    _rh = abs(_y - _py)
    widget.window.draw_rectangle(_gc, gtk.FALSE, _xmin, _ymin, _rw, _rh)

def entry_get_distance(text):
    try:
        _text_dist = eval(text)
    except:
        raise ValueError, "Invalid text: " + str(text)
    _dist = _text_dist
    if not isinstance(_dist, float):
        _dist = float(_text_dist)
    return _dist
            
#
# move objects
#

def move_objects(gtkimage, objlist, tool):
    _init_func = tool.getHandler("initialize")
    _active_layer = gtkimage.getActiveLayer()
    _dx, _dy = tool.getDistance()
    gtkimage.startAction()
    try:
        PythonCAD.Generic.move.move_objects(_active_layer, objlist, _dx, _dy)
    finally:
        gtkimage.endAction()
    gtkimage.redraw()
    gtkimage.setPrompt("Click in the drawing area or enter a distance.")
    tool.reset()
    _init_func(tool)
    
def move_button_press(gtkimage, tool):
    _x, _y = gtkimage.getPoint()
    #
    # need to find if the point is an intersection of drawing objects ...
    #
    tool.pushObject(_x)
    tool.pushObject(_y)

def move_end_button_press_cb(gtkimage, widget, event, tool):
    _x2, _y2 = gtkimage.getPoint()
    _x1, _y1 = tool.getLocation()
    _xmin = min(_x1, _x2)
    _xmax = max(_x1, _x2)
    _ymin = min(_y1, _y2)
    _ymax = max(_y1, _y2)
    _active_layer = gtkimage.getActiveLayer()
    _objlist = _active_layer.objsInRegion(_xmin, _ymin, _xmax, _ymax)
    move_objects(gtkimage, _objlist, tool)

def move_elem_button_press_cb(gtkimage, widget, event, tool):
    _x, _y = gtkimage.getPoint()
    _tol = gtkimage.getTolerance()
    _objdict = gtkimage.mapPoint(_x, _y, _tol, None)
    if len(_objdict):
        _active_layer = gtkimage.getActiveLayer()
        if _active_layer in _objdict:
            _objs = []
            for _obj, _pt in _objdict[_active_layer]:
                _objs.append(_obj)
            _dx, _dy = tool.getDistance()
            move_objects(gtkimage, _objs, tool)
    else:
        _pt, _flag = gtkimage.findPoint(_x, _y, _tol)
        if _pt is not None:
            _x, _y = _pt.getCoords()
        tool.setLocation(_x, _y)
        tool.setHandler("motion_notify", select_motion_notify)
        tool.setHandler("button_press", move_end_button_press_cb)
        _gc = gtkimage.getGC()
        _gc.set_line_attributes(1, gtk.gdk.LINE_SOLID,
                                gtk.gdk.CAP_BUTT, gtk.gdk.JOIN_MITER)
        _gc.set_function(gtk.gdk.INVERT)
    
#
# move horizontal
#

def move_horizontal_entry_event(gtkimage, widget, tool):
    _entry = gtkimage.getEntry()
    _text = _entry.get_chars(0,-1)
    _entry.delete_text(0,-1)
    _dist = entry_get_distance(_text)
    tool.setDistance(_dist, 0.0)
    gtkimage.setPrompt("Click on the objects to move.")
    tool.setHandler("button_press", move_elem_button_press_cb)
    tool.delHandler("entry_event")

def move_horizontal_second_button_press_cb(gtkimage, widget, event, tool):
    _x, _y = gtkimage.getPoint()
    _tol = gtkimage.getTolerance()
    _pt, _flag = gtkimage.findPoint(_x, _y, _tol)
    if _pt is not None:
        _x, _y = _pt.getCoords()
    _x1, _y1 = tool.getLocation()
    tool.setDistance((_x - _x1), 0.0)
    tool.clearLocation()
    gtkimage.setPrompt("Select the objects to move.")
    tool.setHandler("button_press", move_elem_button_press_cb)
    tool.delHandler("entry_event")

def move_horizontal_first_button_press_cb(gtkimage, widget, event, tool):
    _x, _y = gtkimage.getPoint()
    _tol = gtkimage.getTolerance()
    _pt, _flag = gtkimage.findPoint(_x, _y, _tol)
    if _pt is not None:
        _x, _y = _pt.getCoords()
    tool.setLocation(_x, _y)
    gtkimage.setPrompt("Click another point to define the distance")
    tool.setHandler("button_press", move_horizontal_second_button_press_cb)
    
def move_horizontal_init(tool):
    tool.setHandler("button_press", move_horizontal_first_button_press_cb)
    tool.setHandler("entry_event", move_horizontal_entry_event)
    tool.setHandler("initialize", move_horizontal_init)

#
# move vertical
#

def move_vertical_entry_event(gtkimage, widget, tool):
    _entry = gtkimage.getEntry()
    _text = _entry.get_chars(0,-1)
    _entry.delete_text(0,-1)
    _dist = entry_get_distance(_text)
    tool.setDistance(0.0, _dist)
    gtkimage.setPrompt("Click on the objects to move.")
    tool.setHandler("button_press", move_elem_button_press_cb)
    tool.delHandler("entry_event")
    
def move_vertical_second_button_press_cb(gtkimage, widget, event, tool):
    _x, _y = gtkimage.getPoint()
    _tol = gtkimage.getTolerance()
    _pt, _flag = gtkimage.findPoint(_x, _y, _tol)
    if _pt is not None:
        _x, _y = _pt.getCoords()
    _x1, _y1 = tool.getLocation()
    tool.setDistance(0.0, (_y - _y1))
    tool.clearLocation()
    gtkimage.setPrompt("Select the objects to move.")
    tool.setHandler("button_press", move_elem_button_press_cb)
    tool.delHandler("entry_event")

def move_vertical_first_button_press_cb(gtkimage, widget, event, tool):
    _x, _y = gtkimage.getPoint()
    _tol = gtkimage.getTolerance()
    _pt, _flag = gtkimage.findPoint(_x, _y, _tol)
    if _pt is not None:
        _x, _y = _pt.getCoords()
    tool.setLocation(_x, _y)
    gtkimage.setPrompt("Click another point to define the distance")
    tool.setHandler("button_press", move_vertical_second_button_press_cb)

def move_vertical_init(tool):
    tool.setHandler("button_press", move_vertical_first_button_press_cb)
    tool.setHandler("entry_event", move_vertical_entry_event)
    tool.setHandler("initialize", move_vertical_init)

#
# move based on two mouse clicks
#
# it would be good to add an entry event handler here ...
#

def move_twopoint_second_button_press_cb(gtkimage, widget, event, tool):
    _x, _y = gtkimage.getPoint()
    _tol = gtkimage.getTolerance()
    _pt, _flag = gtkimage.findPoint(_x, _y, _tol)
    if _pt is not None:
        _x, _y = _pt.getCoords()
    _x1, _y1 = tool.getLocation()
    tool.setDistance((_x - _x1), (_y - _y1))
    tool.clearLocation()
    gtkimage.setPrompt("Select the objects to move.")
    tool.setHandler("button_press", move_elem_button_press_cb)
    tool.delHandler("entry_event")

def move_twopoint_first_button_press_cb(gtkimage, widget, event, tool):
    _x, _y = gtkimage.getPoint()
    _tol = gtkimage.getTolerance()
    _pt, _flag = gtkimage.findPoint(_x, _y, _tol)
    if _pt is not None:
        _x, _y = _pt.getCoords()
    tool.setLocation(_x, _y)
    gtkimage.setPrompt("Click another point to define the distance")
    tool.setHandler("button_press", move_twopoint_second_button_press_cb)

def move_twopoint_init(tool):
    tool.setHandler("button_press", move_twopoint_first_button_press_cb)
    tool.setHandler("initialize", move_twopoint_init)

#
# delete objects
#

def delete_region_end_cb(gtkimage, widget, event, tool):
    _x2, _y2 = gtkimage.getPoint()
    _x1, _y1 = tool.getLocation()
    _xmin = min(_x1, _x2)
    _xmax = max(_x1, _x2)
    _ymin = min(_y1, _y2)
    _ymax = max(_y1, _y2)
    tool.delHandler("motion_notify")
    tool.setHandler("button_press", delete_button_press_cb)
    _active_layer = gtkimage.getActiveLayer()
    _objs = _active_layer.objsInRegion(_xmin, _ymin, _xmax, _ymax)
    gtkimage.refresh()
    if len(_objs):
        gtkimage.startAction()
        try:
            PythonCAD.Generic.delete.delete_objects(_active_layer, _objs)
        finally:
            gtkimage.endAction()
        tool.reset()
        gtkimage.redraw()
    delete_mode_init(tool)
    
def delete_button_press_cb(gtkimage, widget, event, tool):
    _x, _y = gtkimage.getPoint()
    _active_layer = gtkimage.getActiveLayer()
    _tol = gtkimage.getTolerance()
    _objs = _active_layer.mapPoint((_x, _y), _tol)
    if len(_objs):
        _dims = []
        gtkimage.startAction()
        try:
            for _obj in _objs:
                if isinstance(_obj, Dimension):
                    _dims.append(_obj)
                elif isinstance(_obj, tuple):
                    _entity, _pt = _obj
                    _active_layer.delObject(_entity)
                else:
                    raise TypeError, "Unhandled object: " + `_obj`
            for _dim in _dims:
                if _dim in _active_layer: # it may have been removed ...
                    _active_layer.delObject(_dim)
        finally:
            gtkimage.endAction()
        gtkimage.redraw()
    else:
        tool.setLocation(_x, _y)
        tool.setHandler("motion_notify", select_motion_notify)
        tool.setHandler("button_press", delete_region_end_cb)
        _gc = gtkimage.getGC()
        _gc.set_line_attributes(1, gtk.gdk.LINE_SOLID,
                                gtk.gdk.CAP_BUTT, gtk.gdk.JOIN_MITER)
        _gc.set_function(gtk.gdk.INVERT)
        
def delete_mode_init(tool):
    tool.setHandler("button_press", delete_button_press_cb)
    tool.setHandler("initialize", delete_mode_init)

#
# stretch operations
#

def stretch_end_button_press_cb(gtkimage, widget, event, tool):
    _x2, _y2 = gtkimage.getPoint()
    _y1 = tool.popObject()
    _x1 = tool.popObject()
    _xmin = min(_x1, _x2)
    _xmax = max(_x1, _x2)
    _ymin = min(_y1, _y2)
    _ymax = max(_y1, _y2)
    tool.delHandler("motion_notify")
    _active_layer = gtkimage.getActiveLayer()
    _dx, _dy = tool.getDistance()
    for _pt in _active_layer.getLayerEntities("point"):
        if _pt.inRegion(_xmin, _ymin, _xmax, _ymax):
            _pt.move(_dx, _dy)
    gtkimage.redraw()
    tool.clearLocation()
    tool.clearCurrentPoint()
    tool.setHandler("button_press", stretch_elem_button_press_cb)

def stretch_elem_button_press_cb(gtkimage, widget, event, tool):
    _x, _y = gtkimage.getPoint()
    _tol = gtkimage.getTolerance()
    _active_layer = gtkimage.getActiveLayer()
    _pt = _active_layer.find('point', _x, _y, _tol)
    if _pt is not None:
        _dx, _dy = tool.getDistance()
        _pt.move(_dx, _dy)
        gtkimage.redraw()
    else:
        tool.pushObject(_x)
        tool.pushObject(_y)
        tool.setLocation(_x, _y)
        tool.setHandler("motion_notify", select_motion_notify)
        tool.setHandler("button_press", stretch_end_button_press_cb)
        _gc = gtkimage.getGC()
        _gc.set_line_attributes(1, gtk.gdk.LINE_SOLID,
                                gtk.gdk.CAP_BUTT, gtk.gdk.JOIN_MITER)
        _gc.set_function(gtk.gdk.INVERT)

#
# stretch horizontal
#

def stretch_horiz_button_press_cb(gtkimage, widget, event, tool):
    if not len(tool):
        move_button_press(gtkimage, tool)
        gtkimage.setPrompt("Click a second point to indicate the horizontal distance")
    else:
        _x, _y = gtkimage.getPoint()
        #
        # see if the point is at an intersection of drawing objects ...
        #
        _y1 = tool.popObject()
        _x1 = tool.popObject()
        tool.setDistance((_x - _x1), 0.0)
        gtkimage.setPrompt("Select the points to move.")
        # tool.delHandler("entry_event")
        tool.setHandler("button_press", stretch_elem_button_press_cb)

def stretch_horizontal_init(tool):
    tool.initialize()
    tool.setHandler("button_press", stretch_horiz_button_press_cb)
    # tool.setHandler("entry_event", stretch_horiz_entry_event)

#
# stretch vertical
#

def stretch_vert_button_press_cb(gtkimage, widget, event, tool):
    if not len(tool):
        move_button_press(gtkimage, tool)
        gtkimage.setPrompt("Click a second point to indicate the vertical distance")
    else:
        _x, _y = gtkimage.getPoint()
        #
        # see if the point is at an intersection of drawing objects ...
        #
        _y1 = tool.popObject()
        _x1 = tool.popObject()
        tool.setDistance(0.0, (_y - _y1))
        gtkimage.setPrompt("Select the points to move.")
        # tool.delHandler("entry_event")
        tool.setHandler("button_press", stretch_elem_button_press_cb)

def stretch_vertical_init(tool):
    tool.initialize()
    tool.setHandler("button_press", stretch_vert_button_press_cb)
    # tool.setHandler("entry_event", stretch_horiz_entry_event)

#
# split objects into two pieces or at intersection points
#

def split_end_button_press_cb(gtkimage, widget, event, tool):
    _x2, _y2 = gtkimage.getPoint()
    _y1 = tool.popObject()
    _x1 = tool.popObject()
    _xmin = min(_x1, _x2)
    _xmax = max(_x1, _x2)
    _ymin = min(_y1, _y2)
    _ymax = max(_y1, _y2)
    tool.delHandler("motion_notify")
    _active_layer = gtkimage.getActiveLayer()
    _objs = _active_layer.objsInRegion(_xmin, _ymin, _xmax, _ymax, True)
    gtkimage.refresh()
    if len(_objs):
        _splitable = []
        for _obj in _objs:
            if isinstance(_obj, (Segment, Circle, Arc, Polyline)):
                _splitable.append(_obj)
        if len(_splitable):
            gtkimage.startAction()
            try:
                PythonCAD.Generic.split.split_objects(_active_layer, _splitable)
            finally:
                gtkimage.endAction()
        gtkimage.redraw()
    gtkimage.setPrompt("Click on the objects you want to split.")
    tool.clearLocation()
    tool.clearCurrentPoint()
    tool.setHandler("button_press", split_object_button_press_cb)
    
def split_object_button_press_cb(gtkimage, widget, event, tool):
    _x, _y = gtkimage.getPoint()
    _tol = gtkimage.getTolerance()
    _active_layer = gtkimage.getActiveLayer()
    _objlist = _active_layer.mapPoint((_x, _y), _tol, None)
    if len(_objlist):
        _redraw = False
        for _obj, _pt in _objlist:
            if isinstance(_obj, Segment):
                _redraw = True
                _p1, _p2 = _obj.getEndpoints()
                _lpt = _active_layer.find('point', _pt.x, _pt.y)
                if _lpt is None:
                    _active_layer.addObject(_pt)
                    _lpt = _pt
                _s1, _s2 = PythonCAD.Generic.split.split_segment(_obj, _pt)
                gtkimage.startAction()
                try:
                    _active_layer.addObject(_s1)
                    _active_layer.addObject(_s2)
                    _active_layer.delObject(_obj)
                finally:
                    gtkimage.endAction()
            elif isinstance(_obj, Arc):
                _redraw = True
                _arc1, _arc2 = PythonCAD.Generic.split.split_arc(_obj, _pt)
                gtkimage.startAction()
                try:
                    _active_layer.addObject(_arc1)
                    _active_layer.addObject(_arc2)
                    _active_layer.delObject(_obj)
                finally:
                    gtkimage.endAction()
            elif isinstance(_obj, Circle):
                _redraw = True
                _arc = PythonCAD.Generic.split.split_circle(_obj, _pt)
                gtkimage.startAction()
                try:
                    _active_layer.addObject(_arc)
                    _active_layer.delObject(_obj)
                finally:
                    gtkimage.endAction()
            elif isinstance(_obj, Polyline):
                _redraw = True
                _lpt = _active_layer.find('point', _pt.x, _pt.y)
                gtkimage.startAction()
                try:
                    if _lpt is None:
                        _active_layer.addObject(_pt)
                        _lpt = _pt
                    PythonCAD.Generic.split.split_polyline(_obj, _lpt)
                finally:
                    gtkimage.endAction()
            else:
                pass
        if _redraw:
            gtkimage.redraw()
    else:
        tool.pushObject(_x)
        tool.pushObject(_y)
        tool.setLocation(_x, _y)
        tool.setHandler("motion_notify", select_motion_notify)
        tool.setHandler("button_press", split_end_button_press_cb)
        _gc = gtkimage.getGC()
        _gc.set_line_attributes(1, gtk.gdk.LINE_SOLID,
                                gtk.gdk.CAP_BUTT, gtk.gdk.JOIN_MITER)
        _gc.set_function(gtk.gdk.INVERT)
        
def split_object_init(tool):
    tool.initialize()
    tool.setHandler("button_press", split_object_button_press_cb)
    tool.setHandler("initialize", split_object_init)

#
# transfer objects from one layer to another
#

def transfer_end_button_press_cb(gtkimage, widget, event, tool):
    _x2, _y2 = gtkimage.getPoint()
    _y1 = tool.popObject()
    _x1 = tool.popObject()
    _xmin = min(_x1, _x2)
    _xmax = max(_x1, _x2)
    _ymin = min(_y1, _y2)
    _ymax = max(_y1, _y2)
    tool.delHandler("motion_notify")
    _active_layer = gtkimage.getActiveLayer()
    _layers = [gtkimage.getTopLayer()]
    _objdict = {}
    while len(_layers):
        _layer = _layers.pop()
        if _layer is not _active_layer:
            if _layer.isVisible():
                _objs = _layer.objsInRegion(_xmin, _ymin, _xmax, _ymax)
                if len(_objs):
                    _objdict[_layer] = _objs
        _layers.extend(_layer.getSublayers())
    if len(_objdict):
        gtkimage.startAction()
        try:
            for _layer in _objdict:
                if _layer is not _active_layer:
                    _objs = _objdict[_layer]
                    PythonCAD.Generic.transfer.transfer_objects(_objs, _layer, _active_layer)
        finally:
            gtkimage.endAction()
        gtkimage.redraw()
    tool.clearLocation()
    tool.clearCurrentPoint()
    tool.setHandler("button_press", transfer_object_button_press_cb)
    
def transfer_object_button_press_cb(gtkimage, widget, event, tool):
    _x, _y = gtkimage.getPoint()
    _tol = gtkimage.getTolerance()
    _active_layer = gtkimage.getActiveLayer()
    _objdict = gtkimage.mapPoint(_x, _y, _tol, None)
    if len(_objdict):
        gtkimage.startAction()
        try:
            for _layer in _objdict:
                if _layer is not _active_layer:
                    _objs = []
                    for _obj, _pt in _objdict[_layer]:
                        _objs.append(_obj)
                    PythonCAD.Generic.transfer.transfer_objects(_objs, _layer, _active_layer)
        finally:
            gtkimage.endAction()
        gtkimage.redraw()
    else:
        tool.pushObject(_x)
        tool.pushObject(_y)
        tool.setLocation(_x, _y)
        tool.setHandler("motion_notify", select_motion_notify)
        tool.setHandler("button_press", transfer_end_button_press_cb)
        gc = gtkimage.getGC()
        gc.set_line_attributes(1, gtk.gdk.LINE_SOLID,
                               gtk.gdk.CAP_BUTT, gtk.gdk.JOIN_MITER)
        gc.set_function(gtk.gdk.INVERT)
        
def transfer_object_init(tool):
    tool.initialize()
    tool.setHandler("button_press", transfer_object_button_press_cb)
    
#
# change color
#

def change_color_init(gtkimage):
    _window = gtkimage.getWindow()
    _dialog = gtk.ColorSelectionDialog("Set Active Color")
    _dialog.set_transient_for(_window)
    _colorsel = _dialog.colorsel

    _prev_color = gtkimage.getOption('LINE_COLOR')
    if gtkimage.hasGTKColor(_prev_color):
        _gtk_color = gtkimage.getGTKColor(_prev_color)
    else:
        _da = gtkimage.getDA()
        _cstring = str(_prev_color)
        _gtk_color = _da.get_colormap().alloc_color(_cstring)
        gtkimage.saveGTKColor(_prev_color, _gtk_color)
    _colorsel.set_previous_color(_gtk_color)
    _colorsel.set_current_color(_gtk_color)
    _colorsel.set_has_palette(gtk.TRUE)
    _response = _dialog.run()
    if _response == gtk.RESPONSE_OK:
        _gtk_color = _colorsel.get_current_color()
        _red = int((_gtk_color.red/65535.0) * 255.0)
        _green = int((_gtk_color.green/65535.0) * 255.0)
        _blue = int((_gtk_color.blue/65535.0) * 255.0)
        _col = get_color(_red, _green, _blue)
        if gtkimage.hasSelection():
            _active_layer = gtkimage.getActiveLayer()
            _objs = []
            for _layer, _obj in gtkimage.getSelectedObjects():
                if _layer is _active_layer:
                    if isinstance(_obj, GraphicObject):
                        _objs.append(_obj)
            if len(_objs):
                gtkimage.startAction()
                try:
                    for _obj in _objs:
                        _obj.setColor(_col)
                finally:
                    gtkimage.endAction()
    _dialog.destroy()
    gtkimage.redraw()

#
# change linetypes
#

def change_linetype_init(gtkimage):
    _window = gtkimage.getWindow()
    _dialog = gtk.Dialog("Change Linetype", _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, 2)
    _hbox.set_border_width(2)
    _dialog.vbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 0)
    
    _label = gtk.Label("Linetype:")
    _hbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 0)
    _clt = gtkimage.getOption('LINE_TYPE')
    _linetypes = gtkimage.getImageEntities('linetype')
    _menu = gtk.Menu()
    _idx = 0
    for _i in range(len(_linetypes)):
        _lt = _linetypes[_i]
        if _lt is _clt:
            _idx = _i
        _item = gtk.MenuItem(_lt.getName())
        _menu.append(_item)
    _opt_menu = gtk.OptionMenu()
    _opt_menu.set_menu(_menu)
    _opt_menu.set_history(_idx)
    _hbox.pack_start(_opt_menu, gtk.TRUE, gtk.TRUE, 0)
    _dialog.show_all()
    _response = _dialog.run()
    if _response == gtk.RESPONSE_OK:
        _lt = _linetypes[_opt_menu.get_history()]
        if gtkimage.hasSelection():
            _active_layer = gtkimage.getActiveLayer()
            _objs = []
            for _layer, _obj in gtkimage.getSelectedObjects():
                if _layer is _active_layer:
                    if isinstance(_obj, GraphicObject):
                        _objs.append(_obj)
            if len(_objs):
                gtkimage.startAction()
                try:
                    for _obj in _objs:
                        _obj.setLinetype(_lt)
                finally:
                    gtkimage.endAction()
    _dialog.destroy()
    gtkimage.redraw()

#
# change thickness
#

def change_thickness_init(gtkimage):
    _window = gtkimage.getWindow()
    _dialog = gtk.Dialog("Change Thickness", _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, 2)
    _hbox.set_border_width(2)
    _dialog.vbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 0)
    _label = gtk.Label("Thickness:")
    _hbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 0)
    _thickness = gtkimage.getOption('LINE_THICKNESS')
    _adj = gtk.Adjustment(_thickness, 0.0001, 20.0, 0.1, 1.0, 1.0)
    _sb = gtk.SpinButton(_adj)
    _sb.set_digits(1)
    _sb.set_numeric(gtk.FALSE)
    _hbox.pack_start(_sb, gtk.TRUE, gtk.TRUE, 0)
    _dialog.show_all()
    _response = _dialog.run()
    if _response == gtk.RESPONSE_OK:
        _nt = float(_sb.get_value())
        if gtkimage.hasSelection():
            _active_layer = gtkimage.getActiveLayer()
            _objs = []
            for _layer, _obj in gtkimage.getSelectedObjects():
                if _layer is _active_layer:
                    if isinstance(_obj, GraphicObject):
                        _objs.append(_obj)
            if len(_objs):
                gtkimage.startAction()
                try:
                    for _obj in _objs:
                        _obj.setThickness(_nt)
                finally:
                    gtkimage.endAction()
    _dialog.destroy()
    gtkimage.redraw()

#
# change the style
#

def change_style_init(gtkimage):
    _window = gtkimage.getWindow()
    _dialog = gtk.Dialog("Change Style", _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, 2)
    _hbox.set_border_width(2)
    _dialog.vbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 0)
    _label = gtk.Label("Style:")
    _cst = gtkimage.getOption('LINE_STYLE')
    _styles = gtkimage.getAllStyles()
    _menu = gtk.Menu()
    _idx = 0
    for _i in range(len(_styles)):
        _s = _styles[_i]
        if _s is _cst:
            _idx = _i
        _item = gtk.MenuItem(_s.getName())
        _menu.append(_item)
    _opt_menu = gtk.OptionMenu()
    _opt_menu.set_menu(_menu)
    _opt_menu.set_history(_idx)
    _hbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 0)
    _hbox.pack_start(_opt_menu, gtk.TRUE, gtk.TRUE, 0)
    _dialog.show_all()
    _response = _dialog.run()
    if _response == gtk.RESPONSE_OK:
        _s = _styles[_opt_menu.get_history()]
        if gtkimage.hasSelection():
            _active_layer = gtkimage.getActiveLayer()
            _objs = []
            for _layer, _obj in gtkimage.getSelectedObjects():
                if _layer is _active_layer:
                    if isinstance(_obj, GraphicObject):
                        _objs.append(_obj)
            if len(_objs):
                gtkimage.startAction()
                try:
                    for _obj in _objs:
                        _obj.setStyle(_s)
                finally:
                    gtkimage.endAction()
    _dialog.destroy()
    gtkimage.redraw()

#
# Change TextBlock properties
#

def change_textblock_size_init(gtkimage):
    _window = gtkimage.getWindow()
    _dialog = gtk.Dialog("Change Text Size", _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, 2)
    _hbox.set_border_width(2)
    _dialog.vbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 0)
    _label = gtk.Label("Text Size:")
    _hbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 0)
    _size = gtkimage.getOption('TEXT_SIZE')
    _adj = gtk.Adjustment(_size, 0.0001, 400.0, 0.1, 1.0, 1.0)
    _sb = gtk.SpinButton(_adj)
    _sb.set_digits(1)
    _sb.set_numeric(gtk.FALSE)
    _hbox.pack_start(_sb, gtk.TRUE, gtk.TRUE, 0)
    _dialog.show_all()
    _response = _dialog.run()
    if _response == gtk.RESPONSE_OK:
        _size = float(_sb.get_value())
        if gtkimage.hasSelection():
            _active_layer = gtkimage.getActiveLayer()
            _objs = []
            for _layer, _obj in gtkimage.getSelectedObjects():
                if _layer is _active_layer:
                    if isinstance(_obj, TextBlock):
                        _objs.append(_obj)
            if len(_objs):
                gtkimage.startAction()
                try:
                    for _obj in _objs:
                        _obj.setSize(_size)
                finally:
                    gtkimage.endAction()
    _dialog.destroy()
    gtkimage.redraw()

def change_textblock_family_init(gtkimage):
    _window = gtkimage.getWindow()
    _dialog = gtk.Dialog("Change Font Family", _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, 2)
    _hbox.set_border_width(2)
    _dialog.vbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 0)
    _families = []
    for _family in _window.get_pango_context().list_families():
        _families.append(_family.get_name())
    _families.sort()
    _label = gtk.Label("Family:")
    _family = gtkimage.getOption('FONT_FAMILY')
    _menu = gtk.Menu()    
    _idx = 0
    for _i in range(len(_families)):
        _f = _families[_i]
        if _f == _family:
            _idx = _i
        _item = gtk.MenuItem(_f)
        _menu.append(_item)
    _opt_menu = gtk.OptionMenu()
    _opt_menu.set_menu(_menu)
    _opt_menu.set_history(_idx)
    _hbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 0)
    _hbox.pack_start(_opt_menu, gtk.TRUE, gtk.TRUE, 0)
    _dialog.show_all()
    _response = _dialog.run()
    if _response == gtk.RESPONSE_OK:
        _family = _families[_opt_menu.get_history()]
        if gtkimage.hasSelection():
            _active_layer = gtkimage.getActiveLayer()
            _objs = []
            for _layer, _obj in gtkimage.getSelectedObjects():
                if _layer is _active_layer:
                    if isinstance(_obj, TextBlock):
                        _objs.append(_obj)
            if len(_objs):
                gtkimage.startAction()
                try:
                    for _obj in _objs:
                        _obj.setFamily(_family)
                finally:
                    gtkimage.endAction()
    _dialog.destroy()
    gtkimage.redraw()

def change_textblock_weight_init(gtkimage):
    _window = gtkimage.getWindow()
    _dialog = gtk.Dialog("Change Text Weight", _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, 2)
    _hbox.set_border_width(2)
    _dialog.vbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 0)
    _label = gtk.Label("Text Weight:")
    _weight = gtkimage.getOption('FONT_WEIGHT')
    _idx = 0
    _menu = gtk.Menu()
    _item = gtk.MenuItem('NORMAL')
    _menu.append(_item)
    if _weight == TextStyle.WEIGHT_NORMAL:
        _idx = 0
    _item = gtk.MenuItem('LIGHT')
    _menu.append(_item)
    if _weight == TextStyle.WEIGHT_LIGHT:
        _idx = 1
    _item = gtk.MenuItem('BOLD')
    _menu.append(_item)
    if _weight == TextStyle.WEIGHT_BOLD:
        _idx = 2
    _item = gtk.MenuItem('HEAVY')
    _menu.append(_item)
    if _weight == TextStyle.WEIGHT_HEAVY:
        _idx = 3
    _opt_menu = gtk.OptionMenu()
    _opt_menu.set_menu(_menu)
    _opt_menu.set_history(_idx)
    _hbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 0)
    _hbox.pack_start(_opt_menu, gtk.TRUE, gtk.TRUE, 0)
    _dialog.show_all()
    _response = _dialog.run()
    if _response == gtk.RESPONSE_OK:
        _weight = _opt_menu.get_history()
        if gtkimage.hasSelection():
            _active_layer = gtkimage.getActiveLayer()
            _objs = []
            for _layer, _obj in gtkimage.getSelectedObjects():
                if _layer is _active_layer:
                    if isinstance(_obj, TextBlock):
                        _objs.append(_obj)
            if len(_objs):
                gtkimage.startAction()
                try:
                    for _obj in _objs:
                        _obj.setWeight(_weight)
                finally:
                    gtkimage.endAction()
    _dialog.destroy()
    gtkimage.redraw()

def change_textblock_style_init(gtkimage):
    _window = gtkimage.getWindow()
    _dialog = gtk.Dialog("Change Text Style", _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, 2)
    _hbox.set_border_width(2)
    _dialog.vbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 0)
    _label = gtk.Label("Text Style:")
    _style = gtkimage.getOption('FONT_STYLE')
    _idx = 0
    _menu = gtk.Menu()
    _item = gtk.MenuItem('NORMAL')
    _menu.append(_item)
    if _style == TextStyle.FONT_NORMAL:
        _idx = 0
    _item = gtk.MenuItem('OBLIQUE')
    _menu.append(_item)
    if _style == TextStyle.FONT_OBLIQUE:
        _idx = 1
    _item = gtk.MenuItem('ITALIC')
    _menu.append(_item)
    if _style == TextStyle.FONT_ITALIC:
        _idx = 2
    _opt_menu = gtk.OptionMenu()
    _opt_menu.set_menu(_menu)
    _opt_menu.set_history(_idx)
    _hbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 0)
    _hbox.pack_start(_opt_menu, gtk.TRUE, gtk.TRUE, 0)
    _dialog.show_all()
    _response = _dialog.run()
    if _response == gtk.RESPONSE_OK:
        _style = _opt_menu.get_history()
        if gtkimage.hasSelection():
            _active_layer = gtkimage.getActiveLayer()
            _objs = []
            for _layer, _obj in gtkimage.getSelectedObjects():
                if _layer is _active_layer:
                    if isinstance(_obj, TextBlock):
                        _objs.append(_obj)
            if len(_objs):
                gtkimage.startAction()
                try:
                    for _obj in _objs:
                        _obj.setStyle(_style)
                finally:
                    gtkimage.endAction()
    _dialog.destroy()
    gtkimage.redraw()

def change_textblock_alignment_init(gtkimage):
    _window = gtkimage.getWindow()
    _dialog = gtk.Dialog("Change Text Alignment", _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, 2)
    _hbox.set_border_width(2)
    _dialog.vbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 0)
    _label = gtk.Label("Text Alignment:")
    _align = gtkimage.getOption('TEXT_ALIGNMENT')
    _idx = 0    
    _menu = gtk.Menu()
    _item = gtk.MenuItem('LEFT')
    _menu.append(_item)
    if _align == TextStyle.ALIGN_LEFT:
        _idx = 0
    _item = gtk.MenuItem('CENTER')
    _menu.append(_item)
    if _align == TextStyle.ALIGN_CENTER:
        _idx = 1
    _item = gtk.MenuItem('RIGHT')
    _menu.append(_item)
    if _align == TextStyle.ALIGN_RIGHT:
        _idx = 2
    _opt_menu = gtk.OptionMenu()
    _opt_menu.set_menu(_menu)
    _opt_menu.set_history(_idx)
    _hbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 0)
    _hbox.pack_start(_opt_menu, gtk.TRUE, gtk.TRUE, 0)
    _dialog.show_all()
    _response = _dialog.run()
    if _response == gtk.RESPONSE_OK:
        _align = _opt_menu.get_history()
        if gtkimage.hasSelection():
            _active_layer = gtkimage.getActiveLayer()
            _objs = []
            for _layer, _obj in gtkimage.getSelectedObjects():
                if _layer is _active_layer:
                    if isinstance(_obj, TextBlock):
                        _objs.append(_obj)
            if len(_objs):
                gtkimage.startAction()
                try:
                    for _obj in _objs:
                        _obj.setAlignment(_align)
                finally:
                    gtkimage.endAction()
    _dialog.destroy()
    gtkimage.redraw()

def change_textblock_color_init(gtkimage):
    _window = gtkimage.getWindow()
    _dialog = gtk.ColorSelectionDialog("Change Font Color")
    _dialog.set_transient_for(_window)
    _colorsel = _dialog.colorsel
    _color = gtkimage.getOption('FONT_COLOR')
    if gtkimage.hasGTKColor(_color):
        _gtk_color = gtkimage.getGTKColor(_color)
    else:
        _da = gtkimage.getDA()
        _cstring = str(_color)
        _gtk_color = _da.get_colormap().alloc_color(_cstring)
        gtkimage.saveGTKColor(_color, _gtk_color)
    _colorsel.set_previous_color(_gtk_color)
    _colorsel.set_current_color(_gtk_color)
    _colorsel.set_has_palette(gtk.TRUE)
    _response = _dialog.run()
    if _response == gtk.RESPONSE_OK:
        _gtk_color = _colorsel.get_current_color()
        _red = int((_gtk_color.red/65535.0) * 255.0)
        _green = int((_gtk_color.green/65535.0) * 255.0)
        _blue = int((_gtk_color.blue/65535.0) * 255.0)
        _color = get_color(_red, _green, _blue)
        if gtkimage.hasSelection():
            _active_layer = gtkimage.getActiveLayer()
            _objs = []
            for _layer, _obj in gtkimage.getSelectedObjects():
                if _layer is _active_layer:
                    if isinstance(_obj, TextBlock):
                        _objs.append(_obj)
            if len(_objs):
                gtkimage.startAction()
                try:
                    for _obj in _objs:
                        _obj.setColor(_color)
                finally:
                    gtkimage.endAction()
    _dialog.destroy()
    gtkimage.redraw()

#
# Change Dimension Properties
#

def change_dim_offset_init(gtkimage):
    _window = gtkimage.getWindow()
    _dialog = gtk.Dialog("Change Offset Length", _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, 2)
    _hbox.set_border_width(2)
    _dialog.vbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 0)
    _label = gtk.Label("Length:")
    _hbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 0)
    _offset = gtkimage.getOption('DIM_OFFSET')
    _adj = gtk.Adjustment(_offset, 0.01, 200.0, 0.1, 1.0, 1.0)
    _sb = gtk.SpinButton(_adj)
    _sb.set_digits(2)
    _sb.set_numeric(gtk.FALSE)
    _hbox.pack_start(_sb, gtk.TRUE, gtk.TRUE, 0)
    _dialog.show_all()
    _response = _dialog.run()
    if _response == gtk.RESPONSE_OK:
        _offset = float(_sb.get_value())
        if gtkimage.hasSelection():
            _active_layer = gtkimage.getActiveLayer()
            _objs = []
            for _layer, _obj in gtkimage.getSelectedObjects():
                if _layer is _active_layer:
                    if isinstance(_obj, Dimension):
                        _objs.append(_obj)
            if len(_objs):
                gtkimage.startAction()
                try:
                    for _obj in _objs:
                        _obj.setOffset(_offset)
                finally:
                    gtkimage.endAction()
    _dialog.destroy()
    gtkimage.redraw()

def change_dim_extension_init(gtkimage):
    _window = gtkimage.getWindow()
    _dialog = gtk.Dialog("Change Extension Length", _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, 2)
    _hbox.set_border_width(2)
    _dialog.vbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 0)
    _label = gtk.Label("Length:")
    _hbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 0)
    _extlen = gtkimage.getOption('DIM_EXTENSION')
    _adj = gtk.Adjustment(_extlen, 0.01, 200.0, 0.1, 1.0, 1.0)
    _sb = gtk.SpinButton(_adj)
    _sb.set_digits(2)
    _sb.set_numeric(gtk.FALSE)
    _hbox.pack_start(_sb, gtk.TRUE, gtk.TRUE, 0)
    _dialog.show_all()
    _response = _dialog.run()
    if _response == gtk.RESPONSE_OK:
        _extlen = float(_sb.get_value())
        if gtkimage.hasSelection():
            _active_layer = gtkimage.getActiveLayer()
            _objs = []
            for _layer, _obj in gtkimage.getSelectedObjects():
                if _layer is _active_layer:
                    if isinstance(_obj, Dimension):
                        _objs.append(_obj)
            if len(_objs):
                gtkimage.startAction()
                try:
                    for _obj in _objs:
                        _obj.setExtension(_extlen)
                finally:
                    gtkimage.endAction()
    _dialog.destroy()
    gtkimage.redraw()

def change_dim_endpoint_init(gtkimage):
    _window = gtkimage.getWindow()
    _dialog = gtk.Dialog("Change Endpoint Markers", _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, 2)
    _hbox.set_border_width(2)
    _dialog.vbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 0)
    _label = gtk.Label("Endpoints:")
    _endpt = gtkimage.getOption('DIM_ENDPOINT')
    _idx = 0    
    _menu = gtk.Menu()
    _item = gtk.MenuItem('None')
    _menu.append(_item)
    if _endpt == Dimension.DIM_ENDPT_NONE:
        _idx = 0
    _item = gtk.MenuItem('Arrow')
    _menu.append(_item)
    if _endpt == Dimension.DIM_ENDPT_ARROW:
        _idx = 1
    _item = gtk.MenuItem('Filled Arrow')
    _menu.append(_item)
    if _endpt == Dimension.DIM_ENDPT_FILLED_ARROW:
        _idx = 2
    _item = gtk.MenuItem('Slash')
    _menu.append(_item)
    if _endpt == Dimension.DIM_ENDPT_SLASH:
        _idx = 3
    _item = gtk.MenuItem('Circle')
    _menu.append(_item)
    if _endpt == Dimension.DIM_ENDPT_CIRCLE:
        _idx = 4
    _opt_menu = gtk.OptionMenu()
    _opt_menu.set_menu(_menu)
    _opt_menu.set_history(_idx)
    _hbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 0)
    _hbox.pack_start(_opt_menu, gtk.TRUE, gtk.TRUE, 0)
    _dialog.show_all()
    _response = _dialog.run()
    if _response == gtk.RESPONSE_OK:
        _endpt = _opt_menu.get_history()
        if gtkimage.hasSelection():
            _active_layer = gtkimage.getActiveLayer()
            _objs = []
            for _layer, _obj in gtkimage.getSelectedObjects():
                if _layer is _active_layer:
                    if isinstance(_obj, Dimension):
                        _objs.append(_obj)
            if len(_objs):
                gtkimage.startAction()
                try:
                    for _obj in _objs:
                        _obj.setEndpointType(_endpt)
                finally:
                    gtkimage.endAction()
    _dialog.destroy()
    gtkimage.redraw()

def change_dim_endpoint_size_init(gtkimage):
    _window = gtkimage.getWindow()
    _dialog = gtk.Dialog("Change Endpoint Size", _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, 2)
    _hbox.set_border_width(2)
    _dialog.vbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 0)
    _label = gtk.Label("Length:")
    _hbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 0)
    _size = gtkimage.getOption('DIM_ENDPOINT_SIZE')
    _adj = gtk.Adjustment(_size, 0.01, 200.0, 0.1, 1.0, 1.0)
    _sb = gtk.SpinButton(_adj)
    _sb.set_digits(2)
    _sb.set_numeric(gtk.FALSE)
    _hbox.pack_start(_sb, gtk.TRUE, gtk.TRUE, 0)
    _dialog.show_all()
    _response = _dialog.run()
    if _response == gtk.RESPONSE_OK:
        _size = float(_sb.get_value())
        if gtkimage.hasSelection():
            _active_layer = gtkimage.getActiveLayer()
            _objs = []
            for _layer, _obj in gtkimage.getSelectedObjects():
                if _layer is _active_layer:
                    if isinstance(_obj, Dimension):
                        _objs.append(_obj)
            if len(_objs):
                gtkimage.startAction()
                try:
                    for _obj in _objs:
                        _obj.setEndpointSize(_size)
                finally:
                    gtkimage.endAction()
    _dialog.destroy()
    gtkimage.redraw()

def change_dim_dual_mode_init(gtkimage):
    _window = gtkimage.getWindow()
    _dialog = gtk.Dialog("Change Dual Mode", _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, 2)
    _hbox.set_border_width(2)
    _dialog.vbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 0)
    _cb = gtk.CheckButton("Display Two Dimension Values")
    _mode = gtkimage.getOption('DIM_DUAL_MODE')
    _cb.set_active(_mode)
    _hbox.pack_start(_cb, gtk.TRUE, gtk.TRUE, 0)
    _dialog.show_all()
    _response = _dialog.run()
    if _response == gtk.RESPONSE_OK:
        _mode = _cb.get_active()
        if gtkimage.hasSelection():
            _active_layer = gtkimage.getActiveLayer()
            _objs = []
            for _layer, _obj in gtkimage.getSelectedObjects():
                if _layer is _active_layer:
                    if isinstance(_obj, Dimension):
                        _objs.append(_obj)
            if len(_objs):
                gtkimage.startAction()
                try:
                    for _obj in _objs:
                        _obj.setDualDimMode(_mode)
                finally:
                    gtkimage.endAction()
    _dialog.destroy()
    gtkimage.redraw()

def change_dim_dual_mode_offset_init(gtkimage):
    _window = gtkimage.getWindow()
    _dialog = gtk.Dialog("Change Dual Mode Offset", _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, 2)
    _hbox.set_border_width(2)
    _dialog.vbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 0)
    _label = gtk.Label("Length:")
    _hbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 0)
    _offset = gtkimage.getOption('DIM_DUAL_MODE_OFFSET')
    _adj = gtk.Adjustment(_offset, 0.01, 200.0, 0.1, 1.0, 1.0)
    _sb = gtk.SpinButton(_adj)
    _sb.set_digits(2)
    _sb.set_numeric(gtk.FALSE)
    _hbox.pack_start(_sb, gtk.TRUE, gtk.TRUE, 0)
    _dialog.show_all()
    _response = _dialog.run()
    if _response == gtk.RESPONSE_OK:
        _offset = float(_sb.get_value())
        if gtkimage.hasSelection():
            _active_layer = gtkimage.getActiveLayer()
            _objs = []
            for _layer, _obj in gtkimage.getSelectedObjects():
                if _layer is _active_layer:
                    if isinstance(_obj, Dimension):
                        _objs.append(_obj)
            if len(_objs):
                gtkimage.startAction()
                try:
                    for _obj in _objs:
                        _obj.setDualModeOffset(_offset)
                finally:
                    gtkimage.endAction()
    _dialog.destroy()
    gtkimage.redraw()


def change_dim_thickness_init(gtkimage):
    _window = gtkimage.getWindow()
    _dialog = gtk.Dialog("Change Dim Thickness", _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, 2)
    _hbox.set_border_width(2)
    _dialog.vbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 0)
    _label = gtk.Label("Thickness:")
    _hbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 0)
    _t = gtkimage.getOption('DIM_THICKNESS')
    _adj = gtk.Adjustment(_t, 0.01, 200.0, 0.1, 1.0, 1.0)
    _sb = gtk.SpinButton(_adj)
    _sb.set_digits(2)
    _sb.set_numeric(gtk.FALSE)
    _hbox.pack_start(_sb, gtk.TRUE, gtk.TRUE, 0)
    _dialog.show_all()
    _response = _dialog.run()
    if _response == gtk.RESPONSE_OK:
        _t = float(_sb.get_value())
        if gtkimage.hasSelection():
            _active_layer = gtkimage.getActiveLayer()
            _objs = []
            for _layer, _obj in gtkimage.getSelectedObjects():
                if _layer is _active_layer:
                    if isinstance(_obj, Dimension):
                        _objs.append(_obj)
            if len(_objs):
                gtkimage.startAction()
                try:
                    for _obj in _objs:
                        _obj.setThickness(_t)
                finally:
                    gtkimage.endAction()
    _dialog.destroy()
    gtkimage.redraw()
    
def change_dim_color_init(gtkimage):
    _window = gtkimage.getWindow()
    _dialog = gtk.ColorSelectionDialog("Change Dimension Color")
    _dialog.set_transient_for(_window)
    _colorsel = _dialog.colorsel
    _color = gtkimage.getOption('DIM_COLOR')
    if gtkimage.hasGTKColor(_color):
        _gtk_color = gtkimage.getGTKColor(_color)
    else:
        _da = gtkimage.getDA()
        _cstring = str(_color)
        _gtk_color = _da.get_colormap().alloc_color(_cstring)
        gtkimage.saveGTKColor(_color, _gtk_color)
    _colorsel.set_previous_color(_gtk_color)
    _colorsel.set_current_color(_gtk_color)
    _colorsel.set_has_palette(gtk.TRUE)
    _response = _dialog.run()
    if _response == gtk.RESPONSE_OK:
        _gtk_color = _colorsel.get_current_color()
        _red = int((_gtk_color.red/65535.0) * 255.0)
        _green = int((_gtk_color.green/65535.0) * 255.0)
        _blue = int((_gtk_color.blue/65535.0) * 255.0)
        _color = get_color(_red, _green, _blue)
        if gtkimage.hasSelection():
            _active_layer = gtkimage.getActiveLayer()
            _objs = []
            for _layer, _obj in gtkimage.getSelectedObjects():
                if _layer is _active_layer:
                    if isinstance(_obj, Dimension):
                        _objs.append(_obj)
            if len(_objs):
                gtkimage.startAction()
                try:
                    for _obj in _objs:
                        _obj.setColor(_color)
                finally:
                    gtkimage.endAction()
    _dialog.destroy()
    gtkimage.redraw()

#
# Change DimString properties
#

def change_primary_dimstring_init(gtkimage):
    _window = gtkimage.getWindow()
    _dialog = gtk.Dialog("Change Primary Dimstring", _window,
                         gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
                         (gtk.STOCK_OK, gtk.RESPONSE_OK,
                          gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))

    _label_size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
    _entry_size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
    _menu_size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
    
    #
    # Font Family
    #
    _hbox = gtk.HBox(gtk.FALSE, 2)
    _hbox.set_border_width(2)
    _dialog.vbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 0)
    _label = gtk.Label("Family:")
    _label_size_group.add_widget(_label)
    _hbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 0)
    _families = []
    for _family in _window.get_pango_context().list_families():
        _families.append(_family.get_name())
    _families.sort()
    _menu = gtk.Menu()
    _idx = 0
    _family = gtkimage.getOption('DIM_PRIMARY_FONT_FAMILY')
    for _i in range(len(_families)):
        _f = _families[_i]
        if _family == _f:
            _idx = _i
        _item = gtk.MenuItem(_f)
        _menu.append(_item)
    _family_menu = gtk.OptionMenu()
    _family_menu.set_menu(_menu)
    _family_menu.set_history(_idx)
    _menu_size_group.add_widget(_family_menu)
    _hbox.pack_start(_family_menu, gtk.FALSE, gtk.FALSE, 0)
    #
    # Font Style
    #
    _hbox = gtk.HBox(gtk.FALSE, 2)
    _hbox.set_border_width(2)
    _dialog.vbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 0)
    _label = gtk.Label("Style:")
    _label_size_group.add_widget(_label)
    _hbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 0)
    _style = gtkimage.getOption('DIM_PRIMARY_FONT_STYLE')
    _idx = 0
    _menu = gtk.Menu()
    _item = gtk.MenuItem('NORMAL')
    _menu.append(_item)
    if _style == TextStyle.FONT_NORMAL:
        _idx = 0
    _item = gtk.MenuItem('OBLIQUE')
    _menu.append(_item)
    if _style == TextStyle.FONT_OBLIQUE:
        _idx = 1
    _item = gtk.MenuItem('ITALIC')
    _menu.append(_item)
    if _style == TextStyle.FONT_ITALIC:
        _idx = 2
    _style_menu = gtk.OptionMenu()
    _style_menu.set_menu(_menu)
    _style_menu.set_history(_idx)
    _menu_size_group.add_widget(_style_menu)
    _hbox.pack_start(_style_menu, gtk.FALSE, gtk.FALSE, 0)
    #
    # Font weight
    #
    _hbox = gtk.HBox(gtk.FALSE, 2)
    _hbox.set_border_width(2)
    _dialog.vbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 0)
    _label = gtk.Label("Weight:")
    _label_size_group.add_widget(_label)
    _hbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 0)
    _weight = gtkimage.getOption('DIM_PRIMARY_FONT_WEIGHT')
    _idx = 0
    _menu = gtk.Menu()
    _item = gtk.MenuItem('NORMAL')
    _menu.append(_item)
    if _weight == TextStyle.WEIGHT_NORMAL:
        _idx = 0
    _item = gtk.MenuItem('LIGHT')
    _menu.append(_item)
    if _weight == TextStyle.WEIGHT_LIGHT:
        _idx = 1
    _item = gtk.MenuItem('BOLD')
    _menu.append(_item)
    if _weight == TextStyle.WEIGHT_BOLD:
        _idx = 2
    _item = gtk.MenuItem('HEAVY')
    _menu.append(_item)
    if _weight == TextStyle.WEIGHT_HEAVY:
        _idx = 3
    _weight_menu = gtk.OptionMenu()
    _weight_menu.set_menu(_menu)
    _weight_menu.set_history(_idx)
    _menu_size_group.add_widget(_weight_menu)
    _hbox.pack_start(_weight_menu, gtk.FALSE, gtk.FALSE, 0)
    #
    # Text Size
    #
    _hbox = gtk.HBox(gtk.FALSE, 2)
    _hbox.set_border_width(2)
    _dialog.vbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 0)
    _label = gtk.Label("Size:")
    _label_size_group.add_widget(_label)
    _hbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 0)
    _size = gtkimage.getOption('DIM_PRIMARY_TEXT_SIZE')
    _adj = gtk.Adjustment(_size, 0.0001, 400.0, 0.1, 1.0, 1.0)
    _size_sb = gtk.SpinButton(_adj)
    _size_sb.set_digits(1)
    _size_sb.set_numeric(gtk.FALSE)
    _hbox.pack_start(_size_sb, gtk.FALSE, gtk.FALSE, 0)
    #
    # fixme: add color changer ...
    #
    # Prefix/Suffix
    #
    _table = gtk.Table(4, 3, gtk.FALSE)
    _table.set_border_width(2)
    _table.set_row_spacings(2)
    _table.set_col_spacings(2)
    _dialog.vbox.pack_start(_table, gtk.FALSE, gtk.FALSE, 0)
    #
    _label = gtk.Label("Prefix")
    _label_size_group.add_widget(_label)
    _table.attach(_label, 1, 2, 0, 1,
                  gtk.EXPAND,
                  gtk.EXPAND,
                  2, 2)
    _label = gtk.Label("Suffix")
    _label_size_group.add_widget(_label)
    _table.attach(_label, 2, 3, 0, 1,
                  gtk.EXPAND,
                  gtk.EXPAND,
                  2, 2)
    # Linear/Horizontal/Vertical
    _label = gtk.Label("Linear")
    _label_size_group.add_widget(_label)
    _table.attach(_label, 0, 1, 1, 2,
                  gtk.EXPAND,
                  gtk.EXPAND,
                  2, 2)
    _prefix = gtkimage.getOption('DIM_PRIMARY_PREFIX')
    _lpentry = gtk.Entry()
    _lpentry.set_text(_prefix)
    _entry_size_group.add_widget(_lpentry)
    _table.attach(_lpentry, 1, 2, 1, 2,
                  gtk.EXPAND,
                  gtk.EXPAND,
                  2, 2)
    _suffix = gtkimage.getOption('DIM_PRIMARY_SUFFIX')
    _lsentry = gtk.Entry()
    _lsentry.set_text(_suffix)
    _entry_size_group.add_widget(_lsentry)
    _table.attach(_lsentry, 2, 3, 1, 2,
                  gtk.EXPAND,
                  gtk.EXPAND,
                  2, 2)
    # Radial
    _label = gtk.Label("Radial")
    _label_size_group.add_widget(_label)
    _table.attach(_label, 0, 1, 2, 3,
                  gtk.EXPAND,
                  gtk.EXPAND,
                  2, 2)
    _prefix = gtkimage.getOption('RADIAL_DIM_PRIMARY_PREFIX')
    _rpentry = gtk.Entry()
    _rpentry.set_text(_prefix)
    _entry_size_group.add_widget(_rpentry)
    _table.attach(_rpentry, 1, 2, 2, 3,
                  gtk.EXPAND,
                  gtk.EXPAND,
                  2, 2)
    _suffix = gtkimage.getOption('RADIAL_DIM_PRIMARY_SUFFIX')
    _rsentry = gtk.Entry()
    _rsentry.set_text(_suffix)
    _entry_size_group.add_widget(_rsentry)
    _table.attach(_rsentry, 2, 3, 2, 3,
                  gtk.EXPAND,
                  gtk.EXPAND,
                  2, 2)
    # Angular
    _label = gtk.Label("Angular")
    _label_size_group.add_widget(_label)
    _table.attach(_label, 0, 1, 3, 4,
                  gtk.EXPAND,
                  gtk.EXPAND,
                  2, 2)
    _prefix = gtkimage.getOption('ANGULAR_DIM_PRIMARY_PREFIX')
    _apentry = gtk.Entry()
    _apentry.set_text(_prefix)
    _entry_size_group.add_widget(_apentry)
    _table.attach(_apentry, 1, 2, 3, 4,
                  gtk.EXPAND,
                  gtk.EXPAND,
                  2, 2)
    _suffix = gtkimage.getOption('ANGULAR_DIM_PRIMARY_SUFFIX')
    _asentry = gtk.Entry()
    _asentry.set_text(_suffix)
    _entry_size_group.add_widget(_asentry)
    _table.attach(_asentry, 2, 3, 3, 4,
                  gtk.EXPAND,
                  gtk.EXPAND,
                  2, 2)
    #
    # Precision
    #
    _hbox = gtk.HBox(gtk.FALSE, 2)
    _hbox.set_border_width(2)
    _dialog.vbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 0)
    _label = gtk.Label("Precision:")
    _label_size_group.add_widget(_label)    
    _hbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 0)
    _prec = gtkimage.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)    
    _hbox.pack_start(_sb, gtk.FALSE, gtk.FALSE, 0)
    #
    # Units
    #
    _units = [('Millimeters', PythonCAD.Generic.units.MILLIMETERS),
              ('Micrometers', PythonCAD.Generic.units.MICROMETERS),
              ('Meters', PythonCAD.Generic.units.METERS),
              ('Kilometers', PythonCAD.Generic.units.KILOMETERS),
              ('Inches', PythonCAD.Generic.units.INCHES),
              ('Feet', PythonCAD.Generic.units.FEET),
              ('Yards', PythonCAD.Generic.units.YARDS),
              ('Miles', PythonCAD.Generic.units.MILES),
              ]
    _hbox = gtk.HBox(gtk.FALSE, 2)
    _hbox.set_border_width(2)
    _dialog.vbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 0)
    _label = gtk.Label("Units:")
    _label_size_group.add_widget(_label)
    _hbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 0)
    _unit = gtkimage.getOption('DIM_PRIMARY_UNITS')
    _idx = 0
    _menu = gtk.Menu()
    for _i in range(len(_units)):
        _str, _val = _units[_i]
        if _unit == _val:
            _idx = _i
        _item = gtk.MenuItem(_str)
        _menu.append(_item)
    _unit_menu = gtk.OptionMenu()
    _unit_menu.set_menu(_menu)
    _unit_menu.set_history(_idx)
    _menu_size_group.add_widget(_unit_menu)
    _hbox.pack_start(_unit_menu, gtk.FALSE, gtk.FALSE, 0)
    #
    # Print Zero
    #
    _hbox = gtk.HBox(gtk.FALSE, 2)
    _hbox.set_border_width(2)
    _dialog.vbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 0)
    _pzcb = gtk.CheckButton("Print Leading Zero")
    _pzro = gtkimage.getOption('DIM_PRIMARY_LEADING_ZERO')
    _pzcb.set_active(_pzro)
    _hbox.pack_start(_pzcb, gtk.TRUE, gtk.TRUE, 0)
    #
    # Print Decimal
    #
    _hbox = gtk.HBox(gtk.FALSE, 2)
    _hbox.set_border_width(2)
    _dialog.vbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 0)
    _pdcb = gtk.CheckButton("Print Trailing Decimal")
    _pdec = gtkimage.getOption('DIM_PRIMARY_TRAILING_DECIMAL')
    _pdcb.set_active(_pdec)
    _hbox.pack_start(_pdcb, gtk.TRUE, gtk.TRUE, 0)
    #
    _dialog.show_all()
    _response = _dialog.run()
    if _response == gtk.RESPONSE_OK:
        _family = _families[_family_menu.get_history()]
        _style = _style_menu.get_history()
        _weight = _weight_menu.get_history()
        _size = float(_size_sb.get_value())
        _lprefix = unicode(_lpentry.get_chars(0, -1))
        _lsuffix = unicode(_lsentry.get_chars(0, -1))
        _rprefix = unicode(_rpentry.get_chars(0, -1))
        _rsuffix = unicode(_rsentry.get_chars(0, -1))
        _aprefix = unicode(_apentry.get_chars(0, -1))
        _asuffix = unicode(_asentry.get_chars(0, -1))
        _prec = int(_sb.get_value())
        _unit = _units[_unit_menu.get_history()][1]
        _pzro = _pzcb.get_active()
        _pdec = _pdcb.get_active()
        if gtkimage.hasSelection():
            _active_layer = gtkimage.getActiveLayer()
            _objs = []
            for _layer, _obj in gtkimage.getSelectedObjects():
                if _layer is _active_layer:
                    if isinstance(_obj, Dimension):
                        _objs.append(_obj)
            if len(_objs):
                gtkimage.startAction()
                try:
                    for _obj in _objs:
                        _ds = _obj.getPrimaryDimstring()
                        _ds.setFamily(_family)
                        _ds.setStyle(_style)
                        _ds.setWeight(_weight)
                        _ds.setSize(_size)
                        if isinstance(_obj, AngularDimension):
                            _ds.setPrefix(_aprefix)
                            _ds.setSuffix(_asuffix)
                        elif isinstance(_obj, RadialDimension):
                            _ds.setPrefix(_rprefix)
                            _ds.setSuffix(_rsuffix)
                        else:
                            _ds.setPrefix(_lprefix)
                            _ds.setSuffix(_lsuffix)
                        _ds.setPrecision(_prec)
                        _ds.setUnits(_unit)
                        _ds.setPrintZero(_pzro)
                        _ds.setPrintDecimal(_pdec)
                finally:
                    gtkimage.endAction()
    _dialog.destroy()
    gtkimage.redraw()

def change_secondary_dimstring_init(gtkimage):
    _window = gtkimage.getWindow()
    _dialog = gtk.Dialog("Change Secondary Dimstring", _window,
                         gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
                         (gtk.STOCK_OK, gtk.RESPONSE_OK,
                          gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))

    _label_size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
    _entry_size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
    _menu_size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
    
    #
    # Font Family
    #
    _hbox = gtk.HBox(gtk.FALSE, 2)
    _hbox.set_border_width(2)
    _dialog.vbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 0)
    _label = gtk.Label("Family:")
    _label_size_group.add_widget(_label)
    _hbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 0)
    _families = []
    for _family in _window.get_pango_context().list_families():
        _families.append(_family.get_name())
    _families.sort()
    _menu = gtk.Menu()
    _idx = 0
    _family = gtkimage.getOption('DIM_SECONDARY_FONT_FAMILY')
    for _i in range(len(_families)):
        _f = _families[_i]
        if _family == _f:
            _idx = _i
        _item = gtk.MenuItem(_f)
        _menu.append(_item)
    _family_menu = gtk.OptionMenu()
    _family_menu.set_menu(_menu)
    _family_menu.set_history(_idx)
    _menu_size_group.add_widget(_family_menu)
    _hbox.pack_start(_family_menu, gtk.FALSE, gtk.FALSE, 0)
    #
    # Font Style
    #
    _hbox = gtk.HBox(gtk.FALSE, 2)
    _hbox.set_border_width(2)
    _dialog.vbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 0)
    _label = gtk.Label("Style:")
    _label_size_group.add_widget(_label)
    _hbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 0)
    _style = gtkimage.getOption('DIM_SECONDARY_FONT_STYLE')
    _idx = 0
    _menu = gtk.Menu()
    _item = gtk.MenuItem('NORMAL')
    _menu.append(_item)
    if _style == TextStyle.FONT_NORMAL:
        _idx = 0
    _item = gtk.MenuItem('OBLIQUE')
    _menu.append(_item)
    if _style == TextStyle.FONT_OBLIQUE:
        _idx = 1
    _item = gtk.MenuItem('ITALIC')
    _menu.append(_item)
    if _style == TextStyle.FONT_ITALIC:
        _idx = 2
    _style_menu = gtk.OptionMenu()
    _style_menu.set_menu(_menu)
    _style_menu.set_history(_idx)
    _menu_size_group.add_widget(_style_menu)
    _hbox.pack_start(_style_menu, gtk.FALSE, gtk.FALSE, 0)
    #
    # Font weight
    #
    _hbox = gtk.HBox(gtk.FALSE, 2)
    _hbox.set_border_width(2)
    _dialog.vbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 0)
    _label = gtk.Label("Weight:")
    _label_size_group.add_widget(_label)
    _hbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 0)
    _weight = gtkimage.getOption('DIM_SECONDARY_FONT_WEIGHT')
    _idx = 0
    _menu = gtk.Menu()
    _item = gtk.MenuItem('NORMAL')
    _menu.append(_item)
    if _weight == TextStyle.WEIGHT_NORMAL:
        _idx = 0
    _item = gtk.MenuItem('LIGHT')
    _menu.append(_item)
    if _weight == TextStyle.WEIGHT_LIGHT:
        _idx = 1
    _item = gtk.MenuItem('BOLD')
    _menu.append(_item)
    if _weight == TextStyle.WEIGHT_BOLD:
        _idx = 2
    _item = gtk.MenuItem('HEAVY')
    _menu.append(_item)
    if _weight == TextStyle.WEIGHT_HEAVY:
        _idx = 3
    _weight_menu = gtk.OptionMenu()
    _weight_menu.set_menu(_menu)
    _weight_menu.set_history(_idx)
    _menu_size_group.add_widget(_weight_menu)
    _hbox.pack_start(_weight_menu, gtk.FALSE, gtk.FALSE, 0)
    #
    # Text Size
    #
    _hbox = gtk.HBox(gtk.FALSE, 2)
    _hbox.set_border_width(2)
    _dialog.vbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 0)
    _label = gtk.Label("Size:")
    _label_size_group.add_widget(_label)
    _hbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 0)
    _size = gtkimage.getOption('DIM_SECONDARY_TEXT_SIZE')
    _adj = gtk.Adjustment(_size, 0.0001, 400.0, 0.1, 1.0, 1.0)
    _size_sb = gtk.SpinButton(_adj)
    _size_sb.set_digits(1)
    _size_sb.set_numeric(gtk.FALSE)
    _hbox.pack_start(_size_sb, gtk.FALSE, gtk.FALSE, 0)
    #
    # fixme: add color changer ...
    #
    # Prefix/Suffix
    #
    _table = gtk.Table(4, 3, gtk.FALSE)
    _table.set_border_width(2)
    _table.set_row_spacings(2)
    _table.set_col_spacings(2)
    _dialog.vbox.pack_start(_table, gtk.FALSE, gtk.FALSE, 0)
    #
    _label = gtk.Label("Prefix")
    _label_size_group.add_widget(_label)
    _table.attach(_label, 1, 2, 0, 1,
                  gtk.EXPAND,
                  gtk.EXPAND,
                  2, 2)
    _label = gtk.Label("Suffix")
    _label_size_group.add_widget(_label)
    _table.attach(_label, 2, 3, 0, 1,
                  gtk.EXPAND,
                  gtk.EXPAND,
                  2, 2)
    # Linear/Horizontal/Vertical
    _label = gtk.Label("Linear")
    _label_size_group.add_widget(_label)
    _table.attach(_label, 0, 1, 1, 2,
                  gtk.EXPAND,
                  gtk.EXPAND,
                  2, 2)
    _prefix = gtkimage.getOption('DIM_SECONDARY_PREFIX')
    _lpentry = gtk.Entry()
    _lpentry.set_text(_prefix)
    _entry_size_group.add_widget(_lpentry)
    _table.attach(_lpentry, 1, 2, 1, 2,
                  gtk.EXPAND,
                  gtk.EXPAND,
                  2, 2)
    _suffix = gtkimage.getOption('DIM_SECONDARY_SUFFIX')
    _lsentry = gtk.Entry()
    _lsentry.set_text(_suffix)
    _entry_size_group.add_widget(_lsentry)
    _table.attach(_lsentry, 2, 3, 1, 2,
                  gtk.EXPAND,
                  gtk.EXPAND,
                  2, 2)
    # Radial
    _label = gtk.Label("Radial")
    _label_size_group.add_widget(_label)
    _table.attach(_label, 0, 1, 2, 3,
                  gtk.EXPAND,
                  gtk.EXPAND,
                  2, 2)
    _prefix = gtkimage.getOption('RADIAL_DIM_SECONDARY_PREFIX')
    _rpentry = gtk.Entry()
    _rpentry.set_text(_prefix)
    _entry_size_group.add_widget(_rpentry)
    _table.attach(_rpentry, 1, 2, 2, 3,
                  gtk.EXPAND,
                  gtk.EXPAND,
                  2, 2)
    _suffix = gtkimage.getOption('RADIAL_DIM_SECONDARY_SUFFIX')
    _rsentry = gtk.Entry()
    _rsentry.set_text(_suffix)
    _entry_size_group.add_widget(_rsentry)
    _table.attach(_rsentry, 2, 3, 2, 3,
                  gtk.EXPAND,
                  gtk.EXPAND,
                  2, 2)
    # Angular
    _label = gtk.Label("Angular")
    _label_size_group.add_widget(_label)
    _table.attach(_label, 0, 1, 3, 4,
                  gtk.EXPAND,
                  gtk.EXPAND,
                  2, 2)
    _prefix = gtkimage.getOption('ANGULAR_DIM_SECONDARY_PREFIX')
    _apentry = gtk.Entry()
    _apentry.set_text(_prefix)
    _entry_size_group.add_widget(_apentry)
    _table.attach(_apentry, 1, 2, 3, 4,
                  gtk.EXPAND,
                  gtk.EXPAND,
                  2, 2)
    _suffix = gtkimage.getOption('ANGULAR_DIM_SECONDARY_SUFFIX')
    _asentry = gtk.Entry()
    _asentry.set_text(_suffix)
    _entry_size_group.add_widget(_asentry)
    _table.attach(_asentry, 2, 3, 3, 4,
                  gtk.EXPAND,
                  gtk.EXPAND,
                  2, 2)
    #
    # Precision
    #
    _hbox = gtk.HBox(gtk.FALSE, 2)
    _hbox.set_border_width(2)
    _dialog.vbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 0)
    _label = gtk.Label("Precision:")
    _label_size_group.add_widget(_label)    
    _hbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 0)
    _prec = gtkimage.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)    
    _hbox.pack_start(_sb, gtk.FALSE, gtk.FALSE, 0)
    #
    # Units
    #
    _units = [('Millimeters', PythonCAD.Generic.units.MILLIMETERS),
              ('Micrometers', PythonCAD.Generic.units.MICROMETERS),
              ('Meters', PythonCAD.Generic.units.METERS),
              ('Kilometers', PythonCAD.Generic.units.KILOMETERS),
              ('Inches', PythonCAD.Generic.units.INCHES),
              ('Feet', PythonCAD.Generic.units.FEET),
              ('Yards', PythonCAD.Generic.units.YARDS),
              ('Miles', PythonCAD.Generic.units.MILES),
              ]
    _hbox = gtk.HBox(gtk.FALSE, 2)
    _hbox.set_border_width(2)
    _dialog.vbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 0)
    _label = gtk.Label("Units:")
    _label_size_group.add_widget(_label)
    _hbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 0)
    _unit = gtkimage.getOption('DIM_SECONDARY_UNITS')
    _idx = 0
    _menu = gtk.Menu()
    for _i in range(len(_units)):
        _str, _val = _units[_i]
        if _unit == _val:
            _idx = _i
        _item = gtk.MenuItem(_str)
        _menu.append(_item)
    _unit_menu = gtk.OptionMenu()
    _unit_menu.set_menu(_menu)
    _unit_menu.set_history(_idx)
    _menu_size_group.add_widget(_unit_menu)
    _hbox.pack_start(_unit_menu, gtk.FALSE, gtk.FALSE, 0)
    #
    # Print Zero
    #
    _hbox = gtk.HBox(gtk.FALSE, 2)
    _hbox.set_border_width(2)
    _dialog.vbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 0)
    _pzcb = gtk.CheckButton("Print Leading Zero")
    _pzro = gtkimage.getOption('DIM_SECONDARY_LEADING_ZERO')
    _pzcb.set_active(_pzro)
    _hbox.pack_start(_pzcb, gtk.TRUE, gtk.TRUE, 0)
    #
    # Print Decimal
    #
    _hbox = gtk.HBox(gtk.FALSE, 2)
    _hbox.set_border_width(2)
    _dialog.vbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 0)
    _pdcb = gtk.CheckButton("Print Trailing Decimal")
    _pdec = gtkimage.getOption('DIM_SECONDARY_TRAILING_DECIMAL')
    _pdcb.set_active(_pdec)
    _hbox.pack_start(_pdcb, gtk.TRUE, gtk.TRUE, 0)
    #
    _dialog.show_all()
    _response = _dialog.run()
    if _response == gtk.RESPONSE_OK:
        _family = _families[_family_menu.get_history()]
        _style = _style_menu.get_history()
        _weight = _weight_menu.get_history()
        _size = float(_size_sb.get_value())
        _lprefix = unicode(_lpentry.get_chars(0, -1))
        _lsuffix = unicode(_lsentry.get_chars(0, -1))
        _rprefix = unicode(_rpentry.get_chars(0, -1))
        _rsuffix = unicode(_rsentry.get_chars(0, -1))
        _aprefix = unicode(_apentry.get_chars(0, -1))
        _asuffix = unicode(_asentry.get_chars(0, -1))
        _prec = int(_sb.get_value())
        _unit = _units[_unit_menu.get_history()][1]
        _pzro = _pzcb.get_active()
        _pdec = _pdcb.get_active()
        if gtkimage.hasSelection():
            _active_layer = gtkimage.getActiveLayer()
            _objs = []
            for _layer, _obj in gtkimage.getSelectedObjects():
                if _layer is _active_layer:
                    if isinstance(_obj, Dimension):
                        _objs.append(_obj)
            if len(_objs):
                gtkimage.startAction()
                try:
                    for _obj in _objs:
                        _ds = _obj.getSecondaryDimstring()
                        _ds.setFamily(_family)
                        _ds.setStyle(_style)
                        _ds.setWeight(_weight)
                        _ds.setSize(_size)
                        if isinstance(_obj, AngularDimension):
                            _ds.setPrefix(_aprefix)
                            _ds.setSuffix(_asuffix)
                        elif isinstance(_obj, RadialDimension):
                            _ds.setPrefix(_rprefix)
                            _ds.setSuffix(_rsuffix)
                        else:
                            _ds.setPrefix(_lprefix)
                            _ds.setSuffix(_lsuffix)
                        _ds.setPrecision(_prec)
                        _ds.setUnits(_unit)
                        _ds.setPrintZero(_pzro)
                        _ds.setPrintDecimal(_pdec)
                finally:
                    gtkimage.endAction()
    _dialog.destroy()
    gtkimage.redraw()

def old_change_secondary_dimstring_init(gtkimage):
    _window = gtkimage.getWindow()
    _dialog = gtk.Dialog("Change Secondary Dimstring", _window,
                         gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
                         (gtk.STOCK_OK, gtk.RESPONSE_OK,
                          gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))

    _label_size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
    _entry_size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
    #
    # Prefix
    #
    _hbox = gtk.HBox(gtk.FALSE, 2)
    _hbox.set_border_width(2)
    _dialog.vbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 0)
    _label = gtk.Label("Prefix:")
    _label_size_group.add_widget(_label)
    _hbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 0)
    _prefix = gtkimage.getOption('DIM_SECONDARY_PREFIX')
    _pentry = gtk.Entry()
    _pentry.set_text(_prefix)
    _hbox.pack_start(_pentry, gtk.FALSE, gtk.FALSE, 0)
    _entry_size_group.add_widget(_pentry)
    #
    # Suffix
    #
    _hbox = gtk.HBox(gtk.FALSE, 2)
    _hbox.set_border_width(2)
    _dialog.vbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 0)
    _label = gtk.Label("Suffix:")
    _label_size_group.add_widget(_label)
    _hbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 0)
    _suffix = gtkimage.getOption('DIM_SECONDARY_SUFFIX')
    _sentry = gtk.Entry()
    _sentry.set_text(_suffix)
    _hbox.pack_start(_sentry, gtk.FALSE, gtk.FALSE, 0)
    _entry_size_group.add_widget(_sentry)
    #
    # Precision
    #
    _hbox = gtk.HBox(gtk.FALSE, 2)
    _hbox.set_border_width(2)
    _dialog.vbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 0)
    _label = gtk.Label("Precision:")
    _label_size_group.add_widget(_label)    
    _hbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 0)
    _prec = gtkimage.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)    
    _hbox.pack_start(_sb, gtk.TRUE, gtk.TRUE, 0)
    #
    # Units
    #
    _units = [('Millimeters', PythonCAD.Generic.units.MILLIMETERS),
              ('Micrometers', PythonCAD.Generic.units.MICROMETERS),
              ('Meters', PythonCAD.Generic.units.METERS),
              ('Kilometers', PythonCAD.Generic.units.KILOMETERS),
              ('Inches', PythonCAD.Generic.units.INCHES),
              ('Feet', PythonCAD.Generic.units.FEET),
              ('Yards', PythonCAD.Generic.units.YARDS),
              ('Miles', PythonCAD.Generic.units.MILES),
              ]
    _hbox = gtk.HBox(gtk.FALSE, 2)
    _hbox.set_border_width(2)
    _dialog.vbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 0)
    _label = gtk.Label("Units:")
    _label_size_group.add_widget(_label)
    _hbox.pack_start(_label, gtk.FALSE, gtk.FALSE, 0)
    _unit = gtkimage.getOption('DIM_SECONDARY_UNITS')
    _idx = 0
    _menu = gtk.Menu()
    for _i in range(len(_units)):
        _str, _val = _units[_i]
        if _unit == _val:
            _idx = _i
        _item = gtk.MenuItem(_str)
        _menu.append(_item)
    _opt_menu = gtk.OptionMenu()
    _opt_menu.set_menu(_menu)
    _opt_menu.set_history(_idx)
    _hbox.pack_start(_opt_menu, gtk.TRUE, gtk.TRUE, 0)
    #
    # Print Zero
    #
    _hbox = gtk.HBox(gtk.FALSE, 2)
    _hbox.set_border_width(2)
    _dialog.vbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 0)
    _pzcb = gtk.CheckButton("Print Leading Zero")
    _pzro = gtkimage.getOption('DIM_SECONDARY_LEADING_ZERO')
    _pzcb.set_active(_pzro)
    _hbox.pack_start(_pzcb, gtk.TRUE, gtk.TRUE, 0)
    #
    # Print Decimal
    #
    _hbox = gtk.HBox(gtk.FALSE, 2)
    _hbox.set_border_width(2)
    _dialog.vbox.pack_start(_hbox, gtk.FALSE, gtk.FALSE, 0)
    _pdcb = gtk.CheckButton("Print Trailing Decimal")
    _pdec = gtkimage.getOption('DIM_SECONDARY_TRAILING_DECIMAL')
    _pdcb.set_active(_pdec)
    _hbox.pack_start(_pdcb, gtk.TRUE, gtk.TRUE, 0)
    #
    _dialog.show_all()
    _response = _dialog.run()
    if _response == gtk.RESPONSE_OK:
        _prefix = unicode(_pentry.get_chars(0, -1))
        _suffix = unicode(_sentry.get_chars(0, -1))
        _prec = int(_sb.get_value())
        _unit = _units[_opt_menu.get_history()][1]
        _pzro = _pzcb.get_active()
        _pdec = _pdcb.get_active()
        if gtkimage.hasSelection():
            _active_layer = gtkimage.getActiveLayer()
            _objs = []
            for _layer, _obj in gtkimage.getSelectedObjects():
                if _layer is _active_layer:
                    if isinstance(_obj, Dimension):
                        _objs.append(_obj)
            if len(_objs):
                gtkimage.startAction()
                try:
                    for _obj in _objs:
                        _ds = _obj.getSecondaryDimstring()
                        _ds.setPrefix(_prefix)
                        _ds.setSuffix(_suffix)
                        _ds.setPrecision(_prec)
                        _ds.setUnits(_unit)
                        _ds.setPrintZero(_pzro)
                        _ds.setPrintDecimal(_pdec)
                finally:
                    gtkimage.endAction()
    _dialog.destroy()
    gtkimage.redraw()

#
# arbitrary zoom
#

def zoom_end_button_press_cb(gtkimage, widget, event, tool):
    _xp, _yp = gtkimage.getPoint()
    _x1, _y1 = tool.getLocation()
    _xmin = min(_xp, _x1)
    _ymin = min(_yp, _y1)
    _width, _height = gtkimage.getSize()
    _fw = float(_width)
    _fh = float(_height)
    _wpp = abs(_x1 - _xp)/_fw
    _hpp = abs(_y1 - _yp)/_fh
    if _wpp > _hpp:
        _scale = _wpp
    else:
        _scale = _hpp
    gtkimage.setView(_xmin, _ymin, _scale)
    gtkimage.setPrompt("Click in the drawing.")
    gtkimage.redraw()
    zoom_init(tool)

def zoom_motion_notify(gtkimage, widget, event, tool):
    _tx, _ty = tool.getLocation()
    _px, _py = gtkimage.coordToPixTransform(_tx, _ty)
    # width, height = gtkimage.getSize()
    _gc = gtkimage.getGC()
    _x = int(event.x)
    _y = int(event.y)
    _cp = tool.getCurrentPoint()
    #
    # it would be nice to draw the rectangle in the current
    # shape of the window ...
    #
    if _cp is not None:
        _xc, _yc = _cp
        _xmin = min(_px, _xc)
        _ymin = min(_py, _yc)
        _rw = abs(_xc - _px)
        _rh = abs(_yc - _py)
        widget.window.draw_rectangle(_gc, gtk.FALSE, _xmin, _ymin, _rw, _rh)
    _xmin = min(_x, _px)
    _ymin = min(_y, _py)
    tool.setCurrentPoint(_x, _y)
    _rw = abs(_x - _px)
    _rh = abs(_y - _py)
    widget.window.draw_rectangle(_gc, gtk.FALSE, _xmin, _ymin, _rw, _rh)

def zoom_button_press_cb(gtkimage, widget, event, tool):
    _x, _y = gtkimage.getPoint()
    tool.setLocation(_x, _y)
    tool.setHandler("motion_notify", zoom_motion_notify)
    tool.setHandler("button_press", zoom_end_button_press_cb)
    gtkimage.setPrompt("Click a second point to define the zoom window.")
    _gc = gtkimage.getGC()
    _gc.set_line_attributes(1, gtk.gdk.LINE_SOLID,
                            gtk.gdk.CAP_BUTT, gtk.gdk.JOIN_MITER)
    _gc.set_function(gtk.gdk.INVERT)

def zoom_init(tool):
    tool.initialize()
    tool.setHandler("button_press", zoom_button_press_cb)
