# This file is part of MyPaint. # Copyright (C) 2009 by Martin Renold # # This program 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. import gtk gdk = gtk.gdk import random import numpy, cairo from lib import helpers import colorhistory as ch import windowing """ Worklist (planning/prototyping) - short keypress switches between two colors (==> still possible to do black/white the old way) - long keypress allows to move the mouse over another color - the mouseover color is selected when the key is released - (unsure) pressing the key twice (without painting in-between) cycles through the colors - the problem is that you don't see the colors ==> different concept: - short keypress opens the color ring with cursor centered on hole (ring stays open) - the ring disappears as soon as you touch it (you can just continue painting) - pressing the key again cycles the ring - recent colors should be saved with painting Observation: - it seems quite unnatural that you can have a /shorter/ popup duration by pressing the key /longer/ ==> you rather want a /minimum/ duration """ popup_height = 60 bigcolor_width = popup_height smallcolor_width = popup_height/2 popup_width = bigcolor_width + (ch.num_colors-1)*smallcolor_width class HistoryPopup(windowing.PopupWindow): outside_popup_timeout = 0 def __init__(self, app, doc): windowing.PopupWindow.__init__(self, app) # TODO: put the mouse position onto the selected color self.set_position(gtk.WIN_POS_MOUSE) self.app = app self.app.kbm.add_window(self) self.set_events(gdk.BUTTON_PRESS_MASK | gdk.BUTTON_RELEASE_MASK | gdk.ENTER_NOTIFY | gdk.LEAVE_NOTIFY ) self.connect("button-release-event", self.button_release_cb) self.connect("button-press-event", self.button_press_cb) self.connect("expose_event", self.expose_cb) self.set_size_request(popup_width, popup_height) self.selection = None self.doc = doc doc.stroke_observers.append(self.stroke_finished_cb) def enter(self): # finish pending stroke, if any (causes stroke_finished_cb to get called) self.doc.split_stroke() if self.selection is None: self.selection = ch.num_colors - 1 color = self.app.brush.get_color_hsv() if ch.hsv_equal(ch.colors[self.selection], color): self.selection -= 1 else: self.selection = (self.selection - 1) % ch.num_colors ch.atomic = True self.app.brush.set_color_hsv(ch.colors[self.selection]) ch.atomic = False # popup placement x, y = self.get_position() bigcolor_center_x = self.selection * smallcolor_width + bigcolor_width/2 self.move(x + popup_width/2 - bigcolor_center_x, y + bigcolor_width) self.show_all() self.window.set_cursor(gdk.Cursor(gdk.CROSSHAIR)) def leave(self, reason): self.hide() def button_press_cb(self, widget, event): pass def button_release_cb(self, widget, event): pass def stroke_finished_cb(self, stroke, brush): #print 'stroke finished', stroke.total_painting_time, 'seconds' self.selection = None if not brush.is_eraser(): color = brush.get_color_hsv() ch.push_color(color) 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(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