]> icculus.org git repositories - mikachu/openbox.git/blob - scripts/motion.py
dont snap back onto the screen for resistance
[mikachu/openbox.git] / scripts / motion.py
1 ############################################################################
2 ###    Functions that provide callbacks for motion events to move and    ###
3 ###    resize windows.                                                   ###
4 ############################################################################
5
6 #############################################################################
7 ### Options that can be modified to change the functions' behaviors.      ###
8 ###                                                                       ###
9 # edge_resistance - the amount of resistance to provide to moving a       ###
10 ###                 window past a screen boundary. Specify a value of 0   ###
11 ###                 to disable edge resistance.                           ###
12 edge_resistance = 10                                                      ###
13 ###                                                                       ###
14 # move_popup - display a coordinates popup when moving windows.           ###
15 move_popup = 1                                                            ###
16 ###                                                                       ###
17 # NOT IMPLEMENTED (yet?)                                                  ###
18 # move_rubberband - display an outline while moving instead of moving the ###
19 ###                 actual window, until the move is completed. Good for  ###
20 ###                 slower systems.                                       ###
21 move_rubberband = 0                                                       ###
22 ###                                                                       ###
23 # resize_popup - display a size popup when resizing windows.              ###
24 resize_popup = 1                                                          ###
25 ###                                                                       ###
26 # NOT IMPLEMENTED (yet?)                                                  ###
27 # resize_rubberband - display an outline while resizing instead of        ###
28 ###                   resizing the actual window, until the resize is     ###
29 ###                   completed. Good for slower systems.                 ###
30 resize_rubberband = 0                                                     ###
31 ###                                                                       ###
32 # resize_nearest - 1 to resize from the corner nearest where the mouse    ###
33 ###                is, 0 to resize always from the bottom right corner.   ###
34 resize_nearest = 1                                                        ###
35 ###                                                                       ###
36 ###                                                                       ###
37 # Provides:                                                               ###
38 # def move(data):                                                         ###
39 #     """Moves the window interactively. This should only be used with    ###
40 #        MouseMotion events. If move_popup or move_rubberband is enabled, ###
41 #        then the end_move function needs to be bound as well."""         ###
42 # def end_move(data):                                                     ###
43 #     """Complete the interactive move of a window."""                    ###
44 # def resize(data):                                                       ###
45 #     """Resizes the window interactively. This should only be used with  ###
46 #        MouseMotion events"""                                            ###
47 # def end_resize(data):                                                   ###
48 #     """Complete the interactive resize of a window."""                  ###
49 ###                                                                       ###
50 #############################################################################
51
52 import ob
53 import otk
54
55 _popwidget = 0
56 _poplabel = 0
57
58 # motion state
59 _inmove = 0
60 _inresize = 0
61
62 # last motion data
63 _cx = 0
64 _cy = 0
65 _cw = 0
66 _ch = 0
67 _px = 0
68 _py = 0
69 _dx = 0
70 _dy = 0
71 _client = 0
72 _screen = 0
73
74 _motion_mask = 0
75
76 def _motion_grab(data):
77     global _motion_mask, _inmove, _inresize;
78
79     if data.action == ob.KeyAction.Release:
80         # have all the modifiers this started with been released?
81         if not _motion_mask & data.state:
82             if _inmove:
83                 end_move(data)
84             elif _inresize:
85                 end_resize(data)
86             else:
87                 raise RuntimeError
88
89 _last_x = 0
90 _last_y = 0
91
92 def _do_move():
93     global _screen, _client, _cx, _cy, _dx, _dy
94
95     x = _cx + _dx
96     y = _cy + _dy
97
98     global edge_resistance, _last_x, _last_y
99     if edge_resistance:
100         fs = _client.frame.size()
101         w = _client.area().width() + fs.left + fs.right
102         h = _client.area().height() + fs.top + fs.bottom
103         # use the area based on the struts
104         area = ob.openbox.screen(_screen).area()
105         l = area.left()
106         r = area.right() - w + 1
107         t = area.top()
108         b = area.bottom() - h + 1
109         # left screen edge
110         if _last_x > x and x < l and x >= l - edge_resistance:
111             x = l
112         # right screen edge
113         if _last_x < x and x > r and x <= r + edge_resistance:
114             x = r
115         # top screen edge
116         if _last_y > y and y < t and y >= t - edge_resistance:
117             y = t
118         # right screen edge
119         if _last_y < y and y > b and y <= b + edge_resistance:
120             y = b
121
122     _last_x = x
123     _last_y = y
124
125     global move_rubberband
126     if move_rubberband:
127         # draw the outline ...
128         f=0
129     else:
130         _client.move(x, y)
131
132     global move_popup
133     if move_popup:
134         global _popwidget, _poplabel
135         style = ob.openbox.screen(_screen).style()
136         font = style.labelFont()
137         text = "X: " + str(x) + " Y: " + str(y)
138         length = font.measureString(text)
139         if not _popwidget:
140             _popwidget = otk.Widget(ob.openbox, style,
141                                     otk.Widget.Horizontal, 0,
142                                     style.bevelWidth(), 1)
143             _popwidget.setTexture(style.titlebarFocusBackground())
144             _poplabel = otk.Label(_popwidget)
145             _poplabel.setTexture(style.labelFocusBackground())
146         _poplabel.fitString(text)
147         _poplabel.setText(text)
148         _popwidget.update() 
149         area = otk.display.screenInfo(_screen).rect()
150         _popwidget.move(area.x() + (area.width() -
151                                     _popwidget.width()) / 2,
152                         area.y() + (area.height() -
153                                     _popwidget.height()) / 2)
154         _popwidget.show(1)
155
156 def move(data):
157     """Moves the window interactively. This should only be used with
158        MouseMotion events. If move_popup or move_rubberband is enabled, then
159        the end_move function needs to be bound as well."""
160     if not data.client: return
161
162     # not-normal windows dont get moved
163     if not data.client.normal(): return
164
165     global _screen, _client, _cx, _cy, _dx, _dy
166     _screen = data.screen
167     _client = data.client
168     _cx = data.press_clientx
169     _cy = data.press_clienty
170     _dx = data.xroot - data.pressx
171     _dy = data.yroot - data.pressy
172     _do_move()
173     global _inmove
174     if not _inmove:
175         ob.kgrab(_screen, _motion_grab)
176         _inmove = 1
177
178 def end_move(data):
179     """Complete the interactive move of a window."""
180     global move_rubberband, _inmove
181     global _popwidget, _poplabel
182     if _inmove:
183         r = move_rubberband
184         move_rubberband = 0
185         _do_move()
186         move_rubberband = r
187         _inmove = 0
188     _poplabel = 0
189     _popwidget = 0
190     ob.kungrab()
191
192 def _do_resize():
193     global _screen, _client, _cx, _cy, _cw, _ch, _px, _py, _dx, _dy
194
195     dx = _dx
196     dy = _dy
197     
198     # pick a corner to anchor
199     if not (resize_nearest or _context == ob.MouseContext.Grip):
200         corner = ob.Client.TopLeft
201     else:
202         x = _px - _cx
203         y = _py - _cy
204         if y < _ch / 2:
205             if x < _cw / 2:
206                 corner = ob.Client.BottomRight
207                 dx *= -1
208             else:
209                 corner = ob.Client.BottomLeft
210             dy *= -1
211         else:
212             if x < _cw / 2:
213                 corner = ob.Client.TopRight
214                 dx *= -1
215             else:
216                 corner = ob.Client.TopLeft
217
218     w = _cw + dx
219     h = _ch + dy
220
221     global resize_popup
222     if resize_rubberband:
223         # draw the outline ...
224         f=0
225     else:
226         _client.resize(corner, w, h)
227
228     global resize_popup
229     if resize_popup:
230         global _popwidget, _poplabel
231         style = ob.openbox.screen(_screen).style()
232         ls = _client.logicalSize()
233         text = "W: " + str(ls.x()) + " H: " + str(ls.y())
234         if not _popwidget:
235             _popwidget = otk.Widget(ob.openbox, style,
236                                     otk.Widget.Horizontal, 0,
237                                     style.bevelWidth(), 1)
238             _popwidget.setTexture(style.titlebarFocusBackground())
239             _poplabel = otk.Label(_popwidget)
240             _poplabel.setTexture(style.labelFocusBackground())
241         _poplabel.fitString(text)
242         _poplabel.setText(text)
243         area = otk.display.screenInfo(_screen).rect()
244         _popwidget.update() 
245         _popwidget.move(area.x() + (area.width() -
246                                     _popwidget.width()) / 2,
247                         area.y() + (area.height() -
248                                     _popwidget.height()) / 2)
249         _popwidget.show(1)
250
251 def resize(data):
252     """Resizes the window interactively. This should only be used with
253        MouseMotion events"""
254     if not data.client: return
255
256     # not-normal windows dont get resized
257     if not data.client.normal(): return
258
259     global _screen, _client, _cx, _cy, _cw, _ch, _px, _py, _dx, _dy
260     _screen = data.screen
261     _client = data.client
262     _cx = data.press_clientx
263     _cy = data.press_clienty
264     _cw = data.press_clientwidth
265     _ch = data.press_clientheight
266     _px = data.pressx
267     _py = data.pressy
268     _dx = data.xroot - _px
269     _dy = data.yroot - _py
270     _do_resize()
271     global _inresize
272     if not _inresize:
273         ob.kgrab(_screen, _motion_grab)
274         _inresize = 1
275
276 def end_resize(data):
277     """Complete the interactive resize of a window."""
278     global resize_rubberband, _inresize
279     global _popwidget, _poplabel
280     if _inresize:
281         r = resize_rubberband
282         resize_rubberband = 0
283         _do_resize()
284         resize_rubberband = r
285         _inresize = 0
286     _poplabel = 0
287     _popwidget = 0
288     ob.kungrab()