Beispiel #1
0
    def draw_square(self,width,height,radius):
        img = cairo.ImageSurface(cairo.FORMAT_ARGB32, width,height)
        cr = cairo.Context(img)
        m = radius/sqrt(2.0)

        # Slightly darker border for the colour area
        sw = max(0.75*self.stroke_width, 3.0)
        cr.set_source_rgb(*NEUTRAL_DARK_GREY)
        cr.rectangle(self.x0-m-sw, self.y0-m-sw, 2*(m+sw), 2*(m+sw))
        cr.fill()

        h,s,v = self.hsv
        ds = 2*m*CSTEP
        v = 0.0
        x1 = self.x0-m
        x2 = self.x0+m
        y = self.y0-m
        while v < 1.0:
            g = cairo.LinearGradient(x1,y,x2,y)
            g.add_color_stop_rgb(0.0, *hsv_to_rgb(h,0.0,1.0-v))
            g.add_color_stop_rgb(1.0, *hsv_to_rgb(h,1.0,1.0-v))
            cr.set_source(g)
            cr.rectangle(x1,y, 2*m, ds)
            cr.fill_preserve()
            cr.stroke()
            y += ds
            v += CSTEP
        h,s,v = self.hsv
        x = self.x0-m + s*2*m
        y = self.y0-m + (1-v)*2*m
        cr.set_source_rgb(*hsv_to_rgb(1-h,1-s,1-v))
        cr.arc(x,y, 3.0, 0.0, 2*pi)
        cr.stroke()

        return img
    def brush_selected_cb(self, bm, managed_brush, brushinfo):
        """Responds to the user changing their brush.

        This observer callback is responsible for allocating the current brush
        settings to the current brush singleton in `self.app`. The Brush
        Selector, the Pick Context action, and the Brushkeys and
        Device-specific brush associations all cause this to be invoked.
        """
        self._in_brush_selected_cb = True
        b = self.app.brush
        prev_lock_alpha = b.is_alpha_locked()

        # Changing the effective brush
        b.begin_atomic()
        color = b.get_color_hsv()

        mix_old = b.get_base_value('restore_color')
        b.load_from_brushinfo(brushinfo)
        self.unmodified_brushinfo = b.clone()

        # Preserve color
        mix = b.get_base_value('restore_color')
        if mix:
            c1 = hsv_to_rgb(*color)
            c2 = hsv_to_rgb(*b.get_color_hsv())
            c3 = [(1.0 - mix) * v1 + mix * v2 for v1, v2 in zip(c1, c2)]
            color = rgb_to_hsv(*c3)
        elif mix_old and self._last_selected_color:
            # switching from a brush with fixed color back to a normal one
            color = self._last_selected_color
        b.set_color_hsv(color)

        b.set_string_property("parent_brush_name", managed_brush.name)

        if b.is_eraser():
            # User picked a dedicated eraser brush
            # Unset any lock_alpha state (necessary?)
            self.set_override_setting("lock_alpha", False)
        else:
            # Preserve the old lock_alpha state
            self.set_override_setting("lock_alpha", prev_lock_alpha)

        b.end_atomic()

        # Updates the blend mode buttons to match the new settings.
        # First decide which blend mode is active and which aren't.
        active_blend_mode = self.bm.normal_mode
        for mode in self.bm.modes:
            setting_name = mode.setting_name
            if setting_name is not None:
                if b.has_large_base_value(setting_name):
                    active_blend_mode = mode
        active_blend_mode.active = True

        self._in_brush_selected_cb = False
Beispiel #3
0
 def draw_gradient(self,cr, start,end, hsv=True):
     if hsv:
         clr1 = hsv_to_rgb(*start)
         clr2 = hsv_to_rgb(*end)
     else:
         clr1 = start
         clr2 = end
     g = cairo.LinearGradient(0,0,self.w,self.h)
     g.add_color_stop_rgb(0.0, *clr1)
     g.add_color_stop_rgb(1.0, *clr2)
     cr.set_source(g)
     cr.rectangle(0,0,self.w,self.h)
     cr.fill()
