lkcl / pyjamas-desktop

Google's Webkit, ported to Python, ported to Desktops.

This URL has Read+Write access

pyjamas-desktop / pyjamas-webkit / pyjamas / splitpanel.py
100644 266 lines (219 sloc) 8.919 kb
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
"""
/*
* Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License") you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http:#www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
"""
from ui import Panel, Event
 
import DOM
 
class SplitPanel(Panel):
    """ Abstract base class for {@link HorizontalSplitPanel} and
{@link VerticalSplitPanel}.
"""
 
    def __init__(self, mainElem, splitElem, headElem, tailElem):
        """ Initializes the split panel.
@param mainElem the root element for the split panel
@param splitElem the element that acts as the splitter
@param headElem the element to contain the top or left most widget
@param tailElem the element to contain the bottom or right most widget
"""
 
        Panel.__init__(self)
 
        self.widgets = [None, None]
        self.elements = [headElem, tailElem]
        self.isResizing = False
 
        self.setElement(mainElem)
        self.splitElem = splitElem
        self.sinkEvents(Event.MOUSEEVENTS)
 
    def addAbsolutePositoning(self, elem):
        """ Sets an elements positioning to absolute.
"""
        DOM.setStyleAttribute(elem, "position", "absolute")
 
    def addClipping(self, elem):
        """ Adds clipping to an element.
"""
        DOM.setStyleAttribute(elem, "overflow", "hidden")
 
    def addScrolling(self, elem):
        """ Adds as-needed scrolling to an element.
"""
        DOM.setStyleAttribute(elem, "overflow", "auto")
 
    def expandToFitParentUsingCssOffsets(self, elem):
        """ Sizes and element to consume the full area of its parent
using the CSS properties left, right, top, and
bottom. This method is used for all browsers except IE6/7.
"""
        zeroSize = "0px"
 
        self.addAbsolutePositoning(elem)
        self.setLeft(elem, zeroSize)
        self.setRight(elem, zeroSize)
        self.setTop(elem, zeroSize)
        self.setBottom(elem, zeroSize)
 
    def expandToFitParentUsingPercentages(self, elem):
        """ Sizes an element to consume the full areas of its parent
using 100% width and height. This method is used on IE6/7
where CSS offsets don't work reliably.
"""
        zeroSize = "0px"
        fullSize = "100%"
 
        self.addAbsolutePositoning(elem)
        self.setTop(elem, zeroSize)
        self.setLeft(elem, zeroSize)
        self.setElemWidth(elem, fullSize)
        self.setElemHeight(elem, fullSize)
 
    def getOffsetHeight(self, elem):
        """ Returns the offsetHeight element property.
"""
        return DOM.getIntAttribute(elem, "offsetHeight")
 
    def getOffsetWidth(self, elem):
        """ Returns the offsetWidth element property.
"""
        return DOM.getIntAttribute(elem, "offsetWidth")
 
    def preventBoxStyles(self, elem):
        """ Adds zero or none CSS values for padding, margin and
border to prevent stylesheet overrides. Returns the
element for convenience to support builder pattern.
"""
        DOM.setIntStyleAttribute(elem, "padding", 0)
        DOM.setIntStyleAttribute(elem, "margin", 0)
        DOM.setStyleAttribute(elem, "border", "none")
        return elem
 
    def setBottom(self, elem, size):
        """ Convenience method to set bottom offset of an element.
"""
        DOM.setStyleAttribute(elem, "bottom", size)
 
    def setElemHeight(self, elem, height):
        """ Convenience method to set the height of an element.
"""
        DOM.setStyleAttribute(elem, "height", height)
 
    def setLeft(self, elem, left):
        """ Convenience method to set the left offset of an element.
"""
        DOM.setStyleAttribute(elem, "left", left)
 
    def setRight(self, elem, right):
        """ Convenience method to set the right offset of an element.
"""
        DOM.setStyleAttribute(elem, "right", right)
 
    def setTop(self, elem, top):
        """ Convenience method to set the top offset of an element.
"""
        DOM.setStyleAttribute(elem, "top", top)
 
    def setElemWidth(self, elem, width):
        """ Convenience method to set the width of an element.
"""
        DOM.setStyleAttribute(elem, "width", width)
 
    def add(self, w):
        if self.getWidget(0) == None:
            self.setWidget(0, w)
        elif self.getWidget(1) == None:
            self.setWidget(1, w)
        else:
            raise IllegalStateException("A Splitter can only contain two Widgets.")
 
    def isResizing(self):
        """ Indicates whether the split panel is being resized.
 
@return <code>True</code> if the user is dragging the splitter,
<code>False</code> otherwise
"""
        return self.isResizing
 
    def __iter__(self):
        return self.widgets.__iter__()
 
    def onBrowserEvent(self, event):
        typ = DOM.eventGetType(event)
 
        if typ == "mousedown":
            target = DOM.eventGetTarget(event)
            if DOM.isOrHasChild(self.splitElem, target):
                self.startResizingFrom(DOM.eventGetClientX(event) -
                                       self.getAbsoluteLeft(),
                          DOM.eventGetClientY(event) - self.getAbsoluteTop())
                DOM.setCapture(self.getElement())
                DOM.eventPreventDefault(event)
 
        elif typ == "mouseup":
            DOM.releaseCapture(self.getElement())
            self.stopResizing()
 
        elif typ == 'mousemove':
            if self.isResizing:
                #assert DOM.getCaptureElement() != None
                self.onSplitterResize(DOM.eventGetClientX(event) -
                                      self.getAbsoluteLeft(),
                          DOM.eventGetClientY(event) - self.getAbsoluteTop())
                DOM.eventPreventDefault(event)
 
    def remove(self, widget):
        if widgets[0] == widget:
            setWidget(0, None)
            return True
        elif widgets[1] == widget:
            setWidget(1, None)
            return True
        return False
 
    def setSplitPosition(self, size):
        """ Moves the position of the splitter.
@param size the new size of the left region in CSS units
(e.g. "10px", "1em")
"""
        pass
 
    def getWidgetElement(self, index):
        """ Gets the content element for the given index.
@param index the index of the element, only 0 and 1 are valid.
@return the element
"""
        return self.elements[index]
 
    def getSplitElement(self):
        """ Gets the element that is acting as the splitter.
@return the element
"""
        return self.splitElem
 
    def getWidget(self, index):
        """ Gets one of the contained widgets.
@param index the index of the widget, only 0 and 1 are valid.
@return the widget
"""
        return self.widgets[index]
 
    def setWidget(self, index, w):
        """ Sets one of the contained widgets.
@param index the index, only 0 and 1 are valid
@param w the widget
"""
        oldWidget = self.widgets[index]
 
        if oldWidget == w:
          return
 
        if (w != None):
          w.removeFromParent()
 
        # Remove the old child.
        if (oldWidget != None):
          # Orphan old.
          orphan(oldWidget)
          # Physical detach old.
          DOM.removeChild(self.elements[index], oldWidget.getElement())
 
        # Logical detach old / attach new.
        self.widgets[index] = w
 
        if (w != None):
            # Physical attach new.
            DOM.appendChild(self.elements[index], w.getElement())
 
            # Adopt new.
            self.adopt(w)
 
    def onSplitterResize(self, x, y):
        """ Called on each mouse drag event as the user is dragging
the splitter.
@param x the x coord of the mouse relative to the panel's extent
@param y the y coord of the mosue relative to the panel's extent
"""
        pass
 
    def onSplitterResizeStarted(self, x, y):
        """ Called when the user starts dragging the splitter.
@param x the x coord of the mouse relative to the panel's extent
@param y the y coord of the mouse relative to the panel's extent
"""
 
    def startResizingFrom(self, x, y):
        self.isResizing = True
        self.onSplitterResizeStarted(x, y)
 
    def stopResizing(self):
        self.isResizing = False