PieMenu-like clone - quickly access a different workbench via popup

Need help, or want to share a macro? Post here!
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
Post Reply
User avatar
Kunda1
Veteran
Posts: 13434
Joined: Thu Jan 05, 2017 9:03 pm

PieMenu-like clone - quickly access a different workbench via popup

Post by Kunda1 »

In https://forum.freecadweb.org/viewtopic. ... 47#p322662 user @dcapeletti shares a macro that does the following:
1. Run macro
2. press 'a' key
3. navigational pop-up appears
4. choose a sphere that represents a certain workbench
Result: workbench opens

Here is a screencast of it in action:

Image

Here is the macro:

Code: Select all

from __future__ import division
import FreeCADGui as Gui
from PySide import QtCore, QtGui
import numpy as np

class PieButton(QtGui.QGraphicsEllipseItem):
    def __init__(self, pos=[0, 0], angle_range=(0, 1), size=[50, 50], view=None, parent=None):
        super(PieButton, self).__init__(None, scene=parent)
        self.view = view
        self.angle_range = angle_range
        self.setRect(pos[0] - size[0] / 2, pos[1] - size[1] / 2, size[0], size[1])
        self.setBrush(QtGui.QBrush(QtCore.Qt.red))
        self.setAcceptHoverEvents(True)
        self.command = None
        self.hoover = False

    def setHoover(self, value):
        if not self.hoover == value:
            self.hoover = value
            if value:
                self.setBrush(QtGui.QBrush(QtCore.Qt.blue))
                self.view.setText(self.command[0])
            else:
                self.setBrush(QtGui.QBrush(QtCore.Qt.red))


class PieView(QtGui.QGraphicsView):
    def __init__(self, key, commands, parent=None):
        super(PieView, self).__init__(parent)
        self.key = key
        self.setWindowFlags(QtCore.Qt.Widget | QtCore.Qt.FramelessWindowHint)
        self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
        self.setStyleSheet("QGraphicsView {border-style: none; background: transparent;}" )
        self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.scene = QtGui.QGraphicsScene(self)
        self.scene.setSceneRect(-200, -200, 400, 400)
        self.setScene(self.scene)
        self.center = [0, 0]
        self.buttons = []
        self.label = QtGui.QGraphicsSimpleTextItem("")
        self.scene.addItem(self.label)
        self.add_commands(commands)

    def setText(self, text):
        self.label.setText(text)
        self.label.update()
        self.label.setPos(-self.label.sceneBoundingRect().width() / 2, 0)

    def add_commands(self, commands):
        num = len(commands)
        r = 100
        a = 70
        pie_phi = np.linspace(0, np.pi * 2, num + 1)
        phi = [(p + pie_phi[i + 1]) / 2 for i, p in enumerate(pie_phi[:-1])]
        for i, command in enumerate(commands):
            button = PieButton(
                [r * np.cos(phi[i]), r * np.sin(phi[i])],
                [pie_phi[i], pie_phi[i + 1]],
                [a, a], self, self.scene)
            button.command = command
            self.scene.addItem(button)
            self.buttons.append(button)

    def mouseMoveEvent(self, event):
        r2, angle = self.polarCoordinates
        hoover = False
        for item in self.buttons:
            if (item.angle_range[0] < angle and
                angle < item.angle_range[1] and
                r2 > 1000):
                item.setHoover(True)
                hoover = True
            else:
                item.setHoover(False)
        if not hoover:
            self.setText("")

    @property
    def polarCoordinates(self):
        pos = QtGui.QCursor.pos() - self.center
        r2 = pos.x() ** 2 + pos.y() ** 2
        angle = np.arctan2(pos.y(), pos.x())
        return r2, angle + (angle < 0) * 2 * np.pi

    def showAtMouse(self, event):
        if event["Key"] == self.key:
            self.show()
            self.center = QtGui.QCursor.pos()
            self.move(self.center.x()-(self.width()/2), self.center.y()-(self.height()/2))

    def keyReleaseEvent(self, event):
        super(PieView, self).keyReleaseEvent(event)
        if event.key() == QtGui.QKeySequence(self.key):
            if not event.isAutoRepeat():
                for item in self.scene.items():
                    if hasattr(item, "hoover"):
                        if item.hoover:
                            item.command[1]()
                self.hide()


if __name__ == "__main__":
    def part_design(): Gui.activateWorkbench("PartDesignWorkbench")
    def part(): Gui.activateWorkbench("PartWorkbench")
    def draft(): Gui.activateWorkbench("DraftWorkbench")
    def arch(): Gui.activateWorkbench("ArchWorkbench")
    def fem(): Gui.activateWorkbench("FemWorkbench")
    def sketch(): Gui.activateWorkbench("SketcherWorkbench")
    def draw(): Gui.activateWorkbench("DrawingWorkbench")
    def mesh(): Gui.activateWorkbench("MeshWorkbench")

    command_list = [
        ["PartDesign", part_design],
        ["Part", part],
        ["Draft", draft],
        ["Arch", arch],
        ["Fem", fem],
        ["sketch", sketch],
        ["draw", draw],
        ["mesh", mesh]]

    a = PieView("a", command_list)
    view = Gui.ActiveDocument.ActiveView
    view.addEventCallback("SoKeyboardEvent", a.showAtMouse)
What I would like to do (but have no idea how to read this code), is augment the macro to:
1) Display all available workbenches as spheres with their respective logos
2) When hovering over a specific workbench sphere that it will immediately vanish all the other spheres and open the commands of that said workbench in separate discrete spheres to choose from.
Result: time-saving travel time going back and forth from the toolbars to the canvas

Any pyside-nistas available to help ?
Alone you go faster. Together we go farther
Please mark thread [Solved]
Want to contribute back to FC? Checkout:
'good first issues' | Open TODOs and FIXMEs | How to Help FreeCAD | How to report Bugs
User avatar
looo
Veteran
Posts: 3941
Joined: Mon Nov 11, 2013 5:29 pm

Re: PieMenu-like clone - quickly access a different workbench via popup

Post by looo »

I guess the piemenue from @triplus does exactly this:
https://github.com/triplus/PieMenu

What didn't happen until now is a proposal for a tight integration into freecad. But as the pie menue is heavily dependent on qt/pyside, I am not sure if it's a good idea to integrate it into freecad source.
User avatar
Kunda1
Veteran
Posts: 13434
Joined: Thu Jan 05, 2017 9:03 pm

Re: PieMenu-like clone - quickly access a different workbench via popup

Post by Kunda1 »

According to @dcapeletti
I think in the PieButton class I should set an image on the circle instead of painting it with setBrush. I haven't tried, but I think that might work.

On the selected workbench commands, what occurs to me is that you can load the workbench commands in the circles, after you have selected it. I think it might work.
Alone you go faster. Together we go farther
Please mark thread [Solved]
Want to contribute back to FC? Checkout:
'good first issues' | Open TODOs and FIXMEs | How to Help FreeCAD | How to report Bugs
User avatar
Kunda1
Veteran
Posts: 13434
Joined: Thu Jan 05, 2017 9:03 pm

Re: PieMenu-like clone - quickly access a different workbench via popup

Post by Kunda1 »

maxlem wrote: Fri Jul 26, 2019 3:53 pm I'm a qtquick-for-cad specialist, this layout project is the only qtquick inroad i know of, si here I am.

What I want: learn FreeCAD and be able to improve it

What I need: guidance as to where my efforts would be best spent
Why don't you take a stab at this ?
Alone you go faster. Together we go farther
Please mark thread [Solved]
Want to contribute back to FC? Checkout:
'good first issues' | Open TODOs and FIXMEs | How to Help FreeCAD | How to report Bugs
maxlem
Posts: 26
Joined: Fri Jul 26, 2019 2:32 am

Re: PieMenu-like clone - quickly access a different workbench via popup

Post by maxlem »

Ok. So, since its a macro, I can just install freecad from the ppa and fiddle with the macro code?
maxlem
Posts: 26
Joined: Fri Jul 26, 2019 2:32 am

Re: PieMenu-like clone - quickly access a different workbench via popup

Post by maxlem »

Ok got it working. But this is not qtquick code. its QWidget-based, and my personal opinion is that QWidget is a dead end, with QtQuick receiving all the development efforts. You can consider this opinion as cast in stone as far as I'm concerned, so don't bother arguing.
maxlem
Posts: 26
Joined: Fri Jul 26, 2019 2:32 am

Re: PieMenu-like clone - quickly access a different workbench via popup

Post by maxlem »

Let's see if I can port it to QtQuick... any hints welcome
maxlem
Posts: 26
Joined: Fri Jul 26, 2019 2:32 am

Re: PieMenu-like clone - quickly access a different workbench via popup

Post by maxlem »

I did not find a single example. I suspect the python macro API is not supporting this, which does not surprise me. QWidget and QtQuick are not meant to interract with each other. There are some bridges, but, in the end it is simpler to go full QtQuick.
maxlem
Posts: 26
Joined: Fri Jul 26, 2019 2:32 am

Re: PieMenu-like clone - quickly access a different workbench via popup

Post by maxlem »

Oh!

this https://doc.qt.io/qt-5/qquickwidget.html is promising! I think it should work!

Not sure I will have time to try this today.

[edit] Ugh! if you read the "Limitations" section, you're in for pretty depressing stuff. Not that I personally care, but it will fail with a Direct 3D backend.
triplus
Veteran
Posts: 9471
Joined: Mon Dec 12, 2011 4:45 pm

Re: PieMenu-like clone - quickly access a different workbench via popup

Post by triplus »

looo wrote: Thu Jul 25, 2019 5:18 am But as the pie menue is heavily dependent on qt/pyside, I am not sure if it's a good idea to integrate it into freecad source.
Both C++/Qt and PySide/Qt options are now first-class citizens.
maxlem wrote: Sat Jul 27, 2019 10:32 pm Ok got it working. But this is not qtquick code. its QWidget-based, and my personal opinion is that QWidget is a dead end, with QtQuick receiving all the development efforts. You can consider this opinion as cast in stone as far as I'm concerned, so don't bother arguing.
Currently all of FreeCAD is still Qt Widgets based. Fully migrating is therefore still likely a few years away. Pie menu is Qt Widgets based because otherwise i didn't find a way to make it transparent.
Kunda1 wrote: Thu Jul 25, 2019 12:52 am What I would like to do (but have no idea how to read this code), is augment the macro to:
A few years latter:
1) Display all available workbenches as spheres with their respective logos
Open preferences:
Preferences.png
Preferences.png (23 KiB) Viewed 1692 times
And create a new pie menu named Selector:
Selector.png
Selector.png (42.71 KiB) Viewed 1692 times
Set is as default:
PieMenu.png
PieMenu.png (28.77 KiB) Viewed 1692 times
Now you can use PieMenu as a workbench switcher.
2) When hovering over a specific workbench sphere that it will immediately vanish all the other spheres and open the commands of that said workbench in separate discrete spheres to choose from.
You can enable hover trigger mode:
Hover.png
Hover.png (27.23 KiB) Viewed 1692 times
As for next version of PieMenu and some of yours suggestions:

https://forum.freecadweb.org/viewtopic. ... 08#p237328

This feels like it:
  • Subsequential PieMenu button
  • Support for defining module related PieMenus by module developer
  • Possibility to define and change default PieMenu for each workbench
Post Reply