Pie Menu

Need help, or want to share a macro? Post here!
User avatar
looo
Posts: 3010
Joined: Mon Nov 11, 2013 5:29 pm

Pie Menu

Postby looo » Sat May 09, 2015 12:44 pm

Blender has this pie menu, and I think freecad could also benefit from such a menu. It extends the short-cuts and is useable for both, beginners and power users.
First I tried to directly paint to the graphics view of the viewer but then the pie-menu can be displayed not outside the viewer. (The blender pie-menu is displayed anywhere on the window.) In the code I'm posting below the menu is inside a new graphics view which is shown or hidden on key-press-event ("a" for the example) holding the key will show you the possibilities (no icons yet, but this shouldn't be too hard). Releasing the key hides the menu and executes the highlighted command.
For this example the menu is used as a workbench-switcher. When switching to arch or draft the key-press-event is disabled somehow and the behaviour of the menu changes a bit.

if you want, try it out and if you know how to improve it let me know... :D
thanks

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)
please help with my conda-packaging efforts: https://liberapay.com/looooo/
minimalistic blog: https://looooo.github.io/mini-blog/
drei
Posts: 479
Joined: Sun May 11, 2014 7:47 pm
Location: Mexico
Contact:

Re: Pie Menu

Postby drei » Sat May 09, 2015 7:05 pm

This looks really good :D,

Perhaps an implementation could be set to also use this within the workbenches,
say if I'm in sketcher and I summon the macro it will allow me to select tools within the WB, and if I enter another one, it may allow me to use the commands of that WB.
Need help? Feel free to ask, but please read the guidelines first
User avatar
TT-RS
Posts: 70
Joined: Fri Oct 24, 2014 9:19 pm

Re: Pie Menu

Postby TT-RS » Sat May 09, 2015 7:29 pm

drei wrote:Perhaps an implementation could be set to also use this within the workbenches,
say if I'm in sketcher and I summon the macro it will allow me to select tools within the WB, and if I enter another one, it may allow me to use the commands of that WB.
+1

Yes, such context pop-up menu is good idea, and as drei says it should have functionality dependend on WB.
User avatar
looo
Posts: 3010
Joined: Mon Nov 11, 2013 5:29 pm

Re: Pie Menu

Postby looo » Sun May 10, 2015 8:38 am

That is the plan. One global menu for wb.switch and one locale menu for every workbench. The problem is, that it is too heavy and buggy in this state and I don't know how to improve that. One thing is that background events sometimes close the window, or maybe that is a problem with the autorepeat option of the keyevent. The other thing is the key down suppress of the draft wb...
Here is a short demo of the menu connected with some framebuild functionality in action.
https://vimeo.com/127369120
please help with my conda-packaging efforts: https://liberapay.com/looooo/
minimalistic blog: https://looooo.github.io/mini-blog/
User avatar
looo
Posts: 3010
Joined: Mon Nov 11, 2013 5:29 pm

Re: Pie Menu

Postby looo » Sun May 10, 2015 8:53 am

The other thing is the key down suppress of the draft wb
Ok, I have connected the menu to a key allready used in Draft. So this shouldn't be that difficult to solve.
please help with my conda-packaging efforts: https://liberapay.com/looooo/
minimalistic blog: https://looooo.github.io/mini-blog/
User avatar
microelly2
Posts: 4504
Joined: Tue Nov 12, 2013 4:06 pm
Contact:

Re: Pie Menu

Postby microelly2 » Sun May 10, 2015 6:54 pm

very nice idea,
this is the functionality I have looked for to get direct context sensitive interaction. New opportunities to get the jobs faster done. Thanks.
User avatar
NormandC
Posts: 18534
Joined: Sat Feb 06, 2010 9:52 pm
Location: Québec, Canada

Re: Pie Menu

Postby NormandC » Sun May 10, 2015 8:25 pm

I shared your video on the FreeCAD Google+ community: https://plus.google.com/117324667497119 ... 4Hg7QxbnKZ
ilyxa
Posts: 7
Joined: Mon Mar 23, 2015 12:28 pm

Re: Pie Menu

Postby ilyxa » Mon May 11, 2015 5:32 pm

Can you provide bit more infos about Beam and Shape feature used in this video for fast and nice tube contsruction?
User avatar
looo
Posts: 3010
Joined: Mon Nov 11, 2013 5:29 pm

Re: Pie Menu

Postby looo » Mon May 11, 2015 8:03 pm

thanks for the promotion normandC :)
Can you provide bit more infos about Beam and Shape feature used in this video for fast and nice tube contsruction?
The frame-builder stuff is a macro I've done some time ago. The idea was to simplify the procedure of dragging and rotating a sketch to a line and extruding it. The cutting tools are a miter cut, a plane cut and a shape cut.
if you want you can try: https://bitbucket.org/looooo/beam
please help with my conda-packaging efforts: https://liberapay.com/looooo/
minimalistic blog: https://looooo.github.io/mini-blog/
User avatar
r-frank
Posts: 2181
Joined: Thu Jan 24, 2013 6:26 pm
Location: Möckmühl, Germany
Contact:

Re: Pie Menu

Postby r-frank » Mon May 11, 2015 8:21 pm

Reading about the pie menu ... well I had no idea what you were talking about ...
Then I saw your video on vimeo.
Now this is quite cool ...
It would speed up things and make FreeCAD more user-freindly and context-sensitive.

Please keep on working on this loo.

Roland
Deutsche FreeCAD Tutorials auf Youtube
My GrabCAD FreeCAD-Projects
FreeCAD lessons for beginners in english

Native german speaker - so apologies for my english, no offense intended :)