import time
+def today():
+ t=time.time() - time.timezone
+ day=int(t/86400)
+
+ return(day)
+
+# Defaults for a girl
+defaults={
+ 'cycle': 28, # Cycle length
+ 'menstr': 5, # Duration of menstruation
+ 'ovday': -14, # When ovulation happens. Positive: This number
+ # of days after the start of the cycle.
+ # Negative: This number of days before the end
+ # of the cycle.
+ 'day0': today()
+ }
+
class Algo(object):
def __init__(self):
t=today()
- self.setReference(t, 28)
+ self.setReference(t, defaults)
# set day "day" as the reference day of starting period cycle
# day is int(time.time()/86400)
# cycle is the cycle width in days, starting from 0
- def setReference(self, day, cycle):
+ def setReference(self, day, cfg):
+ self.cfg=cfg
self.refday=day
- self.cycle=cycle
# Convert an arbitary day to a day in cycle
def dayInCycle(self, day):
- d=(day-self.refday) % self.cycle
+ d=(day-self.refday) % self.cfg['cycle']
if d<0:
- d+=self.cycle
+ d+=self.cycleLength()
return(d)
def cycleLength(self):
- return(self.cycle)
+ return(self.cfg['cycle'])
def currentDayInCycle(self):
d=today()
return(self.dayInCycle(d))
+ def menstruationDuration(self):
+ return(self.cfg['menstr'])
+
+ def ovulationDay(self):
+ return(self.cfg['ovday'])
+
# Return:
# ret={
# 'status': ['ok', 'red']
def status(self, day):
d=self.dayInCycle(day)
- ovbefore=14
+ cycle=self.cycleLength()
- if d<5:
+ #ovbefore=14
+ ovday=self.ovulationDay()
+ if ovday>0:
+ ovstart=ovday-3
+ ovmid=ovday
+ ovend=ovday+1
+ else:
+ ovstart=cycle+ovday-3
+ ovmid=cycle+ovday
+ ovend=cycle+ovday+1
+
+ menstr=self.menstruationDuration()
+
+ if d<menstr:
# Red
ret={
'status': 'red',
'day': d,
- 'len': 5,
+ 'len': menstr,
}
- elif d>=self.cycle-7:
+ elif d>=cycle-7:
ret={
'status': 'blue',
- 'day': 7+d-self.cycle,
+ 'day': 7+d-cycle,
'len': 7,
}
- elif d>self.cycle-ovbefore-4 and d<=self.cycle-ovbefore:
+ elif d>=ovstart and d<=ovmid:
ret={
'status': 'green',
- 'day': d-self.cycle+ovbefore+3,
+ 'day': d-ovstart,
'len': 4,
}
- elif d>self.cycle-16 and d<=self.cycle-ovbefore+1:
+ elif d>ovmid and d<=ovend:
ret={
'status': 'green',
'day': 2,
ret={
'status': 'ok',
'day': d,
- 'len': self.cycle
+ 'len': cycle
}
return(ret)
-def today():
- t=time.time() - time.timezone
- day=int(t/86400)
-
- return(day)
-
# vim: set ts=8 sts=4 sw=4 noet formatoptions=r ai nocindent:
import time
import algo
-version="1.2"
+version="1.3"
try:
home=os.environ['HOME']
fn="%s/.maegirls" % (home, )
-# Defaults for a girl
-defaults={
- 'cycle': 28,
- 'day0': algo.today(),
- }
-
# Default config
defaultcfg={
- 'ver': 1, # Configuration version
+ 'ver': 2, # Configuration version
'girls': { # List of configured girls
- 'default': defaults
+ 'default': algo.defaults
},
'cur': "default", # Current girl
}
+def upgradeConfig(cfg):
+ """ Upgrade the loaded config to the latest version """
+
+ if cfg['ver']==1:
+ cfg['ver']=2
+ for i in cfg['girls']:
+ girl=cfg['girls'][i]
+ girl['menstr']=algo.defaults['menstr']
+ girl['ovday']=algo.defaults['ovday']
+
+ return(cfg)
+
def loadConfig():
try:
f=file(fn, "r")
st=f.read()
f.close()
ret=pickle.loads(st)
+ ret=upgradeConfig(ret)
except:
ret={}
return(ret)
def sanitize_before_store(cfg0):
+ """ Ensure that Qt strings (keys) are converted to standard strings """
cfg={
'ver': cfg0['ver'],
'cur': str(cfg0['cur']),
return(cfg)
def storeConfig(cfg0):
- cfg0['ver']=1
+ cfg0['ver']=2
cfg=sanitize_before_store(cfg0)
# print "store:", cfg
st=pickle.dumps(cfg)
cfg['girls'][name]={
'cycle': dt['cycle'],
'day0': dt['day0'],
+ 'ovday': dt['ovday'],
+ 'menstr': dt['menstr'],
}
storeConfig(cfg)
def newGirl(name):
- global defaults
-
- storeGirl(name, defaults)
+ storeGirl(name, algo.defaults)
def loadGirls():
cfg=loadConfig()
if all.has_key(name):
ret=all[name]
else:
- ret=defaults
+ ret=algo.defaults
return(ret)
self.editName=QLineEdit(self)
self.editCycle=QSpinBox(self)
self.editCurrent=QSpinBox(self)
+ self.editMenstr=QSpinBox(self)
+ self.editOvday=QSpinBox(self)
+
self.editCycle.setRange(10,50)
self.editCurrent.setRange(1,50)
+ self.editMenstr.setRange(3,7)
+ self.editOvday.setRange(-30,+30)
+
self.editCurrent.setWrapping(True)
self.editCycle.setSuffix(self.tr(" days"))
+ self.editMenstr.setSuffix(self.tr(' days'))
+ self.editOvday.setSuffix(self.tr(' days'))
self.editCycle.valueChanged.connect(self.slotEditCycleChanged)
l1.addRow(self.tr("Name:"), self.editName)
l1.addRow(self.tr("Cycle length:"), self.editCycle)
l1.addRow(self.tr("Current day in cycle:"), self.editCurrent)
+ l1.addRow(self.tr("Duration of menstruation:"), self.editMenstr)
+ l1.addRow(self.tr("Ovulation day:"), self.editOvday)
self.l0.addLayout(l1)
self.name=str(self.editName.text())
self.cycle=self.editCycle.value()
self.current=self.editCurrent.value()-1
+ self.menstr=self.editMenstr.value()
+ self.ovday=self.editOvday.value()
self.accept()
self.editName.setText(dt['name'])
self.editCycle.setValue(dt['cycle'])
self.editCurrent.setValue(dt['day0']+1)
+ self.editMenstr.setValue(dt['menstr'])
+ self.editOvday.setValue(dt['ovday'])
class MyMsgDialog(QDialog):
"""
txt=self.tr("""
<p> MaeGirls shows information about women's cycle using some generic
-guidelines: It assumes that ovulation happens 14 days before the start
-of the next period and that the period cycle is constant. Also, it assumes
-that sperm can live for 4 days, while an egg can live for 2 days.
+guidelines: By default it assumes that ovulation happens 14 days before the
+start of the next period and that the period cycle is constant. Also, it
+assumes that sperm can live for 4 days, while an egg can live for 2 days.
+
+<p> Using the configure menu you can change the duration of the cycle,
+the duration of the menstruation and the day the ovulation happens. When
+specifying the ovulation you can use negative numbers to indicate the number
+of days before the end of the period, or positive numbers to indicate the
+number of days after the beginning of the period. Default value for ovulation
+is -14.
+
+<p> MaeGirls supports tracking of multiple women. While there have been a lot
+of negative comments for this option, I find it useful even for women.
+Please don't complain or give negative feedback for an option that you're not
+forced to use.
<p style="color: orange;">
-WARNING!!! This is not always correct. There are FAR TOO MANY exceptions
-to the above rules!!! You MUST consult a doctor in order to get accurate
-predictions!!!
+WARNING!!! The prediction is not always correct. There are FAR TOO MANY
+exceptions to the above rules!!! You MUST consult a doctor in order to get
+accurate predictions!!! Use the program at your own risk!!!
<p> Assuming that you understand the risks of blindly trusting this program,
you become entitled to read the graph as follows:
<p> <span style="color: red">In red:</span> The days that menstruation
-happens, assumed to last 5 days.
+happens. Default: 5 days.
<p> <span style="color: green">In green:</span> The fertile days as described above.
<p> <span style="color: blue">In blue:</span> The days of PMS
(Premenstrual Syndrome), assumed to last 7 days.
<p> Navigation is easy: Use left-right finger movement to move the calendar
view. Use up-down finger movement to zoom in/out.
-
-<p> This program supports the "monitoring" of the cycle of multiple girls/women.
""")
self.setWindowTitle(self.tr("Help"))
def setGirl(self, name):
cfg=config.loadGirl(name)
self.girl=name
- self.algo.setReference(cfg['day0'], cfg['cycle'])
+ #self.algo.setReference(cfg['day0'], cfg['cycle'])
+ self.algo.setReference(cfg['day0'], cfg)
self.update()
self.updateTitle()
dt={
'name': self.girl,
'cycle': self.algo.cycleLength(),
- 'day0': self.algo.currentDayInCycle()
+ 'day0': self.algo.currentDayInCycle(),
+ 'menstr': self.algo.menstruationDuration(),
+ 'ovday': self.algo.ovulationDay()
}
self.dlgConfig.initValues(dt)
dt={
'cycle': self.dlgConfig.cycle,
'day0': day0,
+ 'ovday': self.dlgConfig.ovday,
+ 'menstr': self.dlgConfig.menstr,
}
config.storeGirl(name, dt)