import gtk import dialog import utils import random from fract4d import gradient def show_gradients(parent,f): GradientDialog.show(parent,f) class GradientDialog(dialog.T): def __init__(self,main_window,f): global userPrefs dialog.T.__init__( self, _("Gradients"), main_window, gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)) self.set_size_request(300, 320) self.f = f self.grad=gradient.Gradient() self.mousedown = False self.origmpos = self.startmpos = 0 self.cur = -1 # no segment selected #self.create_gradient_dialog() def show(parent,f,grad): dialog.T.reveal(GradientDialog,False, parent, None, f,grad) show = staticmethod(show) def create_gradient_dialog(self): hData = self.grad.getDataFromHandle(self.grad.cur) HSVCo = gradient.RGBtoHSV(hData.col) ###GRADIENT PREVIEW### self.gradarea=gtk.DrawingArea() self.gradarea.set_size_request(256, 64) self.gradarea.connect('realize', self.gradarea_realized) self.gradarea.connect('expose_event', self.gradarea_expose) self.gradarea.add_events( gtk.gdk.BUTTON_RELEASE_MASK | gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.POINTER_MOTION_MASK) self.gradarea.connect('button-press-event', self.gradarea_mousedown) self.gradarea.connect('button-release-event', self.gradarea_clicked) self.gradarea.connect('motion-notify-event', self.gradarea_mousemoved) gradareaBox = gtk.HBox(False, 0) ###CONTEXT MENU### menu_items = ( ( "/_Insert", "I", self.add_handle, 0 ), ( "/_Delete", "D", self.rem_handle, 0 ), ( "/_Coloring Mode", None, None, 0, "" ), ( "/Coloring Mode/_RGB", "R", self.cmode, 0 ), ( "/Coloring Mode/_HSV", "H", self.cmode, 1 ), ( "/_Blending Mode", None, None, 0, "" ), ( "/Blending Mode/_Linear", "L", self.bmode, 0 ), ( "/Blending Mode/_Sinusoidal", None, self.bmode, 1 ), ( "/Blending Mode/Curved _Increasing",None, self.bmode, 2 ), ( "/Blending Mode/Curved _Decreasing",None, self.bmode, 3 ), ( "/Debug", None, self.printstuff, 0 ) ) accel_group = gtk.AccelGroup() self.item_factory= gtk.ItemFactory(gtk.Menu, "", accel_group) self.item_factory.create_items(menu_items) self.add_accel_group(accel_group) self.menu=self.item_factory.get_widget("") ###COLOR SELECTION### if gtk.pygtk_version[0] >= 2 and gtk.pygtk_version[1] >= 4: lblCsel = gtk.Label("Color:") self.csel = gtk.ColorButton( utils.create_color(hData.col[0], hData.col[1], hData.col[2])) self.csel.connect('color-set', self.colorchanged) self.colorbutton = True else: self.csel = gtk.Button("Color...") self.csel.connect('clicked', self.cbutton_clicked) self.csel_dialog = gtk.ColorSelectionDialog("Select a Color") self.csel_dialog.colorsel.set_current_color( utils.create_color(hData.col[0], hData.col[1], hData.col[2])) self.csel_dialog.ok_button.connect('clicked', self.cdialog_response) self.colorbutton = False synccolsB = gtk.Button("Sync Colors") synccolsB.connect('clicked', self.sync_colors) CSelBox = gtk.HBox(False, 0) ###ALTERNATION CONTROL### lblAlternate = gtk.Label(_("Alternation:")) alternate = gtk.SpinButton(gtk.Adjustment(self.grad.getAlt(), 0, .5, 0.01, .5, 0.0)) alternate.set_digits(3) alternate.connect('value-changed', self.alternate_changed) AlternateBox = gtk.HBox(False, 0) ###POSITION CONTROL### lblPos = gtk.Label(_("Position:")) self.pos = gtk.SpinButton(gtk.Adjustment(hData.pos, 0, 1, 0.01, 0.1, 0.0)) self.pos.set_digits(2) self.pos.connect('value-changed', self.pos_changed) PosBox = gtk.HBox(False, 0) ###RANDOMIZE BUTTON### randomize = gtk.Button(_("Randomize")) randomize.connect('clicked', self.randomize) randBox = gtk.HBox(False, 0) ###OFFSET CONTROL### lblOffset = gtk.Label(_("Offset:")) lblOffsetBox = gtk.HBox(False, 0) offset=gtk.HScale(gtk.Adjustment(self.grad.getOffset(), 0, 1, 0.001, 0.01, 0.0)) offset.set_digits(3) offset.connect('value-changed', self.offset_changed) #################### ###WIDGET PACKING### #################### self.vbox.set_homogeneous(0) gradareaBox.pack_start(self.gradarea, 1, 0, 10) self.vbox.pack_start(gradareaBox, 0, 0, 5) if self.colorbutton: CSelBox.pack_start(lblCsel, 0, 0, 10) CSelBox.pack_start(self.csel, 0, 0, 10) CSelBox.pack_end(synccolsB, 0, 0, 10) self.vbox.pack_start(CSelBox, 0, 0, 5) PosBox.pack_start(lblPos, 0, 0, 10) PosBox.pack_start(self.pos, 0, 0, 10) self.vbox.pack_start(PosBox, 0, 0, 5) AlternateBox.pack_start(lblAlternate, 0, 0, 10) AlternateBox.pack_start(alternate, 0, 0, 10) self.vbox.pack_start(AlternateBox, 0, 0, 5) lblOffsetBox.pack_start(lblOffset, 0, 0, 5) self.vbox.pack_start(lblOffsetBox, 0, 0, 5) self.vbox.pack_start(offset, 0, 0, 5) randBox.pack_start(randomize, 1, 0, 10) self.vbox.pack_start(randBox, 0, 0, 5) def offset_changed(self, widget): if self.grad.getOffset() != widget.get_value(): self.grad.setOffset(1-widget.get_value()) self.grad.compute() self.gradarea.queue_draw() self.f.colorlist=self.grad.clist self.f.changed(False) def colourchanged(self, widget): color = widget.get_color() seg, side = self.grad.getSegFromHandle(self.grad.cur) if side == 'left': seg.left.col = [colour.red/256, colour.green/256, colour.blue/256] else: seg.right.col = [colour.red/256, colour.green/256, colour.blue/256] self.grad.compute() self.gradarea.queue_draw() self.f.colorlist=self.grad.clist self.f.changed(False) #The backwards-compatible button was clicked def cbutton_clicked(self, widget): self.csel_dialog.show() def cdialog_response(self, widget): colour = self.csel_dialog.colorsel.get_current_color() seg, side = self.grad.getSegFromHandle(self.grad.cur) if side == 'left': seg.left.col = [colour.red/256, colour.green/256, colour.blue/256] else: seg.right.col = [colour.red/256, colour.green/256, colour.blue/256] self.grad.compute() self.gradarea.queue_draw() self.f.colorlist=self.grad.clist self.f.changed(False) self.csel_dialog.hide() return False ###Each handle is comprised of two handles, whose colours can be set independently. ###This function finds the other handle and sets it to the current handle's colour. def sync_colours(self, widget): if self.grad.cur % 2 == 0: #The handle is the first in its segment if self.grad.cur > 0: self.grad.segments[self.grad.cur/2-1].right.col = self.grad.getDataFromHandle(self.grad.cur).col else: self.grad.segments[-1].right.col = self.grad.getDataFromHandle(self.grad.cur).col else: if self.grad.cur < len(self.grad.segments)*2: self.grad.segments[self.grad.cur/2+1].left.col = self.grad.getDataFromHandle(self.grad.cur).col else: self.grad.segments[0].left.col = self.grad.getDataFromHandle(self.grad.cur).col self.grad.compute() self.gradarea.queue_draw() self.f.colorlist=self.grad.clist self.f.changed(False) ###ALTERNATION CHANGED### def alternate_changed(self, widget): if self.grad.getAlt() != widget.get_value(): self.grad.setAlt(widget.get_value()) self.grad.compute() self.gradarea.queue_draw() self.f.colorlist = self.grad.clist self.f.changed(False) ###POSITION CHANGED### def pos_changed(self, widget): if self.grad.getDataFromHandle(self.grad.cur).pos != widget.get_value(): self.grad.move(self.grad.cur, widget.get_value()-self.grad.getDataFromHandle(self.grad.cur).pos) widget.set_value(self.grad.getDataFromHandle(self.grad.cur).pos) self.grad.compute() self.gradarea.queue_draw() self.f.colorlist = self.grad.clist self.f.changed(False) ###INIT FOR GRADIENT PREVIEW### def gradarea_realized(self, widget): self.gradcol= widget.get_colormap().alloc_color( "#FFFFFFFFFFFF", True, True) self.gradgc = widget.window.new_gc( foreground=self.gradcol, background=self.gradcol, fill=gtk.gdk.SOLID) widget.window.draw_rectangle(widget.style.white_gc, True, 0, 0, widget.allocation.width, widget.allocation.height) return True def gradarea_expose(self, widget, event): #Assume some other process has compute()ed the gradient ##Draw the gradient itself## for col in self.grad.clist: self.gradcol = widget.get_colormap().alloc_color(col[1]*255,col[2]*255,col[3]*255, True, True) self.gradgc.set_foreground(self.gradcol) widget.window.draw_line(self.gradgc, col[0]*self.grad.num+4, 0, col[0]*self.grad.num+4, 56) ##Draw some handles## for seg in self.grad.segments: s_lpos = (seg.left.pos+(1-self.grad.offset)) * self.grad.num s_rpos = (seg.right.pos+(1-self.grad.offset)) * self.grad.num if s_lpos > self.grad.num: s_lpos -= self.grad.num elif s_lpos < 0: s_lpos += self.grad.num if s_rpos > self.grad.num: s_rpos -= self.grad.num elif s_rpos < 0: s_rpos += self.grad.num s_lpos += 4 s_rpos += 4 wgc=widget.style.white_gc bgc=widget.style.black_gc index=self.grad.segments.index(seg) #A vast ugliness that should draw the selected handle with a white centre. #The problem is that each handle is really two handles - the second handle #of the left-hand segment and the first of the right. #The first two branches deal with handles in the middle, whilst the second #two deal with those at the edges. The other is a case for where neither #of the handles in a segment should be highlighted. if self.grad.cur/2.0 == index or (self.grad.cur+1)/2.0 == index: self.draw_handle(widget.window, int(s_lpos), wgc, bgc) self.draw_handle(widget.window, int(s_rpos), bgc, bgc) elif (self.grad.cur-1)/2.0 == index: self.draw_handle(widget.window, int(s_lpos), bgc, bgc) self.draw_handle(widget.window, int(s_rpos), wgc, bgc) elif (self.grad.cur-1)/2.0 == len(self.grad.segments)-1.0 and index == 0: self.draw_handle(widget.window, int(s_lpos), wgc, bgc) self.draw_handle(widget.window, int(s_rpos), bgc, bgc) elif self.grad.cur == 0 and index == len(self.grad.segments)/2.0: self.draw_handle(widget.window, int(s_lpos), bgc, bgc) self.draw_handle(widget.window, int(s_rpos), wgc, bgc) else: self.draw_handle(widget.window, int(s_lpos), bgc, bgc) self.draw_handle(widget.window, int(s_rpos), bgc, bgc) return False def gradarea_mousedown(self, widget, event): if self.mousedown == False and event.button == 1: x=event.x/self.grad.num x-=1-self.grad.offset if x < 0: x+=1 seg = self.grad.getSegAt(x) relx = x - seg.left.pos if relx < (seg.right.pos-seg.left.pos)/2: self.grad.cur=self.grad.segments.index(seg)*2 else: self.grad.cur=self.grad.segments.index(seg)*2+1 hData = self.grad.getDataFromHandle(self.grad.cur) if self.colourbutton == True: self.csel.set_color( utils.create_color(hData.col[0],hData.col[1],hData.col[2])) else: self.csel_dialog.colorsel.set_current_color( utils.create_color(hData.col[0],hData.col[1],hData.col[2])) self.pos.set_value(hData.pos) self.gradarea.queue_draw() if event.button == 1: self.mousedown = True self.origmpos = self.startmpos = event.x elif event.button == 3: self.mousepos = event.x #We can't pass this as callback data, because things're screwed. If this isn't true, please tell! #self.item_factory.popup(int(event.x), int(event.y), event.button) self.menu.popup(None, None, None, event.button, event.time) return False def gradarea_clicked(self, widget, event): self.mousedown = False if self.startmpos != event.x: self.grad.compute() self.gradarea.queue_draw() self.f.colorlist=self.grad.getCList() self.f.changed(False) return False def gradarea_mousemoved(self, widget, event): if self.mousedown: self.grad.move(self.grad.cur, (event.x - self.origmpos)/self.grad.num) self.origmpos = event.x self.grad.compute() self.gradarea.queue_draw() def add_handle(self, action, widget): self.grad.add(self.mousepos/self.grad.num) self.gradarea.queue_draw() def rem_handle(self, action, widget): self.grad.remove(self.grad.cur) self.grad.cur = 0 self.gradarea.queue_draw() def cmode(self, action, widget): seg, side = self.grad.getSegFromHandle(self.grad.cur) if action == 0: seg.cmode = 'RGB' else: seg.cmode = 'HSV' self.grad.compute() self.gradarea.queue_draw() self.f.colorlist=self.grad.getCList() self.f.changed(False) def bmode(self, action, widget): seg, side = self.grad.getSegFromHandle(self.grad.cur) if action == 0: seg.bmode = 'Linear' elif action == 1: seg.bmode = 'Sinusoidal' elif action == 2: seg.bmode = 'CurvedI' else: seg.bmode = 'CurvedD' self.grad.compute() self.gradarea.queue_draw() self.f.colorlist=self.grad.getCList() self.f.changed(False) def printstuff(self, action, widget): for seg in self.grad.segments: print [seg.left.pos, seg.left.col], [seg.right.pos, seg.right.col] def randomize(self, widget): oldcol = [random.randint(0, 255),random.randint(0, 255),random.randint(0, 255)] oldpos = i = 0 poslist = [] for seg in self.grad.segments: poslist.append(random.random()) poslist.sort() for seg in self.grad.segments: seg.left.pos = oldpos seg.left.col = oldcol seg.right.pos = oldpos = poslist[i] seg.right.col = oldcol = [random.randint(0, 255),random.randint(0, 255),random.randint(0, 255)] i+=1 seg.right.pos = 1 seg.right.col = self.grad.segments[0].left.col self.grad.compute() self.gradarea.queue_draw() self.f.colorlist=self.grad.getCList() self.f.changed(False) return False def draw_handle(self, drawable, pos, fill, outline): for y in range(8): drawable.draw_line(fill, pos-y/2, y+56, pos+y/2, y+56) lpos = pos + 3.5 rpos = pos - 3.5 drawable.draw_line(outline, pos, 56, lpos, 63); drawable.draw_line(outline, pos, 56, rpos, 63); drawable.draw_line(outline, lpos, 63, rpos, 63);