From 4274d5117d17e60fa2fa0ae7e4332cd4ca6c41a9 Mon Sep 17 00:00:00 2001 From: paule32 Date: Sun, 17 Nov 2024 18:26:37 +0100 Subject: [PATCH] update --- src/build.bat | 85 ++++++- src/build.bat.bak | 241 +++++++++++-------- src/locales/de_de/LC_MESSAGES/observer.mo.gz | Bin 60461 -> 60461 bytes src/locales/en_us/LC_MESSAGES/observer.mo.gz | Bin 56086 -> 56086 bytes src/observer.py | 225 ++++++++++++++++- 5 files changed, 436 insertions(+), 115 deletions(-) diff --git a/src/build.bat b/src/build.bat index 953b5cd..1e3b13c 100644 --- a/src/build.bat +++ b/src/build.bat @@ -30,14 +30,95 @@ set PO=msgfmt.exe ::if not exists %PY%\python.exe goto pythonSetup :buildApp set BASEDIR=%cd% -%PY% -V ::set PYTHONPATH= ::%PY%\Lib;%PY%\Lib\site-packagesss ::set PYTHONHOME= -set PRJ=T:/a/HelpNDocTools/HelpNDocTools/src +set SRC=%BASEDIR%/src +set VPA=%BASEDIR%/venv + +:: --------------------------------------------------------------------------- +:: check, if Python is installed ... +:: --------------------------------------------------------------------------- +echo try to setup develop system... +python3 --version >nul 2>&1 +if errorlevel 1 ( + echo Python is not installed. Please install Python and try again. + pause + exit /b 1 +) + +:: --------------------------------------------------------------------------- +:: create virtual user environment... +:: --------------------------------------------------------------------------- +python3 -m venv venv +if errorlevel 1 ( + echo "Error: can not setup the virtual environment." + pause + exit /b 1 +) + +for /f "tokens=2 delims=:." %%a in ('"%SystemRoot%\System32\chcp.com"') do ( + set _OLD_CODEPAGE=%%a +) +if defined _OLD_CODEPAGE ( + "%SystemRoot%\System32\chcp.com" 65001 > nul +) + +set VIRTUAL_ENV=%BASEDIR%\venv + +if not defined PROMPT set PROMPT=$P$G + +if defined _OLD_VIRTUAL_PROMPT set PROMPT=%_OLD_VIRTUAL_PROMPT% +if defined _OLD_VIRTUAL_PYTHONHOME set PYTHONHOME=%_OLD_VIRTUAL_PYTHONHOME% + +set "_OLD_VIRTUAL_PROMPT=%PROMPT%" +set "PROMPT=(venv) %PROMPT%" + +if defined PYTHONHOME set _OLD_VIRTUAL_PYTHONHOME=%PYTHONHOME% +set PYTHONHOME= + +if defined _OLD_VIRTUAL_PATH set PATH=%_OLD_VIRTUAL_PATH% +if not defined _OLD_VIRTUAL_PATH set _OLD_VIRTUAL_PATH=%PATH% + +set PATH=%VIRTUAL_ENV%\Scripts;%PATH% +set VIRTUAL_ENV_PROMPT=venv + +cd %BASEDIR%\venv\Scripts +dir + +:: --------------------------------------------------------------------------- +:: check, if pip3 is installed ... +:: --------------------------------------------------------------------------- +python -m pip install --upgrade pip >nul 2>&1 +if errorlevel 1 ( + echo pip is not installed. Try to install pip... + python -m ensurepip + if errorlevel 1 ( + echo Error: could not install pip. Please install it manually. + pause + exit /b 1 + ) +) +python -m pip install --upgrade pip +python -m pip install ast >nul 2>&1 + +echo install requirements... +python -m pip install -r requirements.txt +if errorlevel 1 ( + echo Error: could not install requirement's. + pause + exit /b 1 +) + +:: --------------------------------------------------------------------------- +:: install windows stuff ... +:: --------------------------------------------------------------------------- +pip install pywin32 +python -m pywin32_postinstall -install echo remove old data... +exit rm -rf build rm -rf dist diff --git a/src/build.bat.bak b/src/build.bat.bak index 16d9266..ee9b745 100644 --- a/src/build.bat.bak +++ b/src/build.bat.bak @@ -19,10 +19,9 @@ set APP=observer :: Python 3.1.0 - there should be a Tools directory which comes with the :: official installation files. :: --------------------------------------------------------------------------- -set PY=E:\Python312 -set PO=%PY%\Tools\i18n\msgfmt.py -set PX=%PY%\python.exe -::set PATH=%PY%;%PATH% +set PY=python.exe +set PO=msgfmt.exe + :: --------------------------------------------------------------------------- :: First, check if python is installed. If not, try to install it, else try to :: create the application. @@ -31,14 +30,92 @@ set PX=%PY%\python.exe ::if not exists %PY%\python.exe goto pythonSetup :buildApp set BASEDIR=%cd% -%PX% -V ::set PYTHONPATH= ::%PY%\Lib;%PY%\Lib\site-packagesss ::set PYTHONHOME= -set PRJ=E:/Projekte/HelpNDocTools +set SRC=%BASEDIR%/src +set VPA=%BASEDIR%/venv + +:: --------------------------------------------------------------------------- +:: check, if Python is installed ... +:: --------------------------------------------------------------------------- +echo try to setup develop system... +python3 --version >nul 2>&1 +if errorlevel 1 ( + echo Python is not installed. Please install Python and try again. + pause + exit /b 1 +) + +:: --------------------------------------------------------------------------- +:: create virtual user environment... +:: --------------------------------------------------------------------------- +python3 -m venv venv +if errorlevel 1 ( + echo "Error: can not setup the virtual environment." + pause + exit /b 1 +) + +for /f "tokens=2 delims=:." %%a in ('"%SystemRoot%\System32\chcp.com"') do ( + set _OLD_CODEPAGE=%%a +) +if defined _OLD_CODEPAGE ( + "%SystemRoot%\System32\chcp.com" 65001 > nul +) + +set VIRTUAL_ENV=%BASEDIR%\venv + +if not defined PROMPT set PROMPT=$P$G + +if defined _OLD_VIRTUAL_PROMPT set PROMPT=%_OLD_VIRTUAL_PROMPT% +if defined _OLD_VIRTUAL_PYTHONHOME set PYTHONHOME=%_OLD_VIRTUAL_PYTHONHOME% + +set "_OLD_VIRTUAL_PROMPT=%PROMPT%" +set "PROMPT=(venv) %PROMPT%" + +if defined PYTHONHOME set _OLD_VIRTUAL_PYTHONHOME=%PYTHONHOME% +set PYTHONHOME= + +if defined _OLD_VIRTUAL_PATH set PATH=%_OLD_VIRTUAL_PATH% +if not defined _OLD_VIRTUAL_PATH set _OLD_VIRTUAL_PATH=%PATH% + +set PATH=%VIRTUAL_ENV%\Scripts;%PATH% +set VIRTUAL_ENV_PROMPT=venv + +cd %BASEDIR%\venv\Scripts +dir + +:: --------------------------------------------------------------------------- +:: check, if pip3 is installed ... +:: --------------------------------------------------------------------------- +python -m pip install --upgrade pip >nul 2>&1 +if errorlevel 1 ( + echo pip is not installed. Try to install pip... + python -m ensurepip + if errorlevel 1 ( + echo Error: could not install pip. Please install it manually. + pause + exit /b 1 + ) +) +python -m pip install --upgrade pip +python -m pip install ast + +echo install requirements... +python -m pip install -r requirements.txt +if errorlevel 1 ( + echo Error: could not install requirement's. + pause + exit /b 1 +) + +pip install pywin32 +python -m pywin32_postinstall echo remove old data... +exit rm -rf build rm -rf dist @@ -61,115 +138,68 @@ echo create directories... :: en => English :: de => German :: --------------------------------------------------------------------------- -for %%A in (en_us, de_de) do ( - cd %BASEDIR% - dir /A:D %BASEDIR%\locales >nul 2>&1 - if errorlevel 0 ( - mkdir %BASEDIR%\locales >nul 2>&1 - dir /A:D %BASEDIR%\locales\%%A >nul 2>&1 - if errorlevel 0 ( - echo|set /p="%%A => " - mkdir %BASEDIR%\locales\%%A >nul 2>&1 - dir /A:D locales\%%A\LC_MESSAGES >nul 2>&1 - if errorlevel 0 ( - echo|set /p="ok, " - mkdir locales\%%A\LC_MESSAGES >nul 2>&1 - cd %BASEDIR%\locales\%%A\LC_MESSAGES - echo|set /p="locales compiled => " - msgfmt -o ^ - %BASEDIR%\locales\%%A\LC_MESSAGES\observer.mo ^ - %BASEDIR%\locales\%%A\LC_MESSAGES\observer.po - if errorlevel 0 ( - cd %BASEDIR%\locales\%%A\LC_MESSAGES - rm -rf observer.mo.gz - gzip -9 observer.mo - copy /b observer.mo.gz %BASEDIR%\_internal\locales\%%A\LC_MESSAGES\observer.mo - cd %BASEDIR% - ) else ( - echo error: %%A not created. - ) - ) - ) - ) -) -goto TheEnd +mkdir __pycache__\_internal\locales\de_de\LC_MESSAGES +mkdir __pycache__\_internal\locales\en_us\LC_MESSAGES + +cd %BASEDIR%\locales\de_de\LC_MESSAGES +rm -rf observer.mo.gz +msgfmt -o observer.mo observer.po +gzip -9 observer.mo +copy observer.mo.gz %BASEDIR%\__pycache__\_internal\locales\de_de\LC_MESSAGES + +cd %BASEDIR%\locales\en_us\LC_MESSAGES +rm -rf observer.mo.gz +msgfmt -o observer.mo observer.po +gzip -9 observer.mo +copy observer.mo.gz %BASEDIR%\__pycache__\_internal\locales\en_us\LC_MESSAGES + :: --------------------------------------------------------------------------- :: Python can produce byte-code, and executable files to speed up the loading :: and for information hidding ... :: --------------------------------------------------------------------------- cd %BASEDIR% echo Create Byte-Code... -cd tools -python -m compileall tool001.py -if errorlevel 1 ( - echo fail tool001.pyc - goto error_bytecode) else ( echo tool001.pyc created ) -python tool001.py -if errorlevel 1 ( - echo fail tool001 batch - goto error_bytecode ) else ( echo tool001.py exec ok ) -python -m compileall collection.py -if errorlevel 1 ( - echo fail collection.pyc - goto error_bytecode ) else ( echo collection.pyc created ) -python collection.py -if errorlevel 1 ( - echo fail collection batch - goto error_bytecode ) else ( echo collection.py exec ok ) -cd .. -%PY%\python.exe -m compileall %BASEDIR%\observer.py +::cd tools +::python -m compileall tool001.py +::if errorlevel 1 ( +:: echo fail tool001.pyc +:: goto error_bytecode) else ( echo tool001.pyc created ) +::python tool001.py +::if errorlevel 1 ( +:: echo fail tool001 batch +:: goto error_bytecode ) else ( echo tool001.py exec ok ) +::python -m compileall collection.py +::if errorlevel 1 ( +:: echo fail collection.pyc +:: goto error_bytecode ) else ( echo collection.pyc created ) +::python collection.py +::if errorlevel 1 ( +:: echo fail collection batch +:: goto error_bytecode ) else ( echo collection.py exec ok ) +::cd .. +python -m compileall %BASEDIR%\observer.py if errorlevel 1 ( goto error_bytecode ) -echo ok ] -pyinstaller --noconfirm --console ^ - --icon="%PRJ%/src/img/floppy-disk.ico" ^ +echo installer... +pyinstaller --noupx --noconfirm --console ^ + --icon="%PRJ%/_internal/img/floppy-disk.ico" ^ --clean ^ + --exclude-module tkinter ^ + --exclude-module tk ^ + --exclude-module tk86t ^ + --exclude-module tcl86t ^ --log-level="WARN" ^ - --splash="%PRJ%/src/img/splash.png" ^ + --splash="%PRJ%/_internal/img/splash.png" ^ --strip ^ --hide-console="minimize-late" ^ - --version-file="%PRJ%/src/version.info" ^ + --version-file="%PRJ%/version.info" ^ ^ --paths=./ ^ --paths="C:/Windows/System32" ^ --paths="C:/Windows/SysWOW64" ^ ^ - --paths="%PRJ%/src/interpreter/doxygen" ^ - --paths="%PRJ%/src/interpreter/pascal" ^ - --paths="%PRJ%/src/interpreter/dbase" ^ - --paths="%PRJ%/src/interpreter" ^ - --paths="%PRJ%/src/tools" ^ --paths="%PRJ%/src" ^ ^ - --add-data="%PRJ%/src/locales;locales/" ^ - --add-data="%PRJ%/src/img;img/" ^ - --add-data="%PRJ%/LICENSE;." ^ - --add-data="%PRJ%/README.md;." ^ - --add-data="%PRJ%/CONTRIBUTING.md;." ^ - --add-data="%PRJ%/CODE_OF_CONDUCT.md;." ^ - --add-data="%PRJ%/src/topics.txt;." ^ - --add-data="%PRJ%/src/test.byte;." ^ - --add-data="%PRJ%/src/test.txt;." ^ - ^ - --collect-submodules="%PRJ%/src/exapp.py" ^ - --collect-submodules="%PRJ%/src/exclasses.py" ^ - --collect-submodules="%PRJ%/src/appcollection.py" ^ --collect-submodules="%PRJ%/src/__init__.py" ^ - --collect-submodules="%PRJ%/src/tools/collection.py" ^ - --collect-submodules="%PRJ%/src/tools/data001.py" ^ - --collect-submodules="%PRJ%/src/tools/data002.py" ^ - --collect-submodules="%PRJ%/src/tools/data003.py" ^ - --collect-submodules="%PRJ%/src/tools/data004.py" ^ - --collect-submodules="%PRJ%/src/tools/data005.py" ^ - --collect-submodules="%PRJ%/src/tools/misc.py" ^ - --collect-submodules="%PRJ%/src/tools/__init__.py" ^ - --collect-submodules="%PRJ%/src/interpreter/EParserException.py" ^ - --collect-submodules="%PRJ%/src/interpreter/ParserDSL.py" ^ - --collect-submodules="%PRJ%/src/interpreter/RunTimeLibrary.py" ^ - --collect-submodules="%PRJ%/src/interpreter/VisualComponentLibrary.py" ^ - --collect-submodules="%PRJ%/src/interpreter/doxygen/doxygen.py" ^ - --collect-submodules="%PRJ%/src/interpreter/dbase/dbaseConsole.py" ^ - --collect-submodules="%PRJ%/src/interpreter/dbase/dbase.py" ^ - --collect-submodules="%PRJ%/src/interpreter/pascal/pascal.py" ^ ^ --hidden-import="shutil" ^ --hidden-import="types" ^ @@ -191,7 +221,7 @@ pyinstaller --noconfirm --console ^ --hidden-import="sre_constants" ^ --hidden-import="copyreg" ^ ^ - "%PRJ%/src/observer.py" + "%PRJ%/observer.py" goto TheEnd :: --------------------------------------------------------------------------- :: to create Windows executables, you have to install pyinstaller seperatly. @@ -234,6 +264,20 @@ if exist "dist" ( cd dist if exist "observer" ( cd observer + mkdir _internal\_internal + mkdir _internal\_internal\img\flags + mkdir _internal\_internal\locales\de_de\LC_MESSAGES + mkdir _internal\_internal\locales\en_us\LC_MESSAGES + copy ..\..\locales\de_de\LC_MESSAGES\observer.mo.gz _internal\_internal\locales\de_de\LC_MESSAGES\observer.mo.gz + copy ..\..\locales\en_us\LC_MESSAGES\observer.mo.gz _internal\_internal\locales\en_us\LC_MESSAGES\observer.mo.gz + copy ..\..\observer.ini _internal\_internal\observer.ini + copy ..\..\__pycache__\_internal\img\flags\*.gif _internal\_internal\img\flags\ + copy ..\..\__pycache__\_internal\img\*.gif _internal\_internal\img\ + copy ..\..\__pycache__\_internal\img\*.png _internal\_internal\img\ + copy ..\..\__pycache__\_internal\img\*.bmp _internal\_internal\img\ + copy ..\..\__pycache__\_internal\img\*.ico _internal\_internal\img\ + copy ..\..\__pycache__\_internal\favorites.ini _internal\_internal\favorites.ini + copy ..\..\topics.txt _internal\_internal\topics.txt touch test.txt ) else ( echo observer directory does not exists. @@ -278,6 +322,3 @@ goto skipper :: --------------------------------------------------------------------------- :: E - O - F End of File :: --------------------------------------------------------------------------- - - -::auto-py-to-exe diff --git a/src/locales/de_de/LC_MESSAGES/observer.mo.gz b/src/locales/de_de/LC_MESSAGES/observer.mo.gz index d99bf7db7d2a6aad7743917fa7f33eeff404f626..ba824c75565681dfa3c89375a2ed0d6e18eb242f 100644 GIT binary patch delta 18 acmZ2`gL&-@W_I~*4vxC3mK)jC-T(kb8wV%= delta 18 acmZ2`gL&-@W_I~*4vwdbbvLrBy#WA6ga=Uo diff --git a/src/locales/en_us/LC_MESSAGES/observer.mo.gz b/src/locales/en_us/LC_MESSAGES/observer.mo.gz index bd98ec4091d3b3dd33c43e83cf92f76789c054a9..bd9fbcbc4dbfa5df08058a5296721a56302a041a 100644 GIT binary patch delta 18 acmbQXjd|KOW_I~*4vzY(mK)jmZvy~6&IXSF delta 18 acmbQXjd|KOW_I~*4vwdbbvLr}-v$6cFb1~( diff --git a/src/observer.py b/src/observer.py index f8b07d2..0052d6e 100644 --- a/src/observer.py +++ b/src/observer.py @@ -51,12 +51,10 @@ # ------------------------------------------------------------------------ def check_and_install_module(): required_modules = [ - "re", "dbf", "polib", "requests", "timer", "threading", "glob", - "atexit", "platform", "gzip", "base64", "shutil", "datetime", "gmpy2", - "pkgutil", "ast", "csv", "gettext", "locale", "io", "random", "string", + "dbf", "polib", "requests", "timer", "datetime", "gmpy2", + "locale", "io", "random", "string", "ctypes", "sqlite3", "configparser", "traceback", "marshal", "inspect", - "logging", "PyQt5", "pathlib", "rich", "string", "codecs", "pywin32", - "pywintypes", "PyQtWebEngine" ] + "logging", "PyQt5", "pathlib", "rich", "string", "codecs" ] for module in required_modules: try: @@ -12236,6 +12234,206 @@ def paint(self, painter, option, index): right_circle_rect = QRect(option.rect.right() - 25, option.rect.top() + 5, 10, 10) painter.drawEllipse(right_circle_rect) +class GridGraphicsViewFormDesigner(QGraphicsView): + def __init__(self, scene, window_size): + super().__init__(scene) + self.setRenderHint(QPainter.Antialiasing) + self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn) + self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) + + # Setze die Größe der Szene auf das Doppelte der Fenstergröße + scene.setSceneRect(0, 0, window_size.width() * 2, window_size.height() * 2) + self.selected_item = None # Aktuell ausgewähltes Element + self.resize_mode = None # Speichert den aktiven Ziehpunkt + self.last_resize_pos = None # Speichert die letzte Position für die 10-Pixel-Schritte + self.window_size = window_size # Speichert die Fenstergröße, um die Mausbewegung zu begrenzen + + def drawBackground(self, painter, rect): + super().drawBackground(painter, rect) + + # Gitterabstand und Punktgröße festlegen + grid_size = 10 # Abstand zwischen den Punkten + point_size = 2 # Punktgröße: 2x2 Pixel + + # Pinsel und Farbe für das Gitter definieren + pen = QPen(QColor(200, 200, 200)) # Farbe der Punkte + painter.setPen(pen) + brush = QBrush(QColor(200, 200, 200)) # Füllfarbe der Punkte + painter.setBrush(brush) + + # Start- und Endkoordinaten des sichtbaren Bereichs bestimmen + left = int(rect.left()) - (int(rect.left()) % grid_size) + top = int(rect.top()) - (int(rect.top()) % grid_size) + + # Punkt-Gitter zeichnen als 2x2 Pixel Rechtecke + for x in range(left, int(rect.right()), grid_size): + for y in range(top, int(rect.bottom()), grid_size): + painter.drawRect(x, y, point_size, point_size) + + def drawForeground(self, painter, rect): + super().drawForeground(painter, rect) + + if self.selected_item: + pen = QPen(QColor("red"), 4, Qt.DashLine) + painter.setPen(pen) + item_rect = self.selected_item.sceneBoundingRect() + painter.drawRect(item_rect) + + # Füllfarbe und Größe für die Ziehpunkte festlegen + painter.setBrush(QBrush(QColor("red"))) + rect_size = 12 + + # Berechne und zeichne die Positionen der Ziehpunkte auf jeder Seite + for point in self.calculate_resize_handles(item_rect): + painter.drawRect(int(point.x() - rect_size / 2), int(point.y() - rect_size / 2), rect_size, rect_size) + + def calculate_resize_handles(self, item_rect): + """Berechnet die Positionen der Ziehpunkte an den Seiten des Rahmens.""" + left_center = QPointF(item_rect.left(), item_rect.center().y()) + right_center = QPointF(item_rect.right(), item_rect.center().y()) + top_center = QPointF(item_rect.center().x(), item_rect.top()) + bottom_center = QPointF(item_rect.center().x(), item_rect.bottom()) + return [left_center, right_center, top_center, bottom_center] + + def mousePressEvent(self, event): + # Bestimme das ausgewählte Element und speichere es + item = self.itemAt(event.pos()) + if isinstance(item, QGraphicsItem): + self.selected_item = item + self.last_resize_pos = self.mapToScene(event.pos()) # Setze die Ausgangsposition + else: + self.selected_item = None + self.last_resize_pos = None + + # Prüfe, ob ein Ziehpunkt angeklickt wurde + pos = self.mapToScene(event.pos()) + item_rect = self.selected_item.sceneBoundingRect() if self.selected_item else None + handles = self.calculate_resize_handles(item_rect) if item_rect else [] + + # Zuordnung der Ziehpunkte zu den Seiten mit einem Toleranzbereich von 10 Pixel + if self.selected_item and self.is_near_point(pos, handles[0], threshold=10): + self.resize_mode = 'left' + elif self.selected_item and self.is_near_point(pos, handles[1], threshold=10): + self.resize_mode = 'right' + elif self.selected_item and self.is_near_point(pos, handles[2], threshold=10): + self.resize_mode = 'top' + elif self.selected_item and self.is_near_point(pos, handles[3], threshold=10): + self.resize_mode = 'bottom' + else: + self.resize_mode = None # Keine Ziehpunkte ausgewählt + + self.viewport().update() + super().mousePressEvent(event) + + def mouseMoveEvent(self, event): + # Begrenze die Mausbewegung auf die Fenstergröße + if event.pos().x() < 0 or event.pos().y() < 0 or event.pos().x() > self.window_size.width() or event.pos().y() > self.window_size.height(): + return + + if self.selected_item and self.resize_mode: + pos = self.mapToScene(event.pos()) + delta = pos - self.last_resize_pos # Berechne die Verschiebung seit dem letzten Schritt + + # Anpassung des Rechtecks in 10-Pixel-Schritten + if self.resize_mode == 'left' and abs(delta.x()) >= 10: + adjustment = 10 * (-1 if delta.x() > 0 else 1) + new_width = max(10, self.selected_item.rect().width() + adjustment) + self.selected_item.setRect(self.selected_item.rect().x() - adjustment, + self.selected_item.rect().y(), + new_width, + self.selected_item.rect().height()) + self.last_resize_pos = pos # Aktualisiere die Position + + elif self.resize_mode == 'right' and abs(delta.x()) >= 10: + adjustment = 10 * (1 if delta.x() > 0 else -1) + new_width = max(10, self.selected_item.rect().width() + adjustment) + self.selected_item.setRect(self.selected_item.rect().x(), + self.selected_item.rect().y(), + new_width, + self.selected_item.rect().height()) + self.last_resize_pos = pos # Aktualisiere die Position + + elif self.resize_mode == 'top' and abs(delta.y()) >= 10: + adjustment = 10 * (-1 if delta.y() > 0 else 1) + new_height = max(10, self.selected_item.rect().height() + adjustment) + self.selected_item.setRect(self.selected_item.rect().x(), + self.selected_item.rect().y() - adjustment, + self.selected_item.rect().width(), + new_height) + self.last_resize_pos = pos # Aktualisiere die Position + + elif self.resize_mode == 'bottom' and abs(delta.y()) >= 10: + adjustment = 10 * (1 if delta.y() > 0 else -1) + new_height = max(10, self.selected_item.rect().height() + adjustment) + self.selected_item.setRect(self.selected_item.rect().x(), + self.selected_item.rect().y(), + self.selected_item.rect().width(), + new_height) + self.last_resize_pos = pos # Aktualisiere die Position + + self.viewport().update() + elif self.selected_item: + # Snap-Funktion beim Bewegen des Elements + grid_size = 10 + new_pos = self.mapToScene(event.pos()) + snapped_x = round(new_pos.x() / grid_size) * grid_size + snapped_y = round(new_pos.y() / grid_size) * grid_size + + # Verschieben der Szene, wenn sich das Element an den Rand nähert + buffer_zone = 20 # Abstand zum Rand, um die Szene zu verschieben + move_offset = 10 # Verschiebung der Szene in Pixeln + if new_pos.x() > self.window_size.width() - buffer_zone: + self.setSceneRect(self.sceneRect().adjusted(-move_offset, 0, move_offset, 0)) + elif new_pos.x() < buffer_zone: + self.setSceneRect(self.sceneRect().adjusted(move_offset, 0, -move_offset, 0)) + if new_pos.y() > self.window_size.height() - buffer_zone: + self.setSceneRect(self.sceneRect().adjusted(0, -move_offset, 0, move_offset)) + elif new_pos.y() < buffer_zone: + self.setSceneRect(self.sceneRect().adjusted(0, move_offset, 0, -move_offset)) + + self.selected_item.setPos(snapped_x, snapped_y) + self.viewport().update() + else: + super().mouseMoveEvent(event) + + def mouseReleaseEvent(self, event): + # Zurücksetzen des Resize-Modus nach dem Loslassen + self.resize_mode = None + super().mouseReleaseEvent(event) + + def is_near_point(self, pos, point, threshold=10): + """Hilfsfunktion zur Überprüfung, ob die Position `pos` nahe an einem bestimmten Punkt `point` liegt.""" + return abs(pos.x() - point.x()) < threshold and abs(pos.y() - point.y()) < threshold + +class DraggableComponentFormDesigner(QGraphicsRectItem): + def __init__(self, name, x=0, y=0, width=50, height=50, view=None, label="", connections=[]): + super().__init__(0, 0, width, height) + self.setFlag(QGraphicsItem.ItemIsMovable) + self.setFlag(QGraphicsItem.ItemIsSelectable) + self.setPos(x, y) + self.name = name + self.label = label + self.connections = connections # Speichert relative Positionen der Verankerungen + self.view = view + self.last_snap_pos = QPointF(x, y) + self.scroll_timer = QTimer() + self.scroll_timer.setSingleShot(True) + self.scroll_timer.timeout.connect(self.resume_movement) + self.is_scrolling = False + + def resume_movement(self): + self.is_scrolling = False + + def paint(self, painter, option, widget): + # Hintergrundfarbe und Rahmen zeichnen + painter.setBrush(QColor("skyblue")) + painter.drawRect(self.rect()) + + # Text im Zentrum des Bauteils zeichnen + painter.setPen(QPen(Qt.black)) + painter.drawText(self.rect(), Qt.AlignCenter, self.label) + + class GridGraphicsView(QGraphicsView): def __init__(self, scene, window_size): super().__init__(scene) @@ -12381,6 +12579,7 @@ def is_near_point(self, pos, point, threshold=10): """Hilfsfunktion zur Überprüfung, ob die Position `pos` nahe an einem bestimmten Punkt `point` liegt.""" return abs(pos.x() - point.x()) < threshold and abs(pos.y() - point.y()) < threshold + class DraggableComponent(QGraphicsRectItem): def __init__(self, name, x=0, y=0, width=50, height=50, view=None, label="", connections=[]): super().__init__(0, 0, width, height) @@ -12505,7 +12704,7 @@ def __init__(self): # QGraphicsScene und GridGraphicsView erstellen window_size = QSize(800, 600) self.scene = QGraphicsScene() - self.view = GridGraphicsView(self.scene, window_size) + self.view = GridGraphicsViewFormDesigner(self.scene, window_size) # Layout für das QWidget layout = QVBoxLayout() @@ -12519,27 +12718,27 @@ def __init__(self): def init_components(self): # Bauteile mit individuellen Beschriftungen und Verankerungen hinzufügen - and_gate = DraggableComponent( + and_gate = DraggableComponentFormDesigner( "AND-Gate", x=100, y=100, view=self.view, label="AND", connections=[ - (QPointF(-10, 10), QPointF(0, 10)), # Linke obere Verankerung - (QPointF(-10, 30), QPointF(0, 30)), # Linke untere Verankerung + (QPointF(-10, 10), QPointF( 0, 10)), # Linke obere Verankerung + (QPointF(-10, 30), QPointF( 0, 30)), # Linke untere Verankerung (QPointF( 50, 20), QPointF(60, 20)) # Rechte Verankerung ] ) - lamp = DraggableComponent( + lamp = DraggableComponentFormDesigner( "Lamp", x=200, y=200, view=self.view, label="LED", connections=[ - (QPointF(-10, 20), QPointF(0, 20)), # Linke Verankerung + (QPointF(-10, 20), QPointF( 0, 20)), # Linke Verankerung (QPointF( 50, 20), QPointF(60, 20)) # Rechte Verankerung ] ) - battery = DraggableComponent( + battery = DraggableComponentFormDesigner( "Battery", x=300, y=300, view=self.view, label="SRC", connections=[ - (QPointF(-10, 20), QPointF(0, 20)), # Linke Verankerung + (QPointF(-10, 20), QPointF( 0, 20)), # Linke Verankerung (QPointF( 50, 20), QPointF(60, 20)) # Rechte Verankerung ] )