/usr/share/pyshared/quodlibet/qltk/x.py is in exfalso 3.0.2-3.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 | # Copyright 2005 Joe Wreschnig, Michael Urman
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation
# Things that are more or less direct wrappers around GTK widgets to
# ease constructors.
from gi.repository import Gtk, GObject, GLib, Gio
from quodlibet import util
from quodlibet import config
from quodlibet.qltk import is_accel
from quodlibet.qltk.window import Window, UniqueWindow
class ScrolledWindow(Gtk.ScrolledWindow):
"""Draws a border around all edges that don't touch the parent window"""
__gsignals__ = {'size-allocate': 'override'}
def do_size_allocate(self, alloc):
if self.get_shadow_type() == Gtk.ShadowType.NONE:
return Gtk.ScrolledWindow.do_size_allocate(self, alloc)
toplevel = self.get_toplevel()
top_window = toplevel.get_window()
window = self.get_window()
if not window:
GLib.idle_add(self.queue_resize)
return Gtk.ScrolledWindow.do_size_allocate(self, alloc)
dummy, x1, y1 = top_window.get_origin()
dummy, x2, y2 = window.get_origin()
dx = x2 - x1
dy = y2 - y1
ctx = self.get_style_context()
border = ctx.get_border(self.get_state_flags())
# https://bugzilla.gnome.org/show_bug.cgi?id=694844
border.left = border.top = border.right = border.bottom = 1
# Don't remove the border if the border is drawn inside
# and the scrollbar on that edge is visible
bottom = left = right = top = False
value = GObject.Value()
value.init(GObject.TYPE_BOOLEAN)
# default to True: https://bugzilla.gnome.org/show_bug.cgi?id=701058
value.set_boolean(True)
ctx.get_style_property("scrollbars-within-bevel", value)
scroll_within = value.get_boolean()
value.unset()
if not scroll_within:
h, v = self.get_hscrollbar(), self.get_vscrollbar()
hscroll = vscroll = False
if h.get_visible():
req = h.size_request()
hscroll = bool(req.width + req.height)
if v.get_visible():
req = v.size_request()
vscroll = bool(req.width + req.height)
placement = self.get_placement()
if placement == Gtk.CornerType.TOP_LEFT:
bottom = hscroll
right = vscroll
elif placement == Gtk.CornerType.BOTTOM_LEFT:
right = vscroll
top = hscroll
elif placement == Gtk.CornerType.TOP_RIGHT:
bottom = hscroll
left = vscroll
elif placement == Gtk.CornerType.BOTTOM_RIGHT:
left = vscroll
top = hscroll
width, height = toplevel.get_size()
if alloc.y + alloc.height + dy == height and not bottom:
alloc.height += border.bottom
if alloc.x + alloc.width + dx == width and not right:
alloc.width += border.right
if alloc.y + dy == 0 and not top:
alloc.y -= border.top
alloc.height += border.top
if alloc.x + dx == 0 and not left:
alloc.x -= border.left
alloc.width += border.left
return Gtk.ScrolledWindow.do_size_allocate(self, alloc)
class Notebook(Gtk.Notebook):
"""A regular gtk.Notebook, except when appending a page, if no
label is given, the page's 'title' attribute (either a string or
a widget) is used."""
__gsignals__ = {'size-allocate': 'override'}
def do_size_allocate(self, alloc):
ctx = self.get_style_context()
border = ctx.get_border(self.get_state_flags())
toplevel = self.get_toplevel()
top_window = toplevel.get_window()
window = self.get_window()
if not window:
GLib.idle_add(self.queue_resize)
return Gtk.Notebook.do_size_allocate(self, alloc)
dummy, x1, y1 = top_window.get_origin()
dummy, x2, y2 = window.get_origin()
dx = x2 - x1
dy = y2 - y1
width, height = toplevel.get_size()
if alloc.y + alloc.height + dy == height:
alloc.height += border.bottom
if alloc.x + alloc.width + dx == width:
alloc.width += border.right
if alloc.x + dx == 0:
alloc.x -= border.left
alloc.width += border.left
return Gtk.Notebook.do_size_allocate(self, alloc)
def append_page(self, page, label=None):
if label is None:
try:
label = page.title
except AttributeError:
raise TypeError("no page.title and no label given")
if not isinstance(label, Gtk.Widget):
label = Gtk.Label(label)
super(Notebook, self).append_page(page, label)
def Frame(label, child=None):
"""A Gtk.Frame with no shadow, 12px left padding, and 3px top padding."""
frame = Gtk.Frame()
label_w = Gtk.Label()
label_w.set_markup("<b>%s</b>" % util.escape(label))
align = Gtk.Alignment(xalign=0.0, yalign=0.0, xscale=1.0, yscale=1.0)
align.set_padding(6, 0, 12, 0)
frame.add(align)
frame.set_shadow_type(Gtk.ShadowType.NONE)
frame.set_label_widget(label_w)
if child:
align.add(child)
label_w.set_mnemonic_widget(child)
label_w.set_use_underline(True)
return frame
def Alignment(child=None, top=0, bottom=0, left=0, right=0, border=0):
align = Gtk.Alignment(xscale=1.0, yscale=1.0)
align.set_padding(top + border, bottom + border,
left + border, right + border)
if child:
align.add(child)
return align
def MenuItem(label, stock_id):
"""An ImageMenuItem with a custom label and stock image."""
item = Gtk.ImageMenuItem.new_with_mnemonic(label)
item.set_image(Gtk.Image(stock=stock_id, icon_size=Gtk.IconSize.MENU))
return item
def Button(label, stock_id, size=Gtk.IconSize.BUTTON):
"""A Button with a custom label and stock image. It should pack
exactly like a stock button."""
align = Gtk.Alignment(xscale=0.0, yscale=1.0, xalign=0.5, yalign=0.5)
hbox = Gtk.HBox(spacing=2)
hbox.pack_start(Gtk.Image.new_from_stock(stock_id, size), True, True, 0)
label = Gtk.Label(label)
label.set_use_underline(True)
hbox.pack_start(label, True, True, 0)
align.add(hbox)
button = Gtk.Button()
button.add(align)
return button
class RPaned(Gtk.Paned):
"""A Paned that supports relative (percentage) width/height setting."""
ORIENTATION = None
def __init__(self, *args, **kwargs):
if self.ORIENTATION is not None:
kwargs["orientation"] = self.ORIENTATION
super(RPaned, self).__init__(*args, **kwargs)
# before first alloc: save value in relative and set on the first alloc
# after the first alloc: use the normal properties
self.__alloced = False
self.__relative = None
def set_relative(self, v):
"""Set the relative position of the separator, [0..1]."""
if self.__alloced:
max_pos = self.get_property('max-position')
if not max_pos:
# no children
self.__relative = v
return
self.set_position(int(v * max_pos))
else:
self.__relative = v
def get_relative(self):
"""Return the relative position of the separator, [0..1]."""
if self.__alloced:
max_pos = self.get_property('max-position')
if not max_pos:
# no children
return self.__relative
return (float(self.get_position()) / max_pos)
elif self.__relative is not None:
return self.__relative
else:
# before first alloc and set_relative not called
return 0.5
def do_size_allocate(self, *args):
ret = Gtk.HPaned.do_size_allocate(self, *args)
if not self.__alloced and self.__relative is not None:
self.__alloced = True
self.set_relative(self.__relative)
# call again so the children get alloced
ret = Gtk.HPaned.do_size_allocate(self, *args)
self.__alloced = True
return ret
class RHPaned(RPaned):
ORIENTATION = Gtk.Orientation.HORIZONTAL
class RVPaned(RPaned):
ORIENTATION = Gtk.Orientation.VERTICAL
class ConfigRPaned(RPaned):
def __init__(self, section, option, default, *args, **kwargs):
super(ConfigRPaned, self).__init__(*args, **kwargs)
self.set_relative(config.getfloat(section, option, default))
self.connect('notify::position', self.__changed, section, option)
def __changed(self, widget, event, section, option):
if self.get_property('position-set'):
config.set(section, option, str(self.get_relative()))
class ConfigRHPaned(ConfigRPaned):
ORIENTATION = Gtk.Orientation.VERTICAL
class ConfigRVPaned(ConfigRPaned):
ORIENTATION = Gtk.Orientation.VERTICAL
def ClearButton(entry=None):
clear = Gtk.Button()
clear.add(Gtk.Image.new_from_stock(Gtk.STOCK_CLEAR, Gtk.IconSize.MENU))
clear.set_tooltip_text(_("Clear search"))
if entry is not None:
clear.connect_object('clicked', entry.set_text, '')
return clear
def EntryCompletion(words):
"""Simple string completion."""
model = Gtk.ListStore(str)
for word in sorted(words):
model.append(row=[word])
comp = Gtk.EntryCompletion()
comp.set_model(model)
comp.set_text_column(0)
return comp
def RadioMenuItem(*args, **kwargs):
"""RadioMenuItem that allows None for group"""
if kwargs.get("group", None) is None:
kwargs.pop("group", None)
return Gtk.RadioMenuItem(*args, **kwargs)
def SeparatorMenuItem(*args, **kwargs):
# https://bugzilla.gnome.org/show_bug.cgi?id=670575
# PyGObject 3.2 always sets a label in __init__
if not args and not kwargs:
return Gtk.SeparatorMenuItem.new()
return Gtk.SeparatorMenuItem(*args, **kwargs)
def SymbolicIconImage(name, size, fallbacks=None):
"""Gtk.Image that displays a symbolic version of 'name' and falls
back to the non-symbolic one.
"""
symbolic_name = name + "-symbolic"
gicon = Gio.ThemedIcon.new_from_names([symbolic_name, name])
return Gtk.Image.new_from_gicon(gicon, size)
|