Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@ Or
chart.show()
sys.exit(App.exec())
```

Alternatively a PySide6 based interface is available:

```
from pyside_app.main import main
if __name__ == "__main__":
main()
```
Using the GUI
-------------

Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Pillow==11.1.0
pyephem==9.99
PyQt6==6.8.1
PyQt6_sip==13.8.0
PySide6==6.7.0
pyqtgraph==0.13.7
pyswisseph==2.10.3.2
pytest==7.4.4
Expand Down
1 change: 1 addition & 0 deletions src/jhora/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ numpy==2.1.1
pandas==2.2.2
Pillow==10.4.0
PyQt6==6.7.1
PySide6==6.7.0
pyqtgraph==0.13.7
python_dateutil==2.9.0.post0
pytz==2024.1
Expand Down
4 changes: 4 additions & 0 deletions src/jhora/tests/test_ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import pytest

pytest.skip("Manual UI test", allow_module_level=True)

import sys
from PyQt6.QtWidgets import QApplication

Expand Down
1 change: 1 addition & 0 deletions src/pyside_app/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""PySide6 desktop application for AstroCal."""
105 changes: 105 additions & 0 deletions src/pyside_app/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
"""PySide6 based user interface for AstroCal.

This module defines a simple Qt6 application using PySide6.
It demonstrates how to build scalable layouts with support
for high-DPI displays and a dark theme. Backend calculation
logic should be imported from other modules in the package.
"""

from __future__ import annotations

import sys

from PySide6.QtCore import Qt, QCoreApplication
from PySide6.QtWidgets import (
QApplication,
QLabel,
QMainWindow,
QTabWidget,
QTextEdit,
QVBoxLayout,
QWidget,
)


def init_high_dpi() -> None:
"""Enable Qt high DPI attributes for 4K monitor support."""
QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling, True)
QCoreApplication.setAttribute(Qt.AA_UseHighDpiPixmaps, True)


class MainWindow(QMainWindow):
"""Main application window with tabbed interface."""

def __init__(self) -> None:
super().__init__()
self.setWindowTitle("AstroCal - PySide6")
# Default window size, still resizable
self.resize(1200, 800)

# Apply global dark theme stylesheet and font size
self.setStyleSheet(
"""
QWidget { background-color: #121212; color: #dddddd; font-size: 16px; }
QTabWidget::pane { border: 1px solid #444444; }
QTabBar::tab { background: #333333; padding: 8px; }
QTabBar::tab:selected { background: #555555; }
"""
)


self._init_ui()

def _init_ui(self) -> None:
"""Builds the tabbed user interface."""
tabs = QTabWidget()
tabs.addTab(self._create_chart_tab(), "Chart Data")
tabs.addTab(self._create_bhava_tab(), "Bhava")
tabs.addTab(self._create_pakshi_tab(), "Panchapakshi")
tabs.addTab(self._create_calendar_tab(), "Calendar")
self.setCentralWidget(tabs)

def _create_chart_tab(self) -> QWidget:
"""First tab displaying placeholder chart data."""
tab = QWidget()
layout = QVBoxLayout(tab)

placeholder = QLabel("Chart Data Appears Here")
placeholder.setAlignment(Qt.AlignCenter)
layout.addWidget(placeholder)

example = QTextEdit()
example.setPlainText("Example chart data...\n")
layout.addWidget(example)
return tab

def _create_bhava_tab(self) -> QWidget:
tab = QWidget()
layout = QVBoxLayout(tab)
layout.addWidget(QLabel("Bhava details will appear here"))
return tab

def _create_pakshi_tab(self) -> QWidget:
tab = QWidget()
layout = QVBoxLayout(tab)
layout.addWidget(QLabel("Panchapakshi information goes here"))
return tab

def _create_calendar_tab(self) -> QWidget:
tab = QWidget()
layout = QVBoxLayout(tab)
layout.addWidget(QLabel("Calendar view will be placed here"))
return tab


def main(argv: list[str] | None = None) -> int:
"""Entry point for the PySide6 application."""
init_high_dpi()
app = QApplication(argv or sys.argv)
window = MainWindow()
window.show()
return app.exec()


if __name__ == "__main__": # pragma: no cover
raise SystemExit(main())
17 changes: 17 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import os
import sys
import pytest
from PySide6.QtWidgets import QApplication
from PySide6.QtCore import Qt, QCoreApplication

@pytest.fixture(scope="session")
def qapp():
"""Create a QApplication instance for tests."""
os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
# Enable high DPI attributes before QApplication is created
QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling, True)
QCoreApplication.setAttribute(Qt.AA_UseHighDpiPixmaps, True)
app = QApplication.instance() or QApplication(sys.argv)
yield app
# Teardown - quit application to release resources
app.quit()
11 changes: 11 additions & 0 deletions tests/test_pyside_app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from pyside_app.main import MainWindow
from PySide6.QtWidgets import QTabWidget


def test_mainwindow_tabs(qapp):
window = MainWindow()
central = window.centralWidget()
assert isinstance(central, QTabWidget)
assert central.count() == 4
titles = [central.tabText(i) for i in range(central.count())]
assert titles == ["Chart Data", "Bhava", "Panchapakshi", "Calendar"]