Beispiel #4
0
    def expose_cb(self, widget, event):
        cr = self.window.cairo_create()

        cr.set_source_rgb(0.9, 0.9, 0.9)
        cr.paint()

        cr.set_line_join(cairo.LINE_JOIN_ROUND)

        cr.translate(0.0, popup_height/2.0)

        for i, c in enumerate(self.app.ch.colors):
            if i != self.selection:
                cr.scale(0.5, 0.5)

            line_width = 3.0
            distance = 2*line_width
            rect = [0, -popup_height/2.0, popup_height, popup_height]
            rect[0] += distance/2.0
            rect[1] += distance/2.0
            rect[2] -= distance
            rect[3] -= distance
            cr.rectangle(*rect)
            cr.set_source_rgb(*helpers.hsv_to_rgb(*c))
            cr.fill_preserve()
            cr.set_line_width(line_width)
            cr.set_source_rgb(0, 0, 0)
            cr.stroke()
            cr.translate(popup_height, 0)

            if i != self.selection:
                cr.scale(2.0, 2.0)

        return True
Beispiel #5
0
 def set_color(self, hsv, exclude=None):
     for w in self.widgets:
         if w is not exclude:
             w.set_color(hsv)
     self.color = hsv_to_rgb(*hsv)
     self.hsv = hsv
     self.on_select(hsv)
Beispiel #6
0
 def get_color_hsv(self):
     h = self.get_base_value('color_h')
     s = self.get_base_value('color_s')
     v = self.get_base_value('color_v')
     rgb = helpers.hsv_to_rgb(h, s, v)
     rgb = rgb[0]**(1 / 2.4), rgb[1]**(1 / 2.4), rgb[2]**(1 / 2.4)
     hsv = helpers.rgb_to_hsv(*rgb)
     h, s, v = hsv
     assert not math.isnan(h)
     return (h, s, v)
Beispiel #7
0
 def set_color(self, hsv):
     self.atomic = True
     self.color = r,g,b = hsv_to_rgb(*hsv)
     self.rspin.set_value(r*255)
     self.gspin.set_value(g*255)
     self.bspin.set_value(b*255)
     self.rsel.set_color(hsv)
     self.gsel.set_color(hsv)
     self.bsel.set_color(hsv)
     self.atomic = False
     self.hsv = hsv
Beispiel #8
0
 def set_color(self, hsv):
     self.atomic = True
     self.hsv = h,s,v = hsv
     self.hspin.set_value(h*359)
     self.sspin.set_value(s*100)
     self.vspin.set_value(v*100)
     self.hsel.set_color(hsv)
     self.ssel.set_color(hsv)
     self.vsel.set_color(hsv)
     self.atomic = False
     self.color = hsv_to_rgb(*hsv)
Beispiel #9
0
 def get_color_hsv(self):
     tf = self.EOTF
     h = self.get_base_value('color_h')
     s = self.get_base_value('color_s')
     v = self.get_base_value('color_v')
     rgb = helpers.hsv_to_rgb(h, s, v)
     rgb = rgb[0]**(1 / tf), rgb[1]**(1 / tf), rgb[2]**(1 / tf)
     hsv = helpers.rgb_to_hsv(*rgb)
     h, s, v = hsv
     assert not math.isnan(h)
     return (h, s, v)
Beispiel #10
0
 def push_color(self, color):
     if self.atomic:
         return
     for c in self.colors:
         if self.hsv_equal(c, color):
             self.colors.remove(c)
             break
     self.colors = (self.colors + [color])[-self.num_colors:]
     self.last_color = helpers.hsv_to_rgb(*color)
     self.app.preferences['colorhistory.colors'] = [tuple(hsv) for hsv in self.colors]
     for func in self.color_pushed_observers:
         func(color)
Beispiel #11
0
 def set_color_hsv(self, hsv):
     if not hsv:
         return
     self.begin_atomic()
     try:
         rgb = helpers.hsv_to_rgb(*hsv)
         rgb = rgb[0]**2.4, rgb[1]**2.4, rgb[2]**2.4
         hsv = helpers.rgb_to_hsv(*rgb)
         h, s, v = hsv
         self.set_base_value('color_h', h)
         self.set_base_value('color_s', s)
         self.set_base_value('color_v', v)
     finally:
         self.end_atomic()
Beispiel #12
0
 def set_color_hsv(self, hsv):
     tf = self.EOTF
     if not hsv:
         return
     self.begin_atomic()
     try:
         rgb = helpers.hsv_to_rgb(*hsv)
         rgb = rgb[0]**tf, rgb[1]**tf, rgb[2]**tf
         hsv = helpers.rgb_to_hsv(*rgb)
         h, s, v = hsv
         self.set_base_value('color_h', h)
         self.set_base_value('color_s', s)
         self.set_base_value('color_v', v)
     finally:
         self.end_atomic()
