Esempio n. 1
0
 def popup_context_menu(self, event):
     if self.context_menu is None:
         items = []
         set_unit = self.SetUnit
         for unit in unit_names:
             items.append(MenuCommand(unit, set_unit, unit))
         self.context_menu = UpdatedMenu(self, items, tearoff=0)
     self.context_menu.Popup(event.x_root, event.y_root)
Esempio n. 2
0
 def popup_context_menu(self, event):
     self.set_event_context(event)
     if self.context_menu is None:
         self.context_menu = UpdatedMenu(
             self.frame, [],
             tearoff=0,
             auto_rebuild=self.build_context_menu)
     self.context_menu.Popup(event.x_root, event.y_root)
Esempio n. 3
0
class TEntryExt(TEntry):
    def __init__(self, master=None, cnf={}, **kw):
        TEntry.__init__(self, master, kw)
        self.bind('<ButtonPress-3>', self.popup_context_menu)

#--------ContextMenu-----------------------------------------------------------

    def popup_context_menu(self, event):
        if self["state"] == NORMAL:
            self.context_menu = UpdatedMenu(
                self, [], tearoff=0, auto_rebuild=self.build_context_menu)
            self.context_menu.Popup(event.x_root, event.y_root)

    def build_context_menu(self):
        entries = []
        if self.can_cut():
            entries += [(_("Cut"), self.cut, (), None, None, 'menu_edit_cut')]
        if self.can_copy():
            entries += [(_("Copy"), self.copy, (), None, None,
                         'menu_edit_copy')]
        if self.can_paste():
            entries += [(_("Paste"), self.paste, (), None, None,
                         'menu_edit_paste')]
        entries += [(_("Clear All"), self.clear_all, (), None, None,
                     'menu_edit_clear'), (None, 'small_separator'),
                    (_("Select All"), self.select_all, (), None, None)]
        return map(MakeCommand, entries)

    def can_cut(self):
        return self.select_present()

    def can_copy(self):
        return self.select_present()

    def can_paste(self):
        if self.clipboar_get():
            return 1
        return 0

    def select_all(self):
        self.select_range(0, END)

    def clear_all(self):
        self.delete(0, END)

    def clipboar_get(self):
        try:
            return self.tk.call('::tk::GetSelection', '.', 'CLIPBOARD')
        except:
            return None

    def cut(self):
        self.tk.call('::ttk::entry::Cut', self._w)

    def copy(self):
        self.tk.call('::ttk::entry::Copy', self._w)

    def paste(self):
        self.tk.call('::ttk::entry::Paste', self._w)
Esempio n. 4
0
 def PopupContextMenu(self, event):
     self.context_idx = self.x_to_idx(event.x)
     self.context_pos = (event.x - self.orig_x) / float(self.ximage.width)
     if self.context_menu is None:
         items = [
             MenuCommand(_("Set Handle Color"),
                         self.set_handle_color,
                         sensitivecb=self.can_set_handle_color),
             MenuCommand(_("Delete Handle"),
                         self.delete_handle,
                         sensitivecb=self.can_delete_handle),
             MenuCommand(_("Insert Handle"),
                         self.insert_handle,
                         sensitivecb=self.can_insert_handle)
         ]
         self.context_menu = UpdatedMenu(self, items)
     self.context_menu.Popup(event.x_root, event.y_root)
Esempio n. 5
0
class PositionLabel(UpdatedLabel):

    context_menu = None

    def __init__(self, *args, **kw):
        apply(UpdatedLabel.__init__, (self, ) + args, kw)
        self.bind('<ButtonPress-3>', self.popup_context_menu)
        self.set_unit(config.preferences.default_unit)
        config.preferences.Subscribe(CHANGED, self.preference_changed)

    def Update(self, *rest):
        if self.sensitivecb:
            self.SetSensitive(self.sensitivecb())
        if self.updatecb and self.update_field:
            x, y = self.updatecb()
            x = x / self.factor
            y = y / self.factor
            self[self.update_field] = self.format % (x, y)

    def popup_context_menu(self, event):
        if self.context_menu is None:
            items = []
            set_unit = self.SetUnit
            for unit in unit_names:
                items.append(MenuCommand(unit, set_unit, unit))
            self.context_menu = UpdatedMenu(self, items, tearoff=0)
        self.context_menu.Popup(event.x_root, event.y_root)

    def set_unit(self, unit):
        self.factor = unit_dict[unit]
        self.format = formats[unit]
        self.Update()

    def SetUnit(self, unit):
        self.unit = unit
        if config.preferences.poslabel_sets_default_unit:
            config.preferences.default_unit = unit
        else:
            self.set_unit(unit)

    def preference_changed(self, pref, value):
        if pref == 'default_unit':
            self.set_unit(value)
