diff --git a/src/Mod/Fem/femguiutils/extract_link_view.py b/src/Mod/Fem/femguiutils/extract_link_view.py index acd409765c..619ea358f1 100644 --- a/src/Mod/Fem/femguiutils/extract_link_view.py +++ b/src/Mod/Fem/femguiutils/extract_link_view.py @@ -245,9 +245,6 @@ class _SummaryWidget(QtGui.QWidget): # build the UI - self.stButton = self._button(st_object.Label) - self.stButton.setIcon(st_object.ViewObject.Icon) - self.extrButton = self._button(extr_label) self.extrButton.setIcon(extractor.ViewObject.Icon) @@ -260,6 +257,19 @@ class _SummaryWidget(QtGui.QWidget): else: self.viewButton.setIconSize(QtCore.QSize(0,0)) + if st_object: + self.stButton = self._button(st_object.Label) + self.stButton.setIcon(st_object.ViewObject.Icon) + + else: + # that happens if the source of the extractor was deleted and now + # that property is set to None + self.extrButton.hide() + self.viewButton.hide() + + self.warning = QtGui.QLabel(self) + self.warning.full_text = f"{extractor.Label}: Data source not available" + self.rmButton = QtGui.QToolButton(self) self.rmButton.setIcon(QtGui.QIcon.fromTheme("delete")) self.rmButton.setAutoRaise(True) @@ -270,13 +280,15 @@ class _SummaryWidget(QtGui.QWidget): policy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed) self.setSizePolicy(policy) - self.setMinimumSize(self.stButton.sizeHint()+self.frame.sizeHint()*3) + self.setMinimumSize(self.extrButton.sizeHint()+self.frame.sizeHint()*3) # connect actions. We add functions to widget, as well as the data we need, # and use those as callback. This way every widget knows which objects to use - self.stButton.clicked.connect(self.showVisualization) - self.extrButton.clicked.connect(self.editApp) - self.viewButton.clicked.connect(self.editView) + if st_object: + self.stButton.clicked.connect(self.showVisualization) + self.extrButton.clicked.connect(self.editApp) + self.viewButton.clicked.connect(self.editView) + self.rmButton.clicked.connect(self.deleteTriggered) # make sure initial drawing happened @@ -300,37 +312,47 @@ class _SummaryWidget(QtGui.QWidget): btn_total_size = ((self.size() - self.rmButton.size()).width() - 20) #20 is space to rmButton btn_margin = (self.rmButton.size() - self.rmButton.iconSize()).width() fm = self.fontMetrics() - min_text_width = fm.size(QtGui.Qt.TextSingleLine, "...").width()*2 - pos = 0 - btns = [self.stButton, self.extrButton, self.viewButton] - btn_rel_size = [0.4, 0.4, 0.2] - btn_elide_mode = [QtGui.Qt.ElideMiddle, QtGui.Qt.ElideMiddle, QtGui.Qt.ElideRight] - for i, btn in enumerate(btns): + if self._st_object: - btn_size = btn_total_size*btn_rel_size[i] - txt_size = btn_size - btn.iconSize().width() - btn_margin + min_text_width = fm.size(QtGui.Qt.TextSingleLine, "...").width()*2 - # we elide only if there is enough space for a meaningful text - if txt_size >= min_text_width: + pos = 0 + btns = [self.stButton, self.extrButton, self.viewButton] + btn_rel_size = [0.4, 0.4, 0.2] + btn_elide_mode = [QtGui.Qt.ElideMiddle, QtGui.Qt.ElideMiddle, QtGui.Qt.ElideRight] + for i, btn in enumerate(btns): - text = fm.elidedText(btn.full_text, btn_elide_mode[i], txt_size) - btn.setText(text) - btn.setStyleSheet("text-align:left;padding:6px"); - else: - btn.setText("") - btn.setStyleSheet("text-align:center;"); + btn_size = btn_total_size*btn_rel_size[i] + txt_size = btn_size - btn.iconSize().width() - btn_margin - rect = QtCore.QRect(pos,0, btn_size, btn.sizeHint().height()) - btn.setGeometry(rect) - pos+=btn_size + # we elide only if there is enough space for a meaningful text + if txt_size >= min_text_width: - rmsize = self.stButton.height() + text = fm.elidedText(btn.full_text, btn_elide_mode[i], txt_size) + btn.setText(text) + btn.setStyleSheet("text-align:left;padding:6px"); + else: + btn.setText("") + btn.setStyleSheet("text-align:center;"); + + rect = QtCore.QRect(pos,0, btn_size, btn.sizeHint().height()) + btn.setGeometry(rect) + pos+=btn_size + + else: + warning_txt = fm.elidedText(self.warning.full_text, QtGui.Qt.ElideRight, btn_total_size) + self.warning.setText(warning_txt) + rect = QtCore.QRect(0,0, btn_total_size, self.extrButton.sizeHint().height()) + self.warning.setGeometry(rect) + + + rmsize = self.extrButton.sizeHint().height() pos = self.size().width() - rmsize self.rmButton.setGeometry(pos, 0, rmsize, rmsize) frame_hint = self.frame.sizeHint() - rect = QtCore.QRect(0, self.stButton.height()+frame_hint.height(), self.size().width(), frame_hint.height()) + rect = QtCore.QRect(0, self.extrButton.sizeHint().height()+frame_hint.height(), self.size().width(), frame_hint.height()) self.frame.setGeometry(rect) def resizeEvent(self, event): @@ -563,6 +585,7 @@ class ExtractLinkView(QtGui.QWidget): FreeCADGui.doCommand( f"visualization = {vis_data.module}.{vis_data.factory}(FreeCAD.ActiveDocument)" ) + analysis = self._find_parent_analysis(self._object) if analysis: FreeCADGui.doCommand( @@ -576,10 +599,18 @@ class ExtractLinkView(QtGui.QWidget): FreeCADGui.doCommand( f"extraction.Source = FreeCAD.ActiveDocument.{self._object.Name}" ) + # default values: color + color_prop = FreeCADGui.ActiveDocument.ActiveObject.Proxy.get_default_color_property() + if color_prop: + FreeCADGui.doCommand( + f"extraction.ViewObject.{color_prop} = visualization.ViewObject.Proxy.get_next_default_color()" + ) + FreeCADGui.doCommand( f"visualization.addObject(extraction)" ) + self._post_dialog._recompute() self.repopulate() @@ -596,6 +627,14 @@ class ExtractLinkView(QtGui.QWidget): FreeCADGui.doCommand( f"extraction.Source = FreeCAD.ActiveDocument.{self._object.Name}" ) + + # default values: color + color_prop = FreeCADGui.ActiveDocument.ActiveObject.Proxy.get_default_color_property() + if color_prop: + FreeCADGui.doCommand( + f"extraction.ViewObject.{color_prop} = (Gui.ActiveDocument.{vis_obj.Name}.Proxy.get_next_default_color())" + ) + FreeCADGui.doCommand( f"App.ActiveDocument.{vis_obj.Name}.addObject(extraction)" ) @@ -616,6 +655,14 @@ class ExtractLinkView(QtGui.QWidget): FreeCADGui.doCommand( f"extraction.Source = FreeCAD.ActiveDocument.{post_obj.Name}" ) + + # default values for color + color_prop = FreeCADGui.ActiveDocument.ActiveObject.Proxy.get_default_color_property() + if color_prop: + FreeCADGui.doCommand( + f"extraction.ViewObject.{color_prop} = Gui.ActiveDocument.{self._object.Name}.Proxy.get_next_default_color()" + ) + FreeCADGui.doCommand( f"App.ActiveDocument.{self._object.Name}.addObject(extraction)" ) diff --git a/src/Mod/Fem/femtaskpanels/base_fempostpanel.py b/src/Mod/Fem/femtaskpanels/base_fempostpanel.py index 3e26ac1ce5..a9edb902ec 100644 --- a/src/Mod/Fem/femtaskpanels/base_fempostpanel.py +++ b/src/Mod/Fem/femtaskpanels/base_fempostpanel.py @@ -60,14 +60,6 @@ class _BasePostTaskPanel(base_femtaskpanel._BaseTaskPanel): if button == QtGui.QDialogButtonBox.Apply: self.obj.Document.recompute() - def accept(self): - print("accept") - return super().accept() - - def reject(self): - print("reject") - return super().reject() - # Helper functions # ################ diff --git a/src/Mod/Fem/femviewprovider/view_base_fempostextractors.py b/src/Mod/Fem/femviewprovider/view_base_fempostextractors.py index 46313ba890..143cd8fba5 100644 --- a/src/Mod/Fem/femviewprovider/view_base_fempostextractors.py +++ b/src/Mod/Fem/femviewprovider/view_base_fempostextractors.py @@ -118,6 +118,16 @@ class VPPostExtractor: # To be implemented by subclasses: # ################################ + def get_default_color_property(self): + # Returns the property name to set the default color to. + # Return None if no such property + raise FreeCAD.Base.FreeCADError("Not implemented") + + def get_default_field_properties(self): + # Returns the property name to which the default field name should be set + # ret: [FieldProperty, ComponentProperty] + raise FreeCAD.Base.FreeCADError("Not implemented") + def get_kw_args(self): # Returns the matplotlib plot keyword arguments that represent the # properties of the object. diff --git a/src/Mod/Fem/femviewprovider/view_base_fempostvisualization.py b/src/Mod/Fem/femviewprovider/view_base_fempostvisualization.py index 20714b67c5..b3d244b1ef 100644 --- a/src/Mod/Fem/femviewprovider/view_base_fempostvisualization.py +++ b/src/Mod/Fem/femviewprovider/view_base_fempostvisualization.py @@ -32,6 +32,7 @@ __url__ = "https://www.freecad.org" from PySide import QtGui, QtCore import Plot +import FreeCAD import FreeCADGui from . import view_base_femobject @@ -68,6 +69,8 @@ class VPPostVisualization: # Mark ourself as visible in the tree return True + def getDisplayModes(self, obj): + return ["Dialog"] def doubleClicked(self,vobj): @@ -122,3 +125,10 @@ class VPPostVisualization: def show_visualization(self): # Shows the visualization without going into edit mode raise FreeCAD.Base.FreeCADError("Not implemented") + + def get_next_default_color(self): + # Returns the next default color a new object should use + # Returns color in FreeCAD proeprty notation (r,g,b,a) + # If the relevant extractors do not have color properties, this + # can stay unimplemented + raise FreeCAD.Base.FreeCADError("Not implemented") diff --git a/src/Mod/Fem/femviewprovider/view_post_histogram.py b/src/Mod/Fem/femviewprovider/view_post_histogram.py index 2a6d817e70..69aed4101f 100644 --- a/src/Mod/Fem/femviewprovider/view_post_histogram.py +++ b/src/Mod/Fem/femviewprovider/view_post_histogram.py @@ -289,7 +289,7 @@ class VPPostHistogramFieldData(view_base_fempostextractors.VPPostExtractor): name="LineColor", group="HistogramLine", doc="The color the data bin area is drawn with", - value=(0, 85, 255, 255), + value=(0, 0, 0, 1), # black ), _GuiPropHelper( type="App::PropertyFloatConstraint", @@ -355,6 +355,9 @@ class VPPostHistogramFieldData(view_base_fempostextractors.VPPostExtractor): return kwargs + def get_default_color_property(self): + return "BarColor" + class VPPostHistogramIndexOverFrames(VPPostHistogramFieldData): """ @@ -477,8 +480,10 @@ class VPPostHistogram(view_base_fempostvisualization.VPPostVisualization): def show_visualization(self): if not hasattr(self, "_plot") or not self._plot: - main = Plot.getMainWindow() + main = FreeCADGui.getMainWindow() self._plot = Plot.Plot() + self._plot.setParent(main) + self._plot.setWindowFlags(QtGui.Qt.Dialog) self._plot.resize(main.size().height()/2, main.size().height()/3) # keep it square self.update_visualization() @@ -565,3 +570,9 @@ class VPPostHistogram(view_base_fempostvisualization.VPPostVisualization): self._plot.update() + def get_next_default_color(self): + # we use the next color in order. We do not check (yet) if this + # color is already taken + i = len(self.Object.Group) + cmap = mpl.pyplot.get_cmap("tab10") + return cmap(i) diff --git a/src/Mod/Fem/femviewprovider/view_post_lineplot.py b/src/Mod/Fem/femviewprovider/view_post_lineplot.py index 29c0165275..dfd7f2b5b4 100644 --- a/src/Mod/Fem/femviewprovider/view_post_lineplot.py +++ b/src/Mod/Fem/femviewprovider/view_post_lineplot.py @@ -354,6 +354,9 @@ class VPPostLineplotFieldData(view_base_fempostextractors.VPPostExtractor): kwargs["markersize"] = self.ViewObject.MarkerSize return kwargs + def get_default_color_property(self): + return "Color" + class VPPostLineplotIndexOverFrames(VPPostLineplotFieldData): """ @@ -387,7 +390,7 @@ class VPPostLineplot(view_base_fempostvisualization.VPPostVisualization): name="Grid", group="Lineplot", doc="If be the bars shoud show the cumulative sum left to rigth", - value=False, + value=True, ), _GuiPropHelper( type="App::PropertyEnumeration", @@ -455,8 +458,10 @@ class VPPostLineplot(view_base_fempostvisualization.VPPostVisualization): def show_visualization(self): if not hasattr(self, "_plot") or not self._plot: - main = Plot.getMainWindow() + main = FreeCADGui.getMainWindow() self._plot = Plot.Plot() + self._plot.setParent(main) + self._plot.setWindowFlags(QtGui.Qt.Dialog) self._plot.resize(main.size().height()/2, main.size().height()/3) # keep the aspect ratio self.update_visualization() @@ -481,6 +486,7 @@ class VPPostLineplot(view_base_fempostvisualization.VPPostVisualization): # we do not iterate the table, but iterate the children. This makes it possible # to attribute the correct styles + plotted = False for child in self.Object.Group: table = child.Table @@ -492,6 +498,8 @@ class VPPostLineplot(view_base_fempostvisualization.VPPostVisualization): for i in range(0,table.GetNumberOfColumns(),2): + plotted = True + # add the kw args, with some slide change over color for multiple frames tmp_args = {} for key in kwargs: @@ -534,10 +542,16 @@ class VPPostLineplot(view_base_fempostvisualization.VPPostVisualization): if self.ViewObject.YLabel: self._plot.axes.set_ylabel(self.ViewObject.YLabel) - if self.ViewObject.Legend and self.Object.Group: + if self.ViewObject.Legend and plotted: self._plot.axes.legend(loc = self.ViewObject.LegendLocation) self._plot.axes.grid(self.ViewObject.Grid) - self._plot.update() + def get_next_default_color(self): + # we use the next color in order. We do not check (yet) if this + # color is already taken + i = len(self.Object.Group) + cmap = mpl.pyplot.get_cmap("tab10") + return cmap(i) + diff --git a/src/Mod/Fem/femviewprovider/view_post_table.py b/src/Mod/Fem/femviewprovider/view_post_table.py index 443667e31a..7b07cc785f 100644 --- a/src/Mod/Fem/femviewprovider/view_post_table.py +++ b/src/Mod/Fem/femviewprovider/view_post_table.py @@ -211,6 +211,9 @@ class VPPostTableFieldData(view_base_fempostextractors.VPPostExtractor): name = self.ViewObject.Name return (QtGui.QPixmap(), name) + def get_default_color_property(self): + return None + class VPPostTableIndexOverFrames(VPPostTableFieldData): """ @@ -254,8 +257,13 @@ class VPPostTable(view_base_fempostvisualization.VPPostVisualization): def show_visualization(self): if not hasattr(self, "_tableview") or not self._tableview: + main = FreeCADGui.getMainWindow() self._tableModel = vtv.VtkTableModel() self._tableview = vtv.VtkTableView(self._tableModel) + self._tableview.setParent(main) + self._tableview.setWindowFlags(QtGui.Qt.Dialog) + self._tableview.resize(main.size().height()/2, main.size().height()/3) # keep the aspect ratio + self.update_visualization() self._tableview.show()