def __init__(self, text=None, area_type="window_item"): self.type = area_type self.text = text gtk.Alignment.__init__(self, 0, 0, 1, 1) self.popup_style = PopupStyle() lrp = int(self.popup_style.get("%s_lr_padding" % self.type, 5)) tdp = int(self.popup_style.get("%s_td_padding" % self.type, 5)) self.set_padding(lrp, lrp, tdp, tdp) self.set_app_paintable(1) self.globals = Globals() self.highlighted = False self.pressed_down = False self.active_window = False self.needs_attention = False self.minimized = False self.preview_allocation = [0, 0, 0, 0] if text: self.label = gtk.Label() self.add(self.label) self.label.show() color = self.globals.colors["color2"] self.set_label(text, color) else: self.label = None
def __init__(self, orient="down", no_arrow=False, type_="popup"): gtk.Window.__init__(self, gtk.WINDOW_POPUP) self.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DOCK) gtk_screen = gtk.gdk.screen_get_default() colormap = gtk_screen.get_rgba_colormap() if colormap is None: colormap = gtk_screen.get_rgb_colormap() self.set_colormap(colormap) self.set_app_paintable(1) self.globals = Globals() self.popup_style = PopupStyle() self.popup_type = type_ self._pointer_is_inside = False self.alignment = gtk.Alignment(0, 0, 0, 0) gtk.Window.add(self, self.alignment) self.alignment.show() self.pointer = "" self.no_arrow = no_arrow if orient in ("down", "up"): # The direction of the pointer isn't important here we only need # the right amount of padding so that the popup has right width and # height for placement calculations. self.point("down") else: self.point("left") self.popup_reloaded_sid = self.popup_style.connect( "popup-style-reloaded", self.__on_popup_style_reloaded)
def __init__(self): self.popup_style = PopupStyle() self.size = int(self.popup_style.get("close_button_size", 14)) CairoSmallButton.__init__(self, self.size) self.popup_reloaded_sid = self.popup_style.connect( "popup-style-reloaded", self.__on_popup_style_reloaded)
class CairoVBox(gtk.VBox): __gsignals__ = {"expose-event" : "override"} def __init__(self, label=None, show_menu=False): gtk.VBox.__init__(self) self.set_app_paintable(1) self.globals = Globals() self.popup_style = PopupStyle() def do_expose_event(self, event, arg=None): a = self.get_allocation() ctx = self.window.cairo_create() ctx.rectangle(event.area.x, event.area.y, event.area.width, event.area.height) ctx.clip() self.draw_frame(ctx, a.x, a.y, a.width, a.height) for child in self.get_children(): self.propagate_expose(child, event) def draw_frame(self, ctx, x, y, w, h): color = "#000000" r, g, b = parse_color(color) rd = int(self.popup_style.get("menu_item_roundness", 5)) make_path(ctx, x, y, w, h, rd) ctx.set_source_rgba(r, g, b, 0.20) ctx.fill_preserve() ctx.set_source_rgba(r, g, b, 0.20) ctx.set_line_width(1) ctx.stroke()
class CairoArea(gtk.Alignment): __gsignals__ = {"expose-event" : "override"} def __init__(self, text=None, area_type="window_item"): self.type = area_type self.text = text gtk.Alignment.__init__(self, 0, 0, 1, 1) self.popup_style = PopupStyle() lrp = int(self.popup_style.get("%s_lr_padding" % self.type, 5)) tdp = int(self.popup_style.get("%s_td_padding" % self.type, 5)) self.set_padding(lrp, lrp, tdp, tdp) self.set_app_paintable(1) self.globals = Globals() self.highlighted = False self.pressed_down = False self.active_window = False self.needs_attention = False self.minimized = False self.preview_allocation = [0, 0, 0, 0] if text: self.label = gtk.Label() self.add(self.label) self.label.show() color = self.globals.colors["color2"] self.set_label(text, color) else: self.label = None def set_label(self, text, color=None): self.text = text if color: text = "<span foreground=\"" + color + "\">" + escape(text) + \ "</span>" self.label.set_text(text) self.label.set_use_markup(True) self.label.set_use_underline(True) def set_padding(self, top, bottom, left, right): self.pressed_down = False gtk.Alignment.set_padding(self, top, bottom, left, right) def set_label_color(self, color): label = "<span foreground=\"" + color + "\">" + escape(self.text) + \ "</span>" self.label.set_text(label) self.label.set_use_markup(True) self.label.set_use_underline(True) def do_expose_event(self, event, arg=None): a = self.get_allocation() mx , my = self.get_pointer() preview = self.globals.settings["preview"] and \ self.globals.get_compiz_version() >= "0.9" and \ (self.globals.settings["preview_minimized"] or \ not self.minimized) highlighted = self.highlighted or \ (mx >= 0 and mx < a.width and my >= 0 and my < a.height) if preview or self.active_window or \ highlighted or self.needs_attention: ctx = self.window.cairo_create() ctx.rectangle(event.area.x, event.area.y, event.area.width, event.area.height) ctx.clip() if self.needs_attention: self.draw_type_frame(ctx, a.x, a.y, a.width, a.height, "needs_attention_item") if self.active_window: self.draw_type_frame(ctx, a.x, a.y, a.width, a.height, "active_item") if highlighted: self.draw_frame(ctx, a.x, a.y, a.width, a.height) # Empty preview space if preview: ctx.rectangle(*self.preview_allocation) ctx.set_source_rgba(1, 1, 1, 0) ctx.set_operator(cairo.OPERATOR_SOURCE) ctx.fill() self.propagate_expose(self.get_child(), event) return def draw_frame(self, ctx, x, y, w, h): if self.is_composited(): r, g, b = parse_color(self.globals.colors["color1"]) alpha = parse_alpha(self.globals.colors["color1_alpha"]) else: r = g = b = 0.0 alpha = 0.25 roundness = int(self.popup_style.get("%s_roundness" % \ self.type, 5)) make_path(ctx, x, y, w, h, roundness) ctx.set_source_rgba(r, g, b, alpha) ctx.fill_preserve() bc = self.popup_style.get("%s_border_color" % self.type, "#FFFFFF") if not bc[0] == "#": bc = "#%s" % bc alpha = self.popup_style.get("%s_border_alpha" % self.type, 80) alpha = float(alpha) / 100 r, g, b = parse_color(bc) ctx.set_source_rgba(r, g, b, alpha) ctx.set_line_width(1) ctx.stroke() def draw_type_frame(self, ctx, x, y, w, h, type_): # Todo: make colors themable? if type_ == "active_item": color = self.globals.colors["color3"] elif type_ == "needs_attention_item": color = self.popup_style.get("%s_color" % type_, "#FF0000") roundness = int(self.popup_style.get("%s_roundness" % \ self.type, 5)) make_path(ctx, x, y, w, h, roundness) if color[0] != "#": color = "#%s" % color r, g, b = parse_color(color) # Todo: make alpha adjustable from theme. alpha = self.popup_style.get("%s_alpha" % type_, 15) alpha = float(alpha) / 100 ctx.set_source_rgba(r, g, b, 0.25) ctx.fill_preserve() bc = self.popup_style.get("%s_border_color" % type_, "#FFFFFF") if not bc[0] == "#": bc = "#%s" % bc # Todo: make alpha adjustable from theme. r, g, b = parse_color(bc) alpha = self.popup_style.get("%s_border_alpha" % type_, 15) alpha = float(alpha) / 100 ctx.set_source_rgba(r, g, b, alpha) ctx.set_line_width(1) ctx.stroke() def set_pressed_down(self, pressed): p = self.get_padding() if pressed and not self.pressed_down: gtk.Alignment.set_padding(self, p[0] + 1, p[1] - 1, p[2], p[3]) elif self.pressed_down and not pressed: gtk.Alignment.set_padding(self, p[0] - 1, p[1] + 1, p[2], p[3]) self.pressed_down = pressed def set_highlighted(self, highlighted): self.highlighted = highlighted self.queue_draw() def set_active_window(self, active): self.active_window = active self.queue_draw() def set_needs_attention(self, needs_attention): self.needs_attention = needs_attention self.queue_draw() def set_minimized(self, minimized): self.minimized = minimized self.queue_draw() def set_preview_allocation(self, allocation): self.preview_allocation = allocation def pointer_is_inside(self): mx,my = self.get_pointer() a = self.get_allocation() if mx >= 0 and mx < a.width \ and my >= 0 and my < a.height: # Mouse pointer is inside the "rectangle" # but check if it's still outside the rounded corners x = None y = None r = int(self.popup_style.get("%s_roundness" % self.type, 5)) if mx < r: x = r - mx if (a.width - mx) < r: x = mx - (a.width - r) if my < r: y = r - my if (a.height - my) < r: y = my - (a.height - r) if x is None or y is None \ or (x**2 + y**2) < (r-1)**2: return True else: return False
class CairoPopup(gtk.Window): """CairoPopup is a transparent popup window with rounded corners""" __gsignals__ = {"expose-event": "override", "enter-notify-event": "override", "leave-notify-event": "override"} def __init__(self, orient="down", no_arrow=False, type_="popup"): gtk.Window.__init__(self, gtk.WINDOW_POPUP) self.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DOCK) gtk_screen = gtk.gdk.screen_get_default() colormap = gtk_screen.get_rgba_colormap() if colormap is None: colormap = gtk_screen.get_rgb_colormap() self.set_colormap(colormap) self.set_app_paintable(1) self.globals = Globals() self.popup_style = PopupStyle() self.popup_type = type_ self._pointer_is_inside = False self.alignment = gtk.Alignment(0, 0, 0, 0) gtk.Window.add(self, self.alignment) self.alignment.show() self.pointer = "" self.no_arrow = no_arrow if orient in ("down", "up"): # The direction of the pointer isn't important here we only need # the right amount of padding so that the popup has right width and # height for placement calculations. self.point("down") else: self.point("left") self.popup_reloaded_sid = self.popup_style.connect( "popup-style-reloaded", self.__on_popup_style_reloaded) def destroy(self): self.popup_style.disconnect(self.popup_reloaded_sid) self.popup_style = None gtk.Window.destroy(self) def __get_arrow_size(self): if self.no_arrow: return 0 else: return int(self.popup_style.get("arrow_size", 9)) def add(self, child): self.alignment.add(child) def remove(self, child): self.alignment.remove(child) def point(self, new_pointer, ap=0): self.ap = ap p = int(self.popup_style.get("%s_padding" % self.popup_type, 7)) a = self.__get_arrow_size() if new_pointer != self.pointer: self.pointer = new_pointer padding = {"up":(p+a, p, p, p), "down":(p, p+a, p, p), "left":(p, p, p+a, p), "right":(p, p, p, p+a)}[self.pointer] self.alignment.set_padding(*padding) def do_expose_event(self, event): self.set_shape_mask() w,h = self.get_size() self.ctx = self.window.cairo_create() # set a clip region for the expose event, XShape stuff self.ctx.save() if self.is_composited(): self.ctx.set_source_rgba(1, 1, 1,0) else: self.ctx.set_source_rgb(0.8, 0.8, 0.8) self.ctx.set_operator(cairo.OPERATOR_SOURCE) self.ctx.paint() self.ctx.restore() self.ctx.rectangle(event.area.x, event.area.y, event.area.width, event.area.height) self.ctx.clip() self.draw_frame(self.ctx, w, h) gtk.Window.do_expose_event(self, event) def set_shape_mask(self): # Set window shape from alpha mask of background image w,h = self.get_size() if w==0: w = 800 if h==0: h = 600 pixmap = gtk.gdk.Pixmap (None, w, h, 1) ctx = pixmap.cairo_create() ctx.set_source_rgba(0, 0, 0,0) ctx.set_operator (cairo.OPERATOR_SOURCE) ctx.paint() r = int(self.popup_style.get("popup_roundness", 6)) if self.is_composited(): make_path(ctx, 0, 0, w, h, r, 0, self.__get_arrow_size(), self.pointer, self.ap) ctx.set_source_rgba(1, 1, 1, 1) ctx.fill() self.input_shape_combine_mask(pixmap, 0, 0) else: make_path(ctx, 0, 0, w, h, r, 1, self.__get_arrow_size(), self.pointer, self.ap) ctx.set_source_rgb(0, 0, 0) ctx.fill() self.shape_combine_mask(pixmap, 0, 0) del pixmap def draw_frame(self, ctx, w, h): color = self.globals.colors["color1"] red = float(int(color[1:3], 16))/255 green = float(int(color[3:5], 16))/255 blue = float(int(color[5:7], 16))/255 alpha= float(self.globals.colors["color1_alpha"]) / 255 r = int(self.popup_style.get("popup_roundness", 6)) make_path(ctx, 0, 0, w, h, r, 2.5, self.__get_arrow_size(), self.pointer, self.ap) if self.is_composited(): ctx.set_source_rgba(red, green, blue, alpha) else: ctx.set_source_rgb(red, green, blue) ctx.fill_preserve() # Linear gradients for n in (1, 2, 3): name = "popup_linear_gradient%s" % n if not int(self.popup_style.get("use_%s" % name, 0)): continue angle = int(self.popup_style.get("%s_angle" % name, 0)) start = float(self.popup_style.get("%s_start" % name, 0)) stop = float(self.popup_style.get("%s_stop" % name, 100)) pattern = self.__make_linear_pattern(angle, start, stop, w, h) rpc1 = self.popup_style.get("%s_start_color" % name, "#FFFFFF") if not rpc1[0] == "#": rpc1 = "#%s" % rpc1 red, green, blue = parse_color(rpc1) alpha = self.popup_style.get("%s_start_alpha" % name, 20) alpha = float(alpha) / 100 pattern.add_color_stop_rgba(0.0, red, green, blue, alpha) rpc2 = self.popup_style.get("%s_stop_color" % name, "#FFFFFF") if not rpc2[0] == "#": rpc2 = "#%s" % rpc2 red, green, blue = parse_color(rpc2) alpha = self.popup_style.get("%s_stop_alpha" % name, 0) alpha = float(alpha) / 100 pattern.add_color_stop_rgba(1.0, red, green, blue, alpha) ctx.set_source(pattern) ctx.fill_preserve() # Radial gradients for n in (1, 2, 3): name = "popup_radial_gradient%s" % n if not int(self.popup_style.get("use_%s" % name, 0)): continue args = self.popup_style.get(name, "50,30,10,50,30,100") args = args.split(",") args = [int(arg) for arg in args] pattern = cairo.RadialGradient(*args) rpc1 = self.popup_style.get("%s_color1" % name, "#FFFFFF") if not rpc1[0] == "#": rpc1 = "#%s" % rpc1 red, green, blue = parse_color(rpc1) alpha = self.popup_style.get("%s_alpha1" % name, 20) alpha = float(alpha) / 100 pattern.add_color_stop_rgba(0.0, red, green, blue, alpha) rpc2 = self.popup_style.get("%s_color2" % name, "#FFFFFF") if not rpc2[0] == "#": rpc2 = "#%s" % rpc2 red, green, blue = parse_color(rpc2) alpha = self.popup_style.get("%s_alpha2" % name, 0) alpha = float(alpha) / 100 pattern.add_color_stop_rgba(1.0, red, green, blue, alpha) ctx.set_source(pattern) ctx.fill_preserve() # Background picture if self.popup_style.bg is not None: pattern = cairo.SurfacePattern(self.popup_style.bg) pattern.set_extend(cairo.EXTEND_REPEAT) ctx.set_source(pattern) ctx.fill_preserve() if self.is_composited(): ctx.set_source_rgba(0.0, 0.0, 0.0, 0.8) else: ctx.set_source_rgb(0, 0, 0) bw = float(self.popup_style.get("border_width", 3)) if "border_color2" in self.popup_style.settings: bc = self.popup_style.settings["border_color2"] else: bc = self.popup_style.get("border_color", "#FFFFFF") if bc[0] != "#": bc = "#%s" % bc alpha = self.popup_style.get("border_alpha", 80) alpha = float(alpha) / 100 red = float(int(bc[1:3], 16))/255 green = float(int(bc[3:5], 16))/255 blue = float(int(bc[5:7], 16))/255 if self.is_composited(): ctx.set_source_rgba(red, green, blue, alpha) else: ctx.set_source_rgb(red, green, blue) ctx.set_line_width(bw) if not ("border_color2" in self.popup_style.settings): ctx.stroke() return else: ctx.stroke_preserve() bc = self.popup_style.get("border_color", "#FFFFFF") if bc[0] != "#": bc = "#%s" % bc red = float(int(bc[1:3], 16))/255 green = float(int(bc[3:5], 16))/255 blue = float(int(bc[5:7], 16))/255 alpha = self.popup_style.get("border_alpha2", 100) alpha = float(alpha) / 100 if self.is_composited(): ctx.set_source_rgba(red, green, blue, alpha) else: ctx.set_source_rgb(red, green, blue) ctx.set_line_width(max(bw - 1, 0.5)) ctx.stroke() def __make_linear_pattern(self, angle, start, stop, w, h): start_x = None angle = angle % 360 if angle < 0: angle += 360 if angle == 0: start_x = start * w / 100.0 start_y = 0 stop_x = stop * w / 100.0 stop_y = 0 if angle == 180: start_x = w - (start * w / 100.0) start_y = 0 stop_x = w - (stop * w / 100.0) stop_y = 0 elif angle == 270: start_x = 0 start_y = start * h / 100.0 stop_x = 0 stop_y = stop * h / 100.0 elif angle == 90: start_x = 0 start_y = h - (start * h / 100.0) stop_x = 0 stop_y = h - (stop * h / 100.0) elif angle < 90: x1 = w * start / 100.0 y1 = h - h * start / 100.0 x2 = w * stop / 100.0 y2 = h - h * stop / 100.0 elif 90 < angle and angle < 180: x1 = w - (w * start / 100.0) y1 = h - h * start / 100.0 x2 = w - (w * stop / 100.0) y2 = h - h * stop / 100.0 elif 180 < angle and angle < 270: x1 = w - (w * start / 100.0) y1 = h * start / 100.0 x2 = w - (w * stop / 100.0) y2 = h * stop / 100.0 elif 270 < angle: x1 = w * start / 100.0 y1 = h * start / 100.0 x2 = w * stop / 100.0 y2 = h * stop / 100.0 if start_x is None: k1 = -tan(angle * pi / 180.0 ) k2 = -1 / k1 start_x = x1 start_y = y1 stop_x = (k1 * x1 - k2 * x2 + y2 - y1) / (k1 - k2) stop_y = k1 * (stop_x - x1) + y1 return cairo.LinearGradient(start_x, start_y, stop_x, stop_y) def __on_popup_style_reloaded(self, *args): a = self.__get_arrow_size() p = int(self.popup_style.get("%s_padding" % self.popup_type, 7)) padding = {"up":(p+a, p, p, p), "down":(p, p+a, p, p), "left":(p, p, p+a, p), "right":(p, p, p, p+a)}[self.pointer] self.alignment.set_padding(*padding) if self.popup_type == "locked_list": self.resize(10, 10) def pointer_is_inside(self): ax, ay, width, height = self.alignment.get_allocation() top, bottom, left, right = self.alignment.get_padding() x, y = self.get_pointer() if x >= left and x < width - right and \ y >= top and y <= height - bottom: return True else: return self._pointer_is_inside def do_enter_notify_event(self, *args): self._pointer_is_inside = True gtk.Window.do_enter_notify_event(self, *args) def do_leave_notify_event(self, *args): self._pointer_is_inside = False gtk.Window.do_leave_notify_event(self, *args)
class CairoCloseButton(CairoSmallButton): def __init__(self): self.popup_style = PopupStyle() self.size = int(self.popup_style.get("close_button_size", 14)) CairoSmallButton.__init__(self, self.size) self.popup_reloaded_sid = self.popup_style.connect( "popup-style-reloaded", self.__on_popup_style_reloaded) def draw_button(self, ctx, x, y, w, h): button_source = None if self.mousedown and self.mouseover: if self.popup_style.cb_pressed_pic: button_source = self.popup_style.cb_pressed_pic else: bgc = self.popup_style.get("close_button_pressed_bg_color", "#FF0000") bga = self.popup_style.get("close_button_pressed_bg_alpha", 100) xc = self.popup_style.get("close_button_pressed_x_color", "#FFFFFF") xa = self.popup_style.get("close_button_pressed_x_alpha", 100) elif self.mouseover: if self.popup_style.cb_hover_pic: button_source = self.popup_style.cb_hover_pic else: bgc = self.popup_style.get("close_button_hover_bg_color", "#FF0000") bga = self.popup_style.get("close_button_hover_bg_alpha", 100) xc = self.popup_style.get("close_button_hover_x_color", "#FFFFFF") xa = self.popup_style.get("close_button_hover_x_alpha", 0) else: if self.popup_style.cb_normal_pic: button_source = self.popup_style.cb_normal_pic else: bgc = self.popup_style.get("close_button_bg_color", "#FF0000") bga = self.popup_style.get("close_button_bg_alpha", 50) xc = self.popup_style.get("close_button_x_color", "#FFFFF") xa = self.popup_style.get("close_button_x_alpha", 0) if button_source is None: button_source = self.__make_button_surface(w, h, bgc, bga, xc, xa) ctx.set_source_surface(button_source, x, y) ctx.paint() def __make_button_surface(self, w, h, bgc, bga, xc, xa): button_source = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) bctx = cairo.Context(button_source) r = int(self.popup_style.get("close_button_roundness", 5)) make_path(bctx, 0, 0, w, h, r) red, green, blue = parse_color(bgc) alpha = min(max(float(bga) / 100, 0), 1) bctx.set_source_rgba(red, green, blue, alpha) bctx.fill() bctx.scale(w, h) bctx.move_to(0.3, 0.3) bctx.line_to(0.7, 0.7) bctx.move_to(0.3, 0.7) bctx.line_to(0.7, 0.3) bctx.set_line_width(2.0/w) red, green, blue = parse_color(xc) alpha = min(max(float(xa) / 100, 0), 1) bctx.set_source_rgba(red, green, blue, alpha) bctx.set_operator(cairo.OPERATOR_SOURCE) bctx.stroke() return button_source def __on_popup_style_reloaded(self, *args): size = int(self.popup_style.get("close_button_size", 14)) if size != self.size: self.set_size_request(size, size) self.size = size self.queue_draw()
def __init__(self, label=None, show_menu=False): gtk.VBox.__init__(self) self.set_app_paintable(1) self.globals = Globals() self.popup_style = PopupStyle()