Browse Source

Added interface to add/remove parts on a view (with selection in tree view and/or 3D view)

master
Youen 2 years ago
parent
commit
477d49e1e8
  1. 21
      InitGui.py
  2. 8
      ahb_cmd_new_step.py
  3. 16
      ahb_cmd_view_annotate.py
  4. 62
      ahb_cmd_view_edit_source_parts.py
  5. 34
      ahb_document_observer.py
  6. 82
      ahb_techdraw_extensions.py

21
InitGui.py

@ -1,4 +1,4 @@
#sys.path.append('/usr/local/lib/python3.9/dist-packages/')
sys.path.append('/usr/local/lib/python3.9/dist-packages/')
#import pydevd
#pydevd.settrace()
@ -25,6 +25,7 @@ class AssemblyHandbookWorkbench(Gui.Workbench):
context = None
docObserver = None
docLinkObserver = None
partsCache = None
techDrawExtensions = None
@ -44,8 +45,11 @@ class AssemblyHandbookWorkbench(Gui.Workbench):
if self.context is None:
self.initializeContext()
import ahb_document_observer
if self.docLinkObserver is None:
self.docLinkObserver = ahb_document_observer.DocLinkObserver()
if self.docObserver is None:
import ahb_document_observer
self.docObserver = ahb_document_observer.DocObserver()
App.addDocumentObserver(self.docObserver)
@ -62,6 +66,14 @@ class AssemblyHandbookWorkbench(Gui.Workbench):
code which should be computed when this workbench is deactivated
"""
pass
def ContextMenu(self, recipient):
# This is executed whenever the user right-clicks on an object
# "recipient" will be either "view" or "tree"
contextMenu = ['AHB_view_edit_source_parts']
self.appendContextMenu("", "Separator")
self.appendContextMenu("", contextMenu)
self.appendContextMenu("", "Separator")
def initializeContext(self):
import ahb_context
@ -93,6 +105,11 @@ class AssemblyHandbookWorkbench(Gui.Workbench):
self.importModule('ahb_cmd_view_annotate')
toolbox.append("AHB_view_annotate")
self.importModule('ahb_cmd_view_edit_source_parts')
toolbox.append("AHB_view_edit_source_parts")
toolbox.append("AHB_view_add_source_parts")
toolbox.append("AHB_view_remove_source_parts")
if self.dev:
self.importModule('ahb_cmd_reload')

8
ahb_cmd_new_step.py

@ -64,9 +64,9 @@ class AHB_New_Step:
view = doc.addObject('TechDraw::DrawViewPart', 'View')
view.Perspective = False
view.addProperty("App::PropertyString", "AssemblyHandbook_PreviousStepView", "AssemblyHandbook")
view.addProperty("App::PropertyString", "Assembly_handbook_PreviousStepView", "Assembly_handbook")
if prev_view is not None:
view.AssemblyHandbook_PreviousStepView = prev_view.Name
view.Assembly_handbook_PreviousStepView = prev_view.Name
view.X = prev_view.X
view.Y = prev_view.Y
view.Direction = prev_view.Direction
@ -82,8 +82,8 @@ class AHB_New_Step:
# TODO: re-number next steps if needed
if prev_view is not None:
for obj in doc.Objects:
if obj != view and obj.TypeId == 'TechDraw::DrawViewPart' and 'AssemblyHandbook_PreviousStepView' in obj.PropertiesList and obj.AssemblyHandbook_PreviousStepView == prev_view.Name:
obj.AssemblyHandbook_PreviousStepView = view.Name
if obj != view and obj.TypeId == 'TechDraw::DrawViewPart' and 'Assembly_handbook_PreviousStepView' in obj.PropertiesList and obj.Assembly_handbook_PreviousStepView == prev_view.Name:
obj.Assembly_handbook_PreviousStepView = view.Name
print(obj.Label + ' has been moved after the new step')
if not page.KeepUpdated and len(view.XSource) > 0:

16
ahb_cmd_view_annotate.py

@ -29,11 +29,11 @@ class AHB_View_Annotate:
# Remove balloons referencing missing objects
for balloon in page.Views:
if balloon.TypeId == 'TechDraw::DrawViewBalloon' and "AssemblyHandbook_PartName" in balloon.PropertiesList:
if balloon.TypeId == 'TechDraw::DrawViewBalloon' and "Assembly_handbook_PartName" in balloon.PropertiesList:
if balloon.SourceView != view: continue
partLink = doc.getObject(balloon.AssemblyHandbook_PartName)
partLink = doc.getObject(balloon.Assembly_handbook_PartName)
if partLink is None or partLink not in view.XSource:
print(balloon.Name + " references missing object " + balloon.AssemblyHandbook_PartName + ", removing balloon")
print(balloon.Name + " references missing object " + balloon.Assembly_handbook_PartName + ", removing balloon")
doc.removeObject(balloon.Name)
for partLink in view.XSource:
@ -41,7 +41,7 @@ class AHB_View_Annotate:
# Search an existing balloon to update
for obj in page.Views:
if obj.TypeId == 'TechDraw::DrawViewBalloon' and "AssemblyHandbook_PartName" in obj.PropertiesList and obj.AssemblyHandbook_PartName == partLink.Name:
if obj.TypeId == 'TechDraw::DrawViewBalloon' and "Assembly_handbook_PartName" in obj.PropertiesList and obj.Assembly_handbook_PartName == partLink.Name:
if obj.SourceView != view: continue
balloon = obj
@ -52,11 +52,11 @@ class AHB_View_Annotate:
balloon = doc.addObject("TechDraw::DrawViewBalloon", "Balloon" + partName)
balloon.SourceView = view
balloon.addProperty("App::PropertyString", "AssemblyHandbook_PartName", "AssemblyHandbook")
balloon.AssemblyHandbook_PartName = partName
balloon.addProperty("App::PropertyString", "Assembly_handbook_PartName", "Assembly_handbook")
balloon.Assembly_handbook_PartName = partName
balloon.addProperty("App::PropertyFloat", "AssemblyHandbook_OriginOffsetX", "AssemblyHandbook")
balloon.addProperty("App::PropertyFloat", "AssemblyHandbook_OriginOffsetY", "AssemblyHandbook")
balloon.addProperty("App::PropertyFloat", "Assembly_handbook_OriginOffsetX", "Assembly_handbook")
balloon.addProperty("App::PropertyFloat", "Assembly_handbook_OriginOffsetY", "Assembly_handbook")
page.addView(balloon)

62
ahb_cmd_view_edit_source_parts.py

@ -0,0 +1,62 @@
import FreeCADGui as Gui
import FreeCAD as App
class AHB_EditViewSourceParts:
def GetResources(self):
return {"MenuText": "Edit view source parts",
"ToolTip": "Edits the list of parts that will be rendered in the selected TechDraw view",
"Pixmap": ""
}
def IsActive(self):
workbench = Gui.getWorkbench("AssemblyHandbookWorkbench") #: :type workbench: AssemblyHandbookWorkbench
edit_mode = workbench.techDrawExtensions.edited_view is not None
if edit_mode:
return True
else:
return len(Gui.Selection.getSelection()) == 1 and Gui.Selection.getSelection()[0].TypeId == 'TechDraw::DrawViewPart'
def Activated(self):
workbench = Gui.getWorkbench("AssemblyHandbookWorkbench") #: :type workbench: AssemblyHandbookWorkbench
view = None
if len(Gui.Selection.getSelection()) == 1 and Gui.Selection.getSelection()[0].TypeId == 'TechDraw::DrawViewPart':
view = Gui.Selection.getSelection()[0]
workbench.techDrawExtensions.toggleEditViewSourceParts(view)
class AHB_AddSourcePartsToView:
def GetResources(self):
return {"MenuText": "Add",
"ToolTip": "Adds the selected part(s) to the currently edited view",
"Pixmap": ""
}
def IsActive(self):
workbench = Gui.getWorkbench("AssemblyHandbookWorkbench") #: :type workbench: AssemblyHandbookWorkbench
edit_mode = workbench.techDrawExtensions.edited_view is not None
return edit_mode
def Activated(self):
workbench = Gui.getWorkbench("AssemblyHandbookWorkbench") #: :type workbench: AssemblyHandbookWorkbench
workbench.techDrawExtensions.editViewSourceParts(Gui.Selection.getSelection(), True)
class AHB_RemoveSourcePartsToView:
def GetResources(self):
return {"MenuText": "Remove",
"ToolTip": "Removes the selected part(s) from the currently edited view",
"Pixmap": ""
}
def IsActive(self):
workbench = Gui.getWorkbench("AssemblyHandbookWorkbench") #: :type workbench: AssemblyHandbookWorkbench
edit_mode = workbench.techDrawExtensions.edited_view is not None
return edit_mode
def Activated(self):
workbench = Gui.getWorkbench("AssemblyHandbookWorkbench") #: :type workbench: AssemblyHandbookWorkbench
workbench.techDrawExtensions.editViewSourceParts(Gui.Selection.getSelection(), False)
from ahb_command import AHB_CommandWrapper
AHB_CommandWrapper.addGuiCommand('AHB_view_edit_source_parts', AHB_EditViewSourceParts())
AHB_CommandWrapper.addGuiCommand('AHB_view_add_source_parts', AHB_AddSourcePartsToView())
AHB_CommandWrapper.addGuiCommand('AHB_view_remove_source_parts', AHB_RemoveSourcePartsToView())

34
ahb_document_observer.py

@ -1,6 +1,40 @@
import FreeCAD as App
import FreeCADGui as Gui
# Code copied from Assembly4 to select the top-most link instead of a part or sub-object when clicking in the 3D view
class DocLinkObserver:
select_link_mode = False
def __init__(self):
Gui.Selection.addObserver(self, 0) # 0 forces to resolve the links
def addSelection(self, doc, obj, sub, pnt):
# Since both 3D view clicks and manual tree selection gets into the same callback
# we will determine by clicked coordinates, for manual tree selections the coordinates are (0,0,0)
if self.select_link_mode and pnt != (0,0,0):
# 3D view click
objList = App.getDocument(doc).getObject(obj).getSubObjectList(sub)
# Build the name of the selected sub-object for multiple sub-assembly levels
subObjName = ''
# first look for the linked object of the selected entity:
# Get linked object name that handles sub-sub-assembly
for subObj in objList:
if subObj.TypeId=='App::Link':
subObjName = subObjName + subObj.Name + '.'
# if no App::Link found, let's look for other things:
if subObjName == '':
for subObj in objList:
if subObj.TypeId=='App::Part' or subObj.TypeId=='PartDesign::Body'or subObj.isDerivedFrom('Part::Feature'):
# the objList contains also the top-level object, don't count it twice
if subObj.Name != obj:
subObjName = subObjName + subObj.Name + '.'
# if we found something, make it the selection
if subObjName != '':
Gui.Selection.removeSelection(doc, obj, sub)
Gui.Selection.addSelection(doc, obj, subObjName)
#FCC.PrintMessage("*"+doc+"*"+obj+"*"+subObjName+"*\n")
# The main document observer (also observes selections)
class DocObserver:
changed_object_by_type = {}
selection_by_type = {}

82
ahb_techdraw_extensions.py

@ -61,6 +61,8 @@ class TechDrawExtensions:
updating_balloon = False
edited_view = None
def __init__(self):
workbench = Gui.getWorkbench("AssemblyHandbookWorkbench") #: :type workbench: AssemblyHandbookWorkbench
workbench.docObserver.onObjectTypeChanged('balloon_changed', 'TechDraw::DrawViewBalloon', lambda obj, prop: self.onBalloonChanged(obj, prop))
@ -71,8 +73,6 @@ class TechDrawExtensions:
QTimer.singleShot(100, self._do_repaint)
def _do_repaint(self):
import time
workbench = Gui.getWorkbench("AssemblyHandbookWorkbench") #: :type workbench: AssemblyHandbookWorkbench
to_repaint = self.views_to_repaint.keys()
@ -83,7 +83,7 @@ class TechDrawExtensions:
selected_balloons = []
for obj in Gui.Selection.getSelection():
if obj.TypeId == 'TechDraw::DrawViewBalloon' and obj.SourceView == view and 'AssemblyHandbook_PartName' in obj.PropertiesList:
if obj.TypeId == 'TechDraw::DrawViewBalloon' and obj.SourceView == view and 'Assembly_handbook_PartName' in obj.PropertiesList:
selected_balloons.append(obj)
is_first_part = True
@ -94,7 +94,7 @@ class TechDrawExtensions:
for balloon in selected_balloons:
if balloon is not None:
doc = balloon.Document
partLink = doc.getObject(balloon.AssemblyHandbook_PartName)
partLink = doc.getObject(balloon.Assembly_handbook_PartName)
part_view = workbench.partsCache.getPart2DView(view, partLink)
@ -130,7 +130,7 @@ class TechDrawExtensions:
l1 = App.Vector(line[2], line[3])
#d = abs(edgeData[0] - line[0]) + abs(edgeData[1] - line[1]) + abs(edgeData[2] - line[2]) + abs(edgeData[3] - line[3])
d = v0.distanceToLineSegment(l0, l1).Length + v1.distanceToLineSegment(l0, l1).Length
if d < 0.001:
if d < 0.01:
view.formatGeometricEdge(edgeIdx,1,0.25,(0,0.85,0),True)
is_first_part = False
@ -150,27 +150,81 @@ class TechDrawExtensions:
cursor.setViewPos(App.Vector(selected_balloons[0].OriginX, selected_balloons[0].OriginY))
cursor.setVisible(True)
def toggleEditViewSourceParts(self, view):
workbench = Gui.getWorkbench("AssemblyHandbookWorkbench") #: :type workbench: AssemblyHandbookWorkbench
button = self.getToolbarButton('AHB_view_edit_source_parts')
if self.edited_view is None:
workbench.docLinkObserver.select_link_mode = True
self.edited_view = view
button.setChecked(True)
button.setText('End source parts edition')
Gui.Selection.clearSelection()
for obj in view.XSource:
Gui.Selection.addSelection(obj)
else:
workbench.docLinkObserver.select_link_mode = False
Gui.Selection.clearSelection()
Gui.Selection.addSelection(self.edited_view)
self.edited_view = None
button.setChecked(False)
button.setText('Edit view source parts')
def editViewSourceParts(self, parts, add):
if self.edited_view is None: return
xsource = self.edited_view.XSource
modified = False
for part in parts:
if (part in xsource) != add:
if add:
xsource.append(part)
else:
xsource.remove(part)
modified = True
if modified:
self.edited_view.XSource = xsource
def getToolbarButton(self, buttonName):
mainwin = Gui.getMainWindow()
toolbar = None
for tb in mainwin.findChildren(QtGui.QToolBar):
if tb.objectName()=='Assembly Handbook':
toolbar = tb
button = None
if toolbar is not None:
for action in toolbar.actions():
if action.objectName() == buttonName:
button = action
return button
def onCursorMoved(self, view, new_pos):
if len(Gui.Selection.getSelection()) == 0: return
balloon = Gui.Selection.getSelection()[0]
if balloon.TypeId != 'TechDraw::DrawViewBalloon' or not 'AssemblyHandbook_PartName' in balloon.PropertiesList: return
if balloon.TypeId != 'TechDraw::DrawViewBalloon' or not 'Assembly_handbook_PartName' in balloon.PropertiesList: return
if balloon.SourceView != view: return
balloon.OriginX = new_pos.x
balloon.OriginY = new_pos.y
obj = balloon.Document.getObject(balloon.AssemblyHandbook_PartName)
obj = balloon.Document.getObject(balloon.Assembly_handbook_PartName)
view = balloon.SourceView
center = self.computePartCenter(view, obj)
balloon.AssemblyHandbook_OriginOffsetX = new_pos.x - center.x
balloon.AssemblyHandbook_OriginOffsetY = new_pos.y - center.y
balloon.Assembly_handbook_OriginOffsetX = new_pos.x - center.x
balloon.Assembly_handbook_OriginOffsetY = new_pos.y - center.y
def onBalloonSelected(self, operation, balloon, sub, point):
import time
#print(operation, obj.Name, sub, point)
if "AssemblyHandbook_PartName" in balloon.PropertiesList:
if "Assembly_handbook_PartName" in balloon.PropertiesList:
#print(operation + " " + balloon.Name)
view = balloon.SourceView
self.repaint(view)
@ -181,7 +235,7 @@ class TechDrawExtensions:
return
#print('Balloon changed: ' + obj.Name + '.' + prop)
if prop == 'Y' and "AssemblyHandbook_PartName" in obj.PropertiesList:
if prop == 'Y' and "Assembly_handbook_PartName" in obj.PropertiesList:
self.updating_balloon = True
self.updateBalloon(obj)
self.updating_balloon = False
@ -191,12 +245,12 @@ class TechDrawExtensions:
view = balloon.SourceView
doc = view.Document
obj = doc.getObject(balloon.AssemblyHandbook_PartName)
obj = doc.getObject(balloon.Assembly_handbook_PartName)
objectCenterView = workbench.techDrawExtensions.computePartCenter(view, obj)
balloon.OriginX = objectCenterView.x + balloon.AssemblyHandbook_OriginOffsetX
balloon.OriginY = objectCenterView.y + balloon.AssemblyHandbook_OriginOffsetY
balloon.OriginX = objectCenterView.x + balloon.Assembly_handbook_OriginOffsetX
balloon.OriginY = objectCenterView.y + balloon.Assembly_handbook_OriginOffsetY
balloon.Text = obj.LinkedObject.Document.Name if obj.TypeId == 'App::Link' else obj.Name
balloon.ViewObject.Font = 'DejaVu Sans'

Loading…
Cancel
Save