diff --git a/README.md b/README.md
index a67aa71..78261cf 100644
--- a/README.md
+++ b/README.md
@@ -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
-------------
@@ -807,3 +815,8 @@ See LICENSE file.
Contact
-------
https://github.com/naturalstupid/
+
+FastAPI Backend
+---------------
+A lightweight API implementation using FastAPI is available in `src/astroapi`. Run `uvicorn astroapi.main:app --reload` to start the server.
+For a browser-based UI, open `frontend/index.html` with any static file server.
diff --git a/frontend/index.html b/frontend/index.html
new file mode 100644
index 0000000..a74fbbd
--- /dev/null
+++ b/frontend/index.html
@@ -0,0 +1,91 @@
+
+
+
+
+
+ AstroCal Chart
+
+
+
+
+
+
+
+
+
+
+
diff --git a/requirements.txt b/requirements.txt
index 196676c..23beabc 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,5 +1,4 @@
attr==0.3.2
-conda==4.3.16
geocoder==1.38.1
geopy==2.4.1
img2pdf==0.5.1
@@ -9,13 +8,16 @@ 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
-pytest.egg==info
python_dateutil==2.9.0.post0
pytz==2024.1
Requests==2.32.3
-setuptools==69.5.1
setuptools==75.6.0
timezonefinder==6.5.8
+
+fastapi==0.111.0
+uvicorn==0.29.0
+pydantic==2.7.1
diff --git a/src/astroapi/README.md b/src/astroapi/README.md
new file mode 100644
index 0000000..9fa6c41
--- /dev/null
+++ b/src/astroapi/README.md
@@ -0,0 +1,31 @@
+# AstroCal FastAPI Backend
+
+This module exposes horoscope computations via a simple REST API.
+
+## Endpoints
+
+- `GET /health` – basic health check
+- `POST /chart` or `/generate_chart` – compute a Vedic horoscope
+
+### Example request
+
+```json
+{
+ "name": "John Doe",
+ "gender": "M",
+ "birth_date": "2000-01-01",
+ "birth_time": "12:34:00",
+ "place": "Chennai, India",
+ "latitude": 13.0827,
+ "longitude": 80.2707,
+ "timezone": 5.5
+}
+```
+
+Start the API with:
+
+```bash
+uvicorn astroapi.main:app --reload
+```
+
+The response contains horoscope information ready for client consumption.
diff --git a/src/astroapi/__init__.py b/src/astroapi/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/astroapi/__main__.py b/src/astroapi/__main__.py
new file mode 100644
index 0000000..ee313f4
--- /dev/null
+++ b/src/astroapi/__main__.py
@@ -0,0 +1,5 @@
+from .main import app
+
+if __name__ == "__main__":
+ import uvicorn
+ uvicorn.run(app, host="0.0.0.0", port=8000)
diff --git a/src/astroapi/main.py b/src/astroapi/main.py
new file mode 100644
index 0000000..170cf9d
--- /dev/null
+++ b/src/astroapi/main.py
@@ -0,0 +1,22 @@
+"""FastAPI application exposing horoscope computation endpoints."""
+from fastapi import FastAPI, HTTPException
+
+from .models import ChartRequest
+from .services import compute_chart
+
+app = FastAPI(title="AstroCal API")
+
+@app.get("/health")
+def health_check():
+ """Simple health check endpoint."""
+ return {"status": "ok"}
+
+@app.post("/chart")
+@app.post("/generate_chart")
+def generate_chart(request: ChartRequest):
+ """Compute a Vedic horoscope and return detailed data."""
+ try:
+ return compute_chart(request)
+ except Exception as exc:
+ raise HTTPException(status_code=500, detail=str(exc))
+
diff --git a/src/astroapi/models.py b/src/astroapi/models.py
new file mode 100644
index 0000000..7b7c8c5
--- /dev/null
+++ b/src/astroapi/models.py
@@ -0,0 +1,14 @@
+from datetime import date, time
+from pydantic import BaseModel
+
+class ChartRequest(BaseModel):
+ """Parameters required to compute a horoscope chart."""
+ name: str
+ gender: str
+ birth_date: date
+ birth_time: time
+ place: str
+ latitude: float
+ longitude: float
+ timezone: float
+
diff --git a/src/astroapi/services.py b/src/astroapi/services.py
new file mode 100644
index 0000000..9c8516e
--- /dev/null
+++ b/src/astroapi/services.py
@@ -0,0 +1,37 @@
+"""Utility functions for computing horoscope information."""
+from datetime import datetime
+from typing import Dict, Any
+
+from jhora.horoscope import main
+from jhora.panchanga import drik
+
+from .models import ChartRequest
+
+
+def compute_chart(request: ChartRequest) -> Dict[str, Any]:
+ """Generate horoscope data using existing jhora classes."""
+ dob = drik.Date(request.birth_date.year, request.birth_date.month, request.birth_date.day)
+ tob = (request.birth_time.hour, request.birth_time.minute, request.birth_time.second)
+ place = drik.Place(request.place, request.latitude, request.longitude, request.timezone)
+
+ horo = main.Horoscope(
+ place_with_country_code=request.place,
+ latitude=request.latitude,
+ longitude=request.longitude,
+ timezone_offset=request.timezone,
+ date_in=dob,
+ birth_time=request.birth_time.strftime("%H:%M:%S"),
+ )
+
+ info, charts, houses = horo.get_horoscope_information()
+ vimsottari = horo._get_vimsottari_dhasa_bhukthi(dob, tob, place)
+
+ return {
+ "name": request.name,
+ "gender": request.gender,
+ "info": info,
+ "charts": charts,
+ "ascendant_houses": houses,
+ "vimsottari_dhasa": vimsottari,
+ }
+
diff --git a/src/jhora/__pycache__/__init__.cpython-311.pyc b/src/jhora/__pycache__/__init__.cpython-311.pyc
new file mode 100644
index 0000000..b53fe06
Binary files /dev/null and b/src/jhora/__pycache__/__init__.cpython-311.pyc differ
diff --git a/src/jhora/__pycache__/_package_info.cpython-311.pyc b/src/jhora/__pycache__/_package_info.cpython-311.pyc
new file mode 100644
index 0000000..bf74b95
Binary files /dev/null and b/src/jhora/__pycache__/_package_info.cpython-311.pyc differ
diff --git a/src/jhora/__pycache__/const.cpython-311.pyc b/src/jhora/__pycache__/const.cpython-311.pyc
new file mode 100644
index 0000000..f87e265
Binary files /dev/null and b/src/jhora/__pycache__/const.cpython-311.pyc differ
diff --git a/src/jhora/__pycache__/utils.cpython-311.pyc b/src/jhora/__pycache__/utils.cpython-311.pyc
new file mode 100644
index 0000000..355faa3
Binary files /dev/null and b/src/jhora/__pycache__/utils.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/__pycache__/__init__.cpython-311.pyc b/src/jhora/horoscope/__pycache__/__init__.cpython-311.pyc
new file mode 100644
index 0000000..af095bc
Binary files /dev/null and b/src/jhora/horoscope/__pycache__/__init__.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/__pycache__/main.cpython-311.pyc b/src/jhora/horoscope/__pycache__/main.cpython-311.pyc
new file mode 100644
index 0000000..b494d35
Binary files /dev/null and b/src/jhora/horoscope/__pycache__/main.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/chart/__pycache__/__init__.cpython-311.pyc b/src/jhora/horoscope/chart/__pycache__/__init__.cpython-311.pyc
new file mode 100644
index 0000000..2725695
Binary files /dev/null and b/src/jhora/horoscope/chart/__pycache__/__init__.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/chart/__pycache__/arudhas.cpython-311.pyc b/src/jhora/horoscope/chart/__pycache__/arudhas.cpython-311.pyc
new file mode 100644
index 0000000..45ae1f7
Binary files /dev/null and b/src/jhora/horoscope/chart/__pycache__/arudhas.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/chart/__pycache__/ashtakavarga.cpython-311.pyc b/src/jhora/horoscope/chart/__pycache__/ashtakavarga.cpython-311.pyc
new file mode 100644
index 0000000..37ae7ca
Binary files /dev/null and b/src/jhora/horoscope/chart/__pycache__/ashtakavarga.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/chart/__pycache__/charts.cpython-311.pyc b/src/jhora/horoscope/chart/__pycache__/charts.cpython-311.pyc
new file mode 100644
index 0000000..4ace7d4
Binary files /dev/null and b/src/jhora/horoscope/chart/__pycache__/charts.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/chart/__pycache__/dosha.cpython-311.pyc b/src/jhora/horoscope/chart/__pycache__/dosha.cpython-311.pyc
new file mode 100644
index 0000000..55eba83
Binary files /dev/null and b/src/jhora/horoscope/chart/__pycache__/dosha.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/chart/__pycache__/house.cpython-311.pyc b/src/jhora/horoscope/chart/__pycache__/house.cpython-311.pyc
new file mode 100644
index 0000000..b793a3f
Binary files /dev/null and b/src/jhora/horoscope/chart/__pycache__/house.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/chart/__pycache__/raja_yoga.cpython-311.pyc b/src/jhora/horoscope/chart/__pycache__/raja_yoga.cpython-311.pyc
new file mode 100644
index 0000000..43b4348
Binary files /dev/null and b/src/jhora/horoscope/chart/__pycache__/raja_yoga.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/chart/__pycache__/sphuta.cpython-311.pyc b/src/jhora/horoscope/chart/__pycache__/sphuta.cpython-311.pyc
new file mode 100644
index 0000000..b62cf78
Binary files /dev/null and b/src/jhora/horoscope/chart/__pycache__/sphuta.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/chart/__pycache__/strength.cpython-311.pyc b/src/jhora/horoscope/chart/__pycache__/strength.cpython-311.pyc
new file mode 100644
index 0000000..2e46ed5
Binary files /dev/null and b/src/jhora/horoscope/chart/__pycache__/strength.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/chart/__pycache__/yoga.cpython-311.pyc b/src/jhora/horoscope/chart/__pycache__/yoga.cpython-311.pyc
new file mode 100644
index 0000000..e962fa7
Binary files /dev/null and b/src/jhora/horoscope/chart/__pycache__/yoga.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/__pycache__/__init__.cpython-311.pyc b/src/jhora/horoscope/dhasa/__pycache__/__init__.cpython-311.pyc
new file mode 100644
index 0000000..8de1da1
Binary files /dev/null and b/src/jhora/horoscope/dhasa/__pycache__/__init__.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/__pycache__/sudharsana_chakra.cpython-311.pyc b/src/jhora/horoscope/dhasa/__pycache__/sudharsana_chakra.cpython-311.pyc
new file mode 100644
index 0000000..7e93926
Binary files /dev/null and b/src/jhora/horoscope/dhasa/__pycache__/sudharsana_chakra.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/annual/__pycache__/mudda.cpython-311.pyc b/src/jhora/horoscope/dhasa/annual/__pycache__/mudda.cpython-311.pyc
new file mode 100644
index 0000000..9b373cb
Binary files /dev/null and b/src/jhora/horoscope/dhasa/annual/__pycache__/mudda.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/annual/__pycache__/patyayini.cpython-311.pyc b/src/jhora/horoscope/dhasa/annual/__pycache__/patyayini.cpython-311.pyc
new file mode 100644
index 0000000..41dedda
Binary files /dev/null and b/src/jhora/horoscope/dhasa/annual/__pycache__/patyayini.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/aayu.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/aayu.cpython-311.pyc
new file mode 100644
index 0000000..180a03b
Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/aayu.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/ashtottari.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/ashtottari.cpython-311.pyc
new file mode 100644
index 0000000..efb65c7
Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/ashtottari.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/buddhi_gathi.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/buddhi_gathi.cpython-311.pyc
new file mode 100644
index 0000000..bf52271
Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/buddhi_gathi.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/chathuraaseethi_sama.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/chathuraaseethi_sama.cpython-311.pyc
new file mode 100644
index 0000000..1c07d74
Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/chathuraaseethi_sama.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/dwadasottari.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/dwadasottari.cpython-311.pyc
new file mode 100644
index 0000000..da46674
Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/dwadasottari.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/dwisatpathi.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/dwisatpathi.cpython-311.pyc
new file mode 100644
index 0000000..8280a0b
Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/dwisatpathi.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/kaala.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/kaala.cpython-311.pyc
new file mode 100644
index 0000000..ea4c468
Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/kaala.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/karaka.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/karaka.cpython-311.pyc
new file mode 100644
index 0000000..1e267fc
Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/karaka.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/karana_chathuraaseethi_sama.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/karana_chathuraaseethi_sama.cpython-311.pyc
new file mode 100644
index 0000000..e7f57ff
Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/karana_chathuraaseethi_sama.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/naisargika.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/naisargika.cpython-311.pyc
new file mode 100644
index 0000000..3cea667
Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/naisargika.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/panchottari.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/panchottari.cpython-311.pyc
new file mode 100644
index 0000000..719db84
Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/panchottari.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/saptharishi_nakshathra.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/saptharishi_nakshathra.cpython-311.pyc
new file mode 100644
index 0000000..66c6a58
Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/saptharishi_nakshathra.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/sataatbika.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/sataatbika.cpython-311.pyc
new file mode 100644
index 0000000..6a91d58
Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/sataatbika.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/shastihayani.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/shastihayani.cpython-311.pyc
new file mode 100644
index 0000000..08714ac
Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/shastihayani.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/shattrimsa_sama.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/shattrimsa_sama.cpython-311.pyc
new file mode 100644
index 0000000..a436298
Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/shattrimsa_sama.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/shodasottari.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/shodasottari.cpython-311.pyc
new file mode 100644
index 0000000..0713a6d
Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/shodasottari.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/tara.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/tara.cpython-311.pyc
new file mode 100644
index 0000000..40cfc2c
Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/tara.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/tithi_ashtottari.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/tithi_ashtottari.cpython-311.pyc
new file mode 100644
index 0000000..03677b7
Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/tithi_ashtottari.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/tithi_yogini.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/tithi_yogini.cpython-311.pyc
new file mode 100644
index 0000000..5dd6771
Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/tithi_yogini.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/vimsottari.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/vimsottari.cpython-311.pyc
new file mode 100644
index 0000000..90b0ef2
Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/vimsottari.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/yoga_vimsottari.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/yoga_vimsottari.cpython-311.pyc
new file mode 100644
index 0000000..d9f81c4
Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/yoga_vimsottari.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/yogini.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/yogini.cpython-311.pyc
new file mode 100644
index 0000000..3888828
Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/yogini.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/brahma.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/brahma.cpython-311.pyc
new file mode 100644
index 0000000..f0c8907
Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/brahma.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/chakra.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/chakra.cpython-311.pyc
new file mode 100644
index 0000000..e865cfb
Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/chakra.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/chara.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/chara.cpython-311.pyc
new file mode 100644
index 0000000..c7e70fb
Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/chara.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/drig.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/drig.cpython-311.pyc
new file mode 100644
index 0000000..56c0e16
Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/drig.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/kalachakra.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/kalachakra.cpython-311.pyc
new file mode 100644
index 0000000..48be3cb
Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/kalachakra.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/kendradhi_rasi.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/kendradhi_rasi.cpython-311.pyc
new file mode 100644
index 0000000..b2db59f
Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/kendradhi_rasi.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/lagnamsaka.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/lagnamsaka.cpython-311.pyc
new file mode 100644
index 0000000..45da1de
Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/lagnamsaka.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/mandooka.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/mandooka.cpython-311.pyc
new file mode 100644
index 0000000..f3b1b92
Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/mandooka.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/narayana.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/narayana.cpython-311.pyc
new file mode 100644
index 0000000..7159889
Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/narayana.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/navamsa.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/navamsa.cpython-311.pyc
new file mode 100644
index 0000000..26f723c
Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/navamsa.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/nirayana.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/nirayana.cpython-311.pyc
new file mode 100644
index 0000000..bca9b90
Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/nirayana.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/padhanadhamsa.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/padhanadhamsa.cpython-311.pyc
new file mode 100644
index 0000000..c895dc2
Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/padhanadhamsa.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/paryaaya.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/paryaaya.cpython-311.pyc
new file mode 100644
index 0000000..e872629
Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/paryaaya.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/sandhya.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/sandhya.cpython-311.pyc
new file mode 100644
index 0000000..6e80dff
Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/sandhya.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/shoola.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/shoola.cpython-311.pyc
new file mode 100644
index 0000000..f46a40e
Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/shoola.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/sthira.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/sthira.cpython-311.pyc
new file mode 100644
index 0000000..00252f7
Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/sthira.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/sudasa.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/sudasa.cpython-311.pyc
new file mode 100644
index 0000000..67fc7e7
Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/sudasa.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/tara_lagna.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/tara_lagna.cpython-311.pyc
new file mode 100644
index 0000000..de826fa
Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/tara_lagna.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/trikona.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/trikona.cpython-311.pyc
new file mode 100644
index 0000000..2c807ca
Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/trikona.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/varnada.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/varnada.cpython-311.pyc
new file mode 100644
index 0000000..933b68d
Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/varnada.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/yogardha.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/yogardha.cpython-311.pyc
new file mode 100644
index 0000000..8f00828
Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/yogardha.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/match/__pycache__/__init__.cpython-311.pyc b/src/jhora/horoscope/match/__pycache__/__init__.cpython-311.pyc
new file mode 100644
index 0000000..5403620
Binary files /dev/null and b/src/jhora/horoscope/match/__pycache__/__init__.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/match/__pycache__/compatibility.cpython-311.pyc b/src/jhora/horoscope/match/__pycache__/compatibility.cpython-311.pyc
new file mode 100644
index 0000000..d38fba1
Binary files /dev/null and b/src/jhora/horoscope/match/__pycache__/compatibility.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/prediction/__pycache__/__init__.cpython-311.pyc b/src/jhora/horoscope/prediction/__pycache__/__init__.cpython-311.pyc
new file mode 100644
index 0000000..afc3fff
Binary files /dev/null and b/src/jhora/horoscope/prediction/__pycache__/__init__.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/prediction/__pycache__/general.cpython-311.pyc b/src/jhora/horoscope/prediction/__pycache__/general.cpython-311.pyc
new file mode 100644
index 0000000..3ad9c6b
Binary files /dev/null and b/src/jhora/horoscope/prediction/__pycache__/general.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/transit/__pycache__/__init__.cpython-311.pyc b/src/jhora/horoscope/transit/__pycache__/__init__.cpython-311.pyc
new file mode 100644
index 0000000..425a8f0
Binary files /dev/null and b/src/jhora/horoscope/transit/__pycache__/__init__.cpython-311.pyc differ
diff --git a/src/jhora/horoscope/transit/__pycache__/saham.cpython-311.pyc b/src/jhora/horoscope/transit/__pycache__/saham.cpython-311.pyc
new file mode 100644
index 0000000..14bc566
Binary files /dev/null and b/src/jhora/horoscope/transit/__pycache__/saham.cpython-311.pyc differ
diff --git a/src/jhora/panchanga/__pycache__/__init__.cpython-311.pyc b/src/jhora/panchanga/__pycache__/__init__.cpython-311.pyc
new file mode 100644
index 0000000..c78f5de
Binary files /dev/null and b/src/jhora/panchanga/__pycache__/__init__.cpython-311.pyc differ
diff --git a/src/jhora/panchanga/__pycache__/drik.cpython-311.pyc b/src/jhora/panchanga/__pycache__/drik.cpython-311.pyc
new file mode 100644
index 0000000..98bc45f
Binary files /dev/null and b/src/jhora/panchanga/__pycache__/drik.cpython-311.pyc differ
diff --git a/src/jhora/panchanga/__pycache__/pancha_paksha.cpython-311.pyc b/src/jhora/panchanga/__pycache__/pancha_paksha.cpython-311.pyc
new file mode 100644
index 0000000..5b1b9a2
Binary files /dev/null and b/src/jhora/panchanga/__pycache__/pancha_paksha.cpython-311.pyc differ
diff --git a/src/jhora/panchanga/__pycache__/surya_sidhantha.cpython-311.pyc b/src/jhora/panchanga/__pycache__/surya_sidhantha.cpython-311.pyc
new file mode 100644
index 0000000..f76cbc9
Binary files /dev/null and b/src/jhora/panchanga/__pycache__/surya_sidhantha.cpython-311.pyc differ
diff --git a/src/jhora/panchanga/__pycache__/vratha.cpython-311.pyc b/src/jhora/panchanga/__pycache__/vratha.cpython-311.pyc
new file mode 100644
index 0000000..e1b51af
Binary files /dev/null and b/src/jhora/panchanga/__pycache__/vratha.cpython-311.pyc differ
diff --git a/src/jhora/requirements.txt b/src/jhora/requirements.txt
index 1d1269b..b570b1a 100644
--- a/src/jhora/requirements.txt
+++ b/src/jhora/requirements.txt
@@ -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
diff --git a/src/jhora/tests/test_ui.py b/src/jhora/tests/test_ui.py
index e39d1f1..9dd550c 100644
--- a/src/jhora/tests/test_ui.py
+++ b/src/jhora/tests/test_ui.py
@@ -18,6 +18,10 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
+import pytest
+
+pytest.skip("Manual UI test", allow_module_level=True)
+
import sys
from PyQt6.QtWidgets import QApplication
diff --git a/src/jhora/ui/__pycache__/__init__.cpython-311.pyc b/src/jhora/ui/__pycache__/__init__.cpython-311.pyc
new file mode 100644
index 0000000..7fdfbd6
Binary files /dev/null and b/src/jhora/ui/__pycache__/__init__.cpython-311.pyc differ
diff --git a/src/jhora/ui/__pycache__/chakra.cpython-311.pyc b/src/jhora/ui/__pycache__/chakra.cpython-311.pyc
new file mode 100644
index 0000000..240eed7
Binary files /dev/null and b/src/jhora/ui/__pycache__/chakra.cpython-311.pyc differ
diff --git a/src/jhora/ui/__pycache__/chart_styles.cpython-311.pyc b/src/jhora/ui/__pycache__/chart_styles.cpython-311.pyc
new file mode 100644
index 0000000..d5cb99a
Binary files /dev/null and b/src/jhora/ui/__pycache__/chart_styles.cpython-311.pyc differ
diff --git a/src/jhora/ui/__pycache__/conjunction_dialog.cpython-311.pyc b/src/jhora/ui/__pycache__/conjunction_dialog.cpython-311.pyc
new file mode 100644
index 0000000..d79b55a
Binary files /dev/null and b/src/jhora/ui/__pycache__/conjunction_dialog.cpython-311.pyc differ
diff --git a/src/jhora/ui/__pycache__/dhasa_bhukthi_options_dialog.cpython-311.pyc b/src/jhora/ui/__pycache__/dhasa_bhukthi_options_dialog.cpython-311.pyc
new file mode 100644
index 0000000..11b877d
Binary files /dev/null and b/src/jhora/ui/__pycache__/dhasa_bhukthi_options_dialog.cpython-311.pyc differ
diff --git a/src/jhora/ui/__pycache__/horo_chart_tabs.cpython-311.pyc b/src/jhora/ui/__pycache__/horo_chart_tabs.cpython-311.pyc
new file mode 100644
index 0000000..bfdbeeb
Binary files /dev/null and b/src/jhora/ui/__pycache__/horo_chart_tabs.cpython-311.pyc differ
diff --git a/src/jhora/ui/__pycache__/label_grid.cpython-311.pyc b/src/jhora/ui/__pycache__/label_grid.cpython-311.pyc
new file mode 100644
index 0000000..a3eb71e
Binary files /dev/null and b/src/jhora/ui/__pycache__/label_grid.cpython-311.pyc differ
diff --git a/src/jhora/ui/__pycache__/mixed_chart_dialog.cpython-311.pyc b/src/jhora/ui/__pycache__/mixed_chart_dialog.cpython-311.pyc
new file mode 100644
index 0000000..900ad51
Binary files /dev/null and b/src/jhora/ui/__pycache__/mixed_chart_dialog.cpython-311.pyc differ
diff --git a/src/jhora/ui/__pycache__/options_dialog.cpython-311.pyc b/src/jhora/ui/__pycache__/options_dialog.cpython-311.pyc
new file mode 100644
index 0000000..7dbc7fd
Binary files /dev/null and b/src/jhora/ui/__pycache__/options_dialog.cpython-311.pyc differ
diff --git a/src/jhora/ui/__pycache__/pancha_pakshi_sastra_widget.cpython-311.pyc b/src/jhora/ui/__pycache__/pancha_pakshi_sastra_widget.cpython-311.pyc
new file mode 100644
index 0000000..52ef0c4
Binary files /dev/null and b/src/jhora/ui/__pycache__/pancha_pakshi_sastra_widget.cpython-311.pyc differ
diff --git a/src/jhora/ui/__pycache__/panchangam.cpython-311.pyc b/src/jhora/ui/__pycache__/panchangam.cpython-311.pyc
new file mode 100644
index 0000000..7563b39
Binary files /dev/null and b/src/jhora/ui/__pycache__/panchangam.cpython-311.pyc differ
diff --git a/src/jhora/ui/__pycache__/varga_chart_dialog.cpython-311.pyc b/src/jhora/ui/__pycache__/varga_chart_dialog.cpython-311.pyc
new file mode 100644
index 0000000..83063eb
Binary files /dev/null and b/src/jhora/ui/__pycache__/varga_chart_dialog.cpython-311.pyc differ
diff --git a/src/jhora/ui/__pycache__/vratha_finder.cpython-311.pyc b/src/jhora/ui/__pycache__/vratha_finder.cpython-311.pyc
new file mode 100644
index 0000000..c4dd84d
Binary files /dev/null and b/src/jhora/ui/__pycache__/vratha_finder.cpython-311.pyc differ
diff --git a/src/jhora/ui/horo_chart_tabs.py b/src/jhora/ui/horo_chart_tabs.py
index 14bf437..7839654 100644
--- a/src/jhora/ui/horo_chart_tabs.py
+++ b/src/jhora/ui/horo_chart_tabs.py
@@ -18,21 +18,51 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-import re, sys, os
-sys.path.append('../')
-""" Get Package Version from _package_info.py """
-#import importlib.metadata
-#_APP_VERSION = importlib.metadata.version('PyJHora')
-#----------
-from PyQt6 import QtCore, QtGui
-from PyQt6.QtWidgets import QStyledItemDelegate, QWidget, QVBoxLayout, QHBoxLayout, QTabWidget, QTableWidget, \
- QListWidget, QTextEdit, QAbstractItemView, QAbstractScrollArea, QTableWidgetItem, \
- QGridLayout, QLayout, QLabel, QSizePolicy, QLineEdit, QCompleter, QComboBox, \
- QPushButton, QSpinBox, QCheckBox, QApplication, QDoubleSpinBox, QHeaderView, \
- QListWidgetItem,QMessageBox, QFileDialog, QButtonGroup, QRadioButton, QStackedWidget, \
- QTreeWidget
-from PyQt6.QtGui import QFont, QFontMetrics
+"""PyQt6 based UI for displaying horoscope charts."""
+
+import os
+import re
+import sys
+
+sys.path.append("../")
+
+from PyQt6 import QtGui
+from PyQt6 import QtCore
from PyQt6.QtCore import Qt
+from PyQt6.QtGui import QFont, QFontMetrics
+from PyQt6.QtWidgets import (
+ QApplication,
+ QCompleter,
+ QAbstractItemView,
+ QGridLayout,
+ QAbstractScrollArea,
+ QButtonGroup,
+ QCheckBox,
+ QComboBox,
+ QDoubleSpinBox,
+ QFileDialog,
+ QLabel,
+ QListWidget,
+ QListWidgetItem,
+ QHBoxLayout,
+ QHeaderView,
+ QLineEdit,
+ QLayout,
+ QMessageBox,
+ QPushButton,
+ QRadioButton,
+ QSizePolicy,
+ QSpinBox,
+ QStackedWidget,
+ QStyledItemDelegate,
+ QTabWidget,
+ QTableWidget,
+ QTableWidgetItem,
+ QTextEdit,
+ QTreeWidget,
+ QVBoxLayout,
+ QWidget,
+)
from _datetime import datetime, timedelta, timezone
import img2pdf
from PIL import Image
@@ -64,11 +94,14 @@
_images_path = const._IMAGES_PATH
_IMAGES_PER_PDF_PAGE = 2
_INPUT_DATA_FILE = const._INPUT_DATA_FILE
-_SHOW_GOURI_PANCHANG_OR_SHUBHA_HORA = 0 # 0=Gowri Panchang 1=Shubha Hora
+_SHOW_GOURI_PANCHANG_OR_SHUBHA_HORA = 0 # 0=Gowri Panchang 1=Shubha Hora
_world_city_csv_file = const._world_city_csv_file
-_planet_symbols=const._planet_symbols
+_planet_symbols = const._planet_symbols
_zodiac_symbols = const._zodiac_symbols
-""" UI Constants """
+
+# ---------------------------------------------------------------------------
+# UI Constants
+# ---------------------------------------------------------------------------
_main_window_width = 1000#750 #725
_main_window_height = 725#630 #580 #
_comp_table_font_size = 8
@@ -247,60 +280,116 @@
_compatibility_tab_start = _prediction_tab_start + 1
_tab_count = len(_tab_names)
-available_chart_types = {'south_indian':SouthIndianChart,'north_indian':NorthIndianChart,'east_indian':EastIndianChart,
- 'western':WesternChart,'sudarsana_chakra':SudarsanaChakraChart}
+available_chart_types = {
+ 'south_indian': SouthIndianChart,
+ 'north_indian': NorthIndianChart,
+ 'east_indian': EastIndianChart,
+ 'western': WesternChart,
+ 'sudarsana_chakra': SudarsanaChakraChart,
+}
available_languages = const.available_languages
+
+# ---------------------------------------------------------------------------
+# Delegate classes
+# ---------------------------------------------------------------------------
class AlignDelegate(QStyledItemDelegate):
+ """Center-aligns text within table cells."""
+
def initStyleOption(self, option, index):
- super(AlignDelegate, self).initStyleOption(option, index)
+ super().initStyleOption(option, index)
option.displayAlignment = QtCore.Qt.AlignmentFlag.AlignHCenter
class GrowingTextEdit(QTextEdit):
+ """Text edit that grows vertically to fit its contents."""
def __init__(self, *args, **kwargs):
- super(GrowingTextEdit, self).__init__(*args, **kwargs)
+ super().__init__(*args, **kwargs)
self.document().contentsChanged.connect(self.sizeChange)
self.heightMin = 0
self.heightMax = 65000
- def sizeChange(self):
- docHeight = int(self.document().size().height())
- if self.heightMin <= docHeight <= self.heightMax:
- self.setMinimumHeight(docHeight)
+ def sizeChange(self) -> None:
+ doc_height = int(self.document().size().height())
+ if self.heightMin <= doc_height <= self.heightMax:
+ self.setMinimumHeight(doc_height)
+
+
+# ---------------------------------------------------------------------------
+# Main application widget
+# ---------------------------------------------------------------------------
class ChartTabbed(QWidget):
- def __init__(self,chart_type='south_indian',show_marriage_compatibility=True, calculation_type:str='drik',
- language = 'English',date_of_birth=None,time_of_birth=None,place_of_birth=None, gender=0,
- use_world_city_database=const.check_database_for_world_cities,
- use_internet_for_location_check=const.use_internet_for_location_check):
- """
- @param chart_type: One of 'South_Indian','North_Indian','East_Indian','Western','Sudarsana_Chakra'
- Default: 'south indian'
- @param date_of_birth: string in the format 'yyyy,m,d' e.g. '2024,1,1' or '2024,01,01'
- @param time_of_birth: string in the format 'hh:mm:ss' in 24hr format. e.g. '19:07:04'
- @param place_of_birth: tuple in the format ('place_name',latitude_float,longitude_float,timezone_hrs_float)
- e.g. ('Chennai, India',13.0878,80.2785,5.5)
- @param language: One of 'English','Hindi','Tamil','Telugu','Kannada'; Default:English
- @param gender: 0='Female',1='Male',2='Transgender',3='No preference'; Default=0
- """
+ """Main widget that hosts all horoscope related tabs."""
+
+ def __init__(
+ self,
+ chart_type: str = "south_indian",
+ show_marriage_compatibility: bool = True,
+ calculation_type: str = "drik",
+ language: str = "English",
+ date_of_birth: str | None = None,
+ time_of_birth: str | None = None,
+ place_of_birth: tuple | None = None,
+ gender: int = 0,
+ use_world_city_database: bool = const.check_database_for_world_cities,
+ use_internet_for_location_check: bool = const.use_internet_for_location_check,
+ ) -> None:
+ """Initialize the tabbed horoscope widget."""
+
super().__init__()
+ self._initialize_state(
+ chart_type,
+ show_marriage_compatibility,
+ calculation_type,
+ language,
+ place_of_birth,
+ use_world_city_database,
+ use_internet_for_location_check,
+ )
+
+ self._build_ui()
+ self._populate_defaults(date_of_birth, time_of_birth, gender)
+
+ # ------------------------------------------------------------------
+ # Initialization helpers
+ # ------------------------------------------------------------------
+ def _initialize_state(
+ self,
+ chart_type: str,
+ show_marriage_compatibility: bool,
+ calculation_type: str,
+ language: str,
+ place_of_birth,
+ use_world_city_database: bool,
+ use_internet_for_location_check: bool,
+ ) -> None:
+ """Set up instance variables and global settings."""
+
self._horo = None
self.use_world_city_database = use_world_city_database
self.use_internet_for_location_check = use_internet_for_location_check
- self._chart_type = chart_type if chart_type.lower() in const.available_chart_types else 'south_indian'
- self._language = language; utils.set_language(available_languages[language])
+ self._chart_type = (
+ chart_type if chart_type.lower() in const.available_chart_types else "south_indian"
+ )
+ self._language = language
+ utils.set_language(available_languages[language])
utils.use_database_for_world_cities(use_world_city_database)
self.resources = utils.resource_strings
self._place_name = place_of_birth
self._bhava_chart_type = chart_type
self._calculation_type = calculation_type
self._show_compatibility = show_marriage_compatibility
- ' read world cities'
- #self._df = utils._world_city_db_df
- #self._world_cities_db = utils.world_cities_db
- self._conjunction_dialog_accepted = False; self._conj_planet1=''; self._conj_planet2=''; self._raasi=''
- self._lunar_month_type = ''
- self._separation_angle_list = []
- self._separation_angle_index = 0
+
+ self._conjunction_dialog_accepted = False
+ self._conj_planet1 = ""
+ self._conj_planet2 = ""
+ self._raasi = ""
+ self._lunar_month_type = ""
+ self._separation_angle_list: list = []
+ self._separation_angle_index = 0
+
+ def _build_ui(self) -> None:
+ """Construct all UI widgets."""
+
self._init_main_window()
self._v_layout = QVBoxLayout()
self._create_row1_ui()
@@ -308,24 +397,31 @@ def __init__(self,chart_type='south_indian',show_marriage_compatibility=True, ca
if self._show_compatibility:
self._create_comp_ui()
self._init_tab_widget_ui()
- current_date_str,current_time_str = datetime.now().strftime('%Y,%m,%d;%H:%M:%S').split(';')
- if date_of_birth == None:
+
+ def _populate_defaults(self, date_of_birth: str | None, time_of_birth: str | None, gender: int) -> None:
+ """Populate initial values and compute julian day."""
+
+ current_date_str, current_time_str = datetime.now().strftime("%Y,%m,%d;%H:%M:%S").split(";")
+ if date_of_birth is None:
self.date_of_birth(current_date_str)
- if time_of_birth == None:
+ if time_of_birth is None:
self.time_of_birth(current_time_str)
+
if not self._validate_ui() and self.use_internet_for_location_check:
loc = utils.get_place_from_user_ip_address()
- print('loc from IP address',loc)
- if len(loc)==4:
- print('setting values from loc')
- self.place(loc[0],loc[1],loc[2],loc[3])
- if gender==None or gender not in [0,1,2,3]: self.gender(0)
- year,month,day = self._dob_text.text().split(",")
- dob = (int(year),int(month),int(day))
- tob = tuple([int(x) for x in self._tob_text.text().split(':')])
+ if len(loc) == 4:
+ self.place(loc[0], loc[1], loc[2], loc[3])
+
+ if gender is None or gender not in [0, 1, 2, 3]:
+ self.gender(0)
+ else:
+ self.gender(gender)
+
+ year, month, day = self._dob_text.text().split(",")
+ dob = (int(year), int(month), int(day))
+ tob = tuple(int(x) for x in self._tob_text.text().split(":"))
self._birth_julian_day = utils.julian_day_number(dob, tob)
- """ Commented in V4.0.4 to force explicit calling """
- #self.compute_horoscope(calculation_type=self._calculation_type)
+
def _hide_2nd_row_widgets(self,show=True):
self._dob_label.setVisible(show)
self._dob_text.setVisible(show)
@@ -5616,7 +5712,7 @@ def except_hook(cls, exception, traceback):
sys.excepthook = except_hook
App = QApplication(sys.argv)
chart = ChartTabbed()
- chart.language('Tamil')
+ chart.language('English')
"""
chart.name('XXX')#'('Rama')
chart.gender(1) #(0)
diff --git a/src/pyside_app/__init__.py b/src/pyside_app/__init__.py
new file mode 100644
index 0000000..2a5661f
--- /dev/null
+++ b/src/pyside_app/__init__.py
@@ -0,0 +1 @@
+"""PySide6 desktop application for AstroCal."""
diff --git a/src/pyside_app/main.py b/src/pyside_app/main.py
new file mode 100644
index 0000000..b8737a3
--- /dev/null
+++ b/src/pyside_app/main.py
@@ -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())
diff --git a/tests/conftest.py b/tests/conftest.py
new file mode 100644
index 0000000..8c01c5b
--- /dev/null
+++ b/tests/conftest.py
@@ -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()
diff --git a/tests/test_pyside_app.py b/tests/test_pyside_app.py
new file mode 100644
index 0000000..bb7c733
--- /dev/null
+++ b/tests/test_pyside_app.py
@@ -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"]