home *** CD-ROM | disk | FTP | other *** search
- (**************************************************************************
- * *
- * STATUS.PAS - A Statusline unit, by Thomas S. Carlisle *
- * Free for public use, all I ask is that my name remain *
- * with this code. *
- * *
- * This unit provides easy implementation of a status line. The *
- * statusline will be at the bottom of the screen, and will take on the *
- * colors defined in the system as button face, and button shadow. *
- * *
- * The statusline can have multiple partitions to display different *
- * information. For example, you could have a partition that displays *
- * a clock (see STATUSEX.PAS), another one that displays the current *
- * file open in a word processing application, or virtually anything you *
- * can think up. *
- * *
- * The main object is TStatusLine. TStatusline is an abstract object with *
- * limited default functionality. TStatusline is a statusline with no *
- * partitions. It knows how to draw itself, and most importantly it knows *
- * how to insert partitions. However, TStatusline does not Insert any *
- * partitions. The user must create a descendant object of TStatusLine *
- * that overrides the Setup method to insert some partitions. *
- * *
- * A typical Setup method may look something like this: *
- * PROCEDURE TMyStatusline.Setup; *
- * BEGIN *
- * InsertItem(100,DrawProc); *
- * END; *
- * *
- * That would insert a partition that is 100 pixels wide. The second *
- * parameter is important. It is a procedure. Each partition must be *
- * passed a procedure so it knows who to call to fill in the partition *
- * with the appropriate text. The procedure passed in the InsertItem *
- * statement MUST be a procedure that was previously declared like this: *
- * *
- * PROCEDURE DrawProc(PaintHDC : HDC; VAR PaintInfo : TPaintStruct);FAR; *
- * BEGIN *
- * { your custom draw code goes here... } *
- * END; *
- * *
- * Note proceduremust be declared as FAR. It also MUST have the exact *
- * parameter list as shown. In the body, you can do what you want. A *
- * simple example would be to simply write out a line of text: *
- * *
- * PROCEDURE DrawProc(PaintHDC : HDC; VAR PaintInfo : TPaintStruct);FAR; *
- * BEGIN *
- * TextOut(PaintHdc,3,1,'Test',4); *
- * END; *
- * *
- * Usually you will not have a simple procedure like that. For a better, *
- * more functional example see the procedure Clock in STATUSEX.PAS *
- * *
- *************************************************************************)
-
- UNIT Status;
-
- INTERFACE
-
- USES
- WObjects,WinTypes,WinProcs,WinCrt;
-
- TYPE
- TPaintProc = PROCEDURE(PaintHdc : HDC; VAR PaintInfo : TPaintStruct);
-
- PPartitionCollection = ^TPartitionCollection;
-
- TPartitionCollection = OBJECT(TCollection)
- END;
-
- PPartition = ^TPartition;
-
- TPartition = OBJECT(TWindow)
- PRIVATE
- LeftPosition,
- RightPosition : WORD;
- PaintProc : TPaintProc;
- CONSTRUCTOR Init(AParent : PWindowsObject; ATitle : PCHAR;
- LPos,RPos : WORD; Proc : TPaintProc);
- PROCEDURE Paint(PaintHDC : HDC; VAR PaintInfo : TPaintStruct);
- VIRTUAL;
- END;
-
- PStatusLine = ^TStatusLine;
-
- TStatusLine = OBJECT(TWindow)
- CONSTRUCTOR Init(AParent : PWindowsObject; ATitle : PCHAR);
- PROCEDURE Paint(PaintHDC : HDC; VAR PaintInfo : TPaintStruct);
- VIRTUAL;
- DESTRUCTOR Done;VIRTUAL;
- PROCEDURE InsertItem(StrLength : WORD; Proc : TPaintProc);
- PROCEDURE Setup;VIRTUAL;
- FUNCTION GetPartition(Index : BYTE):PPartition;VIRTUAL;
- PRIVATE
- Partitions : PPartitionCollection;
- END;
-
- IMPLEMENTATION
-
- (************************** TPartition Methods ***************************)
-
- { TPartition is an object descendant of TWindow. All TPartition objects
- are child windows with TStatusLine as the parent.
-
- When a TPartition is inserted in the statusline, it is automaticlly
- inserted right next to the previous TPartition on the statusline.
-
- The Init constructor method is called whenevr a new TPartition is
- inserted in the statusline. The parameters of Init include the
- TPartition's parent window, its title (Nil), the TPartitions left position
- on the statusline, it's right position on the statusline, and most
- importantly -- the last parameter -- is a procedure parameter. This
- procedure parameter is a user defined procedure that will be used by
- the TPartition.Paint method.
-
- Each TPartition knows how to draw itself, with the Paint method. The Paint
- method draws an empty partition (i.e - only the frame, not filled with
- text. The paint method calls the user defined procedure, which is
- responsible for filling the partition frame with the appropriate text.
-
- See STATUSEX.PAS for an example of the user defined procedure }
-
-
- CONSTRUCTOR TPartition.Init(AParent : PWindowsObject; ATitle : PCHAR;
- LPos,RPos : WORD; Proc : TPaintProc);
-
- VAR
- R : TRect;
- BEGIN
- TWindow.Init(AParent,ATitle);
- LeftPosition:=LPos;
- RightPosition:=RPos;
- PaintProc:=Proc;
- WITH Attr DO BEGIN
- Style:=Style OR ws_Child;
- X:=LPos;
- Y:=0;
- W:=RPos-LPos;
- H:=17;
- END;
- END;
-
- PROCEDURE TPartition.Paint(PaintHDC : HDC; VAR PaintInfo : TPaintStruct);
- VAR
- R : TRect;
- TheBrush,
- OldBrush : HBrush;
- Pen,
- OldPen : HPen;
- BEGIN
- GetClientRect(HWindow,R);
- TheBrush:=CreateSolidBrush(GetSysColor(color_BtnFace));
- FillRect(PaintHdc,R,TheBrush);
- DeleteObject(TheBrush);
-
- SetBkColor(PaintHdc,GetSysColor(color_BtnFace));
- PaintProc(PaintHdc,PaintInfo);
-
- Pen:=CreatePen(ps_Solid,1,RGB(255,255,255));
- OldPen:=SelectObject(PaintHDC,Pen);
- MoveTo(PaintHDC,R.Left,R.Top);
- LineTo(PaintHDC,R.Right,R.Top);
- MoveTo(PaintHdc,R.Left,R.Top);
- LineTo(PaintHdc,R.Left,R.Bottom);
- MoveTo(PaintHdc,R.Left+2,R.Top+15);
- LineTo(PaintHdc,R.Right-3,R.Top+15);
- LineTo(PaintHdc,R.Right-3,R.Top+2);
-
- DeleteObject(SelectObject(PaintHdc,OldPen));
- Pen:=CreatePen(ps_Solid,1,GetSysColor(color_btnShadow));
- OldPen:=SelectObject(PaintHDC,Pen);
- MoveTo(PaintHdc,R.Left+2,R.Top+2);
- LineTo(PaintHdc,R.Right-3,R.Top+2);
- MoveTo(PaintHdc,R.Right-1,R.Top);
- LineTo(PaintHdc,R.Right-1,R.Bottom);
- MoveTo(PaintHdc,R.Left+2,R.Top+2);
- LineTo(PaintHdc,R.Left+2,R.Top+15);
-
- DeleteObject(SelectObject(PaintHDC,OldPen));
- END;
-
- (*************************** TStatusLine Methods *************************)
-
- { TStatusLine is an object descendant of TWindow. TStatusLine has a field
- called Partitions, which is a collection of TPartitions.
-
- The InsertItem method is the method responsible for inserting new
- TPartitions in the Partition collection.
-
- The Paint method draws the statusline, and iterates through the Partition
- collection call each ones Paint method. This results in the entire
- statusline being redrawn. }
-
-
- CONSTRUCTOR TStatusLine.Init(AParent : PWindowsObject; ATitle : PCHAR);
- BEGIN
- TWindow.Init(AParent,ATitle);
- WITH Attr DO BEGIN
- Style := Style OR ws_Child OR ws_Border;
- END;
- Partitions:=New(PPartitionCollection,Init(1,1));
- Setup;
- END;
-
- PROCEDURE TStatusLine.InsertItem(StrLength : WORD; Proc : TPaintProc);
- BEGIN
- IF Partitions^.Count=0 THEN BEGIN
- Partitions^.Insert(New(PPartition,Init(@Self,Nil,0,StrLength,
- Proc)));
- END
- ELSE BEGIN
- Partitions^.Insert(New(PPartition,Init(@Self,NIL,PPartition(
- Partitions^.At(Partitions^.Count-1))^.RightPosition,PPartition(
- Partitions^.At(Partitions^.Count-1))^.RightPosition+StrLength,
- Proc)));
- END;
- END;
-
- FUNCTION TStatusLine.GetPartition(Index : BYTE):PPartition;
- BEGIN
- GetPartition:=NIL;
- IF Partitions^.Count<>0 THEN BEGIN
- GetPartition:=Partitions^.At(Index);
- END;
- END;
-
- PROCEDURE TStatusLine.Setup;
- BEGIN
- END;
-
- PROCEDURE TStatusLine.Paint(PaintHDC : HDC; VAR PaintInfo : TPaintStruct);
- VAR
- R : TRect;
- TheBrush : HBrush;
- Pen,
- OldPen : HPen;
-
- PROCEDURE CallPaint(P : PPartition);FAR;
- BEGIN
- P^.Paint(PaintHDC,PaintInfo);
- END;
-
- BEGIN
- GetClientRect(Parent^.HWindow,R);
- MoveWindow(HWindow,0,R.Bottom-18,R.Right-R.Left,R.Bottom,TRUE);
-
- GetClientRect(HWindow,R);
- IF Partitions^.Count<>0 THEN BEGIN
- R.Left:=PPartition(
- Partitions^.At(Partitions^.Count-1))^.RightPosition;
- END;
- TheBrush:=CreateSolidBrush(GetSysColor(color_BtnFace));
- FillRect(PaintHdc,R,TheBrush);
- DeleteObject(TheBrush);
-
- Pen:=CreatePen(ps_Solid,1,RGB(255,255,255));
- OldPen:=SelectObject(PaintHDC,Pen);
- MoveTo(PaintHDC,R.Left,R.Top);
- LineTo(PaintHDC,R.Right,R.Top);
- MoveTo(PaintHdc,R.Left,R.Top);
- LineTo(PaintHdc,R.Left,R.Bottom);
- MoveTo(PaintHdc,R.Left+2,R.Top+15);
- LineTo(PaintHdc,R.Right-3,R.Top+15);
- LineTo(PaintHdc,R.Right-3,R.Top+2);
-
- DeleteObject(SelectObject(PaintHdc,OldPen));
- Pen:=CreatePen(ps_Solid,1,GetSysColor(color_btnShadow));
- OldPen:=SelectObject(PaintHDC,Pen);
- MoveTo(PaintHdc,R.Left+2,R.Top+2);
- LineTo(PaintHdc,R.Right-3,R.Top+2);
- MoveTo(PaintHdc,R.Right-1,R.Top);
- LineTo(PaintHdc,R.Right-1,R.Bottom);
- MoveTo(PaintHdc,R.Left+2,R.Top+2);
- LineTo(PaintHdc,R.Left+2,R.Top+15);
-
- DeleteObject(SelectObject(PaintHdc,OldPen));
-
- Partitions^.ForEach(@CallPaint);
- END;
-
-
- DESTRUCTOR TStatusLine.Done;
- BEGIN
- Dispose(Partitions,Done);
- TWindow.Done;
- END;
-
- END.
-
- {------------------------ DEMO -------------------------}
-
- (*************************************************************************
- * *
- * STATUSEX.PAS - example program using the STATUS unit. *
- * By Thomas S. Carlisle *
- * *
- * *
- * This program sets up an example application demonstrating the use of *
- * the STATUS unit. A main window is created that has a statusline with *
- * a single partition that will display the current time. *
- * *
- * I picked a clock example because it demonstrates how the main window *
- * can communicate with the statusline to tell it a certain partition *
- * needs to be redrawn. *
- * *
- *************************************************************************)
-
- PROGRAM StatusEx;
- USES
- WObjects,WinTypes,WinProcs,Status,WinDOS,Strings;
-
- CONST
- wm_UpdateTime = $0400; { User defined message }
-
- TYPE
- TimeRec = RECORD
- Hour,
- Min : WORD;
- END;
-
- PMyStatusLine = ^TMyStatusLine;
-
- TMyStatusLine = OBJECT(TStatusLine)
- PROCEDURE Setup;VIRTUAL;
- PROCEDURE UpdateTime(VAR Msg : TMessage);
- VIRTUAL wm_First + wm_UpdateTime;
- END;
-
- PMyWindow = ^TMyWindow;
-
- TMyWindow = OBJECT(TWindow)
- StatusLine : PMyStatusLine;
- CONSTRUCTOR Init(AParent : PWindowsObject; ATitle : PCHAR);
- PROCEDURE SetupWindow;VIRTUAL;
- DESTRUCTOR Done;VIRTUAL;
- PROCEDURE Timer(VAR Msg : TMessage);VIRTUAL wm_Timer;
- END;
-
- TMyApp = OBJECT(TApplication)
- PROCEDURE InitMainWindow;VIRTUAL;
- END;
-
-
- (********************************* Globals **************************)
-
- VAR
- OldTime : TimeRec; { OldTime will be used to keep track of
- whether or not the time has changed and
- needs to be redrawn }
-
- PROCEDURE Clock(PaintHdc : HDC; VAR PaintInfo : TPaintStruct);FAR;
-
- { This procedure MUST be declared as FAR because it is passed as a
- parameter to the statusline, so the statusline will know what procedure
- to call when the statusline needs to be drawn. The statusline draws the
- actual box, but this procedure must fill in the text.
-
- Note the parameter list. It is mandatory, but also convenient. You will
- need to use the PaintHDC as the device context for your text output. The
- PaintInfo is there just in case you need it. All procedures designed to be
- passed to the statusline to be used to fill in the statusline partitions
- MUST have these two parameters!
-
- This procedure simply fills the box with the current time. }
-
- VAR
- TimeStr : ARRAY[0..5] OF CHAR;
- Hour,
- Minute,
- Sec,
- HSec : WORD;
- TempStr,
- Temp1 : ARRAY[0..2] OF CHAR;
- BEGIN
- StrCopy(TimeStr,' ');
- GetTime(Hour,Minute,Sec,HSec);
- OldTime.Hour:=Hour; { Fill in OldTime record for future use }
- OldTime.Min:=Minute;
- Str(Hour,TempStr); { Build the string that holds the time }
- StrCat(TimeStr,TempStr);
- StrCopy(TempStr,':');
- StrCat(TimeStr,TempStr);
- Str(Minute,TempStr);
- IF StrLen(TempStr)=1 THEN BEGIN
- StrCopy(Temp1,'0');
- StrCat(Temp1,TempStr);
- StrCopy(TempStr,Temp1);
- END;
- StrCat(TimeStr,TempStr);
- TextOut(PaintHdc,3,1,TimeStr,StrLen(TimeStr)); { Output the time }
- END;
-
- (************************ TMyStatusLine Methods ************************)
-
- PROCEDURE TMyStatusLine.UpdateTime(VAR Msg : TMessage);
-
- { This procedure is a response method for TMyStatusLine. It responds to
- the wm_UpdateTime user defined message. The procedure first checks
- the current time against the time in OldTime. If they are different,
- then the clock status window is invalidated, to force it to be redrawn
- with the new time.
-
- The reason this program is setup to keep track of the OldTime, and have
- this procedure check it, is to avoid flicker that occurs if the time
- is updated when it isn't necessary. }
-
- VAR
- Hour,Min,Sec,HSec : WORD;
- BEGIN
- GetTime(Hour,Min,Sec,HSec);
- IF (OldTime.Hour<>Hour) OR (OldTime.Min<>Min) THEN
- InvalidateRect(GetPartition(0)^.HWindow,NIL,TRUE);
- END;
-
- PROCEDURE TMyStatusLine.Setup;
-
- { Overrides the inherited Setup method. This setup method inserts one
- statusline partition in the status line. }
-
- BEGIN
- InsertItem(75,Clock); { This inserts a new item in the statsuline.
- The first parameter is the length (in pixels)
- of the desired statusline partition. The
- second parameter is the procedure this new
- partition will call whenever it needs to be
- redrawn. As stated earlier, the statusline
- takes care of drawing the statusline and it's
- partitions, but the procedure passed here is
- responsible for filling the partition with
- text }
-
- { If you need more than one partition,
- simply add more InsertItem statements. Each
- one can be passed a length and procedure
- parameter. Very powerful. }
-
- END;
-
- (************************* TMyWindow Methods ***************************)
-
- CONSTRUCTOR TMyWindow.Init(AParent : PWindowsObject; ATitle : PCHAR);
-
- { TMyWindow is a descendant of TWindow. The only difference is it has a
- StatusLine. }
-
- BEGIN
- TWindow.Init(AParent,ATitle);
- Statusline:=New(PMyStatusLine,Init(@Self,Nil));
- END;
-
- PROCEDURE TMyWindow.SetupWindow;
-
- { SetupWindow is needed in this application to start the timer that will
- be used to spark messages every second to make sure the statusline clock
- is kept up to date. }
-
- BEGIN
- TWindow.SetupWindow;
- IF SetTimer(HWindow,1,1000,NIL) = 0 THEN
- MessageBox(HWindow,'ERROR','Timer not available',mb_OK);
- END;
-
- PROCEDURE TMyWindow.Timer(VAR Msg : TMessage);
-
- { Responds to wm_Timer messages. First checks to make sure the incomming
- message is ours (ID=1). If it is, it sends a wm_UpdateTime message
- to the statusline. That is the message the statusline responds to by
- updating the time, if it has changed. }
-
- BEGIN
- IF Msg.wParam=1 THEN BEGIN
- SendMessage(StatusLine^.HWindow,wm_UpdateTime,0,0);
- END;
- END;
-
- DESTRUCTOR TMyWindow.Done;
- { Cleans up by killing the timer we started, and disposing the statusline }
- BEGIN
- KillTimer(HWindow,1);
- Dispose(StatusLine,Done);
- TWindow.Done;
- END;
-
- (****************************** TMyApp Methods ************************)
-
- PROCEDURE TMyApp.InitMainWindow;
- { Gets our main window (TMyWindow) in action }
- BEGIN
- MainWindow:=New(PMyWindow,Init(NIL,'Test'));
- END;
-
- VAR
- MyApp : TMyApp;
- BEGIN
- MyApp.Init('Test');
- MyApp.Run;
- MyApp.Done;
- END.