Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Draft] Snap statusbar #3228

Merged
merged 7 commits into from Apr 20, 2020
Merged

[Draft] Snap statusbar #3228

merged 7 commits into from Apr 20, 2020

Conversation

carlopav
Copy link
Contributor

Thank you for creating a pull request to contribute to FreeCAD! To ease integration, please confirm the following:

  • Branch rebased on latest master git pull --rebase upstream master
  • Unit tests confirmed to pass by running ./bin/FreeCAD --run-test 0
  • Commit message is well-written
  • Commit message includes issue #<id> or fixes #<id> where <id> is the associated MantisBT issue id if one exists

And please remember to update the Wiki with the features added or changed once this PR is merged.
Note: If you don't have wiki access, then please mention your contribution on the 0.19 Changelog Forum Thread.


@vocx-fc
Copy link
Contributor

vocx-fc commented Mar 21, 2020

Is this supposed to be a new version of #3220? In general you don't need to close the previous pull request. You can just edit it as you want, add and remove commits, and then just force push to update everything. You can add, remove, and re-write commits with git rebase -i. It's pretty powerful if you can manage all the options it provides. Basically, select a commit, use edit, then you can commit a new step, and later on you can squash it if you want.

Also, just a reminder, if you are adding new files, you have to include them in the CMakeLists.txt file, otherwise they won't be moved to the appropriate directory when the software is compiled. Also, new icons and images should be added to Draft/Resources/Draft.qrc. All the files listed there will be compiled into the Draft_rc.py that you see in an installed system.

@carlopav
Copy link
Contributor Author

carlopav commented Mar 21, 2020

@vocx-fc I agree, but i'm not so expert and i made a bit of a mess, so i thought it was better to start from scratch.

@vocx-fc
Copy link
Contributor

vocx-fc commented Mar 21, 2020

Ok, no problem. I think in this pull request you don't add new files, but in #3167 you do, so I was just talking in general.

@carlopav
Copy link
Contributor Author

I will probably add a new dialog for preferences, but i'll finish it when I'll be sure it is the right way to go and will be merged after. That's why this is still a Draft PR.

@carlopav carlopav force-pushed the SnapStatusbar branch 4 times, most recently from bd12939 to c05f4ed Compare March 25, 2020 08:00
@carlopav carlopav mentioned this pull request Mar 28, 2020
4 tasks
@carlopav
Copy link
Contributor Author

To be merged after #3167.

@carlopav
Copy link
Contributor Author

@yorikvanhavre
This is meant to be the only PR about Snapper improvements and DraftSnap Statusbar.
It substitutes #3227 , that I closed because I did a bit of a mess when trying to rebase it.

@carlopav carlopav marked this pull request as ready for review April 16, 2020 07:06
@yorikvanhavre
Copy link
Member

Ok your turn now :) Mind to have a look at the merge conflicts @carlopav ?

@carlopav
Copy link
Contributor Author

done, by the way @vocx-fc, we should also change the super() methods here, isn't it?
If you agree I can push another commit

@vocx-fc
Copy link
Contributor

vocx-fc commented Apr 16, 2020

Where exactly? In the various Draft Snap commands? This is done in my branch #3344. Basically, at the end I add the appropriate super for all commands that were moved.

Changed snap toolbar behaviour:
- create a list of available snaps (Gui.Snapper.snaps)
- make it consistent with Snap Gui Commands (in gui_snaps module)
- create a list of active snaps (Gui.Snapper.active_snaps)
- refactor the isEnabled() method to allow it to check if the given snap is in Gui.Snapper.active_snaps and not if the snap toolbar button isChecked()
- updated and reordered the new list of gui snap commands in draftutils.init_tools and used it as a base to refactor the creation of draft toolbar
- updated all the draft snap gui tools to make them control the toolbar buttons directly
.


.


.
[Draft] Attempt to make base classes compatible with super on py2


[Draft] Refactored imports of snapper and snaps gui tools


.


.
@carlopav
Copy link
Contributor Author

@yorikvanhavre Ufff that rebase was definitely hard. I also corrected the super according to @vocx-fc recent findings :)

@@ -1893,8 +1893,7 @@ def getXPM(self,iconname,size=16):
return str(a)

def togglesnap(self):
if hasattr(FreeCADGui,"Snapper"):
FreeCADGui.Snapper.toggle()
FreeCADGui.doCommand('FreeCADGui.runCommand("Draft_Snap_Lock")')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the best way of doing it? I am not entirely sure what class calls which. To run this command, it must be defined first, but DraftGui is one of the early modules loaded. So, it's like calling something that will be defined later.

