コード例 #1
0
ファイル: adjbases.py プロジェクト: mypaint/mypaint
    def __init__(self, prefs, datapath):
        """Initialises with default colors and an empty adjuster list.

        :param prefs: Prefs dict for saving settings.
        :param datapath: Base path for saving palettes and masks.

        """
        super(ColorManager, self).__init__()

        # Defaults
        self._color = None  #: Currently edited color, a UIColor object
        self._hist = []  #: List of previous colors, most recent last
        self._palette = None  #: Current working palette
        self._adjusters = weakref.WeakSet()  #: The set of registered adjusters
        #: Cursor for pickers
        # FIXME: Use Gdk.Cursor.new_for_display()
        self._picker_cursor = Gdk.Cursor.new(Gdk.CursorType.CROSSHAIR)
        self._datapath = datapath  #: Base path for saving palettes and masks
        self._hue_distorts = None  #: Hue-remapping table for color wheels
        self._prefs = prefs  #: Shared preferences dictionary

        # Build the history. Last item is most recent.
        hist_hex = list(prefs.get(PREFS_KEY_COLOR_HISTORY, []))
        hist_hex = self._DEFAULT_HIST + hist_hex
        self._hist = [RGBColor.new_from_hex_str(s) for s in hist_hex]
        self._trim_hist()

        # Restore current color, or use the most recent color.
        col_hex = prefs.get(PREFS_KEY_CURRENT_COLOR, None)
        if col_hex is None:
            col_hex = hist_hex[-1]
        self._color = RGBColor.new_from_hex_str(col_hex)

        # Initialize angle distort table
        wheel_type = prefs.get(PREFS_KEY_WHEEL_TYPE, self._DEFAULT_WHEEL_TYPE)
        distorts_table = self._HUE_DISTORTION_TABLES[wheel_type]
        self._hue_distorts = distorts_table

        # Initialize working palette
        palette_dict = prefs.get(PREFS_PALETTE_DICT_KEY, None)
        if palette_dict is not None:
            palette = Palette.new_from_simple_dict(palette_dict)
        else:
            datapath = self.get_data_path()
            palettes_dir = os.path.join(datapath, DATAPATH_PALETTES_SUBDIR)
            default = os.path.join(palettes_dir, DEFAULT_PALETTE_FILE)
            palette = Palette(filename=default)
        self._palette = palette

        # Capture updates to the working palette
        palette.info_changed += self._palette_changed_cb
        palette.match_changed += self._palette_changed_cb
        palette.sequence_changed += self._palette_changed_cb
        palette.color_changed += self._palette_changed_cb
コード例 #2
0
ファイル: palette.py プロジェクト: Data-link/mypaint
 def _copy_color_in(self, col, name=None):
     if col is self._EMPTY_SLOT_ITEM or col is None:
         result = self._EMPTY_SLOT_ITEM
     else:
         if name is None:
             try:
                 name = col.__name
             except AttributeError:
                 pass
         if name is not None:
             name = unicode(name)
         result = RGBColor(color=col)
         result.__name = name
     return result
コード例 #3
0
ファイル: picker.py プロジェクト: evillair/mypaint
def _get_color_in_window(win, x, y, size=3):
    """Attempts to get the color from a position within a GDK window"""
    # GTK2 used to return a bitdepth as well.
    # The C API docs for GTK3 3.14.5 don't mention that,
    # but its GI wrapper seems to attempt backwards compatibility.
    # Um, yeah.
    # Just write code that won't break when they fix it.
    geom_tuple = win.get_geometry()
    win_x, win_y, win_w, win_h = geom_tuple[0:4]
    # Rectangle to sample
    x = int(max(0, x - size/2))
    y = int(max(0, y - size/2))
    w = int(min(size, win_w - x))
    h = int(min(size, win_h - y))
    if w <= 0 or h <= 0:
        return RGBColor(0, 0, 0)
    # The call below can take over 20ms,
    # and it depends on the window size.
    # It must be causing a full-window pixmap copy somewhere.
    pixbuf = Gdk.pixbuf_get_from_window(win, x, y, w, h)
    if pixbuf is None:
        errcol = RGBColor(1, 0, 0)
        logger.warning(
            "Failed to get pixbuf from screen; returning "
            "error indicator color %r",
            errcol,
        )
        return errcol
    return RGBColor.new_from_pixbuf_average(pixbuf)
