def scrollButtonMove(self, event):
        """

        :param generalgui.app.App self:
        :param event:
        """
        if self.scrollWheelTarget:
            if not self.scrollWheelTarget.isShown(error=False):
                self.scrollButtonRelease()
                return

            coords = Vec2(event.x_root, event.y_root)
            mouseDiff = coords - self.startCoords
            canvasSize = Vec2(self.scrollWheelTarget.widget.winfo_width(),
                              self.scrollWheelTarget.widget.winfo_height())
            fractionMouseDiff = mouseDiff / canvasSize

            visibleFraction = self.getVisibleFraction(self.scrollWheelTarget)
            newFraction = self.startFraction - fractionMouseDiff * visibleFraction

            if visibleFraction.x < 1:
                self.scrollWheelTarget.widget.xview_moveto(newFraction.x)
                self.openMenuOnRelease = False
            if visibleFraction.y < 1:
                self.scrollWheelTarget.widget.yview_moveto(newFraction.y)
                self.openMenuOnRelease = False
Exemple #2
0
    def _traverse(self,
                  checkPosFunc,
                  startPos,
                  step=None,
                  maxPos=None,
                  confine=False,
                  maxSteps=100):
        if step is None:
            step = Vec2(0)
        if maxPos is None:
            maxPos = self.getGridSize() - 1
        if maxPos == -1:
            return None

        pos = startPos.sanitize(ints=True)
        step.sanitize(ints=True)

        pos = self.confinePos(pos, maxPos)

        for i in range(maxSteps + 1):
            if (result := checkPosFunc(pos)) is not None:
                return result
            if step == 0:
                break
            pos += step
            if confine:
                pos = self.confinePos(pos, maxPos)
            if pos == startPos or not pos.inrange(Vec2(0, 0), maxPos):
                break
    def test_pos(self):
        app = App()
        self.assertEqual(Vec2(), app.getWindowPos())
        self.assertEqual(Vec2(1), app.getSize())
        app.show(mainloop=False)
        self.assertEqual(True, app.getWindowPos().inrange(1, 500))

        self.assertEqual(Vec2(), app.getTopLeftPos())
        self.assertEqual(Vec2(200), app.getBottomRightPos())
        self.assertEqual(Vec2(200), app.getSize())

        app.setSize(Vec2(250, 300))
        app.widget.update()
        self.assertEqual(Vec2(250, 300), app.getSize())

        app.setSize(145)
        app.widget.update()
        self.assertEqual(Vec2(145), app.getSize())

        page = Page(app, width=300, height=250)
        page.show(mainloop=False)
        self.assertEqual(Vec2(300, 250), app.getBottomRightPos())
        self.assertEqual(Vec2(300, 250), app.getSize())

        self.assertEqual(True, app.getMouse().inrange(-100000, 100000))

        self.assertEqual(page.frame, app.getElementByPos(10))

        page.remove()
        self.assertEqual(app, app.getElementByPos(10))

        self.assertEqual(None, app.getElementByPos(-10))
        self.assertEqual(None, app.getElementByPos(400))
    def test_place(self):
        app = App()
        Page(app, width=200, height=200).show(mainloop=False)
        page = Page(app, width=10, height=10, bg="green")
        app.showChildren(mainloop=False)

        page.place(Vec2(100, 100))
        self.assertEqual(Vec2(100, 100), page.getTopLeftPos())
Exemple #5
0
    def test_place(self):
        app = App()
        label = Label(Page(app, width=500, height=500), "testing", pack=False)

        label.place(Vec2(100, 100))
        label.show(mainloop=False)

        self.assertEqual(Vec2(100, 100), label.getTopLeftPos())
Exemple #6
0
    def test_getGridElement(self):
        grid = Grid(App())
        self.assertEqual(None, grid.getGridElement(Vec2(1, 0)))

        label = Label(grid, "hello", column=1, row=0)
        self.assertEqual(label, grid.getGridElement(Vec2(1, 0)))

        label = Label(grid, column=0, row=0)
        self.assertEqual(label, grid.getGridElement(Vec2(0, 0)))
Exemple #7
0
    def test_append(self):
        grid = Grid(App())
        # Column 2
        self.assertEqual(Vec2(2, 0),
                         grid.appendToColumn(Label(grid, pack=False), 2))
        self.assertEqual(Vec2(2, 1),
                         grid.appendToColumn(Label(grid, pack=False), 2))
        # Column 1
        self.assertEqual(Vec2(1, 0),
                         grid.appendToColumn(Label(grid, pack=False), 1))

        # Row 0
        self.assertEqual(Vec2(0, 0),
                         grid.appendToRow(Label(grid, pack=False), 0))
        self.assertEqual(Vec2(3, 0),
                         grid.appendToRow(Label(grid, pack=False), 0))
        self.assertEqual(Vec2(4, 0),
                         grid.appendToRow(Label(grid, pack=False), 0))

        # Row 1
        self.assertEqual(Vec2(0, 1),
                         grid.appendToRow(Label(grid, pack=False), 1))
        self.assertEqual(Vec2(1, 1),
                         grid.appendToRow(Label(grid, pack=False), 1))

        # Column 0
        self.assertEqual(Vec2(0, 2),
                         grid.appendToColumn(Label(grid, pack=False), 0))
    def loadDataFrame(self, df=None):
        """
        Update cells to represent a dataFrame with any types of values.
        """
        self.dataFrameIsLoading = True

        if df is not None:
            if not typeChecker(df, pd.DataFrame, error=False):
                df = pd.DataFrame(df)

            self.dataFrame = df
        df = self.dataFrame
        # print(df.to_string())

        if self.columnKeys:
            size = Vec2(len(df.columns), 1)
            self.headerGrid.fillGrid(Frame, Vec2(1, 0), size, height=1)
            self.mainGrid.fillGrid(Frame, Vec2(1, 0), size, height=1)

            self.headerGrid.fillGrid(
                Label,
                Vec2(1, 1),
                size,
                values=df.columns,
                removeExcess=True,
                onClick=lambda e: self.sortColumn(cellValue=e),
                anchor="c")

        if self.rowKeys:
            size = Vec2(1, len(df.index))
            self.indexGrid.fillGrid(Frame, Vec2(0, 1), size, width=1)
            self.mainGrid.fillGrid(Frame, Vec2(0, 1), size, width=1)

            self.indexGrid.fillGrid(
                Label,
                Vec2(1, 1),
                size,
                values=df.index,
                removeExcess=True,
                onClick=lambda e: self.sortRow(cellValue=e))

        values = []
        for row in df.itertuples(index=False):
            values.extend(row)
        self.mainGrid.fillGrid(Label,
                               Vec2(1, 1),
                               Vec2(df.shape[1], df.shape[0]),
                               values=values,
                               removeExcess=True,
                               color=True,
                               **self.cellConfig)

        self.dataFrameIsLoading = False
        self.syncSizes()
    def scrollButton(self, event):
        """

        :param generalgui.app.App self:
        :param event:
        """
        self._checkEventForScrollTarget(event)
        if self.scrollWheelTarget:
            self.startCoords = Vec2(event.x_root, event.y_root)
            self.startFraction = Vec2(self.scrollWheelTarget.widget.xview()[0],
                                      self.scrollWheelTarget.widget.yview()[0])
            self.scrollStyle.enable()
Exemple #10
0
    def appendToColumn(self, part, column):
        """
        Append a part to column, after the last possibly existing cell

        :param generalgui.element.Element or generalgui.page.Page part:
        :param int column: Which column to append to
        :return: Position of filled cell
        """
        firstEmptyPos = self.getFirstEmptyPos(Vec2(column, 0), Vec2(0, 1))
        if firstEmptyPos is None:
            firstEmptyPos = Vec2(column, self.getGridSize().y)
        part.grid(firstEmptyPos)
        return firstEmptyPos
Exemple #11
0
    def test_pos(self):
        app = App()
        label = Button(Page(app), "testing", pack=False)
        self.assertEqual(Vec2(), label.getTopLeftPos())
        self.assertEqual(Vec2(1), label.getSize())

        label.show(mainloop=False)
        self.assertEqual(True, label.getWindowPos().inrange(1, 500))
        self.assertEqual(True, label.getSize().inrange(10, 100))

        self.assertEqual(True, label.getTopLeftPos().inrange(0, 100))
        self.assertLess(label.getTopLeftPos(), label.getBottomRightPos())
        self.assertEqual(True, label.getSize().inrange(10, 100))
Exemple #12
0
    def appendToRow(self, part, row):
        """
        Append a part to column, after the last possibly existing cell

        :param generalgui.element.Element or generalgui.page.Page part:
        :param int row: Which row to append to
        :return: Position of filled cell
        """
        firstEmptyPos = self.getFirstEmptyPos(Vec2(0, row), Vec2(1, 0))
        if firstEmptyPos is None:
            firstEmptyPos = Vec2(self.getGridSize().x, row)
        part.grid(firstEmptyPos)
        return firstEmptyPos
Exemple #13
0
    def getGridElement(self, pos):
        """
        Returns the element in a certain position in grid, or None

        :param Vec2 pos: Grid position to check
        """
        pos = Vec2(pos)
        if not pos >= Vec2(0, 0):
            return None

        pos = pos.sanitize(ints=True)

        if slave := self.getBaseWidget().grid_slaves(column=pos.x, row=pos.y):
            return slave[0].element
