mirror of https://gitlab.com/pamhyr/pamhyr2
Merge branch 'new_design_main_page' into dev_dylan
commit
6d4dc3a22b
|
|
@ -61,6 +61,7 @@ from View.WaitingDialog import WaitingDialog
|
||||||
|
|
||||||
from View.MainWindowTabInfo import WidgetInfo
|
from View.MainWindowTabInfo import WidgetInfo
|
||||||
from View.MainWindowTabChecker import WidgetChecker
|
from View.MainWindowTabChecker import WidgetChecker
|
||||||
|
from View.MainWindowTabGraph import WidgetGraph
|
||||||
|
|
||||||
from View.Configure.Window import ConfigureWindow
|
from View.Configure.Window import ConfigureWindow
|
||||||
from View.Study.Window import NewStudyWindow
|
from View.Study.Window import NewStudyWindow
|
||||||
|
|
@ -235,6 +236,7 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||||
|
|
||||||
def setup_tab(self):
|
def setup_tab(self):
|
||||||
self.setup_tab_info()
|
self.setup_tab_info()
|
||||||
|
self.setup_tab_graph()
|
||||||
self.setup_tab_checker()
|
self.setup_tab_checker()
|
||||||
|
|
||||||
def setup_tab_info(self):
|
def setup_tab_info(self):
|
||||||
|
|
@ -261,6 +263,19 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||||
self._trad["tab_checker_name"]
|
self._trad["tab_checker_name"]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def setup_tab_graph(self):
|
||||||
|
tab_widget = self.findChild(QTabWidget, "tabWidget")
|
||||||
|
|
||||||
|
self._tab_widget_graph = WidgetGraph(
|
||||||
|
study=self._study, trad=self._trad, parent=self
|
||||||
|
)
|
||||||
|
|
||||||
|
tab_widget.insertTab(
|
||||||
|
0, self._tab_widget_graph,
|
||||||
|
self._trad["tab_graph_name"]
|
||||||
|
)
|
||||||
|
tab_widget.setCurrentWidget(self._tab_widget_graph)
|
||||||
|
|
||||||
def enable_actions(self, action: str, enable: bool):
|
def enable_actions(self, action: str, enable: bool):
|
||||||
"""Enable of disable an action componant
|
"""Enable of disable an action componant
|
||||||
|
|
||||||
|
|
@ -545,6 +560,7 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||||
self._do_propagate_update_rec(window, keys)
|
self._do_propagate_update_rec(window, keys)
|
||||||
|
|
||||||
self._tab_widget_checker.update(modules=keys)
|
self._tab_widget_checker.update(modules=keys)
|
||||||
|
self._tab_widget_graph.update()
|
||||||
|
|
||||||
def _do_propagate_update_info_tab(self, keys):
|
def _do_propagate_update_info_tab(self, keys):
|
||||||
modules = Modules.modelling_list()
|
modules = Modules.modelling_list()
|
||||||
|
|
@ -570,6 +586,10 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||||
self._tab_widget_info.study = self._study
|
self._tab_widget_info.study = self._study
|
||||||
self._tab_widget_info.update()
|
self._tab_widget_info.update()
|
||||||
|
|
||||||
|
if self._tab_widget_graph.study != self._study:
|
||||||
|
self._tab_widget_graph.study = self._study
|
||||||
|
self._tab_widget_graph.update()
|
||||||
|
|
||||||
if self._tab_widget_checker.study != self._study:
|
if self._tab_widget_checker.study != self._study:
|
||||||
self._tab_widget_checker.study = self._study
|
self._tab_widget_checker.study = self._study
|
||||||
self._tab_widget_checker.update(modules=Modules.STUDY)
|
self._tab_widget_checker.update(modules=Modules.STUDY)
|
||||||
|
|
@ -1287,6 +1307,9 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
||||||
return
|
return
|
||||||
|
|
||||||
self.network = NetworkWindow(study=self._study, parent=self)
|
self.network = NetworkWindow(study=self._study, parent=self)
|
||||||
|
self.network.networkChanged.connect(
|
||||||
|
self._tab_widget_graph.update, Qt.QueuedConnection
|
||||||
|
)
|
||||||
self.network.show()
|
self.network.show()
|
||||||
|
|
||||||
def open_scenarios(self):
|
def open_scenarios(self):
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,139 @@
|
||||||
|
# MainWindowTabGraph.py -- Pamhyr
|
||||||
|
# Copyright (C) 2026 INRAE
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from View.Tools.Plot.PamhyrCanvas import MplCanvas
|
||||||
|
from View.Tools.Plot.PamhyrToolbar import PamhyrPlotToolbar
|
||||||
|
from View.PlotXY import PlotXY
|
||||||
|
from View.Network.GraphWidget import GraphWidget
|
||||||
|
|
||||||
|
from PyQt5.QtCore import Qt
|
||||||
|
from PyQt5.QtWidgets import (
|
||||||
|
QWidget, QGroupBox, QLabel, QHBoxLayout, QVBoxLayout, QSplitter,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class WidgetGraph(QWidget):
|
||||||
|
"""Read-only network graph displayed in the main window."""
|
||||||
|
|
||||||
|
def __init__(self, study=None, trad=None, parent=None):
|
||||||
|
super(WidgetGraph, self).__init__(parent)
|
||||||
|
|
||||||
|
self._study = study
|
||||||
|
self._trad = trad
|
||||||
|
self._plot_river = None
|
||||||
|
|
||||||
|
layout = QHBoxLayout(self)
|
||||||
|
self._splitter = QSplitter(Qt.Horizontal, self)
|
||||||
|
self._splitter.setChildrenCollapsible(False)
|
||||||
|
layout.addWidget(self._splitter)
|
||||||
|
self._graph_widget = None
|
||||||
|
|
||||||
|
self._graph_group = QGroupBox(
|
||||||
|
self._trad["graph_network_title"], self
|
||||||
|
)
|
||||||
|
self._graph_layout = QVBoxLayout(self._graph_group)
|
||||||
|
|
||||||
|
self._graph_title = QLabel(self._graph_group)
|
||||||
|
self._graph_title.setTextFormat(Qt.PlainText)
|
||||||
|
self._graph_title.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
|
||||||
|
self._graph_title.setWordWrap(True)
|
||||||
|
self._graph_layout.addWidget(self._graph_title)
|
||||||
|
self._update_graph_title()
|
||||||
|
self._splitter.addWidget(self._graph_group)
|
||||||
|
|
||||||
|
self.canvas = MplCanvas(width=5, height=4, dpi=100)
|
||||||
|
self.canvas.setObjectName("canvas_graph")
|
||||||
|
self.toolbar = PamhyrPlotToolbar(
|
||||||
|
self.canvas, self,
|
||||||
|
items=["home", "zoom", "save", "iso", "back/forward", "move"]
|
||||||
|
)
|
||||||
|
self._plot_group = QGroupBox(
|
||||||
|
self._trad["graph_geographic_title"], self
|
||||||
|
)
|
||||||
|
self._plot_layout = QVBoxLayout(self._plot_group)
|
||||||
|
self._plot_layout.addWidget(self.toolbar)
|
||||||
|
self._plot_layout.addWidget(self.canvas, 1)
|
||||||
|
self._splitter.addWidget(self._plot_group)
|
||||||
|
self._splitter.setStretchFactor(0, 1)
|
||||||
|
self._splitter.setStretchFactor(1, 1)
|
||||||
|
self._splitter.setSizes([1000, 1000])
|
||||||
|
|
||||||
|
self.plot = PlotXY(
|
||||||
|
canvas=self.canvas,
|
||||||
|
data=None,
|
||||||
|
trad=self._trad,
|
||||||
|
toolbar=self.toolbar,
|
||||||
|
parent=self
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def study(self):
|
||||||
|
return self._study
|
||||||
|
|
||||||
|
@study.setter
|
||||||
|
def study(self, study):
|
||||||
|
self._study = study
|
||||||
|
self._update_graph_title()
|
||||||
|
|
||||||
|
def _update_graph_title(self):
|
||||||
|
self._graph_title.setText(
|
||||||
|
self._study.name if self._study is not None else ""
|
||||||
|
)
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
river = self._study.river if self._study is not None else None
|
||||||
|
view = None
|
||||||
|
if river is not None and river is self._plot_river:
|
||||||
|
axes = self.canvas.axes
|
||||||
|
if axes.has_data():
|
||||||
|
view = (axes.get_xlim(), axes.get_ylim(),
|
||||||
|
axes.get_aspect(), axes.get_adjustable())
|
||||||
|
|
||||||
|
self._update_graph_title()
|
||||||
|
if (self._graph_widget is not None
|
||||||
|
and (self._study is None
|
||||||
|
or self._graph_widget.graph is not self._study.river)):
|
||||||
|
self._graph_layout.removeWidget(self._graph_widget)
|
||||||
|
self._graph_widget.deleteLater()
|
||||||
|
self._graph_widget = None
|
||||||
|
|
||||||
|
if self._study is not None and self._graph_widget is None:
|
||||||
|
self._graph_widget = GraphWidget(
|
||||||
|
self._study.river,
|
||||||
|
parent=self,
|
||||||
|
only_display=True,
|
||||||
|
trad=self._trad,
|
||||||
|
)
|
||||||
|
self._graph_layout.addWidget(self._graph_widget, 1)
|
||||||
|
elif self._graph_widget is not None:
|
||||||
|
self._graph_widget.display_update()
|
||||||
|
|
||||||
|
data = None
|
||||||
|
geotiff = None
|
||||||
|
if self._study is not None:
|
||||||
|
data = self._study.river.enable_edges()
|
||||||
|
geotiff = self._study.river.geotiff
|
||||||
|
|
||||||
|
self.plot = PlotXY(
|
||||||
|
canvas=self.canvas,
|
||||||
|
data=data,
|
||||||
|
geotiff=geotiff,
|
||||||
|
trad=self._trad,
|
||||||
|
toolbar=self.toolbar,
|
||||||
|
parent=self
|
||||||
|
)
|
||||||
|
self.plot.update()
|
||||||
|
self._plot_river = river
|
||||||
|
if view is not None:
|
||||||
|
x_limits, y_limits, aspect, adjustable = view
|
||||||
|
self.canvas.axes.set_aspect(aspect, adjustable=adjustable)
|
||||||
|
self.canvas.axes.set_xlim(x_limits)
|
||||||
|
self.canvas.axes.set_ylim(y_limits)
|
||||||
|
self.canvas.draw_idle()
|
||||||
|
|
@ -448,6 +448,7 @@ class NewEdgeLine(QGraphicsItem):
|
||||||
class GraphWidget(QGraphicsView):
|
class GraphWidget(QGraphicsView):
|
||||||
changeEdge = pyqtSignal(object)
|
changeEdge = pyqtSignal(object)
|
||||||
changeNode = pyqtSignal(object)
|
changeNode = pyqtSignal(object)
|
||||||
|
currentEdgeChanged = pyqtSignal()
|
||||||
|
|
||||||
def __init__(self, graph, parent=None,
|
def __init__(self, graph, parent=None,
|
||||||
min_size=(400, 400), max_size=None,
|
min_size=(400, 400), max_size=None,
|
||||||
|
|
@ -476,6 +477,7 @@ class GraphWidget(QGraphicsView):
|
||||||
self.m_origin_x = 0.0
|
self.m_origin_x = 0.0
|
||||||
self.m_origin_y = 0.0
|
self.m_origin_y = 0.0
|
||||||
self.clicked = False
|
self.clicked = False
|
||||||
|
self._panning = False
|
||||||
|
|
||||||
self.setup_scene(min_size, max_size, size)
|
self.setup_scene(min_size, max_size, size)
|
||||||
|
|
||||||
|
|
@ -491,8 +493,8 @@ class GraphWidget(QGraphicsView):
|
||||||
self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
|
self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
|
||||||
self.setResizeAnchor(QGraphicsView.AnchorViewCenter)
|
self.setResizeAnchor(QGraphicsView.AnchorViewCenter)
|
||||||
|
|
||||||
self.scale(1, 1)
|
self.scale(0.7, 0.7)
|
||||||
self.previousScale = 1
|
self.previousScale = 0.7
|
||||||
self.centerOn(1000.0, 1000.0)
|
self.centerOn(1000.0, 1000.0)
|
||||||
|
|
||||||
if min_size:
|
if min_size:
|
||||||
|
|
@ -667,6 +669,13 @@ class GraphWidget(QGraphicsView):
|
||||||
Returns:
|
Returns:
|
||||||
Nothing
|
Nothing
|
||||||
"""
|
"""
|
||||||
|
# Scene items are destroyed by clear(); do not retain hover/selection
|
||||||
|
# references to them when refreshing another view of the same graph.
|
||||||
|
self._selected_item = None
|
||||||
|
self._selected_new_edge_src_node = None
|
||||||
|
self._current_edge = None
|
||||||
|
self._current_moved_node = None
|
||||||
|
self.tmp_line = None
|
||||||
self.scene().clear()
|
self.scene().clear()
|
||||||
self.create_items()
|
self.create_items()
|
||||||
|
|
||||||
|
|
@ -875,6 +884,9 @@ class GraphWidget(QGraphicsView):
|
||||||
|
|
||||||
if previous_edge:
|
if previous_edge:
|
||||||
previous_edge.update()
|
previous_edge.update()
|
||||||
|
edge.update()
|
||||||
|
if previous_edge is not edge:
|
||||||
|
self.currentEdgeChanged.emit()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(str(e))
|
logger.warning(str(e))
|
||||||
|
|
||||||
|
|
@ -937,6 +949,8 @@ class GraphWidget(QGraphicsView):
|
||||||
|
|
||||||
def mousePressEvent(self, event):
|
def mousePressEvent(self, event):
|
||||||
if self._only_display:
|
if self._only_display:
|
||||||
|
if event.button() == Qt.LeftButton:
|
||||||
|
self._start_pan(event)
|
||||||
return
|
return
|
||||||
|
|
||||||
if event.button() == Qt.RightButton \
|
if event.button() == Qt.RightButton \
|
||||||
|
|
@ -959,6 +973,12 @@ class GraphWidget(QGraphicsView):
|
||||||
self._selected_new_edge_src_node = None
|
self._selected_new_edge_src_node = None
|
||||||
|
|
||||||
items = self.items(event.pos())
|
items = self.items(event.pos())
|
||||||
|
if event.button() == Qt.LeftButton and not any(
|
||||||
|
isinstance(item, (NodeItem, EdgeItem, NodeText))
|
||||||
|
for item in items
|
||||||
|
):
|
||||||
|
self._start_pan(event)
|
||||||
|
return
|
||||||
if items and type(items[0]) is EdgeItem:
|
if items and type(items[0]) is EdgeItem:
|
||||||
edge = items[0]
|
edge = items[0]
|
||||||
if edge:
|
if edge:
|
||||||
|
|
@ -1007,7 +1027,10 @@ class GraphWidget(QGraphicsView):
|
||||||
def mouseReleaseEvent(self, event):
|
def mouseReleaseEvent(self, event):
|
||||||
self.clicked = False
|
self.clicked = False
|
||||||
|
|
||||||
if self._only_display:
|
if self._panning or self._only_display:
|
||||||
|
self._panning = False
|
||||||
|
self.viewport().unsetCursor()
|
||||||
|
event.accept()
|
||||||
return
|
return
|
||||||
|
|
||||||
locked = self.graph._status.is_read_only()
|
locked = self.graph._status.is_read_only()
|
||||||
|
|
@ -1029,7 +1052,28 @@ class GraphWidget(QGraphicsView):
|
||||||
self.update()
|
self.update()
|
||||||
super(GraphWidget, self).mouseReleaseEvent(event)
|
super(GraphWidget, self).mouseReleaseEvent(event)
|
||||||
|
|
||||||
|
def _start_pan(self, event):
|
||||||
|
self.clicked = True
|
||||||
|
self._panning = True
|
||||||
|
self.m_origin_x = event.x()
|
||||||
|
self.m_origin_y = event.y()
|
||||||
|
self.viewport().setCursor(Qt.ClosedHandCursor)
|
||||||
|
event.accept()
|
||||||
|
|
||||||
def mouseMoveEvent(self, event):
|
def mouseMoveEvent(self, event):
|
||||||
|
if self._panning or self._only_display:
|
||||||
|
if self._panning and event.buttons() & Qt.LeftButton:
|
||||||
|
dx = event.x() - self.m_origin_x
|
||||||
|
dy = event.y() - self.m_origin_y
|
||||||
|
horizontal = self.horizontalScrollBar()
|
||||||
|
vertical = self.verticalScrollBar()
|
||||||
|
horizontal.setValue(horizontal.value() - dx)
|
||||||
|
vertical.setValue(vertical.value() - dy)
|
||||||
|
self.m_origin_x = event.x()
|
||||||
|
self.m_origin_y = event.y()
|
||||||
|
event.accept()
|
||||||
|
return
|
||||||
|
|
||||||
pos = self.mapToScene(event.pos())
|
pos = self.mapToScene(event.pos())
|
||||||
locked = self.graph._status.is_read_only()
|
locked = self.graph._status.is_read_only()
|
||||||
|
|
||||||
|
|
@ -1061,20 +1105,6 @@ class GraphWidget(QGraphicsView):
|
||||||
|
|
||||||
# If state is "move"
|
# If state is "move"
|
||||||
if self._state == "move":
|
if self._state == "move":
|
||||||
# Move on scene
|
|
||||||
if not self.selected_item():
|
|
||||||
if event.buttons() & Qt.LeftButton:
|
|
||||||
old_p = self.mapToScene(
|
|
||||||
int(self.m_origin_x), int(self.m_origin_y)
|
|
||||||
)
|
|
||||||
new_p = self.mapToScene(event.pos())
|
|
||||||
translation = new_p - old_p
|
|
||||||
|
|
||||||
self.translate(translation.x(), translation.y())
|
|
||||||
|
|
||||||
self.m_origin_x = event.x()
|
|
||||||
self.m_origin_y = event.y()
|
|
||||||
|
|
||||||
# Propagate event
|
# Propagate event
|
||||||
self.update()
|
self.update()
|
||||||
super(GraphWidget, self).mouseMoveEvent(event)
|
super(GraphWidget, self).mouseMoveEvent(event)
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,8 @@ _translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
|
||||||
class NetworkWindow(PamhyrWindow):
|
class NetworkWindow(PamhyrWindow):
|
||||||
|
networkChanged = pyqtSignal()
|
||||||
|
|
||||||
_pamhyr_ui = "Network"
|
_pamhyr_ui = "Network"
|
||||||
_pamhyr_name = "River network"
|
_pamhyr_name = "River network"
|
||||||
|
|
||||||
|
|
@ -140,6 +142,8 @@ class NetworkWindow(PamhyrWindow):
|
||||||
self._graph_layout.addWidget(self._graph_widget)
|
self._graph_layout.addWidget(self._graph_widget)
|
||||||
|
|
||||||
def setup_connections(self):
|
def setup_connections(self):
|
||||||
|
self._undo_stack.indexChanged.connect(self.networkChanged)
|
||||||
|
self._graph_widget.currentEdgeChanged.connect(self.networkChanged)
|
||||||
self._nodes_model.dataChanged.connect(self.update)
|
self._nodes_model.dataChanged.connect(self.update)
|
||||||
self._reachs_model.dataChanged.connect(
|
self._reachs_model.dataChanged.connect(
|
||||||
self._graph_widget.display_update)
|
self._graph_widget.display_update)
|
||||||
|
|
|
||||||
|
|
@ -175,6 +175,15 @@ class MainTranslate(UnitTranslate):
|
||||||
self._dict["tab_checker_name"] = _translate(
|
self._dict["tab_checker_name"] = _translate(
|
||||||
"MainWindow", "Checks"
|
"MainWindow", "Checks"
|
||||||
)
|
)
|
||||||
|
self._dict["tab_graph_name"] = _translate(
|
||||||
|
"MainWindow", "Graph"
|
||||||
|
)
|
||||||
|
self._dict["graph_network_title"] = _translate(
|
||||||
|
"MainWindow", "Hydrographic network"
|
||||||
|
)
|
||||||
|
self._dict["graph_geographic_title"] = _translate(
|
||||||
|
"MainWindow", "Geographic view"
|
||||||
|
)
|
||||||
|
|
||||||
self._dict["open_debug"] = _translate(
|
self._dict["open_debug"] = _translate(
|
||||||
"MainWindow", "Open debug window"
|
"MainWindow", "Open debug window"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue