|
1
|
|
|
"""Layout calculation code""" |
|
2
|
|
|
|
|
3
|
|
|
__author__ = "Stephan Sokolow (deitarion/SSokolow)" |
|
4
|
|
|
__license__ = "GNU GPL 2.0 or later" |
|
5
|
|
|
|
|
6
|
|
|
class GravityLayout(object): # pylint: disable=too-few-public-methods |
|
7
|
|
|
"""Helper for translating top-left relative dimensions to other corners. |
|
8
|
|
|
|
|
9
|
|
|
Used to generate L{commands.cycle_dimensions} presets. |
|
10
|
|
|
|
|
11
|
|
|
Expects to operate on decimal percentage values. (0 <= x <= 1) |
|
12
|
|
|
""" |
|
13
|
|
|
#: Possible window alignments relative to the monitor/desktop. |
|
14
|
|
|
#: @todo 1.0.0: Normalize these to X11 or CSS terminology for 1.0 |
|
15
|
|
|
#: (API-breaking change) |
|
16
|
|
|
GRAVITIES = { |
|
17
|
|
|
'top-left': (0.0, 0.0), |
|
18
|
|
|
'top': (0.5, 0.0), |
|
19
|
|
|
'top-right': (1.0, 0.0), |
|
20
|
|
|
'left': (0.0, 0.5), |
|
21
|
|
|
'middle': (0.5, 0.5), |
|
22
|
|
|
'right': (1.0, 0.5), |
|
23
|
|
|
'bottom-left': (0.0, 1.0), |
|
24
|
|
|
'bottom': (0.5, 1.0), |
|
25
|
|
|
'bottom-right': (1.0, 1.0), |
|
26
|
|
|
} |
|
27
|
|
|
|
|
28
|
|
|
def __init__(self, margin_x=0, margin_y=0): |
|
29
|
|
|
""" |
|
30
|
|
|
@param margin_x: Horizontal margin to apply when calculating window |
|
31
|
|
|
positions, as decimal percentage of screen width. |
|
32
|
|
|
@param margin_y: Vertical margin to apply when calculating window |
|
33
|
|
|
positions, as decimal percentage of screen height. |
|
34
|
|
|
""" |
|
35
|
|
|
self.margin_x = margin_x |
|
36
|
|
|
self.margin_y = margin_y |
|
37
|
|
|
|
|
38
|
|
|
# pylint: disable=too-many-arguments |
|
39
|
|
|
def __call__(self, w, h, gravity='top-left', x=None, y=None): |
|
|
|
|
|
|
40
|
|
|
"""Return an C{(x, y, w, h)} tuple relative to C{gravity}. |
|
41
|
|
|
|
|
42
|
|
|
This function takes and returns percentages, represented as decimals |
|
43
|
|
|
in the range 0 <= x <= 1, which can be multiplied by width and height |
|
44
|
|
|
values in actual units to produce actual window geometry. |
|
45
|
|
|
|
|
46
|
|
|
It can be used in two ways: |
|
47
|
|
|
|
|
48
|
|
|
1. If called B{without} C{x} and C{y} values, it will compute a |
|
49
|
|
|
geometry tuple which will align a window C{w} wide and C{h} tall |
|
50
|
|
|
according to C{geometry}. |
|
51
|
|
|
|
|
52
|
|
|
2. If called B{with} C{x} and C{y} values, it will translate a |
|
53
|
|
|
geometry tuple which is relative to the top-left corner so that it is |
|
54
|
|
|
instead relative to another corner. |
|
55
|
|
|
|
|
56
|
|
|
@param w: Desired width |
|
57
|
|
|
@param h: Desired height |
|
58
|
|
|
@param gravity: Desired window alignment from L{GRAVITIES} |
|
59
|
|
|
@param x: Desired horizontal position if not the same as C{gravity} |
|
60
|
|
|
@param y: Desired vertical position if not the same as C{gravity} |
|
61
|
|
|
|
|
62
|
|
|
@returns: C{(x, y, w, h)} |
|
63
|
|
|
|
|
64
|
|
|
@note: All parameters except C{gravity} are decimal values in the range |
|
65
|
|
|
C{0 <= x <= 1}. |
|
66
|
|
|
""" |
|
67
|
|
|
|
|
68
|
|
|
x = x or self.GRAVITIES[gravity][0] |
|
69
|
|
|
y = y or self.GRAVITIES[gravity][1] |
|
70
|
|
|
offset_x = w * self.GRAVITIES[gravity][0] |
|
71
|
|
|
offset_y = h * self.GRAVITIES[gravity][1] |
|
72
|
|
|
|
|
73
|
|
|
return (round(x - offset_x + self.margin_x, 3), |
|
74
|
|
|
round(y - offset_y + self.margin_y, 3), |
|
75
|
|
|
round(w - (self.margin_x * 2), 3), |
|
76
|
|
|
round(h - (self.margin_y * 2), 3)) |
|
77
|
|
|
|
|
78
|
|
|
def make_winsplit_positions(columns): |
|
79
|
|
|
"""Generate the classic WinSplit Revolution tiling presets |
|
80
|
|
|
|
|
81
|
|
|
@todo: Figure out how best to put this in the config file. |
|
82
|
|
|
""" |
|
83
|
|
|
|
|
84
|
|
|
# TODO: Plumb GravityLayout.__init__'s arguments into the config file |
|
85
|
|
|
gvlay = GravityLayout() |
|
86
|
|
|
col_width = 1.0 / columns |
|
87
|
|
|
cycle_steps = tuple(round(col_width * x, 3) |
|
88
|
|
|
for x in range(1, columns)) |
|
89
|
|
|
|
|
90
|
|
|
middle_steps = (1.0,) + cycle_steps |
|
91
|
|
|
edge_steps = (0.5,) + cycle_steps |
|
92
|
|
|
|
|
93
|
|
|
positions = { |
|
94
|
|
|
'middle': [gvlay(width, 1, 'middle') for width in middle_steps], |
|
95
|
|
|
} |
|
96
|
|
|
|
|
97
|
|
|
for grav in ('top', 'bottom'): |
|
98
|
|
|
positions[grav] = [gvlay(width, 0.5, grav) for width in middle_steps] |
|
99
|
|
|
for grav in ('left', 'right'): |
|
100
|
|
|
positions[grav] = [gvlay(width, 1, grav) for width in edge_steps] |
|
101
|
|
|
for grav in ('top-left', 'top-right', 'bottom-left', 'bottom-right'): |
|
102
|
|
|
positions[grav] = [gvlay(width, 0.5, grav) for width in edge_steps] |
|
103
|
|
|
|
|
104
|
|
|
return positions |
|
105
|
|
|
|
This check looks for invalid names for a range of different identifiers.
You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.
If your project includes a Pylint configuration file, the settings contained in that file take precedence.
To find out more about Pylint, please refer to their site.