diff --git a/src/Model/Geometry/ProfileXYZ.py b/src/Model/Geometry/ProfileXYZ.py index 042bf99f..488a6bd3 100644 --- a/src/Model/Geometry/ProfileXYZ.py +++ b/src/Model/Geometry/ProfileXYZ.py @@ -17,6 +17,7 @@ # -*- coding: utf-8 -*- import queue +import types import random import logging import numpy as np @@ -842,7 +843,11 @@ class ProfileXYZ(Profile, SQLSubModel): return poly def wet_points(self, z): - left, right = self.get_water_limits(z) + limits = self.get_water_limits(z) + + if isinstance(limits, types.GeneratorType): + limits = next(limits) + left, right = limits points = list(filter(lambda p: p.z < z, self._points)) points = [left] + points + [right] diff --git a/src/View/BoundaryCondition/Edit/Window.py b/src/View/BoundaryCondition/Edit/Window.py index 1a53049d..81095dae 100644 --- a/src/View/BoundaryCondition/Edit/Window.py +++ b/src/View/BoundaryCondition/Edit/Window.py @@ -188,7 +188,10 @@ class EditBoundaryConditionWindow(PamhyrWindow): self.canvas = MplCanvas(width=5, height=4, dpi=100) self.canvas.setObjectName("canvas") self.toolbar = PamhyrPlotToolbar( - self.canvas, self + self.canvas, self, items=[ + "home", "move", "zoom", "save", + "iso", "back/forward" + ] ) self.verticalLayout.addWidget(self.toolbar) self.verticalLayout.addWidget(self.canvas) diff --git a/src/View/HydraulicStructures/PlotAC.py b/src/View/HydraulicStructures/PlotAC.py index 7c39ec19..e15efe34 100644 --- a/src/View/HydraulicStructures/PlotAC.py +++ b/src/View/HydraulicStructures/PlotAC.py @@ -42,7 +42,7 @@ class PlotAC(PamhyrPlot): self._isometric_axis = False self._auto_relim_update = True - self._autoscale_update = False + self._autoscale_update = True @property def river(self): diff --git a/src/View/HydraulicStructures/PlotRKC.py b/src/View/HydraulicStructures/PlotRKC.py index e65150d6..d8886658 100644 --- a/src/View/HydraulicStructures/PlotRKC.py +++ b/src/View/HydraulicStructures/PlotRKC.py @@ -31,6 +31,14 @@ _translate = QCoreApplication.translate class PlotRKC(PamhyrPlot): + # Class attributes: PlotRKZ (frictions) does not call this __init__ + _selected = None # Selected hydraulic structure, in blue + profile = None + line_rk_zmin = None + line_rk_zmin_zmax = None + hs_vlines = None + _hs_drawn = [] # Structures of hs_vlines, in order + def __init__(self, canvas=None, trad=None, toolbar=None, river=None, reach=None, profile=None, parent=None): @@ -134,19 +142,14 @@ class PlotRKC(PamhyrPlot): vymin = [] vymax = [] self.anotate_lst = [] + self._hs_drawn = [] hs_color = [] - index = self.parent.tableView.selectedIndexes() - for i, hs in enumerate(lhs): + for hs in lhs: section = hs.input_section if section is None: continue - if i == index[0].row(): - color = "blue" - elif hs.enabled: - color = "red" - else: - color = "darkgrey" + color = self._hs_color(hs) x = section.rk if x is not None: @@ -164,6 +167,7 @@ class PlotRKC(PamhyrPlot): vymin.append(min(z_min)) vymax.append(max(z_max)) hs_color.append(color) + self._hs_drawn.append(hs) self.hs_vlines = self.canvas.axes.vlines( x=vx, ymin=vymin, ymax=vymax, @@ -172,6 +176,28 @@ class PlotRKC(PamhyrPlot): color=hs_color, ) + def _hs_color(self, hs): + if hs is self._selected: + return "blue" + if hs.enabled: + return "red" + return "darkgrey" + + def set_selected(self, hs): + """Draw the selected structure in blue, without redrawing the + plot (the view is kept)""" + self._selected = hs + if self.hs_vlines is None: + return + + colors = [self._hs_color(h) for h in self._hs_drawn] + if colors: + self.hs_vlines.set_color(colors) + for annotation, color in zip(self.anotate_lst, colors): + annotation.set_color(color) + + self.canvas.figure.canvas.draw_idle() + def color_highlight(self, highlight): reach = self._current_reach @@ -255,7 +281,8 @@ class PlotRKC(PamhyrPlot): closest = self._closest_profile(event) index = self.parent.tableView.selectedIndexes() - if self.parent._table is not None: + # Moves the selected structure: nothing to do without selection + if self.parent._table is not None and len(index) > 2: self.parent._table.setData(index[2], closest) return diff --git a/src/View/HydraulicStructures/Window.py b/src/View/HydraulicStructures/Window.py index 734b1a65..361c87fb 100644 --- a/src/View/HydraulicStructures/Window.py +++ b/src/View/HydraulicStructures/Window.py @@ -130,11 +130,13 @@ class HydraulicStructuresWindow(PamhyrWindow): self._checkbox = self.find(QCheckBox, f"checkBox") self._set_checkbox_state() + _toolbar_items = ["home", "move", "zoom", "save", "iso", "back/forward"] + def setup_plots(self): self.canvas = MplCanvas(width=5, height=4, dpi=100) self.canvas.setObjectName("canvas") self.toolbar = PamhyrPlotToolbar( - self.canvas, self + self.canvas, self, items=self._toolbar_items ) self.plot_layout = self.find(QVBoxLayout, "verticalLayout") self.plot_layout.addWidget(self.toolbar) @@ -143,7 +145,7 @@ class HydraulicStructuresWindow(PamhyrWindow): self.plot_rkc = PlotRKC( canvas=self.canvas, river=self._study.river, - reach=None, + reach=self._displayed_reach(None), profile=None, trad=self._trad, toolbar=self.toolbar, @@ -154,7 +156,7 @@ class HydraulicStructuresWindow(PamhyrWindow): self.canvas_2 = MplCanvas(width=5, height=4, dpi=100) self.canvas_2.setObjectName("canvas_2") self.toolbar_2 = PamhyrPlotToolbar( - self.canvas_2, self + self.canvas_2, self, items=self._toolbar_items ) self.plot_layout_2 = self.find(QVBoxLayout, "verticalLayout_2") self.plot_layout_2.addWidget(self.toolbar_2) @@ -183,7 +185,7 @@ class HydraulicStructuresWindow(PamhyrWindow): table = self.find(QTableView, "tableView") table.selectionModel()\ .selectionChanged\ - .connect(self.update) + .connect(self.update_selection) self._table.dataChanged.connect(self.update) self._table.layoutChanged.connect(self.update) @@ -283,10 +285,17 @@ class HydraulicStructuresWindow(PamhyrWindow): ) def update(self): + """Data changed: plots redrawn, fitted to their data""" self._set_checkbox_state() - self._update_clear_plot() + self._update_plots(redraw=True) - def _update_clear_plot(self): + def update_selection(self): + """Selection changed: the selected structure is drawn in blue, + the view is kept (unless its reach is another one)""" + self._set_checkbox_state() + self._update_plots(redraw=False) + + def _selected_structure(self): rows = self.index_selected_rows() if (len(rows) == 0 or diff --git a/src/View/InitialConditions/Table.py b/src/View/InitialConditions/Table.py index 6ee0b9a3..f7bc0251 100644 --- a/src/View/InitialConditions/Table.py +++ b/src/View/InitialConditions/Table.py @@ -384,9 +384,19 @@ class InitialConditionTableModel(PamhyrTableModel): self.layoutChanged.emit() def generate(self, generator, param, option): + self.layoutAboutToBeChanged.emit() + + self._undo.beginMacro(f"generate {generator}") self._undo.push( GenerateCommand( self._lst, generator, param, option ) ) + self._undo.push( + SortCommand( + self._lst, False + ) + ) + self._undo.endMacro() + self.layoutChanged.emit() diff --git a/src/View/InitialConditions/UndoCommand.py b/src/View/InitialConditions/UndoCommand.py index d5af00f5..95f1ee47 100644 --- a/src/View/InitialConditions/UndoCommand.py +++ b/src/View/InitialConditions/UndoCommand.py @@ -100,15 +100,19 @@ class SortCommand(QUndoCommand): self._indexes = None def undo(self): - ll = self._ics.data + order = { + id(x): self._indexes[i] + for i, x in enumerate(self._ics.data) + } self._ics.sort( - key=lambda x: self._indexes[ll.index(x)] + key=lambda x: order.get(id(x), len(order)) ) def redo(self): self._ics.sort( reverse=self._reverse, - key=lambda x: x["rk"].rk + key=lambda x: ((x["rk"] is None), + 0.0 if x["rk"] is None else x["rk"].rk) ) if self._indexes is None: self._indexes = list( @@ -182,11 +186,19 @@ class GenerateCommand(QUndoCommand): self._ics = ics self._param = param self._option = option - self._copy = self._ics.data + # All the rows, with their deleted flag: the generation marks the + # previous rows as deleted (clear_data) + self._copy = list(self._ics._data) + self._deleted = [d.is_deleted() for d in self._copy] self._generator = generator def undo(self): - self._ics.data = self._copy + for data, deleted in zip(self._copy, self._deleted): + if deleted: + data.set_as_deleted() + else: + data.set_as_not_deleted() + self._ics.data = list(self._copy) def redo(self): if self._generator == "growing":