source: cprs/branches/foia-cprs/CPRS-Chart/Vitals/uVitals.pas@ 459

Last change on this file since 459 was 459, checked in by Kevin Toppenberg, 16 years ago

Adding foia-cprs branch

File size: 19.4 KB
Line 
1unit uVitals;
2{ Old class TVital currently not used - commented out at bottom of unit }
3
4interface
5
6uses
7 SysUtils, Dialogs, Controls, Windows, Classes, ORClasses, ORCtrls, ORFn, Forms;
8
9const
10 NoVitalOverrideValue = '^None^';
11
12type
13 TVitalType = (vtUnknown, vtTemp, vtPulse, vtResp, vtBP, vtHeight, vtWeight, vtPain,
14 vtPO2, vtCVP, vtCircum);
15 TValidVitalTypes = vtTemp..vtCircum;
16
17procedure InitPainCombo(cboPain: TORComboBox);
18procedure ConvertVital(VType: TVitalType; var VValue, VUnit: string);
19function GetVitalStr(VType: TVitalType; rte, unt, UserStr, DateStr: string): string;
20function GetVitalUser: string;
21procedure AssignVitals2List(List: TStrings; ADateTime: TFMDateTime;
22 ALocation, ABP, ATemp, ATempUnits,
23 AResp, APulse, AHeight, AHeightUnits,
24 AWeight, AWeightUnits, APain: string);
25function VitalInvalid(VitalControl: TControl; UnitsControl: TControl = nil;
26 OverrideValue: string = NoVitalOverrideValue): boolean;
27function VitalControlTag(VType: TVitalType; UnitControl: boolean = FALSE): integer;
28function ConvertHeight2Inches(Ht: string): string;
29function FormatVitalForNote(VitalStr: string):String;
30function ConvertVitalData(const Value: string; VitalType: TVitalType; UnitType: string = ''): string;
31procedure VitalsFrameCreated(Frame: TFrame);
32procedure SetVitalsMetric(const Value: boolean);
33procedure SetVitCVPmmHg(const Value: boolean);
34function ValidVitalsDate(var ADate: TFMDateTime; SkipFirst: boolean = FALSE): boolean;
35function IsNumericWeight(const x: string): Boolean;
36
37const
38 VitalPCECodes: array[TValidVitalTypes] of string =
39 { vtTemp } ('TMP',
40 { vtPulse } 'PU',
41 { vtResp } 'RS',
42 { vtBP } 'BP',
43 { vtHeight } 'HT',
44 { vtWeight } 'WT',
45 { vtPain } 'PN',
46 { vtPO2 } 'PO2',
47 { vtCVP } 'CVP',
48 { vtCircum } 'CG');
49
50
51 VitalCodes: array[TValidVitalTypes] of string =
52 { vtTemp } ('T',
53 { vtPulse } 'P',
54 { vtResp } 'R',
55 { vtBP } 'BP',
56 { vtHeight } 'HT',
57 { vtWeight } 'WT',
58 { vtPain } 'PN',
59 { vtPO2 } 'PO2',
60 { vtCVP } 'CVP',
61 { vtCircum } 'CG');
62
63 TAG_VITTEMP = 2;
64 TAG_VITPULSE = 4;
65 TAG_VITRESP = 3;
66 TAG_VITBP = 1;
67 TAG_VITHEIGHT = 5;
68 TAG_VITWEIGHT = 6;
69 TAG_VITTEMPUNIT= 7;
70 TAG_VITHTUNIT = 8;
71 TAG_VITWTUNIT = 9;
72 TAG_VITPAIN = 10;
73 TAG_VITDATE = 11;
74
75 VitalDateStr = 'VST^DT^';
76 VitalPatientStr = 'VST^PT^';
77 VitalLocationStr = 'VST^HL^';
78
79type
80 VitalTags = TAG_VITBP..TAG_VITPAIN;
81
82const
83 VitalTagSet = [TAG_VITBP..TAG_VITPAIN];
84 VitalDateTagSet = [TAG_VITBP..TAG_VITDATE];
85
86 VitalTagCodes: array[VitalTags] of TVitalType =
87 { TAG_VITBP } (vtBP,
88 { TAG_VITTEMP } vtTemp,
89 { TAG_VITRESP } vtResp,
90 { TAG_VITPULSE } vtPulse,
91 { TAG_VITHEIGHT } vtHeight,
92 { TAG_VITWEIGHT } vtWeight,
93 { TAG_VITTEMPUNIT } vtTemp,
94 { TAG_VITHTUNIT } vtHeight,
95 { TAG_VITWTUNIT } vtWeight,
96 { TAG_VITPAIN } vtPain);
97
98 VitalDesc: array[TVitalType] of string =
99 { vtUnknown } ('Unknown',
100 { vtTemp } 'Temperature',
101 { vtPulse } 'Pulse',
102 { vtResp } 'Respiration',
103 { vtBP } 'Blood Pressure',
104 { vtHeight } 'Height',
105 { vtWeight } 'Weight',
106 { vtPain } 'Pain Score',
107 { vtPO2 } 'Pulse Oximetry',
108 { vtCVP } 'Central Venous Pressure',
109 { vtCircum } 'Circumference/Girth');
110
111 VitalFormatedDesc: array[TValidVitalTypes] of string =
112 { vtTemp } ('Temperature ',
113 { vtPulse } 'Pulse ',
114 { vtResp } 'Resp ',
115 { vtBP } 'Blood Press. ',
116 { vtHeight } 'Height ',
117 { vtWeight } 'Weight ',
118 { vtPain } 'Pain Scale. ',
119 { vtPO2 } 'Pulse Ox. ',
120 { vtCVP } 'Cnt Vns Pres ',
121 { vtCircum } 'Circum/Girth ');
122 vnumType = 2;
123 vnumValue = 3;
124 vnumDate = 4;
125
126implementation
127
128uses
129 uCore, rCore, rVitals, Contnrs, mVitBase, mVitMetric, fVitalsDate;
130
131var
132 uVitalFrames: TComponentList = nil;
133
134function VitalErrorText(VType: TVitalType): string;
135begin
136 case VType of
137 vtTemp, vtHeight, vtWeight:
138 Result := '- check rate and unit.';
139 else
140 Result := 'reading entered.';
141 end;
142 Result := 'Invalid ' + VitalDesc[VType] + ' ' + Result;
143end;
144
145procedure InitPainCombo(cboPain: TORComboBox);
146begin
147 cboPain.Items.Clear;
148 cboPain.Items.Add('0^ - no pain');
149 cboPain.Items.Add('1^ - slightly uncomfortable');
150 cboPain.Items.Add('2^');
151 cboPain.Items.Add('3^');
152 cboPain.Items.Add('4^');
153 cboPain.Items.Add('5^');
154 cboPain.Items.Add('6^');
155 cboPain.Items.Add('7^');
156 cboPain.Items.Add('8^');
157 cboPain.Items.Add('9^');
158 cboPain.Items.Add('10^ - worst imaginable');
159 cboPain.Items.Add('99^ - unable to respond');
160end;
161
162procedure ConvertVital(VType: TVitalType; var VValue, VUnit: string);
163begin
164 case VType of
165 vtTemp: if(VUnit = 'C') then //if metric, convert to standard
166 begin
167 if StrToFloat(VValue) > 0 then
168 //VValue := FloatToStr(StrToFloat(VValue) * 9.0 / 5.0 +32.0);
169 VValue := FloatToStr(Round((StrToFloat(VValue) * 9.0 / 5.0 +32.0)*100)/100);
170 VUnit := 'F';
171 end;
172
173 vtHeight: if VUnit = 'CM' then
174 begin
175 if StrToFloat(VValue) > 0 then
176 //VValue := FloatToStr(StrtoFloat(VValue) / 2.54);
177 VValue := FloatToStr(Round((StrtoFloat(VValue) / 2.54)*1000)/1000);
178 VUnit := 'IN';
179 end;
180
181 vtWeight: if VUnit = 'KG' then
182 begin
183 if StrToFloat(VValue) > 0 then
184 //VValue := FloatToStr(StrtoFloat(VValue) * 2.2046);
185 //
186 // the vitals package uses 2.2 (not 2.2046), so the GUI needs to use the
187 // same so conversions back & forth don't lead to errors
188 // this probably shouldn't even be done here - it should be done by the
189 // vitals package - KCM
190 //
191 VValue := FloatToStr(Round(StrtoFloat(VValue) * 2.2{046} *1000)/1000);
192 VUnit := 'LB';
193 end;
194 end;
195end;
196
197function GetVitalStr(VType: TVitalType; rte, unt, UserStr, DateStr: string): string;
198begin
199 Result := '';
200 ConvertVital(VType, rte, unt);
201 if rte <> '' then
202 begin
203 if(VType = vtPain) then unt := U;
204 Result := 'VIT'+U+VitalPCECodes[VType]+U+U+U+rte+U+UserStr+U+unt+U+DateStr;
205 end;
206end;
207
208function GetVitalUser: string;
209var
210 UserID: Int64;
211
212begin
213 UserID := Encounter.Provider;
214 if UserID <= 0 then
215 UserID := User.DUZ;
216 Result := IntToStr(UserID);
217end;
218
219procedure AssignVitals2List(List: TStrings; ADateTime: TFMDateTime;
220 ALocation, ABP, ATemp, ATempUnits,
221 AResp, APulse, AHeight, AHeightUnits,
222 AWeight, AWeightUnits, APain: string);
223var
224 UserStr, DateStr: string;
225
226 procedure AddVital(VType: TVitalType; ARte: string; AUnit: string = '');
227 var
228 VStr: string;
229
230 begin
231 VStr := GetVitalStr(VType, ARte, AUnit, UserStr, DateStr);
232 if(VStr <> '') then
233 List.Add(VStr);
234 end;
235
236begin
237 with List do
238 begin
239 UserStr := GetVitalUser;
240 DateStr := FloatToStr(ADateTime);
241 clear;
242
243 Add(VitalDateStr + DateStr);
244 Add(VitalPatientStr + Patient.DFN); // encounter Patient //*DFN*
245 Add(VitalLocationStr + ALocation);
246 AddVital(vtBP, ABP); // Blood Pressure
247 AddVital(vtTemp, ATemp, ATempUnits); // Temperature
248 AddVital(vtResp, AResp); // Resp
249 AddVital(vtPulse, APulse); // Pulse
250 AddVital(vtHeight, AHeight, AHeightUnits); // Height
251 AddVital(vtWeight, AWeight, AWeightUnits); // Weight
252 AddVital(vtPain, APain); // Pain
253 end;
254end;
255
256function VitalInvalid(VitalControl: TControl; UnitsControl: TControl = nil;
257 OverrideValue: string = NoVitalOverrideValue): boolean;
258var
259 rte, unt: string;
260 Tag: integer;
261 VType: TVitalType;
262
263begin
264 Tag := -1;
265
266 if(OverrideValue = NoVitalOverrideValue) then
267 begin
268 if(assigned(VitalControl)) then
269 begin
270 rte := TORExposedControl(VitalControl).Text;
271 Tag := VitalControl.Tag;
272 end
273 else
274 rte := '';
275 end
276 else
277 begin
278 rte := OverrideValue;
279 if(assigned(VitalControl)) then
280 Tag := VitalControl.Tag;
281 end;
282
283 if(assigned(UnitsControl)) then
284 begin
285 unt := TORExposedControl(UnitsControl).Text;
286 if(Tag < 0) then
287 Tag := UnitsControl.Tag;
288 end
289 else
290 unt := '';
291
292 if(Tag >= low(VitalTags)) and (Tag <= high(VitalTags)) then
293 VType := VitalTagCodes[Tag]
294 else
295 VType := vtUnknown;
296 //pain does not need to be validated because the combo box limits the selection.
297 if(VType = vtPain) then
298 Result := FALSE
299 else
300 begin
301 Result := TRUE;
302 if(VType <> vtUnknown) then
303 begin
304 if (rte = '') then
305 Result := FALSE
306 else
307 if (VerifyVital(VitalPCECodes[VType],rte,unt) = True) then
308 Result := FALSE;
309 end;
310 end;
311 // GRE 2/12/03 added to disallow user entering "lb" with weight NOIS MWV-0103-22037
312 if VType = vtWeight then
313 begin
314 if (IsNumericWeight(rte) = FALSE) then
315 Result := True;
316 end;
317 if(Result) then
318 ShowMessage(VitalErrorText(VType));
319end;
320
321function VitalControlTag(VType: TVitalType; UnitControl: boolean = FALSE): integer;
322var
323 i,cnt: integer;
324
325begin
326 if UnitControl then
327 cnt := 0
328 else
329 cnt := 1;
330 Result := -1;
331 for i := low(VitalTags) to high(VitalTags) do
332 begin
333 if(VitalTagCodes[i] = VType) then
334 begin
335 inc(cnt);
336 if(cnt = 2) then
337 begin
338 Result := i;
339 break;
340 end;
341 end;
342 end;
343end;
344
345function ConvertHeight2Inches(Ht: string): string;
346var
347 c: char;
348 i: integer; //counter
349 inchstr,feetstr : string;
350 feet: boolean;
351 v: double;
352
353begin
354 feet := False;
355 result := '';
356 feetstr := '';
357 inchstr := '';
358
359 // check for feet
360 for i := 1 to (length(Ht)) do
361 begin
362 c := Ht[i];
363 if (c = '''') then feet := True;
364 end;
365
366 if (feet = True) then
367 begin
368 i := 1;
369 while (Ht[i] <> '''') do
370 begin
371 if (Ht[i] in ['0'..'9']) or (Ht[i] = '.') then
372 feetstr := feetstr + Ht[i];
373 inc(i);
374 end;
375 while (i <= length(Ht)) and (Ht[i] <> '"') and
376 (Ht[i] <> '') do
377 begin
378 if (Ht[i] in ['0'..'9']) or (Ht[i] = '.') then
379 inchstr := inchstr + Ht[i];
380 inc(i);
381 end;
382 v := 0;
383 if (feetstr <> '') then
384 v := v + (StrTofloat(feetstr)*12);
385 if(inchstr <> '') then
386 v := v + StrToFloat(inchstr);
387 result := floatToStr(v);
388 //add here to convert to CM if CM is the unit
389
390 end
391 else //no feet
392 begin
393 for i := 1 to (length(Ht)) do
394 begin
395 c := Ht[i]; //first character
396 if (c in ['0'..'9']) or (c = '.') then
397 result := result + c;
398 if (c = '"') then break;
399 end;
400 end;
401end;
402
403{
4041215^T^98.6^2991108.11^98.6 F^(37.0 C)
4051217^P^70^2991108.11^70
4061216^R^18^2991108.11^18
4071214^BP^120/70^2991108.11^120/70
4081218^HT^70^2991108.11^70 in^(177.8 cm)
4091219^WT^200^2991108.11^200 lb^(90.0 kg)
4101220^PN^1^2991108.11^1
411}
412 //format string as it should appear on the PCE panel.
413function FormatVitalForNote(VitalStr: string):String;
414var
415 Code, Value: string;
416 v: TVitalType;
417
418begin
419 Code := UpperCase(Piece(VitalStr, U, vnumType));
420 for v := low(TValidVitalTypes) to high(TValidVitalTypes) do
421 begin
422 if(Code = VitalCodes[v]) then
423 begin
424 Value := ConvertVitalData(Piece(VitalStr, U, vnumValue), v);
425 if(v = vtPain) and (Value = '99') then
426 Value := 'Unable to respond.';
427 Result := VitalFormatedDesc[v] + Value + ' ' +
428 FormatFmDateTime('mmm dd,yyyy hh:nn',(StrToFloat(Piece(VitalStr, U, vnumDate))));
429 end
430 end;
431end;
432
433function ConvertVitalData(const Value: string; VitalType: TVitalType; UnitType: string = ''): string;
434var
435 dbl: Double;
436
437begin
438 Result := Value;
439 if(VitalType in [vtTemp, vtHeight, vtWeight]) then
440 begin
441 try
442 dbl := StrToFloat(Value);
443 except
444 on EConvertError do
445 dbl := 0
446 else
447 raise;
448 end;
449 if(dbl <> 0) then
450 begin
451 UnitType := UpperCase(UnitType);
452 case VitalType of
453 vtTemp:
454 begin
455 if(UnitType = 'C') then
456 begin
457 dbl := dbl * (9/5);
458 dbl := dbl + 32;
459 dbl := round(dbl * 10) / 10;
460 Result := FloatToStr(dbl) + ' F (' + Result + ' C)';
461 end
462 else
463 begin
464 dbl := dbl - 32;
465 dbl := dbl * (5/9);
466 dbl := round(dbl * 10) / 10;
467 Result := Result + ' F (' + FloatToStr(dbl) + ' C)';
468 end;
469 end;
470
471 vtHeight:
472 begin
473 if(UnitType = 'CM') then
474 begin
475 dbl := dbl / 2.54;
476 dbl := round(dbl * 10) / 10;
477 Result := FloatToStr(dbl) + ' in [' + Result + ' cm)';
478 end
479 else
480 begin
481 dbl := dbl * 2.54;
482 dbl := round(dbl * 10) / 10;
483 Result := Result + ' in [' + FloatToStr(dbl) + ' cm)';
484 end;
485 end;
486
487 vtWeight:
488 begin
489 if(UnitType = 'KG') then
490 begin
491 dbl := dbl * 2.2;
492 dbl := round(dbl * 10) / 10;
493 Result := FloatToStr(dbl) + ' lb (' + Result + ' kg)';
494 end
495 else
496 begin
497 dbl := dbl / 2.2;
498 dbl := round(dbl * 10) / 10;
499 Result := Result + ' lb (' + FloatToStr(dbl) + ' kg)';
500 end;
501 end;
502 end;
503 end;
504 end;
505end;
506
507procedure VitalsFrameCreated(Frame: TFrame);
508begin
509 if not assigned(uVitalFrames) then
510 uVitalFrames := TComponentList.Create(FALSE);
511 uVitalFrames.Add(Frame);
512end;
513
514procedure SetVitalsMetric(const Value: boolean);
515var
516 i: integer;
517
518begin
519 if(uVitalsMetric <> Value) then
520 begin
521 uVitalsMetric := Value;
522 for i := 0 to uVitalFrames.Count-1 do
523 begin
524 if uVitalFrames[i] is TfraVitBase then
525 TfraVitBase(uVitalFrames[i]).VitalsMetricChanged
526 else
527 if uVitalFrames[i] is TfraVitMetric then
528 TfraVitMetric(uVitalFrames[i]).VitalsMetricChanged
529 end;
530 end;
531end;
532
533procedure SetVitCVPmmHg(const Value: boolean);
534var
535 i: integer;
536
537begin
538 if(uVitCVPmmHg <> Value) then
539 begin
540 uVitCVPmmHg := Value;
541 for i := 0 to uVitalFrames.Count-1 do
542 if uVitalFrames[i] is TfraVitBase then
543 TfraVitBase(uVitalFrames[i]).VitalsCVPUnitsChanged;
544 end;
545end;
546
547function ValidVitalsDate(var ADate: TFMDateTime; SkipFirst: boolean = FALSE): boolean;
548var
549 frmVitalsDate: TfrmVitalsDate;
550 ok: boolean;
551
552begin
553 Result := TRUE;
554 while (Result and (SkipFirst or (ADate > FMNow))) do
555 begin
556 if(SkipFirst) then
557 begin
558 ok := TRUE;
559 SkipFirst := FALSE;
560 end
561 else
562 ok := (InfoBox('Vital sign Date/Time entered (' + FormatFMDateTime('mmm dd yyyy hh:nn', ADate) +
563 ') cannot be in the future.' + CRLF +
564 'If you do not change the entered date/time vitals information will be lost.' + CRLF +
565 'Do you want to enter a new Date/Time?',
566 'Invalid Vital Entry Date/Time',
567 MB_YESNO + MB_ICONWARNING) = ID_YES);
568 if ok then
569 begin
570 frmVitalsDate := TfrmVitalsDate.Create(Application);
571 try
572 frmVitalsDate.dteVitals.FMDateTime := ADate;
573 if frmVitalsDate.ShowModal = mrOK then
574 ADate := frmVitalsDate.dteVitals.FMDateTime;
575 finally
576 frmVitalsDate.Free;
577 end;
578 end
579 else
580 Result := FALSE;
581 end;
582end;
583function IsNumericWeight(const x: string): Boolean;
584var
585 i: Integer;
586begin
587 Result := True;
588 for i := 1 to Length(x) do if not (x[i] in ['0'..'9','.']) then Result := False;
589end;
590(* Old class currently not used
591{$OPTIMIZATION OFF} // REMOVE AFTER UNIT IS DEBUGGED
592
593interface
594
595uses SysUtils, Classes;
596
597type
598 TVital = class(TObject)
599 {class for vital}
600 Private
601 Fsend: Boolean; //do we need this?
602 public
603 Typ: String; //type
604 Value: Single;
605 Unt: String; //unit
606 Provider: Integer;
607 procedure Assign(Src: TVital); //will we need assign?
608 procedure Clear;
609 procedure SetFromString(const x: string);
610 function DelimitedStr: string;
611 end;
612
613
614implementation
615
616uses ORFn, fPCEEdit, uPCE;
617
618Procedure TVital.Assign(Src: TVital);
619{assigns the values from one vital to another}
620begin
621 Fsend := Src.Fsend;
622 Typ := Src.Typ;
623 Value := Src.Value;
624 Unt := Src.Unt;
625 provider := Src.Provider;
626end;
627
628procedure Tvital.Clear;
629{clear all fields}
630begin
631 Fsend := False;
632 Typ := '';
633 Value := 0.0;
634 Unt := ''; //will default to Inches/LBs/Farenheit on M side,
635 //depending on the Type
636 //Provider := UProvider;
637end;
638
639Procedure TVital.SetFromString(const X: string);
640begin
641 Typ := Piece(x, U, 2);
642 Value := StrToFloat(Piece(x, U, 5));
643 Provider := StrToInt(Piece(x, U, 6));
644 Unt := Piece(x, U, 7);
645end;
646
647function TVital.DelimitedStr: string;
648begin
649 Result := 'VIT' + U + Typ + U + U + U + FloatToStr(Value) + U +
650 IntToStr(Provider) + U + Unt;
651end;
652*)
653
654initialization
655
656finalization
657 KillObj(@uVitalFrames);
658
659end.
Note: See TracBrowser for help on using the repository browser.