Exemplo n.º 1
0
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)
Exemplo n.º 2
0
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)