Esempio n. 6
0
 def popup_context_menu(self, event):
     if self["state"] == NORMAL:
         self.context_menu = UpdatedMenu(
             self, [], tearoff=0, auto_rebuild=self.build_context_menu)
         self.context_menu.Popup(event.x_root, event.y_root)
Esempio n. 7
0
    def popup_context_menu(self, event):
	self.set_event_context(event)
	if self.context_menu is None:
            self.context_menu = UpdatedMenu(self.frame, [], tearoff = 0,
                                      auto_rebuild = self.build_context_menu)
        self.context_menu.Popup(event.x_root, event.y_root)
Esempio n. 8
0
class LayerPanel(SketchPanel):

    title = _("Layers")
    receivers = SketchPanel.receivers[:]

    def __init__(self, master, main_window, doc):
	self.info_list = []
	SketchPanel.__init__(self, master, main_window, doc, name = 'layerdlg')

    def build_dlg(self):
	top = self.top

	frame = Frame(top)
	frame.pack(side = BOTTOM, fill = X)
	button = UpdatedButton(frame, bitmap = pixmaps.LayerNew, name = 'new',
			       command = self.new_layer)
	button.pack(side = LEFT, fill = BOTH, expand = 1)
	button = UpdatedButton(frame, bitmap = pixmaps.LayerUp, name = 'up',
			       command = self.layer_up)
	button.pack(side = LEFT, fill = BOTH, expand = 1)
	button = UpdatedButton(frame, bitmap = pixmaps.LayerDown,
			       name = 'down', command = self.layer_down)
	button.pack(side = LEFT, fill = BOTH, expand = 1)
	button = UpdatedButton(frame, text = _("Close"), name = 'close',
			       command = self.close_dlg)
	button.pack(side = LEFT, fill = BOTH, expand = 1)

	list_frame = Frame(top)
	list_frame.pack(side = LEFT, expand = 1, fill = BOTH)

	sb_vert = Scrollbar(list_frame, takefocus = 0)
	sb_vert.pack(side = RIGHT, fill = Y)

	self.canvas = canvas = Canvas(list_frame)
	canvas.pack(expand = 1, fill = BOTH)

	self.frame = frame = Frame(canvas, name = 'list')
	canvas.create_window(0, 0, window = frame, anchor = NW)
	sb_vert['command'] = (canvas, 'yview')
	canvas['yscrollcommand'] = (sb_vert, 'set')

	self.active_var = IntVar(top)

    def init_from_doc(self):
	self.Update(LAYER_ORDER)

    receivers.append((LAYER, 'Update'))
    def Update(self, detail = '', *args):
	if detail != LAYER_ACTIVE:
	    if detail == LAYER_ORDER:
		self.create_widget_list()
	    else:
		self.update_widgets()
	self.update_active()

    def create_widget_list(self):
	frame = self.frame
	set_active_layer = self.set_active_layer
	set_layer_state = self.set_layer_state
	set_color = self.set_color
	context_menu = self.popup_context_menu
	rows = self.info_list
	layers = self.document.NumLayers()
	if layers > len(rows):
	    for idx in range(len(rows), layers):
		row = LayerInfo(frame, idx, (), self.active_var,
				self.rename_layer, set_active_layer,
				set_layer_state, set_color, context_menu)
		row.PlaceWidgets(idx)
		rows.append(row)
	elif layers < len(rows):
	    for row in rows[layers:]:
		row.Destroy()
	    del rows[layers:]
	self.update_widgets()
	frame.update()
	self.canvas['scrollregion'] = (0, 0, frame.winfo_reqwidth(),
				       frame.winfo_reqheight())
	self.canvas['width'] = frame.winfo_reqwidth()

    def update_widgets(self):
        layers = self.document.layers[:]
        layers.reverse()
	for idx in range(len(layers)):
	    self.info_list[idx].SetInfo(idx, layers[idx])

    def update_active(self):
	idx = self.document.ActiveLayerIdx()
        if idx is None:
            idx = -1
	self.active_var.set(self.document.NumLayers() - 1 - idx)

    def set_active_layer(self):
        idx = self.document.NumLayers() - self.active_var.get() - 1
	self.document.SetActiveLayer(idx)

    def set_layer_state(self, idx):
	idx = int(idx)
	row = self.info_list[idx]
	idx = self.document.NumLayers() - idx - 1
	state = row.State()
	apply(self.document.SetLayerState, (idx,) + state)

    def set_color(self, idx):
	idx = int(idx)
	row = self.info_list[idx]
	idx = self.document.NumLayers() - idx - 1
	self.document.SetLayerColor(idx, row.Color())

    def set_event_context(self, event):
	for idx in range(len(self.info_list)):
	    if self.info_list[idx].button == event.widget:
		break
	else:
	    return
	self.context_idx = self.document.NumLayers() - 1 - idx
	self.context_layer = self.document.Layers()[self.context_idx]

    context_menu = None
    def popup_context_menu(self, event):
	self.set_event_context(event)
	if self.context_menu is None:
            self.context_menu = UpdatedMenu(self.frame, [], tearoff = 0,
                                      auto_rebuild = self.build_context_menu)
        self.context_menu.Popup(event.x_root, event.y_root)

    def build_context_menu(self):
        entries = [
            (_("Rename"), self.rename_layer),
            None,
            (_("Lower Layer"), self.layer_down, 0),
            (_("Raise Layer"), self.layer_up, 0),
            (_("Delete"), self.delete_layer, (), self.can_delete_layer),
            None,
            (_("Move Selection Here"), self.move_selection_here, (),
             self.can_move_selection),
            (_("Select All Children"), self.select_layer, SelectAdd,
             self.is_not_locked),
            (_("Deselect All Children"), self.select_layer, SelectSubtract,
             self.is_not_locked)
            ]
        if self.context_layer.is_GuideLayer:
            entries.append(None)
            entries.append(self.main_window.commands.CreateGuideDialog)
        if self.context_layer.is_GridLayer:
            entries.append(None)
            entries.append(self.main_window.commands.CreateGridDialog)
        return map(MakeCommand, entries)

    def close_dlg(self):
	SketchPanel.close_dlg(self)
	if self.context_menu is not None:
	    self.context_menu.destroy()

    def rename_layer(self, event = None):
	if event is not None:
	    self.set_event_context(event)
	name = GetName(self.top, self.context_layer.Name())
	if name != None:
	    self.document.SetLayerName(self.context_idx, name)

    def delete_layer(self):
	self.document.DeleteLayer(self.context_idx)

    def can_delete_layer(self):
	return self.document.CanDeleteLayer(self.context_idx)

    def new_layer(self):
	self.document.NewLayer()

    def layer_up(self, active_layer = 1):
	if active_layer:
            active_idx = self.active_var.get()
            if active_idx < 0:
                return
	    idx = self.document.NumLayers() - 1 - active_idx
	else:
	    idx = self.context_idx
	self.document.MoveLayerUp(idx)

    def layer_down(self, active_layer = 1):
	if active_layer:
            active_idx = self.active_var.get()
            if active_idx < 0:
                return
	    idx = self.document.NumLayers() - 1 - active_idx
	else:
	    idx = self.context_idx
	self.document.MoveLayerDown(idx)

    def move_selection_here(self):
	self.document.MoveSelectionToLayer(self.context_idx)

    def can_move_selection(self):
	return not self.context_layer.Locked() and self.document.HasSelection()

    def is_not_locked(self):
	return not self.context_layer.Locked()

    def select_layer(self, mode):
	self.document.SelectLayer(self.context_idx, mode)
