class HorizontalCollapsePanel(FlowPanel): def __init__(self, *args, **kwargs): # set defaults if not 'StyleName' in kwargs: kwargs['StyleName'] = "rjw-HorizontalCollapsePanel" FlowPanel.__init__(self, *args, **kwargs) self._containers = [ ScrollPanel(StyleName = self.getStylePrimaryName() + '-left'), ScrollPanel(StyleName = self.getStylePrimaryName() + '-right'), ] self._collapse_widget = ScrollPanel(StyleName = self.getStylePrimaryName() + '-collapse') collapse_button = ToggleButton(StyleName = self.getStylePrimaryName() + '-collapse-button') collapse_button.addClickListener(self._sync_collapse) self._collapse_widget.add(collapse_button) FlowPanel.add(self, self._containers[0]) FlowPanel.add(self, self._collapse_widget) FlowPanel.add(self, self._containers[1]) self._sync_collapse() def _sync_collapse(self, w=None): collapse_button = self._collapse_widget.getWidget(0) if collapse_button.isDown(): self.addStyleName(self.getStylePrimaryName() + '-collapsed') else: self.removeStyleName(self.getStylePrimaryName() + '-collapsed') def getWidget(self, index): if index >= 0 and index < len(self._containers): return self._containers[index].getWidget() console.error('HorizontalCollapsePanel.getWidget passed invalid index: ' + str(index)) raise IndexError('Index out of range') def setWidget(self, index, widget): if index >= 0 and index < len(self._containers): return self._containers[index].setWidget(widget) console.error('HorizontalCollapsePanel.setWidget passed invalid index: ' + str(index)) raise IndexError('Index out of range') # Adds a widget to a pane def add(self, widget): if self.getWidget(0) == None: self.setWidget(0, widget) elif self.getWidget(1) == None: self.setWidget(1, widget) else: console.error("HorizontalCollapsePanel can only contain two child widgets.") # Removes a child widget. def remove(self, widget): if self.getWidget(0) == widget: self._containers[0].remove(widget) elif self.getWidget(1) == widget: self._containers[1].remove(widget) else: AbsolutePanel.remove(self, widget)
class SplitPanel(AbsolutePanel, MouseHandler, EventGenerator): """ Provides the SplitPanel baseclass functionality A SplitPanel is an AbsolutePanel containing an HTMLTable with three cells. The first cell holds the first ScrollPanel, while the center cell holds a Splitter, and the last cell holds the other ScrollPanel. """ def __init__(self, vertical=False, **kwargs): # set defaults if not 'StyleName' in kwargs: if vertical: # vertical split panel kwargs['StyleName'] = "gwt-VerticalSplitPanel" else: kwargs['StyleName'] = "gwt-HorizontalSplitPanel" # splitter drag state vars self._drag_start = None self._pos = "50%" # orientation self._vertical = vertical # now init the bases AbsolutePanel.__init__(self, **kwargs) MouseHandler.__init__(self) # add our event support? self.addListenedEvent("Resize") # create the top/left widget container self._container1 = ScrollPanel() # create the bottom/right widget container self._container2 = ScrollPanel() # create the splitter self._splitter = SplitPanelSplitter(self) # add splitter handling self._splitter.addMouseListener(self) # add mouse event handling self.addMouseListener(self) # add the parts AbsolutePanel.add(self, self._container1, 0, 0) AbsolutePanel.add(self, self._splitter, 0, 0) AbsolutePanel.add(self, self._container2, 0, 0) # set the layout if vertical: # vertical split panel self._splitter.setStyleName("vsplitter") self._splitter.setWidth("100%") self._container1.setWidth("100%") self._container2.setWidth("100%") # set drag cursor DOM.setStyleAttribute(self._splitter.getElement(), "cursor", "n-resize") else: # horizontal split panel self._splitter.setStyleName("hsplitter") self._splitter.setHeight("100%") self._container1.setHeight("100%") self._container2.setHeight("100%") # set drag cursor DOM.setStyleAttribute(self._splitter.getElement(), "cursor", "e-resize") def onAttach(self): AbsolutePanel.onAttach(self) self.setSplitPosition() # fixup the container 2 size and position def _finalizePositions(self, pos=None): finalized = False if self._vertical: if pos is None: pos = self._container1.getOffsetHeight() space = self.getOffsetHeight() sz = self._splitter.getOffsetHeight() if space > 0 and sz > 0 and pos > 0: # limit pos if pos > space - sz: pos = space - sz self._container1.setHeight(pos) self.setWidgetPosition(self._splitter, 0, pos) self.setWidgetPosition(self._container2, 0, pos + sz) self._container2.setHeight(space - (pos + sz)) finalized = True else: if pos is None: pos = self._container1.getOffsetWidth() space = self.getOffsetWidth() sz = self._splitter.getOffsetWidth() if space > 0 and sz > 0 and pos > 0: # limit pos if pos > space - sz: pos = space - sz self._container1.setWidth(pos) self.setWidgetPosition(self._splitter, pos, 0) self.setWidgetPosition(self._container2, pos + sz, 0) self._container2.setWidth(space - (pos + sz)) finalized = True if finalized: self.dispatchResizeEvent(self, pos) return finalized # end a drag operation def _stopDragging(self): if self._drag_start is not None: # we are no longer dragging self._drag_start = None # deactivate the transparent overlay GlassWidget.hide() # don't let a mouse-up become a click event DOM.eventCancelBubble(DOM.eventGetCurrentEvent(), True) def _isDragging(self): return self._drag_start is not None # start a drag operation (called by splitter) def startSplitterDrag(self, x, y): if self._drag_start is None: # remember where on the slider we are dragging if self._vertical: self._drag_start = y else: self._drag_start = x # activate the transparent overlay to keep mouse events flowing to # the splitter (and to us) even if the mouse leaves the splitter GlassWidget.show(self) # add handlers for mouse events to support dragging the slider # NOTE: the x,y positioni s relative to the splitter def onMouseMove(self, sender, x, y): # if dragging, then use current mouse position # to reset splitter position if not self._isDragging(): return # remove the offset into the splitter # where we started dragging if self._vertical: self._pos = y - self._drag_start else: self._pos = x - self._drag_start # apply limit if self._pos < 1: self._pos = 1 # apply new position self.setSplitPosition() def onMouseUp(self, sender, x, y): ev = DOM.eventGetCurrentEvent() # ignore right-button ups if DOM.eventGetButton(ev) != Event.BUTTON_LEFT: return DOM.eventPreventDefault(ev) # if we are dragging if self._isDragging(): # stop dragging on mouse up self._stopDragging() # called when we start dragging def onMouseGlassEnter(self, sender): pass # called when we drag out of the window # (NOT called when we just stop dragging) def onMouseGlassLeave(self, sender): # we left the window, so stop dragging self._stopDragging() # # Start the inherited 'public' API # # specify splitter position in pix OR percentage # if pixels (number) specified, we can make change now # otherwise, we have to set the offset as specified, then # 'fixup' the remaining space after rendering def setSplitPosition(self, pos=None): if pos is not None: # remember last pos set self._pos = pos else: pos = self._pos if pos < 1: pos = 1 self._pos = pos # change adjustable dimension if self._vertical: self._container1.setHeight(pos) else: self._container1.setWidth(pos) # if pix are given, we can try to finalize the positions finalized = False if isinstance(pos, int): finalized = self._finalizePositions(pos) # if needed, queue callback to finalize if not finalized: DeferredCommand.add(self._finalizePositions) def getWidget(self, index): if index == 0: return self._container1.getWidget() return self._container2.getWidget() def setWidget(self, index, widget): if index == 0: return self._container1.setWidget(widget) return self._container2.setWidget(widget) # Adds a widget to a pane def add(self, widget): if self.getWidget(0) == None: self.setWidget(0, widget) elif self.getWidget(1) == None: self.setWidget(1, widget) else: console.error("SimplePanel can only contain one child widget") # Removes a child widget. def remove(self, widget): if self.getWidget(0) == widget: self._container1.remove(widget) elif self.getWidget(1) == widget: self._container2.remove(widget) else: AbsolutePanel.remove(self, widget) # Gets the content element for the given index. def getElement(self, index=None): if index is None: return AbsolutePanel.getElement(self) return self.getWidget(index).getElement() # Gets the widget in the pane at end of the line direction for the layout def getEndOfLineWidget(self): return self.getWidget(1) # Gets the element that is acting as the splitter. def getSplitElement(self): return self._splitter.getElement() # Gets the widget in the pane at the start of line direction for the layout def getStartOfLineWidget(self): return self.getWidget(0) # Indicates whether the split panel is being resized. def isResizing(self): return False # Sets the widget in the pane at the end of line direction for the layout def setEndOfLineWidget(self, widget): self.setWidget(1, widget) def setStartOfLineWidget(self, widget): self.setWidget(0, widget)
class SplitPanel(AbsolutePanel, MouseHandler, EventGenerator): """ Provides the SplitPanel baseclass functionality A SplitPanel is an AbsolutePanel containing an HTMLTable with three cells. The first cell holds the first ScrollPanel, while the center cell holds a Splitter, and the last cell holds the other ScrollPanel. """ def __init__(self, vertical=False, **kwargs): # set defaults if not 'StyleName' in kwargs: if vertical: # vertical split panel kwargs['StyleName'] = "gwt-VerticalSplitPanel" else: kwargs['StyleName'] = "gwt-HorizontalSplitPanel" # splitter drag state vars self._drag_start = None self._pos = "50%" # orientation self._vertical = vertical # now init the bases AbsolutePanel.__init__(self, **kwargs) MouseHandler.__init__(self) # add our event support? self.addListenedEvent("Resize") # create the top/left widget container self._container1 = ScrollPanel() # create the bottom/right widget container self._container2 = ScrollPanel() # create the splitter self._splitter = SplitPanelSplitter(self) # add splitter handling self._splitter.addMouseListener(self) # add mouse event handling self.addMouseListener(self) # add the parts AbsolutePanel.add(self, self._container1, 0, 0) AbsolutePanel.add(self, self._splitter, 0, 0) AbsolutePanel.add(self, self._container2, 0, 0) # set the layout if vertical: # vertical split panel self._splitter.setStyleName("vsplitter") self._splitter.setWidth("100%") self._container1.setWidth("100%") self._container2.setWidth("100%") # set drag cursor DOM.setStyleAttribute(self._splitter.getElement(), "cursor", "n-resize") else: # horizontal split panel self._splitter.setStyleName("hsplitter") self._splitter.setHeight("100%") self._container1.setHeight("100%") self._container2.setHeight("100%") # set drag cursor DOM.setStyleAttribute(self._splitter.getElement(), "cursor", "e-resize") def onAttach(self): AbsolutePanel.onAttach(self) self.setSplitPosition() # fixup the container 2 size and position def _finalizePositions(self, pos=None): finalized = False if self._vertical: if pos is None: pos = self._container1.getOffsetHeight() space = self.getOffsetHeight() sz = self._splitter.getOffsetHeight() if space > 0 and sz > 0 and pos > 0: # limit pos if pos > space - sz: pos = space - sz self._container1.setHeight(pos) self.setWidgetPosition(self._splitter, 0, pos) self.setWidgetPosition(self._container2, 0, pos + sz) self._container2.setHeight(space - (pos + sz)) finalized = True else: if pos is None: pos = self._container1.getOffsetWidth() space = self.getOffsetWidth() sz = self._splitter.getOffsetWidth() if space > 0 and sz > 0 and pos > 0: # limit pos if pos > space - sz: pos = space - sz self._container1.setWidth(pos) self.setWidgetPosition(self._splitter, pos, 0) self.setWidgetPosition(self._container2, pos + sz, 0) self._container2.setWidth(space - (pos + sz)) finalized = True if finalized: self.dispatchResizeEvent(self, pos) return finalized # end a drag operation def _stopDragging(self): if self._drag_start is not None: # we are no longer dragging self._drag_start = None # deactivate the transparent overlay GlassWidget.hide() # don't let a mouse-up become a click event DOM.eventCancelBubble(DOM.eventGetCurrentEvent(), True) def _isDragging(self): return self._drag_start is not None # start a drag operation (called by splitter) def startSplitterDrag(self, x, y): if self._drag_start is None: # remember where on the slider we are dragging if self._vertical: self._drag_start = y else: self._drag_start = x # activate the transparent overlay to keep mouse events flowing to # the splitter (and to us) even if the mouse leaves the splitter GlassWidget.show(self) # add handlers for mouse events to support dragging the slider # NOTE: the x,y positioni s relative to the splitter def onMouseMove(self, sender, x, y): # if dragging, then use current mouse position # to reset splitter position if not self._isDragging(): return # remove the offset into the splitter # where we started dragging if self._vertical: self._pos = y - self._drag_start else: self._pos = x - self._drag_start # apply limit if self._pos < 1: self._pos = 1 # apply new position self.setSplitPosition() def onMouseUp(self, sender, x, y): ev = DOM.eventGetCurrentEvent() # ignore right-button ups if DOM.eventGetButton(ev) != Event.BUTTON_LEFT: return DOM.eventPreventDefault(ev) # if we are dragging if self._isDragging(): # stop dragging on mouse up self._stopDragging() # called when we start dragging def onMouseGlassEnter(self, sender): pass # called when we drag out of the window # (NOT called when we just stop dragging) def onMouseGlassLeave(self, sender): # we left the window, so stop dragging self._stopDragging() # # Start the inherited 'public' API # # specify splitter position in pix OR percentage # if pixels (number) specified, we can make change now # otherwise, we have to set the offset as specified, then # 'fixup' the remaining space after rendering def setSplitPosition(self, pos=None): if pos is not None: # remember last pos set self._pos = pos else: pos = self._pos if pos < 1: pos = 1 self._pos = pos # change adjustable dimension if self._vertical: self._container1.setHeight(pos) else: self._container1.setWidth(pos) # if pix are given, we can try to finalize the positions finalized = False if isinstance(pos, int): finalized = self._finalizePositions(pos) # if needed, queue callback to finalize if not finalized: queue_Call(self._finalizePositions) def getWidget(self, index): if index == 0: return self._container1.getWidget() return self._container2.getWidget() def setWidget(self, index, widget): if index == 0: return self._container1.setWidget(widget) return self._container2.setWidget(widget) # Adds a widget to a pane def add(self, widget): if self.getWidget(0) == None: self.setWidget(0, widget) elif self.getWidget(1) == None: self.setWidget(1, widget) else: console.error("SimplePanel can only contain one child widget") # Removes a child widget. def remove(self, widget): if self.getWidget(0) == widget: self._container1.remove(widget) elif self.getWidget(1) == widget: self._container2.remove(widget) else: AbsolutePanel.remove(self, widget) # Gets the content element for the given index. def getElement(self, index=None): if index is None: return AbsolutePanel.getElement(self) return self.getWidget(index).getElement() # Gets the widget in the pane at end of the line direction for the layout def getEndOfLineWidget(self): return self.getWidget(1) # Gets the element that is acting as the splitter. def getSplitElement(self): return self._splitter.getElement() # Gets the widget in the pane at the start of line direction for the layout def getStartOfLineWidget(self): return self.getWidget(0) # Indicates whether the split panel is being resized. def isResizing(self): return False # Sets the widget in the pane at the end of line direction for the layout def setEndOfLineWidget(self, widget): self.setWidget(1, widget) def setStartOfLineWidget(self, widget): self.setWidget(0, widget)