Beispiel #13
0
 def draw(self,w, event):
     if not self.window:
         return
     cr = self.window.cairo_create()
     h,s,v = self.hsv
     dx = self.w*CSTEP
     x = 0
     h1 = 0.
     while h1 < 1:
         cr.set_source_rgb(*hsv_to_rgb(h1,s,v))
         cr.rectangle(x,0,dx,self.h)
         cr.fill_preserve()
         cr.stroke()
         h1 += CSTEP
         x += dx
     x1 = h*self.w
     self.draw_line_at(cr, x1)
Beispiel #14
0
 def draw_circle(self, w, h):
     if self.circle_img:
         return self.circle_img
     img = cairo.ImageSurface(cairo.FORMAT_ARGB32, w,h)
     cr = cairo.Context(img)
     cr.set_line_width(0.75*self.stroke_width)
     a1 = 0.0
     while a1 < 2*pi:
         clr = hsv_to_rgb(a1/(2*pi), 1.0, 1.0)
         x1,y1,x2,y2 = self.calc_line(a1)
         a1 += CSTEP
         cr.set_source_rgb(*clr)
         cr.move_to(x1,y1)
         cr.line_to(x2,y2)
         cr.stroke()
     self.circle_img = img
     return img
Beispiel #15
0
 def select_color_at(self, x,y):
     color, is_hsv = self.get_color_at(x,y)
     if color is None:
         return
     if is_hsv:
         self.hsv = color
         self.color = hsv_to_rgb(*color)
     else:
         self.color = color
         self.hsv = rgb_to_hsv(*color)
     if self.device_pressed:
         selected_color = self.color
         # Potential device change, therefore brush & colour change...
         self.app.doc.tdw.device_used(self.device_pressed)
         self.color = selected_color #... but *this* is what the user wants
     self.redraw_on_select()
     self.on_select(self.hsv)
Beispiel #16
0
 def set_color(self, hsv):
     self.hsv = hsv
     self.color = hsv_to_rgb(*hsv)
     self.queue_draw()
Beispiel #17
0
 def get_color_rgb(self):
     hsv = self.get_color_hsv()
     return helpers.hsv_to_rgb(*hsv)
Beispiel #18
0
 def set_color(self, hsv, redraw=True):
     self.hsv = hsv
     self.color = hsv_to_rgb(*hsv)
     if redraw:
         self.queue_draw()
Beispiel #19
0
    def brush_selected_cb(self, bm, managed_brush, brushinfo):
        """Responds to the user changing their brush.

        This observer callback is responsible for allocating the current brush
        settings to the current brush singleton in `self.app`. The Brush
        Selector, the Pick Context action, and the Brushkeys and
        Device-specific brush associations all cause this to be invoked.
        """
        self._in_brush_selected_cb = True
        b = self.app.brush
        prev_lock_alpha = b.is_alpha_locked()

        # Changing the effective brush
        # Preserve colour
        b.begin_atomic()
        color = b.get_color_hsv()

        mix_old = b.get_base_value('restore_color')
        b.load_from_brushinfo(brushinfo)
        self.unmodified_brushinfo = b.clone()

        mix = b.get_base_value('restore_color')
        if mix:
            c1 = hsv_to_rgb(*color)
            c2 = hsv_to_rgb(*b.get_color_hsv())
            c3 = [(1.0-mix)*v1 + mix*v2 for v1, v2 in zip(c1, c2)]
            color = rgb_to_hsv(*c3)
        elif mix_old:
            # switching from a brush with fixed color back to a normal one
            color = self._last_selected_color

        b.set_color_hsv(color)
        b.set_string_property("parent_brush_name", managed_brush.name)
        if b.is_eraser():
            # User picked a dedicated eraser brush
            # Unset any lock_alpha state (necessary?)
            self.set_override_setting("lock_alpha", False)
        else:
            # Preserve the old lock_alpha state
            self.set_override_setting("lock_alpha", prev_lock_alpha)
        b.end_atomic()

        # Updates the blend mode buttons to match the new settings.
        # First decide which blend mode is active and which aren't.
        active_blend_mode = self.normal_mode
        blend_modes = []
        for mode_action in self.action_group.list_actions():
            setting_name = mode_action.setting_name
            if setting_name is not None:
                if b.has_large_base_value(setting_name):
                    active_blend_mode = mode_action
            blend_modes.append(mode_action)
        blend_modes.remove(active_blend_mode)

        # Twiddle the UI to match without emitting "activate" signals.
        active_blend_mode.block_activate()
        active_blend_mode.set_active(True)
        active_blend_mode.unblock_activate()
        for other in blend_modes:
            other.block_activate()
            other.set_active(False)
            other.unblock_activate()

        self._in_brush_selected_cb = False
Beispiel #20
0
    def draw_harmony_ring(self,width,height):
        """Draws the harmony ring if any colour harmonies are visible."""
        if not self.window:
            return
        points_size = min(width,height)/27.
        img = cairo.ImageSurface(cairo.FORMAT_ARGB32, width,height)
        cr = cairo.Context(img)
        if not self.has_harmonies_visible():
            self.draw_central_fill(cr, self.r2)
            return img
        h,s,v = self.hsv
        a = h*2*pi
        self.angles = []
        self.simple_colors = []
        cr.set_line_width(0.75*self.stroke_width)
        self.samples = [self.hsv]
        for i in range(int(CIRCLE_N)):
            c1 = c = h + i/CIRCLE_N
            if c1 > 1:
                c1 -= 1
            clr = hsv_to_rgb(c1,s,v)
            hsv = c1,s,v
            self.simple_colors.append(clr)
            delta = c1 - h
            an = -c1*2*pi
            self.angles.append(-an+pi/CIRCLE_N)
            a1 = an-pi/CIRCLE_N
            a2 = an+pi/CIRCLE_N
            cr.new_path()
            cr.set_source_rgb(*clr)
            cr.move_to(self.x0,self.y0)
            cr.arc(self.x0, self.y0, self.r2, a1, a2)
            cr.line_to(self.x0,self.y0)
            cr.fill_preserve()
            cr.set_source_rgb(*NEUTRAL_DARK_GREY) # "lines" between samples
            cr.stroke()
            # Indicate harmonic colors
            if self.app.preferences.get("colorsampler.triadic", False) and i%(CIRCLE_N/3)==0:
                self.small_triangle(cr, points_size, self.inv(clr), an, (self.r2+self.rd)/2)
                try_put(self.samples, hsv)
            if self.app.preferences.get("colorsampler.complementary", False) and i%(CIRCLE_N/2)==0:
                self.small_circle(cr, points_size, self.inv(clr), an, (self.r2+self.rd)/2)
                try_put(self.samples, hsv)
            if self.app.preferences.get("colorsampler.square", False) and i%(CIRCLE_N/4)==0:
                self.small_square(cr, points_size, self.inv(clr), an, (self.r2+self.rd)/2)
                try_put(self.samples, hsv)
# FIXME: should this harmonies be expressed in terms of CIRCLE_N?
            if self.app.preferences.get("colorsampler.double_comp", False) and i in [0,2,6,8]:
                self.small_rect_vert(cr, points_size, self.inv(clr), an, (self.r2+self.rd)/2)
                try_put(self.samples, hsv)
            if self.app.preferences.get("colorsampler.split_comp", False) and i in [0,5,7]:
                self.small_triangle_down(cr, points_size, self.inv(clr), an, (self.r2+self.rd)/2)
                try_put(self.samples, hsv)
            if self.app.preferences.get("colorsampler.analogous", False) and i in [0,1,CIRCLE_N-1]:
                self.small_rect(cr, points_size, self.inv(clr), an, (self.r2+self.rd)/2)
                try_put(self.samples, hsv)
        # Fill the centre
        self.draw_central_fill(cr, self.rd)
        # And an inner thin line
        cr.set_source_rgb(*NEUTRAL_DARK_GREY)
        cr.arc(self.x0, self.y0, self.rd, 0, 2*pi)
        cr.stroke()
        return img
 def set_color_hsv(self, h, s, v):
     self.rgb = helpers.hsv_to_rgb(h, s, v)
     self.queue_draw()
Beispiel #22
0
 def hsv_equal(a, b):
     # hack required because we somewhere have an rgb<-->hsv conversion roundtrip
     a_ = numpy.array(helpers.hsv_to_rgb(*a))
     b_ = numpy.array(helpers.hsv_to_rgb(*b))
     return ((a_ - b_)**2).sum() < (3*1.0/256)**2