Esempio n. 9
0
class LayerPanel(SketchPanel):

    title = _("Layers")
    receivers = SketchPanel.receivers[:]

    def __init__(self, master, main_window, doc):
        self.info_list = []
        SketchPanel.__init__(self, master, main_window, doc, name='layerdlg')

    def build_dlg(self):
        top = self.top

        frame = Frame(top)
        frame.pack(side=BOTTOM, fill=X)
        button = UpdatedButton(frame,
                               bitmap=pixmaps.LayerNew,
                               name='new',
                               command=self.new_layer)
        button.pack(side=LEFT, fill=BOTH, expand=1)
        button = UpdatedButton(frame,
                               bitmap=pixmaps.LayerUp,
                               name='up',
                               command=self.layer_up)
        button.pack(side=LEFT, fill=BOTH, expand=1)
        button = UpdatedButton(frame,
                               bitmap=pixmaps.LayerDown,
                               name='down',
                               command=self.layer_down)
        button.pack(side=LEFT, fill=BOTH, expand=1)
        button = UpdatedButton(frame,
                               text=_("Close"),
                               name='close',
                               command=self.close_dlg)
        button.pack(side=LEFT, fill=BOTH, expand=1)

        list_frame = Frame(top)
        list_frame.pack(side=LEFT, expand=1, fill=BOTH)

        sb_vert = Scrollbar(list_frame, takefocus=0)
        sb_vert.pack(side=RIGHT, fill=Y)

        self.canvas = canvas = Canvas(list_frame)
        canvas.pack(expand=1, fill=BOTH)

        self.frame = frame = Frame(canvas, name='list')
        canvas.create_window(0, 0, window=frame, anchor=NW)
        sb_vert['command'] = (canvas, 'yview')
        canvas['yscrollcommand'] = (sb_vert, 'set')

        self.active_var = IntVar(top)

    def init_from_doc(self):
        self.Update(LAYER_ORDER)

    receivers.append((LAYER, 'Update'))

    def Update(self, detail='', *args):
        if detail != LAYER_ACTIVE:
            if detail == LAYER_ORDER:
                self.create_widget_list()
            else:
                self.update_widgets()
        self.update_active()

    def create_widget_list(self):
        frame = self.frame
        set_active_layer = self.set_active_layer
        set_layer_state = self.set_layer_state
        set_color = self.set_color
        context_menu = self.popup_context_menu
        rows = self.info_list
        layers = self.document.NumLayers()
        if layers > len(rows):
            for idx in range(len(rows), layers):
                row = LayerInfo(frame, idx, (), self.active_var,
                                self.rename_layer, set_active_layer,
                                set_layer_state, set_color, context_menu)
                row.PlaceWidgets(idx)
                rows.append(row)
        elif layers < len(rows):
            for row in rows[layers:]:
                row.Destroy()
            del rows[layers:]
        self.update_widgets()
        frame.update()
        self.canvas['scrollregion'] = (0, 0, frame.winfo_reqwidth(),
                                       frame.winfo_reqheight())
        self.canvas['width'] = frame.winfo_reqwidth()

    def update_widgets(self):
        layers = self.document.layers[:]
        layers.reverse()
        for idx in range(len(layers)):
            self.info_list[idx].SetInfo(idx, layers[idx])

    def update_active(self):
        idx = self.document.ActiveLayerIdx()
        if idx is None:
            idx = -1
        self.active_var.set(self.document.NumLayers() - 1 - idx)

    def set_active_layer(self):
        idx = self.document.NumLayers() - self.active_var.get() - 1
        self.document.SetActiveLayer(idx)

    def set_layer_state(self, idx):
        idx = int(idx)
        row = self.info_list[idx]
        idx = self.document.NumLayers() - idx - 1
        state = row.State()
        apply(self.document.SetLayerState, (idx, ) + state)

    def set_color(self, idx):
        idx = int(idx)
        row = self.info_list[idx]
        idx = self.document.NumLayers() - idx - 1
        self.document.SetLayerColor(idx, row.Color())

    def set_event_context(self, event):
        for idx in range(len(self.info_list)):
            if self.info_list[idx].button == event.widget:
                break
        else:
            return
        self.context_idx = self.document.NumLayers() - 1 - idx
        self.context_layer = self.document.Layers()[self.context_idx]

    context_menu = None

    def popup_context_menu(self, event):
        self.set_event_context(event)
        if self.context_menu is None:
            self.context_menu = UpdatedMenu(
                self.frame, [],
                tearoff=0,
                auto_rebuild=self.build_context_menu)
        self.context_menu.Popup(event.x_root, event.y_root)

    def build_context_menu(self):
        entries = [(_("Rename"), self.rename_layer), None,
                   (_("Lower Layer"), self.layer_down, 0),
                   (_("Raise Layer"), self.layer_up, 0),
                   (_("Delete"), self.delete_layer, (), self.can_delete_layer),
                   None,
                   (_("Move Selection Here"), self.move_selection_here, (),
                    self.can_move_selection),
                   (_("Select All Children"), self.select_layer, SelectAdd,
                    self.is_not_locked),
                   (_("Deselect All Children"), self.select_layer,
                    SelectSubtract, self.is_not_locked)]
        if self.context_layer.is_GuideLayer:
            entries.append(None)
            entries.append(self.main_window.commands.CreateGuideDialog)
        if self.context_layer.is_GridLayer:
            entries.append(None)
            entries.append(self.main_window.commands.CreateGridDialog)
        return map(MakeCommand, entries)

    def close_dlg(self):
        SketchPanel.close_dlg(self)
        if self.context_menu is not None:
            self.context_menu.destroy()

    def rename_layer(self, event=None):
        if event is not None:
            self.set_event_context(event)
        name = GetName(self.top, self.context_layer.Name())
        if name != None:
            self.document.SetLayerName(self.context_idx, name)

    def delete_layer(self):
        self.document.DeleteLayer(self.context_idx)

    def can_delete_layer(self):
        return self.document.CanDeleteLayer(self.context_idx)

    def new_layer(self):
        self.document.NewLayer()

    def layer_up(self, active_layer=1):
        if active_layer:
            active_idx = self.active_var.get()
            if active_idx < 0:
                return
            idx = self.document.NumLayers() - 1 - active_idx
        else:
            idx = self.context_idx
        self.document.MoveLayerUp(idx)

    def layer_down(self, active_layer=1):
        if active_layer:
            active_idx = self.active_var.get()
            if active_idx < 0:
                return
            idx = self.document.NumLayers() - 1 - active_idx
        else:
            idx = self.context_idx
        self.document.MoveLayerDown(idx)

    def move_selection_here(self):
        self.document.MoveSelectionToLayer(self.context_idx)

    def can_move_selection(self):
        return not self.context_layer.Locked() and self.document.HasSelection()

    def is_not_locked(self):
        return not self.context_layer.Locked()

    def select_layer(self, mode):
        self.document.SelectLayer(self.context_idx, mode)