Exemple #14
0
    def test_getGridSize(self):
        grid = Grid(App())
        self.assertEqual(Vec2(0, 0), grid.getGridSize())

        label1 = Label(grid, "hello", column=1, row=0)
        self.assertEqual(Vec2(2, 1), grid.getGridSize())

        label2 = Label(grid, "hello", column=2, row=1)
        self.assertEqual(Vec2(3, 2), grid.getGridSize())

        label2.remove()
        self.assertEqual(Vec2(2, 1), grid.getGridSize())

        label1.remove()
        self.assertEqual(Vec2(0, 0), grid.getGridSize())
Exemple #15
0
 def getGridSize(self):
     """
     Get current grid size as a Vec2.
     Only looks at cell with greatest position, so you could say (gridSize - Vec2(1)) is just pos of bottom right cell.
     """
     size = self.getBaseWidget().grid_size()
     return Vec2(size[0], size[1])
    def getTopLeftPos(self):
        """
        Get top left corner of this part's widget.

        :param generalgui.element.Element or generalgui.page.Page or generalgui.app.App self: Element, Page or App
        """
        return Vec2(self.getTopWidget().winfo_rootx(),
                    self.getTopWidget().winfo_rooty()) - self.getWindowPos()
    def getMouse(self):
        """
        Get mouse vector2 from event, can be any part in whole app.

        :param generalgui.element.Element or generalgui.page.Page or generalgui.app.App self: Element, Page or App
        """
        return Vec2(self.app.widget.winfo_pointerx(),
                    self.app.widget.winfo_pointery()) - self.getWindowPos()
    def getSize(self):
        """
        Get size of this part's widget.

        :param generalgui.element.Element or generalgui.page.Page or generalgui.app.App self: Element, Page or App
        """
        return Vec2(self.getTopWidget().winfo_width(),
                    self.getTopWidget().winfo_height())
Exemple #19
0
    def getVisibleFraction(self, canvas):
        """
        Get visible fraction of a canvas, not meant to be used other than by scroll feature.

        :param generalgui.app.App self:
        :param generalgui.Canvas canvas:
        :raises AttributeError: If canvas is not shown
        """
        if not canvas.isShown():
            raise AttributeError("Canvas is not shown")

        canvasSize = Vec2(canvas.widget.winfo_width(),
                          canvas.widget.winfo_height())
        scrollRegions = canvas.getWidgetConfig("scrollregion").split(" ")
        scrollSize = Vec2(int(scrollRegions[2]), int(scrollRegions[3]))
        visibleFraction = canvasSize / scrollSize
        return visibleFraction
    def getWindowPos(self):
        """
        Get current window position of the upper left corner.

        :param generalgui.element.Element or generalgui.page.Page or generalgui.app.App self: Element, Page or App
        """
        return Vec2(self.app.widget.winfo_rootx(),
                    self.app.widget.winfo_rooty())
    def setSize(self, size):
        """
        Set size of this part's widget.

        :param generalgui.element.Element or generalgui.page.Page or generalgui.app.App self: Element, Page or App
        :param Vec2 or Float size:
        """
        size = Vec2(size)
        return self.getTopElement().widgetConfig(width=size.x, height=size.y)
    def test_getVisibleFraction(self):
        app = App()
        page = Page(app, width=100, height=100, scrollable=True)
        page2 = Page(page, width=196, height=196)

        with self.assertRaises(AttributeError):
            app.getVisibleFraction(page.canvas)

        page2.show(mainloop=False)
        self.assertEqual(Vec2(0.5), app.getVisibleFraction(page.canvas))
Exemple #23
0
    def confinePos(self, pos, maxPos=None):
        """
        Returns a confined pos between 0 and gridSize - 1

        :param Vec2 pos:
        :param Vec2 maxPos:
        """
        if maxPos is None:
            maxPos = self.getGridSize() - 1
        return pos.confineTo(Vec2(0, 0), maxPos, margin=0.5)
Exemple #24
0
    def test_getGridPos(self):
        grid = Grid(App())

        label = Label(Grid(App()), "hello")
        self.assertRaises(AttributeError, grid.getGridPos, label)

        label = Label(grid, "hello", column=1, row=1, pack=False)
        self.assertRaises(AttributeError, grid.getGridPos, label)

        label.pack()
        self.assertEqual(Vec2(1, 1), grid.getGridPos(label))
    def _syncColumnKeysWidth(self, test=False):
        """
        Sync the widths of all cells with headers
        """
        if not self.columnKeys:
            return

        columnSize = self.headerGrid.getGridSize()
        mainSize = self.mainGrid.getGridSize()

        if columnSize.x != mainSize.x:
            print(self.headerGrid.getChildren())
            raise AttributeError(f"Columns mismatch {columnSize}, {mainSize}")

        columnFrames = []
        mainFrames = []
        for pos in Vec2(1, 0).range(Vec2(columnSize.x - 1, 1)):
            columnFrame = self.headerGrid.getGridElement(pos)
            # print(columnFrame)
            columnFrame.widgetConfig(width=0)
            columnFrames.append(columnFrame)

            mainFrame = self.mainGrid.getGridElement(pos)
            # print(mainFrame)
            mainFrame.widgetConfig(width=0)
            mainFrames.append(mainFrame)

        if test:
            return

        self.app.widget.update_idletasks()

        for i, columnFrame in enumerate(columnFrames):
            mainFrame = mainFrames[i]
            columnWidth = columnFrame.widget.winfo_width()
            mainWidth = mainFrame.widget.winfo_width()
            if columnWidth > mainWidth:
                mainFrame.widgetConfig(width=columnWidth)
            else:
                columnFrame.widgetConfig(width=mainWidth)
Exemple #26
0
    def getFirstPatternPos(self,
                           startPos=Vec2(0),
                           firstStep=Vec2(0, 1),
                           secondStep=Vec2(1, 0),
                           maxFirstSteps=5):
        """
        Get position of first empty pos in pattern.
        When firstStep has been made maxFirstSteps times we subtract all firstSteps and then make one secondStep.
        If maxfirststeps is 1 then only second step is used.

        :param Vec2 startPos: Inclusive position to start search
        :param Vec2 firstStep: Directional Vec2 to be used as step for each maxFirstSteps
        :param Vec2 secondStep: Directional Vec2 to be used as step for each time firstStep has been made maxFirstSteps times
        :param maxFirstSteps: Number of firstSteps before one secondStep
        """
        pos = startPos
        while True:
            for i in range(maxFirstSteps):
                if not self.getGridElement(pos):
                    return pos
                pos += firstStep
            pos = pos - firstStep * maxFirstSteps + secondStep
    def _syncRowKeysHeight(self, test=False):
        """
        Sync the heights of all cells with indexes
        """
        if not self.rowKeys:
            return

        rowSize = self.indexGrid.getGridSize()
        mainSize = self.mainGrid.getGridSize()

        if rowSize.y != mainSize.y:
            raise AttributeError(f"Row mismatch {rowSize}, {mainSize}")

        rowFrames = []
        mainFrames = []
        for pos in Vec2(0, 1).range(Vec2(1, rowSize.y - 1)):
            rowFrame = self.indexGrid.getGridElement(pos)
            # print(rowFrame)
            rowFrame.widgetConfig(height=0)
            rowFrames.append(rowFrame)

            mainFrame = self.mainGrid.getGridElement(pos)
            # print(mainFrame)
            mainFrame.widgetConfig(height=0)
            mainFrames.append(mainFrame)

        if test:
            return

        self.app.widget.update_idletasks()

        for i, rowFrame in enumerate(rowFrames):
            mainFrame = mainFrames[i]
            rowHeight = rowFrame.widget.winfo_height()
            mainHeight = mainFrame.widget.winfo_height()
            if rowHeight > mainHeight:
                mainFrame.widgetConfig(height=rowHeight)
            else:
                rowFrame.widgetConfig(height=mainHeight)
Exemple #28
0
    def removeInput(self, key):
        """
        Remove label and input pair that represents a key value.

        :param str key:
        :returns: Whether input existed to be removed or not
        """
        if element := self.getInputElement(key):
            label = self.getGridElement(self.getGridPos(element) - Vec2(1, 0))
            element.remove()
            label.remove()
            del self._inputElements[key]
            return True
Exemple #29
0
    def setInputElement(self, key, value):
        """
        Set the default value of a new or existing input element, removes old if it exists.
        Automatically choses between Checkbutton and Entry

        :param str key:
        :param any value:
        """
        if key in self._inputElements:
            self.removeInput(key)

        label = self.app.Label(self, key)
        pos = self.getFirstPatternPos(secondStep=Vec2(2, 0),
                                      maxFirstSteps=self.maxFirstSteps)
        label.grid(pos)
        if value is True or value is False:
            element = self.app.Checkbutton(parentPage=self, default=value)
        else:
            element = self.app.Entry(parentPage=self, default=str(value))
        element.grid(pos + Vec2(1, 0))

        self._inputElements[key] = element
Exemple #30
0
    def _checkEventForScrollTarget(self, event):
        if not event:
            return
        eventElement = event.widget.element
        if typeChecker(eventElement, "App", error=False):
            return

        pages = eventElement.getParents()
        for page in pages:
            if page.scrollable and page.mouseScroll:
                visibleFraction = self.getVisibleFraction(page.canvas)
                if not visibleFraction >= Vec2(1):
                    self.scrollWheelTarget = page.canvas
                    break