1 """GNUmed pregnancy related dates widgets.
2 """
3
4 __author__ = "M. Bonert, R. Terry, I. Haywood, K.Hilbert"
5 __licence__ = "GPL v2 or later"
6
7
8 import sys
9 import datetime as pydt
10
11
12 import wx
13
14
15 from Gnumed.pycommon import gmDateTime
16 from Gnumed.pycommon import gmTools
17 from Gnumed.business import gmClinicalCalculator
18 from Gnumed.wxpython import gmGuiHelpers
19
20
64
65
66 from Gnumed.wxGladeWidgets import wxgEdcCalculatorDlg
67
69
74
76 edc = self.__calc.get_EDC(lmp = None, nullipara = self._CHBOX_first_pregnancy.GetValue())
77 txt = _(
78 'Algorithm: %s\n'
79 '\n'
80 'Source: %s'
81 ) % (
82 edc.formula_name,
83 edc.formula_source
84 )
85 self._TCTRL_algo.SetValue(txt)
86 self._PRW_lmp.add_callback_on_selection(self._on_lmp_selected)
87 self._PRW_edc.add_callback_on_modified(self._on_edc_modified)
88
89 self._PRW_lmp.SetFocus()
90
93
97
99 event.Skip()
100 self.__recalculate()
101
106
115
117 lmp = self._PRW_lmp.date
118 if lmp is None:
119 self._PRW_edc.SetData(None)
120 self._TCTRL_details.SetValue('')
121 return
122
123 edc = self.__calc.get_EDC(lmp = lmp, nullipara = self._CHBOX_first_pregnancy.GetValue())
124
125 self._PRW_edc.SetData(edc.numeric_value)
126 details = ''
127 now = gmDateTime.pydt_now_here()
128
129 if (lmp < now) and (edc.numeric_value > (now + pydt.timedelta(days = 380))):
130 age = now - lmp
131 weeks, days = divmod(age.days, 7)
132 week = weeks
133 if days > 0:
134 week = weeks + 1
135 month, tmp = divmod(age.days, 28)
136 if days > 0:
137 month += 1
138 details += _(
139 'Current age of pregnancy (%s):\n'
140 ' day %s = %s weeks %s days = week %s = month %s\n\n'
141 ) % (
142 gmDateTime.pydt_strftime(now, '%Y %b %d'),
143 age.days,
144 int(weeks),
145 int(days),
146 week,
147 month
148 )
149
150 details += edc.format (
151 left_margin = 1,
152 width = 50,
153 with_formula = False,
154 with_warnings = True,
155 with_variables = True,
156 with_sub_results = True,
157 return_list = False
158 )
159 self._TCTRL_details.SetValue(details)
160
161
162
164 return self._PRW_edc.date
165
170
171 EDC = property(_get_EDC, _set_EDC)
172
175
176 patient = property(lambda x:x, _set_patient)
177
178
179
180
181
182
183
184 import math, zlib, random, string, os.path
185
186
187 import wx.lib.rcsizer
188
189 """
190 Calculates from LMP:
191 - EDC
192 - 18th week ultrasound scan
193
194 Naegele's rule is easy for manual calculation, but a pain to code
195 Enter Haywood's rule ;-), human gestation is defined as 24192000 seconds.
196 (Ian, can you please explain a bit more ?)
197
198 TODO:
199 ideally, tool should query backend for parity, race, etc. for exact measurement
200 """
201
202
203 LMP_FIELD = 0
204 US_FIELD = 1
205
206 ID_LMP = wx.NewId()
207 ID_DUE = wx.NewId()
208 ID_DAY = wx.NewId()
209 ID_WEEK = wx.NewId()
210 ID_MENU = wx.NewId()
211
212 GESTATION = 24192000
213 WEEK = 604800
214 DAY = 86400
215 US18_52 = 10886400
216
217
219 """
220 The new pregnancy calculator.
221 """
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
239 myStyle = wx.MINIMIZE_BOX | wx.CAPTION | wx.ALIGN_CENTER | \
240 wx.ALIGN_CENTER_VERTICAL | wx.TAB_TRAVERSAL | wx.STAY_ON_TOP
241 wx.Frame.__init__(self, parent, -1, _("Pregnancy Calculator"), style=myStyle)
242
243
244 self.xfer_cal_date_to=LMP_FIELD
245
246
247
248 self.ustxt=wx.DateTime_Today()
249
250
251
252
253
254 if __name__ == '__main__':
255 png_fname = os.path.join('..', 'bitmaps', 'preg_calculator.png')
256 else:
257 from Gnumed.pycommon import gmGuiBroker
258 gb = gmGuiBroker.GuiBroker()
259 png_fname = os.path.join(gb['gnumed_dir'], 'bitmaps', 'preg_calculator.png')
260 icon = wx.Icon()
261 icon.LoadFile(png_fname, wx.BITMAP_TYPE_PNG)
262 self.SetIcon(icon)
263
264 szr_rc = wx.lib.rcsizer.RowColSizer()
265
266
267
268
269 label = wx.StaticText(self,-1,_("LMP"),size = (50,20))
270 label.SetFont(wx.Font(12,wx.SWISS,wx.NORMAL,wx.NORMAL,False,''))
271 label.SetForegroundColour(wx.Colour(0,0,0))
272
273 self.txt_lmp = wx.TextCtrl(self,-1,"",size=(100,20))
274 self.txt_lmp.SetFont(wx.Font(12,wx.SWISS,wx.NORMAL,wx.NORMAL,False,''))
275 self.txt_lmp.SetToolTip(wx.ToolTip(_("Click on calendar to enter the last menstrual period date")))
276 tiplmp=self.txt_lmp.GetToolTip()
277
278 szr_row1 = wx.BoxSizer(wx.HORIZONTAL)
279 szr_row1.Add(self.txt_lmp,1,wx.EXPAND|wx.ALL,2)
280 wx.EVT_SET_FOCUS(self.txt_lmp, self.OnSetFocus_lmp)
281
282 szr_lmp = wx.BoxSizer(wx.HORIZONTAL)
283 szr_lmp.Add(label, 1, 0, 0)
284 szr_lmp.Add((10,1),0,0)
285 szr_rc.Add(szr_lmp, flag=wx.EXPAND, row=0, col=1)
286 szr_rc.Add(szr_row1, flag=wx.EXPAND, row=0, col=2, colspan=5)
287
288
289
290 label = wx.StaticText(self,-1,_("Gest."),size = (50,20))
291 label.SetFont(wx.Font(12,wx.SWISS,wx.NORMAL,wx.NORMAL,False,''))
292 label.SetForegroundColour(wx.Colour(0,0,0))
293
294 self.txtgest = wx.TextCtrl(self,-1,"",size=(100,20))
295 self.txtgest.Enable(False)
296 self.txtgest.SetFont(wx.Font(12,wx.SWISS,wx.NORMAL,wx.NORMAL,False,''))
297 self.txtgest_szr = wx.BoxSizer(wx.HORIZONTAL)
298 self.txtgest_szr.Add(self.txtgest,1,wx.EXPAND|wx.ALL,2)
299
300 szr_gest = wx.BoxSizer(wx.HORIZONTAL)
301 szr_gest.Add(label, 1, 0, 0)
302 szr_gest.Add((10,1),0,0)
303 szr_rc.Add(szr_gest, flag=wx.EXPAND, row=1, col=1)
304 szr_rc.Add(self.txtgest_szr, flag=wx.EXPAND, row=1, col=2, colspan=5)
305
306
307
308
309 label = wx.StaticText(self,-1,_("EDC"),size = (50,20))
310 label.SetFont(wx.Font(12,wx.SWISS,wx.NORMAL,wx.NORMAL,False,''))
311 label.SetForegroundColour(wx.Colour(0,0,0))
312
313 self.txtedc = wx.TextCtrl(self,-1,"",size=(100,20))
314 self.txtedc.Enable(False)
315 self.txtedc.SetFont(wx.Font(12,wx.SWISS,wx.NORMAL,wx.NORMAL,False,''))
316 szr_txtedc = wx.BoxSizer(wx.HORIZONTAL)
317 szr_txtedc.Add(self.txtedc,1,wx.EXPAND|wx.ALL,2)
318 szr_edc = wx.BoxSizer(wx.HORIZONTAL)
319 szr_edc.Add(label,1,0,0)
320 szr_edc.Add((10,1),0,0)
321 szr_rc.Add(szr_edc, flag=wx.EXPAND, row=2, col=1)
322 szr_rc.Add(szr_txtedc, flag=wx.EXPAND, row=2, col=2, colspan=5)
323
324
325
326
327 us_label = wx.StaticText(self,-1,_("18 Week Ultrasound Scan"),size = (200,20))
328 us_label.SetFont(wx.Font(10,wx.SWISS,wx.NORMAL,wx.BOLD,False,''))
329 us_label.SetForegroundColour(wx.Colour(50,50,204))
330 szr_backgrnd_18WkScanDue = wx.BoxSizer(wx.VERTICAL)
331 szr_backgrnd_18WkScanDue.Add((1,3), 0)
332 szr_backgrnd_18WkScanDue.Add(us_label,1,wx.EXPAND,1)
333 szr_rc.Add(szr_backgrnd_18WkScanDue, flag=wx.ALIGN_CENTRE_HORIZONTAL, row=3, col=2, colspan=5)
334
335
336
337 label = wx.StaticText(self,-1,_("Due"),size = (100,20))
338 label.SetFont(wx.Font(12,wx.SWISS,wx.NORMAL,wx.NORMAL,False,''))
339 label.SetForegroundColour(wx.Colour(0,0,0))
340
341 self.txtdue = wx.TextCtrl(self,-1,"",size=(100,20))
342 self.txtdue.Enable(False)
343 self.txtdue.SetFont(wx.Font(12,wx.SWISS,wx.NORMAL,wx.NORMAL,False,''))
344 self.szr_txtdue = wx.BoxSizer(wx.HORIZONTAL)
345 self.szr_txtdue.Add(self.txtdue,1,wx.EXPAND|wx.ALL,2)
346 szr_due = wx.BoxSizer(wx.HORIZONTAL)
347 szr_due.Add(label,1,0,0)
348 szr_due.Add((10,1),0,0)
349 szr_rc.Add(szr_due, flag=wx.EXPAND, row=4, col=1)
350 szr_rc.Add(self.szr_txtdue, flag=wx.EXPAND, row=4, col=2, colspan=5)
351
352
353
354
355 rev_edc_label = wx.StaticText(self,-1,_("Ultrasound Scan - Revised EDC"),size = (300,20))
356 rev_edc_label.SetFont(wx.Font(10,wx.SWISS,wx.NORMAL,wx.BOLD,False,''))
357 rev_edc_label.SetForegroundColour(wx.Colour(50,50,204))
358 szr_backgrnd_RevEDCLabel = wx.BoxSizer(wx.VERTICAL)
359 szr_backgrnd_RevEDCLabel.Add((1,3), 0)
360 szr_backgrnd_RevEDCLabel.Add(rev_edc_label,1,wx.EXPAND,1)
361 szr_rc.Add(szr_backgrnd_RevEDCLabel, flag=wx.ALIGN_CENTRE_HORIZONTAL, row=5, col=2, colspan=5)
362
363
364
365
366 label1 = wx.StaticText(self,-1,_("Scan Date"),size = (25,20))
367 label1.SetFont(wx.Font(12,wx.SWISS,wx.NORMAL,wx.NORMAL,False,''))
368 label1.SetForegroundColour(wx.Colour(0,0,0))
369 self.txtdate = wx.TextCtrl(self,-1,"",size=(25,20))
370 self.txtdate.SetFont(wx.Font(12,wx.SWISS,wx.NORMAL,wx.NORMAL,False,''))
371 self.txtdate.SetToolTip(wx.ToolTip(_("Click on this field and then the ultrasound scan date on the calendar")))
372 tipdue=self.txtdate.GetToolTip()
373 wx.ToolTip_Enable(1)
374 self.szr_txtdate = wx.BoxSizer(wx.HORIZONTAL)
375 self.szr_txtdate.Add(self.txtdate,1,wx.EXPAND|wx.ALL,2)
376 wx.EVT_SET_FOCUS(self.txtdate, self.OnSetFocus_USDate)
377
378 szr_label1 = wx.BoxSizer(wx.HORIZONTAL)
379 szr_label1.Add(label1,1,0,0)
380 szr_label1.Add((10,1),0,0)
381 szr_rc.Add(szr_label1, flag=wx.EXPAND, row=6, col=1)
382 szr_rc.Add(self.szr_txtdate, flag=wx.EXPAND, row=6, col=2, colspan=5)
383
384
385
386 label2 = wx.StaticText(self,-1,_("Weeks"),size = (25,20))
387 label2.SetFont(wx.Font(12,wx.SWISS,wx.NORMAL,wx.NORMAL,False,''))
388 label2.SetForegroundColour(wx.Colour(0,0,0))
389 self.txtweeks = wx.SpinCtrl (self, -1, value = "0", min = 0, max = 42)
390 wx.EVT_SPINCTRL (self.txtweeks ,self.txtweeks.GetId(), self.EvtText_calcnewedc)
391 self.txtweeks.SetFont(wx.Font(12,wx.SWISS,wx.NORMAL,wx.NORMAL,False,''))
392 self.szr_txtweeks = wx.BoxSizer(wx.HORIZONTAL)
393 self.szr_txtweeks.Add(self.txtweeks,1,wx.EXPAND|wx.ALL,2)
394
395 label3 = wx.StaticText(self,-1,_("Days"),size = (25,20))
396 label3.SetFont(wx.Font(12,wx.SWISS,wx.NORMAL,wx.NORMAL,False,''))
397 label3.SetForegroundColour(wx.Colour(0,0,0))
398 self.txtdays = wx.SpinCtrl (self, -1, value = "0", min = 0, max = 6)
399 wx.EVT_SPINCTRL (self.txtdays ,self.txtdays.GetId(), self.EvtText_calcnewedc)
400 self.txtdays.SetFont(wx.Font(12,wx.SWISS,wx.NORMAL,wx.NORMAL,False,''))
401 self.szr_txtdays = wx.BoxSizer(wx.HORIZONTAL)
402 self.szr_txtdays.Add(self.txtdays,1,wx.EXPAND|wx.ALL,2)
403
404 szr_label2 = wx.BoxSizer(wx.HORIZONTAL)
405 szr_label2.Add(label2,1,wx.ALIGN_CENTRE_VERTICAL,0)
406 szr_label2.Add((10,1),0,0)
407 szr_label3 = wx.BoxSizer(wx.HORIZONTAL)
408 szr_label3.Add((10,1),0,0)
409 szr_label3.Add(label3,1,wx.ALIGN_CENTRE_VERTICAL,0)
410 szr_label3.Add((10,1),0,0)
411 szr_rc.Add(szr_label2, flag=wx.EXPAND, row=7, col=1)
412 szr_rc.Add(self.szr_txtweeks, flag=wx.EXPAND, row=7, col=2, colspan=2)
413 szr_rc.Add(szr_label3, flag=wx.EXPAND, row=7, col=4)
414 szr_rc.Add(self.szr_txtdays, flag=wx.EXPAND, row=7, col=5, colspan=2)
415
416
417
418
419 label = wx.StaticText(self,-1,_("Rev EDC"),size = (100,20))
420 label.SetFont(wx.Font(12,wx.SWISS,wx.NORMAL,wx.NORMAL,False,''))
421 label.SetForegroundColour(wx.Colour(0,0,0))
422
423 self.txtnewedc = wx.TextCtrl(self,-1,"",size=(100,20))
424 self.txtnewedc.Enable(False)
425 self.txtnewedc.SetFont(wx.Font(12,wx.SWISS,wx.NORMAL,wx.NORMAL,False,''))
426 self.szr_txtnewedc = wx.BoxSizer(wx.HORIZONTAL)
427 self.szr_txtnewedc.Add(self.txtnewedc,1,wx.EXPAND|wx.ALL,2)
428 szr_label=wx.BoxSizer(wx.HORIZONTAL)
429 szr_label.Add(label,1,0,0)
430 szr_label.Add((10,1),0,0)
431 szr_rc.Add(szr_label, flag=wx.EXPAND, row=8, col=1)
432 szr_rc.Add(self.szr_txtnewedc, flag=wx.EXPAND, row=8, col=2, colspan=5)
433 self.btnPrint = wx.Button(self,1011,_('&Print'))
434 self.btnSave = wx.Button(self,1011,_('&Save'))
435 szr_buttons = wx.BoxSizer(wx.HORIZONTAL)
436 szr_buttons.Add(self.btnPrint,0,wx.EXPAND)
437 szr_buttons.Add(self.btnSave,0,wx.EXPAND)
438 szr_rc.Add(szr_buttons, flag=wx.EXPAND,row=9, col=3, colspan=4)
439
440
441
442 szr_main_rt = wx.BoxSizer(wx.VERTICAL)
443 szr_main_rt.Add(szr_rc)
444 wx.EVT_BUTTON(self,1010,self.EvtReset)
445 wx.EVT_BUTTON(self,1011,self.EvtPrint)
446 wx.EVT_BUTTON(self,1012,self.EvtSave)
447
448
449
450 self.lmp_cal = wx.calendar.CalendarCtrl (self, ID_LMP,style = wx.RAISED_BORDER)
451 wx.calendar.EVT_CALENDAR_SEL_CHANGED(self.lmp_cal, ID_LMP, self.OnCalcByLMP)
452
453 szr_main_lf = wx.BoxSizer(wx.VERTICAL)
454 szr_main_lf.Add(self.lmp_cal,0,wx.ALIGN_CENTRE_HORIZONTAL)
455 btn_reset = wx.Button(self, 1010, _('&Reset'))
456
457 szr_main_lf.Add(btn_reset,0,wx.EXPAND)
458
459
460
461
462 szr_main_top= wx.BoxSizer(wx.HORIZONTAL)
463 szr_main_top.Add(szr_main_lf,0,0)
464 szr_main_top.Add((15,0),0,0)
465 szr_main_top.Add(szr_main_rt,0,0)
466
467
468
469
470
471 szr_main= wx.BoxSizer(wx.HORIZONTAL)
472 szr_main.Add(szr_main_top,1,wx.EXPAND|wx.ALL,10)
473 self.SetSizer (szr_main)
474 self.SetAutoLayout (1)
475 szr_main.Fit (self)
476
477 wx.EVT_CLOSE (self, self.OnClose )
478
479
481
482 if(self.xfer_cal_date_to==LMP_FIELD):
483
484
485
486
487
488
489
490
491 self.lmp = self.lmp_cal.GetDate ().GetTicks ()
492 today = wx.DateTime_Today().GetTicks()
493 due = self.lmp + GESTATION
494 gest = today - self.lmp
495 self.ultrasound18_52 = self.lmp + US18_52
496
497
498
499 lmp_txt = wx.DateTime()
500 lmp_txt.SetTimeT(self.lmp)
501 self.txt_lmp.SetValue(self.PurgeTime(lmp_txt))
502
503
504 gest_week = gest / WEEK
505 gest_day = (gest % WEEK) / DAY
506 if(gest_day==1):
507 days_label=_('day')
508 else:
509 days_label=_('days')
510 if(gest_week==1):
511 weeks_label=_('week')
512 else:
513 weeks_label=_('weeks')
514
515 txtgest_str=str(gest_week)+" "+weeks_label+", "+str(gest_day)+" "+days_label
516 self.txtgest.SetValue(txtgest_str)
517
518
519 edctxt = wx.DateTime()
520 edctxt.SetTimeT(due)
521 self.txtedc.SetValue(self.PurgeTime(edctxt))
522
523
524 self.ustxt = wx.DateTime()
525 self.ustxt.SetTimeT(self.ultrasound18_52)
526 self.txtdue.SetValue(self.PurgeTime(self.ustxt))
527
528 else:
529
530 self.usdate = self.lmp_cal.GetDate ().GetTicks ()
531 usdatetxt = wx.DateTime()
532 usdatetxt.SetTimeT(self.usdate)
533 self.txtdate.SetValue(self.PurgeTime(usdatetxt))
534
535
536 if( self.txtnewedc.GetValue() !=""):
537 self.EvtText_calcnewedc(self)
538
539
540 - def EvtText_calcnewedc (self, event):
541 try:
542 weeks=self.txtweeks.GetValue()
543 days=self.txtdays.GetValue()
544
545
546 newedc=self.usdate+GESTATION-WEEK*weeks-DAY*days
547
548 wx.D=wx.DateTime()
549 wx.D.SetTimeT(newedc)
550 self.txtnewedc.SetValue(self.PurgeTime(wx.D))
551 except:
552 pass
553
554
556
557 self.txt_lmp.SetValue("")
558 self.txtgest.SetValue("")
559 self.txtedc.SetValue("")
560 self.txtdue.SetValue("")
561
562 self.txtdate.SetValue("")
563 self.ustxt=wx.DateTime_Today()
564
565 self.txtweeks.SetValue(0)
566 self.txtdays.SetValue(0)
567 self.txtnewedc.SetValue("")
568
569 self.xfer_cal_date_to=LMP_FIELD
570 self.lmp_cal.SetDate(wx.DateTime_Today())
571
572
575
578
579
580
581
584
585
587 time_loc=string.find(str(date),":00:00")
588 date_str=str(date)
589 return date_str[:(time_loc-3)]
590
591
595
596
598 self.lmp_cal.SetDate(self.ustxt)
599 self.xfer_cal_date_to=US_FIELD
600 event.Skip()
601
602
603
604
605
606
607 if __name__ == '__main__':
608
614
615 import gettext
616 _ = gettext.gettext
617 gettext.textdomain ('gnumed')
618 app = TestApp()
619 app.MainLoop()
620
621
622