forked from youen/assembly_handbook
Added interface to add/remove parts on a view (with selection in tree view and/or 3D view)
This commit is contained in:
parent
339ebba88e
commit
477d49e1e8
21
InitGui.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)
|
||||
|
||||
@ -63,6 +67,14 @@ class AssemblyHandbookWorkbench(Gui.Workbench):
|
||||
"""
|
||||
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
|
||||
self.context = ahb_context.AHB_Context()
|
||||
@ -94,6 +106,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')
|
||||
toolbox.append("AHB_reload")
|
||||
|
@ -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:
|
||||
|
@ -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
Normal file
62
ahb_cmd_view_edit_source_parts.py
Normal file
@ -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())
|
@ -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 = {}
|
||||
|
@ -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…
Reference in New Issue
Block a user