If this is the case, then DraftGui must be loaded after the gui_snaps commands are loaded.

As I can see, Draft_Snap_Lock basically calls Gui.Snapper.masterbutton.toggle(), so it looks very similar to Gui.Snapper.toggle().

Anyway, it's just a comment. As I said, DraftGui is quite complex because it is both the DraftToolBar, the snap toolbar, and the task panel interface for most commands.

Copy link
Contributor Author

@carlopav carlopav Apr 18, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I can see, Draft_Snap_Lock basically calls Gui.Snapper.masterbutton.toggle(), so it looks very similar to Gui.Snapper.toggle().

This was the previous behaviour. With proposed changes Draft_Snap_Lock just calls Gui.Snapper.toggle_snap('Lock') and sync the interface (toolbar and statusbar).
I wish the default behaviour to always interact with Snapper through Snaps commands to set the active_snaps. (EDIT and with current PR also Draft_Snap_Lock became exactly as other snaps seen from outside the Snapper)
Do you think we should modify something in the order the modules are loaded?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm just not sure how it works really. I've never investigated deeply this behavior. But ideally we should try split DraftGui in discrete parts as much as possible.

@@ -32,21 +32,28 @@
# This module provides tools to handle point snapping and
# everything that goes with it (toolbar buttons, cursor icons, etc.).

import FreeCAD as App
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please notice that we want to import first the generic modules, that is, modules provided by Python itself, or Python packages; at the end we want to import our own modules, meaning FreeCAD et al.

This is the reason I placed the import of FreeCAD after the Qt imports. Qt imports are more generic, while FreeCAD, Draft, DraftVecUtil, etc., are more specific.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, i thought FreeCAD had to be the first one... no problem to change this.