Esempio n. 10
0
class GradientView(PyWidget, Publisher):

    accept_drop = (DROP_COLOR, )

    def __init__(self, master, width, height, gradient, **kw):
        image = PIL.Image.new('RGB', (width, height))
        self.orig_x = handle_height / 2
        if not kw.has_key('width'):
            kw["width"] = width + handle_height
        if not kw.has_key('height'):
            kw["height"] = height + handle_height
        apply(PyWidget.__init__, (self, master), kw)
        self.set_gradient(gradient)
        self.update_pending = 0
        self.dragging = 0
        self.drag_idx = 0
        self.drag_start = 0
        self.drag_min = self.drag_max = 0.0
        self.gc_initialized = 0
        self.image = image
        self.ximage = None
        self.context_menu = None
        self.bind('<ButtonPress-3>', self.PopupContextMenu)
        self.bind('<ButtonPress>', self.ButtonPressEvent)
        self.bind('<Motion>', self.PointerMotionEvent)
        self.bind('<ButtonRelease>', self.ButtonReleaseEvent)

    def __del__(self):
        pdebug('__del__', '__del__', self)

    def MapMethod(self):
        if not self.gc_initialized:
            self.init_gc()
            self.tk.call(self._w, 'motionhints')
            self.gc_initialized = 1

    def DestroyMethod(self):
        if self.context_menu is not None:
            self.context_menu.clean_up()
        self.context_menu = None
        PyWidget.DestroyMethod(self)

    def init_gc(self):
        self.gc = self.tkwin.GetGC()
        self.visual = color.skvisual
        w = self.tkwin
        width, height = self.image.size
        depth = self.visual.depth
        if depth > 16:
            bpl = 4 * width
        elif depth > 8:
            bpl = ((2 * width + 3) / 4) * 4
        elif depth == 8:
            bpl = ((width + 3) / 4) * 4
        else:
            raise SketchError('unsupported depth for images')
        self.ximage = w.CreateImage(depth, X.ZPixmap, 0, None, width, height,
                                    32, bpl)
        self.set_image(self.image)

    def set_image(self, image):
        self.image = image
        if self.ximage:
            ximage = self.ximage
            _sketch.copy_image_to_ximage(self.visual, image.im, ximage, 0, 0,
                                         ximage.width, ximage.height)
            self.UpdateWhenIdle()

    def ResizedMethod(self, width, height):
        pass

    def set_gradient(self, gradient):
        gradient = gradient.Colors()
        self.gradient = []
        for pos, color in gradient:
            self.gradient.append((pos, tuple(color)))

    def reverse(self):
        for i in range(len(self.gradient)):
            self.gradient[i] = (1 - self.gradient[i][0], self.gradient[i][1])
        self.gradient.reverse()
        self.UpdateWhenIdle()

    def x_to_idx(self, x):
        width = self.ximage.width
        w2 = handle_height / 2
        orig_x = self.orig_x
        for i in range(len(self.gradient)):
            if abs(x - orig_x - self.gradient[i][0] * width) < w2:
                return i
        return -1

    def ButtonPressEvent(self, event):
        if not self.dragging:
            self.drag_idx = self.x_to_idx(event.x)
            if self.drag_idx < 0:
                return
            if self.drag_idx == 0:
                self.gradient.insert(0, self.gradient[0])
                self.drag_idx = self.drag_idx + 1
            if self.drag_idx == len(self.gradient) - 1:
                self.gradient.append(self.gradient[-1])
            self.drag_start = event.x, self.gradient[self.drag_idx][0]
            if self.drag_idx > 0:
                self.drag_min = self.gradient[self.drag_idx - 1][0]
            else:
                self.drag_min = 0.0
            if self.drag_idx < len(self.gradient) - 1:
                self.drag_max = self.gradient[self.drag_idx + 1][0]
            else:
                self.drag_max = 1.0

        self.dragging = self.dragging + 1

    def ButtonReleaseEvent(self, event):
        if self.dragging:
            self.dragging = self.dragging - 1
            self.move_to(event.x)
            if self.drag_idx == 1 and \
               self.gradient[0][0] == self.gradient[1][0]:
                del self.gradient[0]
            elif self.drag_idx == len(self.gradient) - 2 and \
                 self.gradient[-1][0] == self.gradient[-2][0]:
                del self.gradient[-1]

    def PointerMotionEvent(self, event):
        if self.dragging:
            x = self.tkwin.QueryPointer()[4]
            self.move_to(x)

    def move_to(self, x):
        start_x, start_pos = self.drag_start
        pos = x - start_x + start_pos * self.ximage.width
        pos = float(pos) / self.ximage.width
        if pos < self.drag_min:
            pos = self.drag_min
        if pos > self.drag_max:
            pos = self.drag_max
        color = self.gradient[self.drag_idx][-1]
        self.gradient[self.drag_idx] = (pos, color)
        self.UpdateWhenIdle()

    def PopupContextMenu(self, event):
        self.context_idx = self.x_to_idx(event.x)
        self.context_pos = (event.x - self.orig_x) / float(self.ximage.width)
        if self.context_menu is None:
            items = [
                MenuCommand(_("Set Handle Color"),
                            self.set_handle_color,
                            sensitivecb=self.can_set_handle_color),
                MenuCommand(_("Delete Handle"),
                            self.delete_handle,
                            sensitivecb=self.can_delete_handle),
                MenuCommand(_("Insert Handle"),
                            self.insert_handle,
                            sensitivecb=self.can_insert_handle)
            ]
            self.context_menu = UpdatedMenu(self, items)
        self.context_menu.Popup(event.x_root, event.y_root)

    def delete_handle(self):
        if 0 < self.context_idx < len(self.gradient) - 1:
            del self.gradient[self.context_idx]
            self.UpdateWhenIdle()

    def can_delete_handle(self):
        return 0 < self.context_idx < len(self.gradient) - 1

    def insert_handle(self):
        gradient = self.gradient
        pos = self.context_pos
        if 0.0 <= pos <= 1.0:
            for i in range(len(gradient) - 1):
                if gradient[i][0] < pos < gradient[i + 1][0]:
                    p1, c1 = gradient[i]
                    p2, c2 = gradient[i + 1]
                    color = Blend(apply(CreateRGBColor, c2),
                                  apply(CreateRGBColor, c1),
                                  (pos - p1) / (p2 - p1))
                    gradient.insert(i + 1, (pos, tuple(color)))
                    self.UpdateWhenIdle()
                    break

    def can_insert_handle(self):
        return self.context_idx < 0 and 0.0 <= self.context_pos <= 1.0

    def set_handle_color(self):
        if self.context_idx >= 0:
            pos, color = self.gradient[self.context_idx]
            color = GetColor(self, apply(CreateRGBColor, color))
            if color is not None:
                self.gradient[self.context_idx] = (pos, tuple(color))
                self.UpdateWhenIdle()

    def can_set_handle_color(self):
        return self.context_idx >= 0

    def update_gradient(self):
        _sketch.fill_axial_gradient(self.image.im, self.gradient, 0, 0,
                                    self.image.size[0] - 1, 0)
        self.set_image(self.image)

    def UpdateWhenIdle(self):
        if not self.update_pending:
            self.update_pending = 1
            PyWidget.UpdateWhenIdle(self)

    def RedrawMethod(self, region=None):
        if self.update_pending:
            self.update_gradient()
            self.update_pending = 0
        pixmap = self.tkwin.CreatePixmap()
        width = self.ximage.width
        height = self.ximage.height
        startx = handle_height / 2
        self.gc.SetDrawable(pixmap)
        self.tkborder.Fill3DRectangle(pixmap, 0, 0, self.tkwin.width,
                                      self.tkwin.height, 0, pax.TK_RELIEF_FLAT)
        self.gc.PutImage(self.ximage, 0, 0, startx, 0, width, height)

        border = self.tkborder
        win = self.tkwin
        w2 = handle_height / 2
        bot = handle_height + height
        for pos in self.gradient:
            pos = pos[0]
            x = int(pos * width) + startx
            poly = [(x - w2, bot), (x, height), (x + w2, bot)]
            border.Draw3DPolygon(pixmap, poly, -2, pax.TK_RELIEF_SUNKEN)

        self.gc.SetDrawable(self.tkwin)
        pixmap.CopyArea(self.tkwin, self.gc, 0, 0, self.tkwin.width,
                        self.tkwin.height, 0, 0)

    def DropAt(self, x, y, what, data):
        if what == DROP_COLOR:
            idx = self.x_to_idx(x)
            if idx >= 0:
                pos, color = self.gradient[idx]
                self.gradient[idx] = (pos, tuple(data))
                self.UpdateWhenIdle()

    def GetGradient(self):
        result = []
        for pos, color in self.gradient:
            result.append((pos, apply(CreateRGBColor, color)))
        return MultiGradient(result)