コード例 #4
0
ファイル: picker.py プロジェクト: Jehan/mypaint
def get_color_in_window(win, x, y, size=3):
    """Attempts to get the color from a position within a GDK window.
    """

    # [GTK3] GDK2 and GDK3 return different tuples: no bitdepth in GDK3
    # We use GTK3 now but for some reason users still get different results,
    # see https://gna.org/bugs/?20791
    geom_tuple = win.get_geometry()
    win_x, win_y, win_w, win_h = geom_tuple[0:4]

    x = int(max(0, x - size/2))
    y = int(max(0, y - size/2))
    w = int(min(size, win_w - x))
    h = int(min(size, win_h - y))
    if w <= 0 or h <= 0:
        return RGBColor(0, 0, 0)
    # The call below can take over 20ms, and it depends on the window size!
    # It must be causing a full-window pixmap copy somewhere.
    pixbuf = gdk.pixbuf_get_from_window(win, x, y, w, h)
    if pixbuf is None:
        errcol = RGBColor(1, 0, 0)
        logger.warning("Failed to get pixbuf from screen; returning "
                       "error indicator color %r", errcol)
        return errcol
    return RGBColor.new_from_pixbuf_average(pixbuf)
コード例 #5
0
ファイル: drawutils.py プロジェクト: TuringMachinegun/mypaint
def render_round_floating_color_chip(cr, x, y, color, radius, z=2):
    """Draw a round color chip with a slight drop shadow

    :param cairo.Context cr: Context in which to draw.
    :param float x: X coordinate of the center pixel.
    :param float y: Y coordinate of the center pixel.
    :param lib.color.UIColor color: Color for the chip.
    :param float radius: Circle radius, in pixels.
    :param int z: Simulated height of the object above the canvas.

    Currently used for accept/dismiss/delete buttons and control points
    on the painting canvas, in certain modes.

    The button's style is similar to that used for the paint chips in
    the dockable palette panel. As used here with drop shadows to
    indicate that the blob can be interacted with, the style is similar
    to Google's Material Design approach. This style adds a subtle edge
    highlight in a brighter variant of "color", which seems to help
    address adjacent color interactions.

    """
    x = round(float(x))
    y = round(float(y))
    radius = round(radius)

    cr.save()
    cr.set_dash([], 0)
    cr.set_line_width(0)

    base_col = RGBColor(color=color)
    hi_col = _get_paint_chip_highlight(base_col)

    cr.arc(x, y, radius+0, 0, 2*math.pi)
    cr.set_line_width(2)
    render_drop_shadow(cr, z=z)

    cr.set_source_rgb(*base_col.get_rgb())
    cr.fill_preserve()
    cr.clip_preserve()

    cr.set_source_rgb(*hi_col.get_rgb())
    cr.stroke()

    cr.restore()
コード例 #6
0
ファイル: drawutils.py プロジェクト: Jehan/mypaint
def render_round_floating_color_chip(cr, x, y, color, radius):
    """Draw a round color chip with a slight drop shadow

    Currently used for dismiss/delete buttons and control points.
    The button's style is similar to that used for the paint chips
    in the dockable palette panel.

    """
    x = round(float(x))
    y = round(float(y))

    cr.save()
    cr.set_dash([], 0)
    cr.set_line_width(0)

    base_col = RGBColor(color=color)
    hi_col = _get_paint_chip_highlight(base_col)

    xoffs = gui.style.DROP_SHADOW_X_OFFSET
    yoffs = gui.style.DROP_SHADOW_Y_OFFSET
    blur = gui.style.DROP_SHADOW_BLUR
    alpha = gui.style.DROP_SHADOW_ALPHA
    drop_shadow = cairo.RadialGradient(
        x+xoffs, y+yoffs, radius,
        x+xoffs, y+yoffs, radius + blur,
    )
    drop_shadow.add_color_stop_rgba(0, 0, 0, 0, alpha)
    drop_shadow.add_color_stop_rgba(1, 0, 0, 0, 0.0)
    cr.arc(x+xoffs, y+yoffs, radius + blur + 1, 0, 2*math.pi)
    cr.set_source(drop_shadow)
    cr.fill()

    cr.arc(x, y, radius, 0, 2*math.pi)
    cr.set_source_rgb(*base_col.get_rgb())
    cr.fill_preserve()
    cr.clip_preserve()

    cr.set_source_rgb(*hi_col.get_rgb())
    cr.set_line_width(2)
    cr.stroke()

    cr.restore()
