Minor changes
This commit is contained in:
commit
79ce6bc894
11 changed files with 491 additions and 0 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
env/
|
||||
**/__pycache__
|
||||
**/*.db
|
6
notes.org
Normal file
6
notes.org
Normal file
|
@ -0,0 +1,6 @@
|
|||
|
||||
|
||||
|
||||
|
||||
- [[https://doc.qt.io/qtforpython-6/PySide6/QtGui/QPainterPath.html][Qt6 Python doc]]
|
||||
- [[https://stackoverflow.com/questions/9249842/how-does-qt-draw-a-border-around-a-rectangle][How rectangle border drawn]]
|
1
tropical/__init__.py
Normal file
1
tropical/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
|
49
tropical/calstate.py
Normal file
49
tropical/calstate.py
Normal file
|
@ -0,0 +1,49 @@
|
|||
|
||||
import calendar
|
||||
from datetime import date, timedelta
|
||||
|
||||
class CalState:
|
||||
|
||||
def __init__(self):
|
||||
self.gotoToday()
|
||||
self.firstWeekDay=0
|
||||
|
||||
def setFirstWeekDay(self, i):
|
||||
self.firstWeekDay=i
|
||||
|
||||
def goto(self, year, month, day):
|
||||
self.year=year
|
||||
self.month=month
|
||||
self.day=day
|
||||
|
||||
def gotoToday(self):
|
||||
today = date.today()
|
||||
self.goto(today.year, today.month, today.day)
|
||||
|
||||
def gotoNextWeek(self):
|
||||
day=date(self.year,self.month,self.day) + timedelta(weeks=1)
|
||||
self.goto(day.year,day.month, day.day)
|
||||
|
||||
def gotoPrevWeek(self):
|
||||
day=date(self.year,self.month,self.day) - timedelta(weeks=1)
|
||||
self.goto(day.year,day.month, day.day)
|
||||
|
||||
def getMonthDays(self):
|
||||
cal=calendar.Calendar()
|
||||
days=list()
|
||||
for day in cal.itermonthdays4(self.year, self.month):
|
||||
days.append(day)
|
||||
return days
|
||||
|
||||
def getWeekDays(self):
|
||||
daysMonth=self.getMonthDays()
|
||||
daysWeek=list()
|
||||
for year, month, day, count in daysMonth:
|
||||
daysWeek.append((year,month,day,count))
|
||||
if len(daysWeek) >= 7:
|
||||
# Check if day within the week
|
||||
for yy, mm, dd, cc in daysWeek:
|
||||
if (yy, mm, dd) == (self.year, self.month, self.day):
|
||||
return daysWeek
|
||||
daysWeek.clear()
|
||||
return None
|
37
tropical/db.py
Normal file
37
tropical/db.py
Normal file
|
@ -0,0 +1,37 @@
|
|||
import sqlite3, time, socket
|
||||
|
||||
|
||||
class CalDB:
|
||||
__DBVERSION__="1"
|
||||
|
||||
def __init__(self, dbPath):
|
||||
self.path=dbPath
|
||||
self.con=sqlite3.connect(dbPath)
|
||||
self.cur=self.con.cursor()
|
||||
|
||||
# Init database
|
||||
res=self.cur.execute('SELECT name FROM sqlite_master WHERE type="table" AND name="infos";')
|
||||
if res.fetchone() is None:
|
||||
self.initDB()
|
||||
|
||||
def initDB(self):
|
||||
# Infos table
|
||||
self.cur.execute("CREATE TABLE infos(name UNIQUE, value TEXT)")
|
||||
self.cur.execute('INSERT INTO infos VALUES("dbversion", "'+CalDB.__DBVERSION__+'")')
|
||||
self.cur.execute('INSERT INTO infos VALUES("creation", "'+str(time.time())+'")')
|
||||
self.cur.execute('INSERT INTO infos VALUES("created_on", "'+socket.gethostname()+'")')
|
||||
# Calendars table
|
||||
self.cur.execute("CREATE TABLE calendars(id INTEGER PRIMARY KEY, name TEXT, description TEXT, color TEXT)")
|
||||
# Events table
|
||||
self.cur.execute("CREATE TABLE events(id INTEGER PRIMARY KEY, name TEXT, calendar INTEGER, description TEXT, start REAL, end REAL, repeat TEXT, frequency INTEGER, FOREIGN KEY(calendar) REFERENCES calendars(id))")
|
||||
self.con.commit()
|
||||
|
||||
def keyExists(self, db, key):
|
||||
res=self.cur.execute("SELECT * FROM {} WHERE id={}".format(db,key))
|
||||
return not res.fetchone() is None
|
||||
|
||||
def addEvent(self, event):
|
||||
"""
|
||||
Event format: { name: str, calendar: int, desc: str, start: float, end: float, repeat: str, frequency: int }
|
||||
"""
|
||||
pass
|
1
tropical/qt/__init__.py
Normal file
1
tropical/qt/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
|
192
tropical/qt/caldrawer.py
Normal file
192
tropical/qt/caldrawer.py
Normal file
|
@ -0,0 +1,192 @@
|
|||
|
||||
from PyQt6.QtWidgets import QGraphicsScene, QGraphicsView, QSizePolicy
|
||||
from PyQt6 import uic, QtGui, QtCore
|
||||
from PyQt6.QtCore import Qt, QRect
|
||||
import math
|
||||
#https://forum.qt.io/topic/93327/how-can-i-use-qpainter-to-paint-on-qgraphicsview/5
|
||||
#https://www.pythonguis.com/tutorials/pyqt6-bitmap-graphics/#qpainter
|
||||
|
||||
# to solve the fit problem: https://stackoverflow.com/questions/61886358/qgraphicsview-fitinview-not-working-as-expected
|
||||
|
||||
class CalQGraphicsView(QGraphicsView):
|
||||
def __init__(self, scene):
|
||||
super().__init__(None)
|
||||
self.setScene(scene)
|
||||
|
||||
def resizeEvent(self, event):
|
||||
self.fitInView(self.sceneRect(), Qt.AspectRatioMode.IgnoreAspectRatio)
|
||||
|
||||
|
||||
class CalDrawerScene(QGraphicsScene):
|
||||
def __init__(self, calState):
|
||||
self.gridWidth=2
|
||||
self.daysLabelBG="#dddddd"
|
||||
self.eventsLabelBG="#36e364"
|
||||
super().__init__(None)
|
||||
self.showWeekends=True
|
||||
self.daysRect=list()
|
||||
self.eventsRect=list()
|
||||
self.calState=calState
|
||||
self.daysNames=["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"]
|
||||
|
||||
def drawForeground(self, painter, rect):
|
||||
origXF, origYF, widthF, heightF = rect.getRect()
|
||||
origXI, origYI, widthI, heightI = (int(origXF),int(origYF),int(widthF),int(heightF))
|
||||
self.defaultBrush=painter.brush()
|
||||
self.daysRect.clear()
|
||||
self.eventsRect.clear()
|
||||
daysNamesH=self.drawDaysName(painter, origXI, origYI, widthI, heightI)
|
||||
self.drawGrid(painter, origXI, origYI+daysNamesH, widthI, heightI-daysNamesH)
|
||||
self.drawDaysLabel(painter)
|
||||
self.drawEvents(painter)
|
||||
|
||||
def drawDaysName(self, painter, x, y, width, height):
|
||||
# Init Pen
|
||||
pen=QtGui.QPen()
|
||||
pen.setWidth(self.gridWidth)
|
||||
pen.setJoinStyle(Qt.PenJoinStyle.MiterJoin)
|
||||
po=int(self.gridWidth/2) # Pen offset
|
||||
painter.setPen(pen)
|
||||
# Init Brush
|
||||
painter.setBrush(Qt.BrushStyle.NoBrush)
|
||||
# Setup dimensions
|
||||
weekLength=7
|
||||
font=painter.font()
|
||||
metric=QtGui.QFontMetrics(font);
|
||||
labelH=metric.boundingRect("".join(self.daysNames)).height()
|
||||
margin=0
|
||||
offsetY=int(labelH/2)+int(labelH/4)+margin
|
||||
w=int((width-po*2)/weekLength)
|
||||
h=int(labelH)
|
||||
for i in range(0, 7):
|
||||
labelW=metric.boundingRect(self.daysNames[i]).width()
|
||||
offsetX=int(w/2-labelW/2)
|
||||
# painter.drawText(x+offsetX+w*i,y+offsetY,self.daysNames[i])
|
||||
painter.drawText(x+w*i,y,w,h,Qt.AlignmentFlag.AlignHCenter,self.daysNames[i])
|
||||
rect=QRect(x+po+w*i,y+po,w,h) # Draw grid
|
||||
painter.drawRect(rect)
|
||||
return labelH
|
||||
|
||||
def drawGrid(self,painter, x, y, width, height):
|
||||
# Init Pen
|
||||
pen=QtGui.QPen()
|
||||
pen.setWidth(self.gridWidth)
|
||||
pen.setJoinStyle(Qt.PenJoinStyle.MiterJoin)
|
||||
po=int(self.gridWidth/2) # Pen offset
|
||||
painter.setPen(pen)
|
||||
# Init Brush
|
||||
painter.setBrush(Qt.BrushStyle.NoBrush)
|
||||
# Setup dimensions
|
||||
weekLength=7
|
||||
if not self.showWeekends:
|
||||
weekLength=5
|
||||
daysCount=weekLength*6
|
||||
|
||||
|
||||
# brush=QtGui.QBrush()
|
||||
# brush.setColor(QtGui.QColor("#0000FF"))
|
||||
# brush.setStyle(Qt.BrushStyle.SolidPattern)
|
||||
|
||||
|
||||
w=int((width-po*2)/weekLength)
|
||||
h=int((height-po*2)/6)
|
||||
row=0
|
||||
col=0
|
||||
self.daysRect.clear()
|
||||
while row*weekLength+col<daysCount:
|
||||
rect=QRect(x+po+w*col,y+po+row*h,w,h) # Draw grid
|
||||
rectInside=QRect(rect.x()+po,rect.y()+po,rect.width()-po*2,rect.height()-po*2) # Area within grid (within stroke)
|
||||
self.daysRect.append(rectInside) # Store this region for later drawing
|
||||
# if col==0 and row == 0:
|
||||
# painter.setBrush(brush)
|
||||
# painter.setPen(Qt.PenStyle.NoPen)
|
||||
# painter.drawRect(QRect(b.x(),b.y(),b.width(),b.height()))
|
||||
# painter.setPen(self.gridPen)
|
||||
# painter.setBrush(self.defaultBrush)
|
||||
painter.drawRect(rect)
|
||||
col+=1
|
||||
if col==weekLength:
|
||||
col=0
|
||||
row+=1
|
||||
|
||||
def drawDaysLabel(self,painter):
|
||||
# Init Pen
|
||||
pen=QtGui.QPen()
|
||||
pen.setWidth(self.gridWidth)
|
||||
pen.setJoinStyle(Qt.PenJoinStyle.MiterJoin)
|
||||
po=int(self.gridWidth/2) # Pen offset
|
||||
# Init Brush
|
||||
brush=QtGui.QBrush()
|
||||
brush.setColor(QtGui.QColor(self.daysLabelBG))
|
||||
brush.setStyle(Qt.BrushStyle.SolidPattern)
|
||||
painter.setBrush(brush)
|
||||
# Init various things
|
||||
days=self.calState.getMonthDays()
|
||||
font=painter.font()
|
||||
metric=QtGui.QFontMetrics(font);
|
||||
labelH=metric.boundingRect("1234567890").height()
|
||||
margin=0
|
||||
offsetY=int(labelH/2)+int(labelH/4)+margin
|
||||
# Draw labels
|
||||
for i in range(0,len(self.daysRect)):
|
||||
r=self.daysRect[i]
|
||||
d=days[i]
|
||||
dayLabel=str(d[2])
|
||||
labelW=metric.boundingRect(dayLabel).width()
|
||||
offsetX=int(r.width()/2-labelW/2)
|
||||
painter.setPen(Qt.PenStyle.NoPen)
|
||||
painter.drawRect(r.x(),r.y(),r.width(),labelH) # Remember r is within grid stroke
|
||||
painter.setPen(pen)
|
||||
# painter.drawText(r.x()+offsetX,r.y()+offsetY,dayLabel)
|
||||
painter.drawText(r,Qt.AlignmentFlag.AlignHCenter,dayLabel)
|
||||
self.eventsRect.append(QRect(r.x(),r.y()+labelH+margin,r.width(),r.height()-(labelH+margin)))
|
||||
|
||||
def drawEvents(self,painter):
|
||||
# Init Pen
|
||||
pen=QtGui.QPen()
|
||||
pen.setWidth(self.gridWidth)
|
||||
pen.setJoinStyle(Qt.PenJoinStyle.MiterJoin)
|
||||
po=int(self.gridWidth/2) # Pen offset
|
||||
# Init Brush
|
||||
brush=QtGui.QBrush()
|
||||
brush.setColor(QtGui.QColor(self.eventsLabelBG))
|
||||
brush.setStyle(Qt.BrushStyle.SolidPattern)
|
||||
painter.setBrush(brush)
|
||||
# Init various things
|
||||
days=self.calState.getMonthDays()
|
||||
font=painter.font()
|
||||
metric=QtGui.QFontMetrics(font);
|
||||
labelH=metric.height()
|
||||
margin=0
|
||||
colMark=5
|
||||
colMarkPadding=2
|
||||
offsetY=int(labelH/2)+int(labelH/4)+margin
|
||||
# Draw
|
||||
po=int(self.gridWidth/2) # Pen offset
|
||||
for r in self.eventsRect:
|
||||
offsetX=colMark+colMarkPadding
|
||||
painter.drawText(r.x()+po+offsetX,r.y(),r.width()-offsetX-po*2,r.height(),0,"event testddddddddddddd")
|
||||
painter.setPen(Qt.PenStyle.NoPen)
|
||||
painter.drawRect(r.x(),r.y(),colMark,labelH) # Remember r is within grid stroke
|
||||
painter.setPen(pen)
|
||||
|
||||
class CalDrawer():
|
||||
|
||||
def __init__(self, layout, calState):
|
||||
self.gs=CalDrawerScene(calState)
|
||||
self.gv=CalQGraphicsView(self.gs)
|
||||
# Setup propertion
|
||||
spLeft=QSizePolicy(QSizePolicy.Policy.Preferred,QSizePolicy.Policy.Preferred);
|
||||
spLeft.setHorizontalStretch(3);
|
||||
self.gv.setSizePolicy(spLeft);
|
||||
|
||||
# if jean:
|
||||
# spLeft=QSizePolicy(QSizePolicy.Policy.Preferred,QSizePolicy.Policy.Preferred);
|
||||
# spLeft.setHorizontalStretch(2);
|
||||
# self.gv.setSizePolicy(spLeft);
|
||||
# else:
|
||||
# spLeft=QSizePolicy(QSizePolicy.Policy.Preferred,QSizePolicy.Policy.Preferred);
|
||||
# spLeft.setHorizontalStretch(1);
|
||||
# self.gv.setSizePolicy(spLeft);
|
||||
layout.addWidget(self.gv)
|
||||
|
81
tropical/qt/designer/MainWindow.ui
Normal file
81
tropical/qt/designer/MainWindow.ui
Normal file
|
@ -0,0 +1,81 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>448</width>
|
||||
<height>623</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MainWindow</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::LeftToRight</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QFrame" name="calContainer">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2"/>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton">
|
||||
<property name="text">
|
||||
<string>PushButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>448</width>
|
||||
<height>22</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuFile">
|
||||
<property name="title">
|
||||
<string>File</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuAbout">
|
||||
<property name="title">
|
||||
<string>About</string>
|
||||
</property>
|
||||
</widget>
|
||||
<addaction name="menuFile"/>
|
||||
<addaction name="menuAbout"/>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
<widget class="QToolBar" name="toolBar">
|
||||
<property name="windowTitle">
|
||||
<string>toolBar</string>
|
||||
</property>
|
||||
<attribute name="toolBarArea">
|
||||
<enum>TopToolBarArea</enum>
|
||||
</attribute>
|
||||
<attribute name="toolBarBreak">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
61
tropical/qt/eventdrawer.py
Normal file
61
tropical/qt/eventdrawer.py
Normal file
|
@ -0,0 +1,61 @@
|
|||
|
||||
from PyQt6.QtWidgets import QGraphicsScene, QGraphicsView, QSizePolicy
|
||||
from PyQt6 import uic, QtGui, QtCore
|
||||
from PyQt6.QtCore import Qt, QRect
|
||||
import math
|
||||
#https://forum.qt.io/topic/93327/how-can-i-use-qpainter-to-paint-on-qgraphicsview/5
|
||||
#https://www.pythonguis.com/tutorials/pyqt6-bitmap-graphics/#qpainter
|
||||
|
||||
# to solve the fit problem: https://stackoverflow.com/questions/61886358/qgraphicsview-fitinview-not-working-as-expected
|
||||
|
||||
class EvtQGraphicsView(QGraphicsView):
|
||||
def __init__(self, scene):
|
||||
super().__init__(None)
|
||||
self.setScene(scene)
|
||||
|
||||
def resizeEvent(self, event):
|
||||
self.fitInView(self.sceneRect(), Qt.AspectRatioMode.IgnoreAspectRatio)
|
||||
|
||||
|
||||
class EvtDrawerScene(QGraphicsScene):
|
||||
def __init__(self, calState):
|
||||
self.gridWidth=2
|
||||
super().__init__(None)
|
||||
self.calState=calState
|
||||
|
||||
def drawForeground(self, painter, rect):
|
||||
origXF, origYF, widthF, heightF = rect.getRect()
|
||||
origXI, origYI, widthI, heightI = (int(origXF),int(origYF),int(widthF),int(heightF))
|
||||
self.drawEvents(painter,origXI, origYI, widthI, heightI)
|
||||
|
||||
|
||||
def drawEvents(self,painter,x,y,width,height):
|
||||
# Init Pen
|
||||
pen=QtGui.QPen()
|
||||
pen.setWidth(self.gridWidth)
|
||||
pen.setJoinStyle(Qt.PenJoinStyle.MiterJoin)
|
||||
po=int(self.gridWidth/2) # Pen offset
|
||||
painter.setPen(pen)
|
||||
|
||||
painter.drawRect(x+po,y+po,width-po*2,height-po*2)
|
||||
|
||||
class EvtDrawer():
|
||||
|
||||
def __init__(self, layout, calState):
|
||||
self.gs=EvtDrawerScene(calState)
|
||||
self.gv=EvtQGraphicsView(self.gs)
|
||||
# Setup propertion
|
||||
spLeft=QSizePolicy(QSizePolicy.Policy.Preferred,QSizePolicy.Policy.Preferred);
|
||||
spLeft.setHorizontalStretch(1);
|
||||
self.gv.setSizePolicy(spLeft);
|
||||
|
||||
# if jean:
|
||||
# spLeft=QSizePolicy(QSizePolicy.Policy.Preferred,QSizePolicy.Policy.Preferred);
|
||||
# spLeft.setHorizontalStretch(2);
|
||||
# self.gv.setSizePolicy(spLeft);
|
||||
# else:
|
||||
# spLeft=QSizePolicy(QSizePolicy.Policy.Preferred,QSizePolicy.Policy.Preferred);
|
||||
# spLeft.setHorizontalStretch(1);
|
||||
# self.gv.setSizePolicy(spLeft);
|
||||
layout.addWidget(self.gv)
|
||||
|
41
tropical/qt/mainwindow.py
Normal file
41
tropical/qt/mainwindow.py
Normal file
|
@ -0,0 +1,41 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
|
||||
from PyQt6.QtWidgets import QApplication, QWidget, QMainWindow
|
||||
from PyQt6 import uic, QtGui
|
||||
from PyQt6.QtCore import Qt
|
||||
from .caldrawer import CalDrawer
|
||||
from .eventdrawer import EvtDrawer
|
||||
|
||||
# Only needed for access to command line arguments
|
||||
import sys, os
|
||||
|
||||
|
||||
class MainWindow(QMainWindow):
|
||||
|
||||
def __init__(self,uipath, calState):
|
||||
super(MainWindow,self).__init__()
|
||||
uic.loadUi(uipath+"/MainWindow.ui",self)
|
||||
self.calDrawer=CalDrawer(self.calContainer.layout(),calState)
|
||||
self.evtDrawer=EvtDrawer(self.calContainer.layout(),calState)
|
||||
self.calState=calState
|
||||
self.show()
|
||||
|
||||
def setVersion(self,version):
|
||||
self.statusbar.showMessage("Calanus v"+version,0)
|
||||
|
||||
def StartApplication(version,calState):
|
||||
path = os.path.dirname(os.path.abspath(__file__))+"/designer"
|
||||
# You need one (and only one) QApplication instance per application.
|
||||
# Pass in sys.argv to allow command line arguments for your app.
|
||||
# If you know you won't use command line arguments QApplication([]) works too.
|
||||
app = QApplication(sys.argv)
|
||||
|
||||
# Create a Qt widget, which will be our window.
|
||||
window = MainWindow(path, calState)
|
||||
window.setVersion(version)
|
||||
window.show() # IMPORTANT!!!!! Windows are hidden by default.
|
||||
|
||||
# Start the event loop.
|
||||
app.exec()
|
||||
return window
|
19
tropical/tropical.py
Executable file
19
tropical/tropical.py
Executable file
|
@ -0,0 +1,19 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import qt.mainwindow as QtCalanus
|
||||
from calstate import CalState
|
||||
from db import CalDB
|
||||
|
||||
__VERSION__ = "0.1"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
calState=CalState()
|
||||
QtCalanus.StartApplication(__VERSION__,calState)
|
||||
#print(db.keyExists("calendars",1))
|
||||
#db=CalDB("sqlite.db")
|
Loading…
Add table
Reference in a new issue