{ GPC demo program for the CRT unit. Copyright (C) 1999-2006, 2013-2021 Free Software Foundation, Inc. Author: Frank Heckenbach This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . As a special exception, if you incorporate even large parts of the code of this demo program into another program with substantially different functionality, this does not cause the other program to be covered by the GNU General Public License. This exception does not however invalidate any other reasons why it might be covered by the GNU General Public License. } {$gnu-pascal,I+} (* second style of comment *) // Free-pascal style comment. var x:Char = 12 /* 45; // This /* does not start a comment. var x:Char = (/ 4); // This (/ does not start a comment. var a_to_b : integer; // 'to' should not be highlighted program CRTDemo; uses GPC, CRT; type TFrameChars = array [1 .. 8] of Char; TSimulateBlockCursorKind = (bc_None, bc_Blink, bc_Static); const SingleFrame: TFrameChars = (chCornerTLS, chLineHS, chCornerTRS, chLineVS, chLineVS, chCornerBLS, chLineHS, chCornerBRS); DoubleFrame: TFrameChars = (chCornerTLD, chLineHD, chCornerTRD, chLineVD, chLineVD, chCornerBLD, chLineHD, chCornerBRD); var ScrollState: Boolean = True; SimulateBlockCursorKind: TSimulateBlockCursorKind = bc_None; CursorShape: TCursorShape = CursorNormal; MainPanel: TPanel; OrigScreenSize: TPoint; procedure FrameWin (const Title: String; const Frame: TFrameChars; TitleInverse: Boolean); var w, h, y, Color: Integer; Attr: TTextAttr; begin HideCursor; SetPCCharSet (True); ClrScr; w := GetXMax; h := GetYMax; WriteCharAt (1, 1, 1, Frame[1], TextAttr); WriteCharAt (2, 1, w - 2, Frame[2], TextAttr); WriteCharAt (w, 1, 1, Frame[3], TextAttr); for y := 2 to h - 1 do begin WriteCharAt (1, y, 1, Frame[4], TextAttr); WriteCharAt (w, y, 1, Frame[5], TextAttr) end; WriteCharAt (1, h, 1, Frame[6], TextAttr); WriteCharAt (2, h, w - 2, Frame[7], TextAttr); WriteCharAt (w, h, 1, Frame[8], TextAttr); SetPCCharSet (False); Attr := TextAttr; if TitleInverse then begin Color := GetTextColor; TextColor (GetTextBackground); TextBackground (Color) end; WriteStrAt ((w - Length (Title)) div 2 + 1, 1, Title, TextAttr); TextAttr := Attr end; function GetKey (TimeOut: Integer) = Key: TKey; forward; procedure ClosePopUpWindow; begin PanelDelete (GetActivePanel); PanelDelete (GetActivePanel) end; function PopUpConfirm (XSize, YSize: Integer; const Msg: String): Boolean; var ax, ay: Integer; Key: TKey; SSize: TPoint; begin repeat SSize := ScreenSize; ax := (SSize.x - XSize - 4) div 2 + 1; ay := (SSize.y - YSize - 4) div 2 + 1; PanelNew (ax, ay, ax + XSize + 3, ay + YSize + 1, False); TextBackground (Black); TextColor (Yellow); SetControlChars (True); FrameWin ('', DoubleFrame, False); NormalCursor; PanelNew (ax + 2, ay + 1, ax + XSize + 2, ay + YSize, False); ClrScr; Write (Msg); Key := GetKey (-1); if Key = kbScreenSizeChanged then ClosePopUpWindow until Key <> kbScreenSizeChanged; PopUpConfirm := not (Key in [kbEsc, kbAltEsc]) end; procedure MainDraw; begin WriteLn ('3, F3 : Open a window'); WriteLn ('4, F4 : Close window'); WriteLn ('5, F5 : Previous window'); WriteLn ('6, F6 : Next window'); WriteLn ('7, F7 : Move window'); WriteLn ('8, F8 : Resize window'); Write ('q, Esc: Quit') end; procedure StatusDraw; const YesNo: array [Boolean] of String [3] = ('No', 'Yes'); SimulateBlockCursorIDs: array [TSimulateBlockCursorKind] of String [8] = ('Off', 'Blinking', 'Static'); CursorShapeIDs: array [TCursorShape] of String [7] = ('Ignored', 'Hidden', 'Normal', 'Fat', 'Block'); var SSize: TPoint; begin WriteLn ('You can change some of the following'); WriteLn ('settings by pressing the key shown'); WriteLn ('in parentheses. Naturally, color and'); WriteLn ('changing the cursor shape or screen'); WriteLn ('size does not work on all terminals.'); WriteLn; WriteLn ('XCurses version: ', YesNo[XCRT]); WriteLn ('CRTSavePreviousScreen: ', YesNo[CRTSavePreviousScreenWorks]); WriteLn ('(M)onochrome: ', YesNo[IsMonochrome]); SSize := ScreenSize; WriteLn ('Screen (C)olumns: ', SSize.x); WriteLn ('Screen (L)ines: ', SSize.y); WriteLn ('(R)estore screen size'); WriteLn ('(B)reak checking: ', YesNo[CheckBreak]); WriteLn ('(S)crolling: ', YesNo[ScrollState]); WriteLn ('S(i)mulated block cursor: ', SimulateBlockCursorIDs[SimulateBlockCursorKind]); Write ('C(u)rsor shape: ', CursorShapeIDs[CursorShape]); GotoXY (36, WhereY) end; procedure RedrawAll; forward; procedure CheckScreenSize; forward; procedure StatusKey (Key: TKey); var SSize, NewSize: TPoint; begin case LoCase (Key2Char (Key)) of 'm': begin SetMonochrome (not IsMonochrome); RedrawAll end; 'c': begin SSize := ScreenSize; if SSize.x > 40 then NewSize.x := 40 else NewSize.x := 80; if SSize.y > 25 then NewSize.y := 50 else NewSize.y := 25; SetScreenSize (NewSize.x, NewSize.y); CheckScreenSize end; 'l': begin SSize := ScreenSize; if SSize.x > 40 then NewSize.x := 80 else NewSize.x := 40; if SSize.y > 25 then NewSize.y := 25 else NewSize.y := 50; SetScreenSize (NewSize.x, NewSize.y); CheckScreenSize end; 'r': begin SetScreenSize (OrigScreenSize.x, OrigScreenSize.y); CheckScreenSize end; 'b': CheckBreak := not CheckBreak; 's': ScrollState := not ScrollState; 'i': if SimulateBlockCursorKind = High (SimulateBlockCursorKind) then SimulateBlockCursorKind := Low (SimulateBlockCursorKind) else Inc (SimulateBlockCursorKind); 'u': case CursorShape of CursorNormal: CursorShape := CursorBlock; CursorFat, CursorBlock : CursorShape := CursorHidden; else CursorShape := CursorNormal end; end; ClrScr; StatusDraw end; procedure TextAttrDemo; var f, b, y, x1, y1, x2, y2, Fill, n1, n2, n3: Integer; begin GetWindow (x1, y1, x2, y2); Window (x1 - 1, y1, x2, y2); TextColor (White); TextBackground (Blue); ClrScr; SetScroll (False); Fill := GetXMax - 32; for y := 1 to GetYMax do begin GotoXY (1, y); b := (y - 1) mod 16; n1 := 0; for f := 0 to 15 do begin TextAttr := f + 16 * b; n2 := (Fill * (1 + 2 * f) + 16) div 32; n3 := (Fill * (2 + 2 * f) + 16) div 32; Write ('' : n2 - n1, NumericBaseDigitsUpper[b], NumericBaseDigitsUpper[f], '' : n3 - n2); n1 := n3 end end end; procedure CharSetDemo (UsePCCharSet: Boolean); var h, l, y, x1, y1, x2, y2, Fill, n1, n2: Integer; begin GetWindow (x1, y1, x2, y2); Window (x1 - 1, y1, x2, y2); ClrScr; SetScroll (False); SetPCCharSet (UsePCCharSet); SetControlChars (False); Fill := GetXMax - 35; for y := 1 to GetYMax do begin GotoXY (1, y); h := (y - 2) mod 16; n1 := (Fill + 9) div 18; if y = 1 then Write ('' : 3 + n1) else Write (16 * h : 3 + n1); for l := 0 to 15 do begin n2 := (Fill * (2 + l) + 9) div 18; if y = 1 then Write ('' : n2 - n1, l : 2) else Write ('' : n2 - n1 + 1, Chr (16 * h + l)); n1 := n2 end end end; procedure NormalCharSetDemo; begin CharSetDemo (False) end; procedure PCCharSetDemo; begin CharSetDemo (True) end; procedure FKeyDemoDraw; var x1, y1, x2, y2: Integer; begin GetWindow (x1, y1, x2, y2); Window (x1, y1, x2 - 1, y2); ClrScr; SetScroll (False); WriteLn ('You can type the following keys'); WriteLn ('(function keys if present on the'); WriteLn ('terminal, letters as alternatives):'); GotoXY (1, 4); WriteLn ('S, Left : left (wrap-around)'); WriteLn ('D, Right : right (wrap-around)'); WriteLn ('E, Up : up (wrap-around)'); WriteLn ('X, Down : down (wrap-around)'); WriteLn ('A, Home : go to first column'); WriteLn ('F, End : go to last column'); WriteLn ('R, Page Up : go to first line'); WriteLn ('C, Page Down: go to last line'); WriteLn ('Y, Ctrl-PgUp: first column and line'); GotoXY (1, 13); WriteLn ('B, Ctrl-PgDn: last column and line'); WriteLn ('Z, Ctrl-Home: clear screen'); WriteLn ('N, Ctrl-End : clear to end of line'); WriteLn ('V, Insert : insert a line'); WriteLn ('T, Delete : delete a line'); WriteLn ('# : beep'); WriteLn ('* : flash'); WriteLn ('Tab, Enter, Backspace, other'); WriteLn (' normal characters: write text') end; procedure FKeyDemoKey (Key: TKey); const TabSize = 8; var ch: Char; NewX: Integer; begin case LoCaseKey (Key) of Ord ('s'), kbLeft : if WhereX = 1 then GotoXY (GetXMax, WhereY) else GotoXY (WhereX - 1, WhereY); Ord ('d'), kbRight : if WhereX = GetXMax then GotoXY (1, WhereY) else GotoXY (WhereX + 1, WhereY); Ord ('e'), kbUp : if WhereY = 1 then GotoXY (WhereX, GetYMax) else GotoXY (WhereX, WhereY - 1); Ord ('x'), kbDown : if WhereY = GetYMax then GotoXY (WhereX, 1) else GotoXY (WhereX, WhereY + 1); Ord ('a'), kbHome : Write (chCR); Ord ('f'), kbEnd : GotoXY (GetXMax, WhereY); Ord ('r'), kbPgUp : GotoXY (WhereX, 1); Ord ('c'), kbPgDn : GotoXY (WhereX, GetYMax); Ord ('y'), kbCtrlPgUp: GotoXY (1, 1); Ord ('b'), kbCtrlPgDn: GotoXY (GetXMax, GetYMax); Ord ('z'), kbCtrlHome: ClrScr; Ord ('n'), kbCtrlEnd : ClrEOL; Ord ('v'), kbIns : InsLine; Ord ('t'), kbDel : DelLine; Ord ('#') : Beep; Ord ('*') : Flash; kbTab : begin NewX := ((WhereX - 1) div TabSize + 1) * TabSize + 1; if NewX <= GetXMax then GotoXY (NewX, WhereY) else WriteLn end; kbCR : WriteLn; kbBkSp : Write (chBkSp, ' ', chBkSp); else ch := Key2Char (Key); if ch <> #0 then Write (ch) end end; procedure KeyDemoDraw; begin WriteLn ('Press some keys ...') end; procedure KeyDemoKey (Key: TKey); var ch: Char; begin ch := Key2Char (Key); if ch <> #0 then begin Write ('Normal key'); if IsPrintable (ch) then Write (' `', ch, ''''); WriteLn (', ASCII #', Ord (ch)) end else WriteLn ('Special key ', Ord (Key2Scan (Key))) end; procedure IOSelectPeriodical; var CurrentTime: TimeStamp; s: String (8); i: Integer; begin GetTimeStamp (CurrentTime); with CurrentTime do WriteStr (s, Hour : 2, ':', Minute : 2, ':', Second : 2); for i := 1 to Length (s) do if s[i] = ' ' then s[i] := '0'; GotoXY (1, 12); Write ('The time is: ', s) end; procedure IOSelectDraw; begin WriteLn ('IOSelect is a way to handle I/O from'); WriteLn ('or to several places simultaneously,'); WriteLn ('without having to use threads or'); WriteLn ('signal/interrupt handlers or waste'); WriteLn ('CPU time with busy waiting.'); WriteLn; WriteLn ('This demo shows how IOSelect works'); WriteLn ('in connection with CRT. It displays'); WriteLn ('a clock, but still reacts to user'); WriteLn ('input immediately.'); IOSelectPeriodical end; procedure ModifierPeriodical; const Pressed: array [Boolean] of String [8] = ('Released', 'Pressed'); ModifierNames: array [1 .. 7] of record Modifier: Integer; Name: String (17) end = ((shLeftShift, 'Left Shift'), (shRightShift, 'Right Shift'), (shLeftCtrl, 'Left Control'), (shRightCtrl, 'Right Control'), (shAlt, 'Alt (left)'), (shAltGr, 'AltGr (right Alt)'), (shExtra, 'Extra')); var ShiftState, i: Integer; begin ShiftState := GetShiftState; for i := 1 to 7 do with ModifierNames[i] do begin GotoXY (1, 4 + i); ClrEOL; Write (Name, ':'); GotoXY (20, WhereY); Write (Pressed[(ShiftState and Modifier) <> 0]) end end; procedure ModifierDraw; begin WriteLn ('Modifier keys (NOTE: only'); WriteLn ('available on some systems;'); WriteLn ('X11: only after key press):'); ModifierPeriodical end; procedure ChecksDraw; begin WriteLn ('(O)S shell'); WriteLn ('OS shell with (C)learing'); WriteLn ('(R)efresh check'); Write ('(S)ound check') end; procedure ChecksKey (Key: TKey); var i, j: Integer; WasteTime: Real; attribute (volatile); procedure DoOSShell; var Result: Integer; Shell: TString; begin Shell := GetShellPath (Null); {$I-} Result := Execute (Shell); {$I+} if (InOutRes <> 0) or (Result <> 0) then begin ClrScr; if InOutRes <> 0 then WriteLn (GetIOErrorMessage, ' while trying to execute `', Shell, '''.') else WriteLn ('`', Shell, ''' returned status ', Result, '.'); Write ('Any key to continue.'); BlockCursor; Discard (GetKey (-1)) end end; begin case LoCase (Key2Char (Key)) of 'o': begin if PopUpConfirm (36, 12, 'You will now get an OS shell. Unless' + NewLine + 'CRTDemo is running in its own (GUI)' + NewLine + 'window, the shell will run on the' + NewLine + 'same screen as CRTDemo which is not' + NewLine + 'cleared before the shell is started.' + NewLine + 'If possible, the screen contents are' + NewLine + 'restored to the state before CRTDemo' + NewLine + 'was started. After leaving the shell' + NewLine + 'in the usual way (usually by enter-' + NewLine + 'ing `exit''), you will get back to' + NewLine + 'the demo. to abort, any other' + NewLine + 'key to start.') then begin RestoreTerminal (True); DoOSShell end; ClosePopUpWindow end; 'c': begin if PopUpConfirm (36, 9, 'You will now get an OS shell. Unless' + NewLine + 'CRTDemo is running in its own (GUI)' + NewLine + 'window, the screen will be cleared,' + NewLine + 'and the cursor will be moved to the' + NewLine + 'top before the shell is started.' + NewLine + 'After leaving the shell in the usual' + NewLine + 'way (usually by entering `exit''),' + NewLine + 'you will get back to the demo. ' + NewLine + 'to abort, any other key to start.') then begin RestoreTerminalClearCRT; DoOSShell end; ClosePopUpWindow end; 'r': begin if PopUpConfirm (36, 11, 'The program will now get busy with' + NewLine + 'some dummy computations. However,' + NewLine + 'CRT output in the form of dots will' + NewLine + 'still appear continuously one by one' + NewLine + '(rather than the whole line at once' + NewLine + 'in the end). While running, the test' + NewLine + 'cannot be interrupted. to' + NewLine + 'abort, any other key to start.') then begin SetCRTUpdate (UpdateRegularly); BlockCursor; WriteLn; WriteLn; for i := 1 to GetXMax - 2 do begin Write ('.'); for j := 1 to 400000 do WasteTime := Random end; SetCRTUpdate (UpdateInput); WriteLn; Write ('Press any key.'); Discard (GetKey (-1)) end; ClosePopUpWindow end; 's': begin if PopUpConfirm (32, 4, 'You will now hear some sounds if' + NewLine + 'supported (otherwise there will' + NewLine + 'just be a short pause). to' + NewLine + 'abort, any other key to start.') then begin BlockCursor; for i := 0 to 7 do begin Sound (Round (440 * 2 ** (Round (i * 12 / 7 + 0.3) / 12))); if GetKey (400000) in [kbEsc, kbAltEsc] then Break end; NoSound end; ClosePopUpWindow end; end end; type PWindowList = ^TWindowList; TWindowList = record Next, Prev: PWindowList; Panel, FramePanel: TPanel; WindowType: Integer; x1, y1, xs, ys: Integer; State: (ws_None, ws_Moving, ws_Resizing); end; TKeyProc = procedure (Key: TKey); TProcedure = procedure; const MenuNameLength = 16; WindowTypes: array [0 .. 9] of record DrawProc, PeriodicalProc: procedure; KeyProc : TKeyProc; Name : String (MenuNameLength); Color, Background, MinSizeX, MinSizeY, PrefSizeX, PrefSizeY : Integer; RedrawAlways, WantCursor : Boolean end = ((MainDraw , nil , nil , 'CRT Demo' , LightGreen, Blue , 26, 7, 0, 0, False, False), (StatusDraw , nil , StatusKey , 'Status' , White , Red , 38, 16, 0, 0, True, True), (TextAttrDemo , nil , nil , 'Text Attributes' , White , Blue , 32, 16, 64, 16, False, False), (NormalCharSetDemo, nil , nil , 'Character Set' , Black , Green , 35, 17, 53, 17, False, False), (PCCharSetDemo , nil , nil , 'PC Character Set', Black , Brown , 35, 17, 53, 17, False, False), (KeyDemoDraw , nil , KeyDemoKey , 'Keys' , Blue , LightGray, 29, 5, -1, -1, False, True), (FKeyDemoDraw , nil , FKeyDemoKey, 'Function Keys' , Blue , LightGray, 37, 22, -1, -1, False, True), (ModifierDraw , ModifierPeriodical, nil , 'Modifier Keys' , Black , Cyan , 29, 11, 0, 0, True, False), (IOSelectDraw , IOSelectPeriodical, nil , 'IOSelect Demo' , White , Magenta , 38, 12, 0, 0, False, False), (ChecksDraw , nil , ChecksKey , 'Various Checks' , Black , Red , 26, 4, 0, 0, False, False)); MenuMax = High (WindowTypes); MenuXSize = MenuNameLength + 4; MenuYSize = MenuMax + 2; var WindowList: PWindowList = nil; procedure RedrawFrame (p: PWindowList); begin with p^, WindowTypes[WindowType] do begin PanelActivate (FramePanel); Window (x1, y1, x1 + xs - 1, y1 + ys - 1); ClrScr; case State of ws_None : if p = WindowList then FrameWin (' ' + Name + ' ', DoubleFrame, True) else FrameWin (' ' + Name + ' ', SingleFrame, False); ws_Moving : FrameWin (' Move Window ', SingleFrame, True); ws_Resizing: FrameWin (' Resize Window ', SingleFrame, True); end end end; procedure DrawWindow (p: PWindowList); begin with p^, WindowTypes[WindowType] do begin RedrawFrame (p); PanelActivate (Panel); Window (x1 + 2, y1 + 1, x1 + xs - 2, y1 + ys - 2); ClrScr; DrawProc end end; procedure RedrawAll; var LastPanel: TPanel; p: PWindowList; x2, y2: Integer; begin LastPanel := GetActivePanel; PanelActivate (MainPanel); TextBackground (Blue); ClrScr; p := WindowList; if p <> nil then repeat with p^ do begin PanelActivate (FramePanel); GetWindow (x1, y1, x2, y2); { updated automatically by CRT } xs := x2 - x1 + 1; ys := y2 - y1 + 1 end; DrawWindow (p); p := p^.Next until p = WindowList; PanelActivate (LastPanel) end; procedure CheckScreenSize; var LastPanel: TPanel; MinScreenSizeX, MinScreenSizeY, i: Integer; SSize: TPoint; begin LastPanel := GetActivePanel; PanelActivate (MainPanel); HideCursor; MinScreenSizeX := MenuXSize; MinScreenSizeY := MenuYSize; for i := Low (WindowTypes) to High (WindowTypes) do with WindowTypes[i] do begin MinScreenSizeX := Max (MinScreenSizeX, MinSizeX + 2); MinScreenSizeY := Max (MinScreenSizeY, MinSizeY + 2) end; SSize := ScreenSize; Window (1, 1, SSize.x, SSize.y); if (SSize.x < MinScreenSizeX) or (SSize.y < MinScreenSizeY) then begin NormVideo; ClrScr; RestoreTerminal (True); WriteLn (StdErr, 'Sorry, your screen is too small for this demo (', SSize.x, 'x', SSize.y, ').'); WriteLn (StdErr, 'You need at least ', MinScreenSizeX, 'x', MinScreenSizeY, ' characters.'); Halt (2) end; PanelActivate (LastPanel); RedrawAll end; procedure Die; attribute (noreturn); begin NoSound; RestoreTerminalClearCRT; WriteLn (StdErr, 'You''re trying to kill me. Since I have break checking turned off,'); WriteLn (StdErr, 'I''m not dying, but I''ll do you a favor and terminate now.'); Halt (3) end; function GetKey (TimeOut: Integer) = Key: TKey; var NeedSelect, SelectValue: Integer; SimulateBlockCursorCurrent: TSimulateBlockCursorKind; SelectInput: array [1 .. 1] of PAnyFile = (@Input); NextSelectTime: MicroSecondTimeType = 0; attribute (static); TimeOutTime: MicroSecondTimeType; LastPanel: TPanel; p: PWindowList; begin LastPanel := GetActivePanel; if TimeOut < 0 then TimeOutTime := High (TimeOutTime) else TimeOutTime := GetMicroSecondTime + TimeOut; NeedSelect := 0; if TimeOut >= 0 then Inc (NeedSelect); SimulateBlockCursorCurrent := SimulateBlockCursorKind; if SimulateBlockCursorCurrent <> bc_None then Inc (NeedSelect); p := WindowList; repeat if @WindowTypes[p^.WindowType].PeriodicalProc <> nil then Inc (NeedSelect); p := p^.Next until p = WindowList; p := WindowList; repeat with p^, WindowTypes[WindowType] do if RedrawAlways then begin PanelActivate (Panel); ClrScr; DrawProc end; p := p^.Next until p = WindowList; if NeedSelect <> 0 then repeat CRTUpdate; SelectValue := IOSelectRead (SelectInput, Max (0, Min (NextSelectTime, TimeOutTime) - GetMicroSecondTime)); if SelectValue = 0 then begin case SimulateBlockCursorCurrent of bc_None : ; bc_Blink : SimulateBlockCursor; bc_Static: begin SimulateBlockCursor; SimulateBlockCursorCurrent := bc_None; Dec (NeedSelect) end end; NextSelectTime := GetMicroSecondTime + 120000; p := WindowList; repeat with p^, WindowTypes[WindowType] do if @PeriodicalProc <> nil then begin PanelActivate (Panel); PeriodicalProc end; p := p^.Next until p = WindowList end; until (NeedSelect = 0) or (SelectValue <> 0) or ((TimeOut >= 0) and (GetMicroSecondTime >= TimeOutTime)); if NeedSelect = 0 then SelectValue := 1; if SelectValue = 0 then Key := 0 else Key := ReadKeyWord; if SimulateBlockCursorKind <> bc_None then SimulateBlockCursorOff; if IsDeadlySignal (Key) then Die; if Key = kbScreenSizeChanged then CheckScreenSize; PanelActivate (LastPanel) end; function Menu = n: Integer; var i, ax, ay: Integer; Key: TKey; Done: Boolean; SSize: TPoint; begin n := 1; repeat SSize := ScreenSize; ax := (SSize.x - MenuXSize) div 2 + 1; ay := (SSize.y - MenuYSize) div 2 + 1; PanelNew (ax, ay, ax + MenuXSize - 1, ay + MenuYSize - 1, False); SetControlChars (True); TextColor (Blue); TextBackground (LightGray); FrameWin (' Select Window ', DoubleFrame, True); IgnoreCursor; PanelNew (ax + 1, ay + 1, ax + MenuXSize - 2, ay + MenuYSize - 2, False); ClrScr; TextColor (Black); SetScroll (False); Done := False; repeat for i := 1 to MenuMax do begin GotoXY (1, i); if i = n then TextBackground (Green) else TextBackground (LightGray); ClrEOL; Write (' ', WindowTypes[i].Name); ChangeTextAttr (2, i, 1, Red + $10 * GetTextBackground) end; Key := GetKey (-1); case LoCaseKey (Key) of kbUp : if n = 1 then n := MenuMax else Dec (n); kbDown : if n = MenuMax then n := 1 else Inc (n); kbHome, kbPgUp, kbCtrlPgUp, kbCtrlHome : n := 1; kbEnd, kbPgDn, kbCtrlPgDn, kbCtrlEnd : n := MenuMax; kbCR : Done := True; kbEsc, kbAltEsc : begin n := -1; Done := True end; Ord ('a') .. Ord ('z'): begin i := MenuMax; while (i > 0) and (LoCase (Key2Char (Key)) <> LoCase (WindowTypes[i].Name[1])) do Dec (i); if i > 0 then begin n := i; Done := True end end; end until Done or (Key = kbScreenSizeChanged); ClosePopUpWindow until Key <> kbScreenSizeChanged end; procedure NewWindow (WindowType, ax, ay: Integer); var p, LastWindow: PWindowList; MaxX1, MaxY1: Integer; SSize: TPoint; begin New (p); if WindowList = nil then begin p^.Prev := p; p^.Next := p end else begin p^.Prev := WindowList; p^.Next := WindowList^.Next; p^.Prev^.Next := p; p^.Next^.Prev := p; end; p^.WindowType := WindowType; with p^, WindowTypes[WindowType] do begin SSize := ScreenSize; if PrefSizeX > 0 then xs := PrefSizeX else xs := MinSizeX; if PrefSizeY > 0 then ys := PrefSizeY else ys := MinSizeY; xs := Min (xs + 2, SSize.x); ys := Min (ys + 2, SSize.y); MaxX1 := SSize.x - xs + 1; MaxY1 := SSize.y - ys + 1; if ax = 0 then x1 := Random (MaxX1) + 1 else x1 := Min (ax, MaxX1); if ay = 0 then y1 := Random (MaxY1) + 1 else y1 := Min (ay, MaxY1); if (ax = 0) and (PrefSizeX < 0) then Inc (xs, Random (SSize.x - x1 - xs + 2)); if (ax = 0) and (PrefSizeY < 0) then Inc (ys, Random (SSize.y - y1 - ys + 2)); State := ws_None; PanelNew (1, 1, 1, 1, False); FramePanel := GetActivePanel; SetControlChars (True); TextColor (Color); TextBackground (Background); PanelNew (1, 1, 1, 1, False); SetPCCharSet (False); Panel := GetActivePanel; end; LastWindow := WindowList; WindowList := p; if LastWindow <> nil then RedrawFrame (LastWindow); DrawWindow (p) end; procedure OpenWindow; var WindowType: Integer; begin WindowType := Menu; if WindowType >= 0 then NewWindow (WindowType, 0, 0) end; procedure NextWindow; var LastWindow: PWindowList; begin LastWindow := WindowList; WindowList := WindowList^.Next; PanelTop (WindowList^.FramePanel); PanelTop (WindowList^.Panel); RedrawFrame (LastWindow); RedrawFrame (WindowList) end; procedure PreviousWindow; var LastWindow: PWindowList; begin PanelMoveAbove (WindowList^.Panel, MainPanel); PanelMoveAbove (WindowList^.FramePanel, MainPanel); LastWindow := WindowList; WindowList := WindowList^.Prev; RedrawFrame (LastWindow); RedrawFrame (WindowList) end; procedure CloseWindow; var p: PWindowList; begin if WindowList^.WindowType <> 0 then begin p := WindowList; NextWindow; PanelDelete (p^.FramePanel); PanelDelete (p^.Panel); p^.Next^.Prev := p^.Prev; p^.Prev^.Next := p^.Next; Dispose (p) end end; procedure MoveWindow; var Done, Changed: Boolean; SSize: TPoint; begin with WindowList^ do begin Done := False; Changed := True; State := ws_Moving; repeat if Changed then DrawWindow (WindowList); Changed := True; case LoCaseKey (GetKey (-1)) of Ord ('s'), kbLeft : if x1 > 1 then Dec (x1); Ord ('d'), kbRight : if x1 + xs - 1 < ScreenSize.x then Inc (x1); Ord ('e'), kbUp : if y1 > 1 then Dec (y1); Ord ('x'), kbDown : if y1 + ys - 1 < ScreenSize.y then Inc (y1); Ord ('a'), kbHome : x1 := 1; Ord ('f'), kbEnd : x1 := ScreenSize.x - xs + 1; Ord ('r'), kbPgUp : y1 := 1; Ord ('c'), kbPgDn : y1 := ScreenSize.y - ys + 1; Ord ('y'), kbCtrlPgUp: begin x1 := 1; y1 := 1 end; Ord ('b'), kbCtrlPgDn: begin SSize := ScreenSize; x1 := SSize.x - xs + 1; y1 := SSize.y - ys + 1 end; kbCR, kbEsc, kbAltEsc : Done := True; else Changed := False end until Done; State := ws_None; DrawWindow (WindowList) end end; procedure ResizeWindow; var Done, Changed: Boolean; SSize: TPoint; begin with WindowList^, WindowTypes[WindowType] do begin Done := False; Changed := True; State := ws_Resizing; repeat if Changed then DrawWindow (WindowList); Changed := True; case LoCaseKey (GetKey (-1)) of Ord ('s'), kbLeft : if xs > MinSizeX + 2 then Dec (xs); Ord ('d'), kbRight : if x1 + xs - 1 < ScreenSize.x then Inc (xs); Ord ('e'), kbUp : if ys > MinSizeY + 2 then Dec (ys); Ord ('x'), kbDown : if y1 + ys - 1 < ScreenSize.y then Inc (ys); Ord ('a'), kbHome : xs := MinSizeX + 2; Ord ('f'), kbEnd : xs := ScreenSize.x - x1 + 1; Ord ('r'), kbPgUp : ys := MinSizeY + 2; Ord ('c'), kbPgDn : ys := ScreenSize.y - y1 + 1; Ord ('y'), kbCtrlPgUp: begin xs := MinSizeX + 2; ys := MinSizeY + 2 end; Ord ('b'), kbCtrlPgDn: begin SSize := ScreenSize; xs := SSize.x - x1 + 1; ys := SSize.y - y1 + 1 end; kbCR, kbEsc, kbAltEsc : Done := True; else Changed := False end until Done; State := ws_None; DrawWindow (WindowList) end end; procedure ActivateCursor; begin with WindowList^, WindowTypes[WindowType] do begin PanelActivate (Panel); if WantCursor then SetCursorShape (CursorShape) else HideCursor end; SetScroll (ScrollState) end; var Key: TKey; ScreenShot, Done: Boolean; begin ScreenShot := ParamStr (1) = '--screenshot'; if ParamCount <> Ord (ScreenShot) then begin RestoreTerminal (True); WriteLn (StdErr, ParamStr (0), ': invalid argument `', ParamStr (Ord (ScreenShot) + 1), ''''); Halt (1) end; CRTSavePreviousScreen (True); SetCRTUpdate (UpdateInput); MainPanel := GetActivePanel; CheckScreenSize; OrigScreenSize := ScreenSize; if ScreenShot then begin CursorShape := CursorBlock; NewWindow (6, 1, 1); NewWindow (2, 1, MaxInt); NewWindow (8, MaxInt, 1); NewWindow (5, 1, 27); KeyDemoKey (Ord ('f')); KeyDemoKey (246); KeyDemoKey (kbDown); NewWindow (3, MaxInt, 13); NewWindow (4, MaxInt, 31); NewWindow (7, MaxInt, MaxInt); NewWindow (9, MaxInt, 33); NewWindow (0, 1, 2); NewWindow (1, 1, 14); ActivateCursor; OpenWindow end else NewWindow (0, 3, 2); Done := False; repeat ActivateCursor; Key := GetKey (-1); case LoCaseKey (Key) of Ord ('3'), kbF3 : OpenWindow; Ord ('4'), kbF4 : CloseWindow; Ord ('5'), kbF5 : PreviousWindow; Ord ('6'), kbF6 : NextWindow; Ord ('7'), kbF7 : MoveWindow; Ord ('8'), kbF8 : ResizeWindow; Ord ('q'), kbEsc, kbAltEsc: Done := True; else if WindowList <> nil then with WindowList^, WindowTypes[WindowType] do if @KeyProc <> nil then begin TextColor (Color); TextBackground (Background); KeyProc (Key) end end until Done end.