diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..6e84572 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,53 @@ +# github action build python package + +name: Build Python Package + +on: + push: + branches: [ main ] + tags: ['*'] + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: 3.11 + - name: Install build dependencies + run: | + python -m pip install build + - name: Build package using build + run: | + python -m build + + - name: Upload artifact + uses: actions/upload-artifact@v3 + with: + name: dist + path: dist + +# job to upload the package to PyPI + upload-to-pypi: + needs: build + runs-on: ubuntu-latest + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') + environment: + name: pypi + url: https://pypi.org/p/ + permissions: + id-token: write # IMPORTANT: this permission is mandatory for trusted publishing + steps: + - uses: actions/download-artifact@v3 + with: + name: dist + path: dist + + - name: Publish package distributions to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + print-hash: true \ No newline at end of file diff --git a/README.md b/README.md index 622289f..83e56da 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,71 @@ - # Qore Widgets -status: Working in progress - -Yet another collection of those core widgets for a modern qt application. +![PyPI - Version](https://img.shields.io/pypi/v/QoreWidgets)![PyPI - Downloads](https://img.shields.io/pypi/dm/QoreWidgets?label=monthly%20installed)![GitHub License](https://img.shields.io/github/license/du33169/QoreWidgets) -The widgets is designed to be functional extended but not decorated, style them as you wish. +Yet another collection of those core widgets for a modern Qt application. -Currently only PySide6 is supported. +Backend Support: Currently **only PySide6 is supported.** ## Widget List -SideTabWidget -ImmersiveTitleBar -FramelessWindow -ImmersiveMessageBox(todo) -## Install +| Qore Widget
[Base Widget] | Desc | Screenshot | +| ----------------------------------------------------- | ------------------------------------------------------------ | ---------- | +| **SideTabWidget**
[TabWidget] | A TabWidget with horizontal and foldable tabs. Animated. | | +| **ImmersiveTitleBar**
[ImmersiveTitleBarContainer] | A simple immersive title bar with icon, title, and close, maximize, minimize buttons. | | +| **ImmersiveTitleBarContainer**
[QWidget] | An immersive title bar Container with only buttons. Put any widgets you like. | | +| **FramelessWindow**
[QMainWindow] | A frameless window with resize grips. Better use it with the ImmersiveTitleBar. | | +| **ImmersiveMesageBox**
[QMessageBox] | (todo) | | +| **DrawerWidget** | (todo) | | + + + +## Installation + +```bash +pip install qorewidgets +``` ## Usage -## Gallery +There are two ways to integrate QoreWidgets into your project: + +### Programmatically + +Most Qore Widgets are designed as drop-in replacements for their corresponding base widgets. + +### With Qt Designer + +Note: If you installed PySide6 using pip, the designer is also installed as `pyside6-designer` executable. + +1. Create the base widget in Qt Designer +2. Right-click on the widget and select "Promote To..." +3. Enter the desired Qore Widget name as the **promoted class name**, and "QoreWidgets.h" as the **header file** +4. Use the `pyside6-uic` tool (also installed with PySide6) to convert the .ui file to a .py file +5. the base widget will be replaced by the appropriate Qore Widget during the conversion + +Refer to the [Qt Doc: using custom widgets in designer](https://doc.qt.io/qt-6/designer-using-custom-widgets.html) for more detailed instructions. + +### Documentation + +for more infomation, check out our [QoreWidgets Documentation](https://github.com/du33169/QoreWidgets/wiki). + + + +## Examples + +The QoreWidgets Gallery app provides examples about how to use these widgets. To run the gallery app: + +```bash +git clone https://github.com/du33169/QoreWidgets +cd QoreWidgets +pip install PySide6 +python gallery/app.py +``` + +Note: the gallery app will first attempt to import QoreWidgets from installed python packages. If not installed, it will import from the local `src` directory. + + + +## Styling -## Acknowledgment +QoreWidgets mainly focus on functional enhancements with minimal emphasis on decoration. However, they should fit in with your global theme or stylesheets, for example, [QDarkStyleSheet](https://github.com/ColinDuquesnoy/QDarkStyleSheet). diff --git a/gallery/app.py b/gallery/app.py index d642821..52b4752 100644 --- a/gallery/app.py +++ b/gallery/app.py @@ -7,6 +7,7 @@ try: import QoreWidgets except ImportError: + print("QoreWidgets not installed, trying to import from local src") import sys import os # switch to current path diff --git a/src/QoreWidgets/__pyside6__/__framelessWindow__/framelessWindow.py b/src/QoreWidgets/__pyside6__/__framelessWindow__/framelessWindow.py index 38fea96..85ddce6 100644 --- a/src/QoreWidgets/__pyside6__/__framelessWindow__/framelessWindow.py +++ b/src/QoreWidgets/__pyside6__/__framelessWindow__/framelessWindow.py @@ -6,8 +6,9 @@ @dataclass class FramelessWindowConfig: - HEIGHT: int = 48 GRIP_WIDTH: int = 8 + SHADOW: bool = True + # GRIP_COLOR: QColor = field(default_factory=lambda: QColor(0,0,0,0)) _N_=1000 # weight of x def unit2id(ux,uy)->int: @@ -126,6 +127,7 @@ def follow_geometry(self): self.raise_() class FramelessWindow(QMainWindow): + '''Frameless Window with resize grips''' def __init__(self, parent=None,flConfig:FramelessWindowConfig=FramelessWindowConfig()): super(FramelessWindow, self).__init__(parent) self.flConfig=flConfig @@ -156,4 +158,20 @@ def resizeEvent(self, event: QResizeEvent) -> None: [grip.follow_geometry() for grip in self.pos2grip.values()] def init_shadow(self): - pass \ No newline at end of file + if self.flConfig.SHADOW: # DROP SHADOW + self.shadowWidget = QWidget(self) + # self.shadowWidget.setGeometry(100,100,100,100) + self.setCentralWidget(self.shadowWidget) + # self.layout().setParent(self.shadowWidget) + self.shadowWidget.show() + self.shadowWidget.raise_() + + self.shadowWidget.setStyleSheet("background-color: rgba(0, 0, 0, 150);") + self.shadow = QGraphicsDropShadowEffect(self) + self.shadow.setBlurRadius(17) + self.shadow.setXOffset(0) + self.shadow.setYOffset(0) + self.shadow.setColor(QColor(0, 0, 0, 150)) + # move self.layout to self.shadowWidget + + self.shadowWidget.setGraphicsEffect(self.shadow) \ No newline at end of file diff --git a/src/QoreWidgets/__pyside6__/__sideTabWidget__/sideTabWidget.py b/src/QoreWidgets/__pyside6__/__sideTabWidget__/sideTabWidget.py index e02f76d..943bb75 100644 --- a/src/QoreWidgets/__pyside6__/__sideTabWidget__/sideTabWidget.py +++ b/src/QoreWidgets/__pyside6__/__sideTabWidget__/sideTabWidget.py @@ -141,7 +141,7 @@ def paintEvent(self, event: QPaintEvent) -> None: painter.drawControl(QStyle.ControlElement.CE_PushButton, option) class SideTabWidget(QTabWidget): - + '''A TabWidget with horizontal and foldable tabs. Animated.''' foldStateChanged=Signal(bool) # pass the fold state from the tabbar to the parent widget def __init__(self, parent=None, stConfig:SideTabConfig=SideTabConfig()):