コード例 #7
0
ファイル: palette.py プロジェクト: Data-link/mypaint
 def new_from_simple_dict(class_, simple):
     """Constructs and returns a palette from the simple dict form."""
     pal = class_()
     pal.set_name(simple.get("name", None))
     pal.set_columns(simple.get("columns", None))
     for entry in simple.get("entries", []):
         if entry is None:
             pal.append(None)
         else:
             s, name = entry
             col = RGBColor.new_from_hex_str(s)
             pal.append(col, name)
     return pal
コード例 #8
0
ファイル: palette.py プロジェクト: Data-link/mypaint
 def _copy_color_out(self, col):
     if col is self._EMPTY_SLOT_ITEM:
         return None
     result = RGBColor(color=col)
     result.__name = col.__name
     return result
コード例 #9
0
ファイル: palette.py プロジェクト: Data-link/mypaint
    def load(self, filehandle, silent=False):
        """Load contents from a file handle containing a GIMP palette.

        :param filehandle: File-like object (.readline, line iteration)
        :param bool silent: If true, don't emit any events.

        >>> pal = Palette()
        >>> with open("palettes/MyPaint_Default.gpl", "r") as fp:
        ...     pal.load(fp)
        >>> len(pal) > 1
        True

        If the file format is incorrect, a RuntimeError will be raised.

        """
        comment_line_re = re.compile(r'^#')
        field_line_re = re.compile(r'^(\w+)\s*:\s*(.*)$')
        color_line_re = re.compile(r'^(\d+)\s+(\d+)\s+(\d+)\s*(?:\b(.*))$')
        fp = filehandle
        self.clear(silent=True)   # method fires events itself
        line = fp.readline()
        if line.strip() != "GIMP Palette":
            raise RuntimeError("Not a valid GIMP Palette")
        header_done = False
        line_num = 0
        for line in fp:
            line = line.strip()
            line_num += 1
            if line == '':
                continue
            if comment_line_re.match(line):
                continue
            if not header_done:
                match = field_line_re.match(line)
                if match:
                    key, value = match.groups()
                    key = key.lower()
                    if key == 'name':
                        self._name = value.strip()
                    elif key == 'columns':
                        self._columns = int(value)
                    else:
                        logger.warning("Unknown 'key:value' pair %r", line)
                    continue
                else:
                    header_done = True
            match = color_line_re.match(line)
            if not match:
                logger.warning("Expected 'R G B [Name]', not %r", line)
                continue
            r, g, b, col_name = match.groups()
            col_name = col_name.strip()
            r = float(clamp(int(r), 0, 0xff))/0xff
            g = float(clamp(int(g), 0, 0xff))/0xff
            b = float(clamp(int(b), 0, 0xff))/0xff
            if r == g == b == 0 and col_name == self._EMPTY_SLOT_NAME:
                self.append(None)
            else:
                col = RGBColor(r, g, b)
                col.__name = col_name
                self._colors.append(col)
        if not silent:
            self.info_changed()
            self.sequence_changed()
            self.match_changed()
コード例 #10
0
ファイル: hcywheel.py プロジェクト: briend/mypaint
 def _unflatten_mask(flat_mask):
     mask = []
     for shape_flat in flat_mask:
         shape_colors = [RGBColor.new_from_hex_str(s) for s in shape_flat]
         mask.append(shape_colors)
     return mask
コード例 #11
0
ファイル: style.py プロジェクト: mypaint/mypaint
# Transient on-canvas information, intended to be read quickly.
# Used for fading textual info or vanishing positional markers.
# Need to be high-contrast, and clear. Black and white is good.

TRANSIENT_INFO_BG_RGBA = (0, 0, 0, 0.666)  #: Transient text bg / outline
TRANSIENT_INFO_RGBA = (1, 1, 1, 1)  #: Transient text / marker


# Editable on-screen items.
# Used for editable handles on things like the document frame,
# when it's being edited.
# It's a good idea to use this and a user-tuneable alpha if the item
# is to be shown on screen permanently, in modes other than the object's
# own edit mode.

EDITABLE_ITEM_COLOR = RGBColor.new_from_hex_str("#ECF0F1")


# Active/dragging state for editable items.

ACTIVE_ITEM_COLOR = RGBColor.new_from_hex_str("#F1C40F")


# Prelight color (for complex modes, when there needs to be a distinction)

PRELIT_ITEM_COLOR = tuple(
        ACTIVE_ITEM_COLOR.interpolate(EDITABLE_ITEM_COLOR, 3)
    )[1]

コード例 #12
0
ファイル: sliders.py プロジェクト: briend/mypaint
 def get_color_for_bar_amount(self, amt):
     col = RGBColor(color=self.get_managed_color())
     col.b = amt
     return col