@@ -75,6 +82,7 @@ class Snapper:
"""

def __init__(self):

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need a new line here because we don't have docstring. The docstring was already placed in the class definition above.

@@ -191,14 +236,12 @@ def snap(self, screenpos,

self.running = True

global Part, DraftGeomUtils
import Part, DraftGeomUtils
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason the modules are placed in this function is because we don't want to globaly import Part when we import the snapper. According to Yorik this makes loading of Draft quite slow, so for the time being, I would leave these imports here. Maybe I'd remove the global keyword.

To be honest I didn't check this thoroughly because I was doing many things. But eventually I need to test this better.

if o and (self.isEnabled('extension')
or self.isEnabled('parallel')):
ob = FreeCAD.ActiveDocument.getObject(o)
for o in [self.lastObj[1], self.lastObj[0]]:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just nitpicking here but you'll see that in various iterations when you search for something in a list, it is theoretically faster to search in a tuple than in a list.

So, in many cases I use for obj in (...) rather than for obj in [...]. Apparently there is tiny difference.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The way I heard is that lists are mutable (you can modify an element of the list after it has been created, while tuples not. So when creating a tuple, the exact amount of memory is allocated to it, while for lists there is more memory allocated because it might grow later on, and they are much less efficient. So the idea is always use tuples when you know your list won't need to be modified later on

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, pretty much this.

p = Vector(info['x'], info['y'], info['z'])

def snapToVertex(self,info,active=False):
p = App.Vector(info['x'],info['y'],info['z'])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spaces after commas.

if self.isEnabled("passive"):
return [p, 'endpoint', self.toWP(p)]
if self.isEnabled("Near"):
return [p,'endpoint',self.toWP(p)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spaces after commas


if (Draft.getType(obj) == "Wall"):
# special snapping for wall: snap to its base shape if it is linear
if obj.Base:
if not obj.Base.Shape.Solids:
for v in obj.Base.Shape.Vertexes:
snaps.append([v.Point, 'special', self.toWP(v.Point)])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think here you have to reduce the indentation.

def getScreenDist(self, dist, cursor):
"""Return a distance in 3D space from a screen pixels distance."""
view = Draft.get3DView()
p1 = view.getPoint(cursor)
p2 = view.getPoint((cursor[0] + dist, cursor[1]))
return (p2.sub(p1)).Length


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These methods are inside a class, so they only need one newline of space between them. For methods outside of a class, that is, functions, the spacing is two empty newlines.

plane=FreeCAD.DraftWorkingPlane,
mask=FreeCADGui.Snapper.affinity)
plane = App.DraftWorkingPlane,
mask = App.Snapper.affinity)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are key=value arguments inside a function. In this case, there should not be a space around the equals sign.

functions(key=value, one="string")

The space is needed outside of function arguments.

result = function()
b = second_f(key=result, another_key="some string")

b.setText(QtCore.QCoreApplication.translate("Draft_Snap", "Snap " + gc[11:]))
b.setToolTip(QtCore.QCoreApplication.translate("Draft_Snap", "Snap " + gc[11:]))
b.setObjectName(gc + button_suffix)
b.setWhatsThis("Draft_"+gc[11:].capitalize())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Space around plus sign.

b.setChecked(state)
# restore toolbar buttons state
if snap_modes:
for a in toolbar.findChildren(QtGui.QAction):
Copy link
Contributor

@vocx-fc vocx-fc Apr 18, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest you use better variables than a or b. Maybe action or button?

"""retuns snap toolbar object"""
mw = Gui.getMainWindow()
if mw:
toolbar = mw.findChild(QtGui.QToolBar,"Draft Snap")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Space after comma.

self.savedButtonStates.append(self.toolbarButtons[i].isChecked())
self.toolbarButtons[i].setEnabled(False)
self.saveSnapModes()
"toggle FreeCAD Draft Grid"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Triple quotes and capital letter for docstring. It should end in a dot.
"""Toggle Draft grid."""

return False

def isEnabled(self, snap):
"Returns true if the given snap is on"
Copy link
Contributor

@vocx-fc vocx-fc Apr 18, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Imperative mood.
"""Return true if the given snap is on."""



def toggle_snap(self, snap, set_to = None):
"Sets the given snap on/off according to the given parameter"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

def toggle_snap(self, snap, set_to=None):
    """Set the given snap on/off according to the given parameter."""

def setGrid(self):
"""Set the grid, if visible."""
self.setTrackers()
if self.grid and (not self.forceGridOff):
if self.grid.Visible:
self.grid.set()


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for extra newline.

Cleanup after @vocx-fc review
import FreeCADGui as Gui
import draftguitools.gui_base as gui_base

from PySide import QtGui
from PySide.QtCore import QT_TRANSLATE_NOOP
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again these imports should occur first because they are not specific to FreeCAD.



def get_snap_statusbar_widget():
"""retuns snap statusbar button"""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Imperative



def sync_snap_toolbar_button(button, status):
"""set snap toolbar button to given state"""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Capital letter at the beginning, and period at the end.


import FreeCAD as App
import FreeCADGui as Gui
from PySide import QtGui
from PySide import QtCore, QtGui
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One imported module per line.

)
custom_scale = QtGui.QInputDialog.getText(None, "Set custom scale", dialog_text)
custom_scale = QtGui.QInputDialog.getText(None, "Set custom scale",
dialog_text)
if custom_scale[1]:
print(custom_scale[0])
scale = label_to_scale(custom_scale[0])
if scale is None: return
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return must be in its own line.

gridbutton.setFlat(True)
QtCore.QObject.connect(gridbutton,QtCore.SIGNAL("clicked()"),
lambda f=Gui.doCommand,
arg='Gui.runCommand("Draft_ToggleGrid")':f(arg))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure of the syntax here. Is it supposed to be
Gui.doCommand('Gui.runCommand("Draft_ToggleGrid")')

This looks convoluted. I think you mean to run just Gui.runCommand("Draft_ToggleGrid").

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well, the fact is that I wanted the string Gui.runCommand("Draft_ToggleGrid") to be printed into the console... like if you were activating the command straight from the UI.

'Draft_Snap_Intersection', 'Draft_Snap_Perpendicular',
'Draft_Snap_Extension', 'Draft_Snap_Parallel',
'Draft_Snap_Special', 'Draft_Snap_Near',
'Draft_Snap_Ortho', 'Draft_Snap_Grid',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many of these lines have whitespace at the end that must be removed.

from draftutils.translate import _tr


# UTILITIES -----------------------------------------------------------------


def get_snap_statusbar_widget():
"""retuns snap statusbar button"""
"""Retuns snap statusbar button."""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"""Return snap statusbar button."""

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My bad, I'll correct it now!

thanks to vocx revisions
@yorikvanhavre
Copy link
Member

Thanks for the hard work and extensive reviewing guys! Merging now

@yorikvanhavre yorikvanhavre merged commit c857754 into FreeCAD:master Apr 20, 2020
@carlopav
Copy link
Contributor Author

Yuppi!!!
@vocx-fc @yorikvanhavre
Thanks guys for the support :)

@carlopav carlopav deleted the SnapStatusbar branch April 20, 2020 10:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants