|
@@ -1,5 +1,5 @@
|
|
MODULE TermBox;
|
|
MODULE TermBox;
|
|
-IMPORT G := Graph2, Strings, Int, Out;
|
|
|
|
|
|
+IMPORT G := Graph2, Strings, Int, Out, Platform;
|
|
|
|
|
|
CONST
|
|
CONST
|
|
partW = 512;
|
|
partW = 512;
|
|
@@ -7,6 +7,7 @@ CONST
|
|
emptyCh = ' ';
|
|
emptyCh = ' ';
|
|
nofcolors = 16;
|
|
nofcolors = 16;
|
|
cursorTickSpeed = 4.0;
|
|
cursorTickSpeed = 4.0;
|
|
|
|
+ flipSpeed = 1 / 60;
|
|
stdW = 80;
|
|
stdW = 80;
|
|
stdH = 25;
|
|
stdH = 25;
|
|
|
|
|
|
@@ -250,15 +251,16 @@ TYPE
|
|
mod*: SET (* Key modifiers *)
|
|
mod*: SET (* Key modifiers *)
|
|
END;
|
|
END;
|
|
|
|
|
|
- Cell* = RECORD
|
|
|
|
- ch*: CHAR;
|
|
|
|
- fg*, bg*: INTEGER
|
|
|
|
|
|
+ Cell = RECORD
|
|
|
|
+ ch, oldCh: CHAR;
|
|
|
|
+ fg, oldFg: INTEGER;
|
|
|
|
+ bg, oldBg: INTEGER;
|
|
|
|
+ updated: INTEGER (* > 0 means need to redraw, 2 means redraw in any case *)
|
|
END;
|
|
END;
|
|
|
|
|
|
Part* = POINTER TO PartDesc; (* Part of screen buffer *)
|
|
Part* = POINTER TO PartDesc; (* Part of screen buffer *)
|
|
PartDesc* = RECORD
|
|
PartDesc* = RECORD
|
|
cells: ARRAY partH, partW OF Cell;
|
|
cells: ARRAY partH, partW OF Cell;
|
|
- updated: ARRAY partH, partW OF BOOLEAN; (* TRUE means need to redraw *)
|
|
|
|
w, h: INTEGER; (* Actually used sizes of array *)
|
|
w, h: INTEGER; (* Actually used sizes of array *)
|
|
redraw: BOOLEAN; (* TRUE if any cell needs to be redrawn *)
|
|
redraw: BOOLEAN; (* TRUE if any cell needs to be redrawn *)
|
|
down, right: Part
|
|
down, right: Part
|
|
@@ -271,6 +273,8 @@ TYPE
|
|
END;
|
|
END;
|
|
|
|
|
|
VAR
|
|
VAR
|
|
|
|
+ t0, t1: REAL;
|
|
|
|
+
|
|
wantTitle: ARRAY 256 OF CHAR; (* Assigned in procedure SetTitle *)
|
|
wantTitle: ARRAY 256 OF CHAR; (* Assigned in procedure SetTitle *)
|
|
wantZoom: REAL;
|
|
wantZoom: REAL;
|
|
wantW, wantH: INTEGER;
|
|
wantW, wantH: INTEGER;
|
|
@@ -285,6 +289,7 @@ VAR
|
|
curX, curY: INTEGER; (* Text cursor position *)
|
|
curX, curY: INTEGER; (* Text cursor position *)
|
|
cursorShown: BOOLEAN; (* TRUE if text cursor is show while it is blinking *)
|
|
cursorShown: BOOLEAN; (* TRUE if text cursor is show while it is blinking *)
|
|
cursorTimer: G.Timer; (* Text cursor tick timer *)
|
|
cursorTimer: G.Timer; (* Text cursor tick timer *)
|
|
|
|
+ flipTimer: G.Timer; (* Frame change timer *)
|
|
userTimer: G.Timer; (* User timer set by StartTimer *)
|
|
userTimer: G.Timer; (* User timer set by StartTimer *)
|
|
|
|
|
|
needFlip: INTEGER;
|
|
needFlip: INTEGER;
|
|
@@ -294,48 +299,45 @@ VAR
|
|
|
|
|
|
Done*: BOOLEAN;
|
|
Done*: BOOLEAN;
|
|
|
|
|
|
-PROCEDURE SetPartCell(p: Part; x, y: INTEGER; ch: CHAR; fg, bg: INTEGER);
|
|
|
|
|
|
+PROCEDURE SetPartCellUpdated(p: Part; VAR cell: Cell);
|
|
BEGIN
|
|
BEGIN
|
|
- fg := fg MOD nofcolors; bg := bg MOD nofcolors;
|
|
|
|
- IF (p.cells[y, x].ch # ch) OR
|
|
|
|
- (p.cells[y, x].fg # fg) OR
|
|
|
|
- (p.cells[y, x].bg # bg)
|
|
|
|
- THEN
|
|
|
|
- p.cells[y, x].ch := ch;
|
|
|
|
- p.cells[y, x].fg := fg;
|
|
|
|
- p.cells[y, x].bg := bg;
|
|
|
|
- p.updated[y, x] := TRUE;
|
|
|
|
- p.redraw := TRUE
|
|
|
|
|
|
+ IF (cell.ch # cell.oldCh) OR
|
|
|
|
+ (cell.fg # cell.oldFg) OR
|
|
|
|
+ (cell.bg # cell.oldBg)
|
|
|
|
+ THEN cell.updated := 1; p.redraw := TRUE
|
|
|
|
+ ELSIF cell.updated # 2 THEN cell.updated := 0
|
|
END
|
|
END
|
|
|
|
+END SetPartCellUpdated;
|
|
|
|
+
|
|
|
|
+PROCEDURE ClearUpdated(VAR cell: Cell);
|
|
|
|
+BEGIN cell.updated := 0; cell.oldCh := cell.ch;
|
|
|
|
+ cell.oldFg := cell.fg; cell.oldBg := cell.bg
|
|
|
|
+END ClearUpdated;
|
|
|
|
+
|
|
|
|
+PROCEDURE SetPartCell(p: Part; x, y: INTEGER; ch: CHAR; fg, bg: INTEGER);
|
|
|
|
+BEGIN
|
|
|
|
+ p.cells[y, x].ch := ch;
|
|
|
|
+ p.cells[y, x].fg := fg MOD nofcolors;
|
|
|
|
+ p.cells[y, x].bg := bg MOD nofcolors;
|
|
|
|
+ SetPartCellUpdated(p, p.cells[y, x])
|
|
END SetPartCell;
|
|
END SetPartCell;
|
|
|
|
|
|
PROCEDURE SetPartChar(p: Part; x, y: INTEGER; ch: CHAR);
|
|
PROCEDURE SetPartChar(p: Part; x, y: INTEGER; ch: CHAR);
|
|
BEGIN
|
|
BEGIN
|
|
- IF p.cells[y, x].ch # ch THEN
|
|
|
|
- p.cells[y, x].ch := ch;
|
|
|
|
- p.updated[y, x] := TRUE;
|
|
|
|
- p.redraw := TRUE
|
|
|
|
- END
|
|
|
|
|
|
+ p.cells[y, x].ch := ch;
|
|
|
|
+ SetPartCellUpdated(p, p.cells[y, x])
|
|
END SetPartChar;
|
|
END SetPartChar;
|
|
|
|
|
|
PROCEDURE SetPartFg(p: Part; x, y, fg: INTEGER);
|
|
PROCEDURE SetPartFg(p: Part; x, y, fg: INTEGER);
|
|
BEGIN
|
|
BEGIN
|
|
- fg := fg MOD nofcolors;
|
|
|
|
- IF p.cells[y, x].fg # fg THEN
|
|
|
|
- p.cells[y, x].fg := fg;
|
|
|
|
- p.updated[y, x] := TRUE;
|
|
|
|
- p.redraw := TRUE
|
|
|
|
- END
|
|
|
|
|
|
+ p.cells[y, x].fg := fg MOD nofcolors;
|
|
|
|
+ SetPartCellUpdated(p, p.cells[y, x])
|
|
END SetPartFg;
|
|
END SetPartFg;
|
|
|
|
|
|
PROCEDURE SetPartBg(p: Part; x, y, bg: INTEGER);
|
|
PROCEDURE SetPartBg(p: Part; x, y, bg: INTEGER);
|
|
BEGIN
|
|
BEGIN
|
|
- bg := bg MOD nofcolors;
|
|
|
|
- IF p.cells[y, x].bg # bg THEN
|
|
|
|
- p.cells[y, x].bg := bg;
|
|
|
|
- p.updated[y, x] := TRUE;
|
|
|
|
- p.redraw := TRUE
|
|
|
|
- END
|
|
|
|
|
|
+ p.cells[y, x].bg := bg MOD nofcolors;
|
|
|
|
+ SetPartCellUpdated(p, p.cells[y, x])
|
|
END SetPartBg;
|
|
END SetPartBg;
|
|
|
|
|
|
PROCEDURE GetPart(S: Buffer; VAR x, y: INTEGER): Part;
|
|
PROCEDURE GetPart(S: Buffer; VAR x, y: INTEGER): Part;
|
|
@@ -398,16 +400,13 @@ END GetMousePos;
|
|
PROCEDURE UpdateCell(x, y: INTEGER);
|
|
PROCEDURE UpdateCell(x, y: INTEGER);
|
|
VAR p: Part;
|
|
VAR p: Part;
|
|
BEGIN p := GetPart(buffer, x, y);
|
|
BEGIN p := GetPart(buffer, x, y);
|
|
- IF p # NIL THEN p.updated[y, x] := TRUE; p.redraw := TRUE END
|
|
|
|
|
|
+ IF p # NIL THEN p.cells[y, x].updated := 2; p.redraw := TRUE END
|
|
END UpdateCell;
|
|
END UpdateCell;
|
|
|
|
|
|
PROCEDURE Flip(forse: BOOLEAN);
|
|
PROCEDURE Flip(forse: BOOLEAN);
|
|
BEGIN
|
|
BEGIN
|
|
- IF ~G.HasEvents() OR forse OR (needFlip > 4) THEN
|
|
|
|
- G.Flip; needFlip := 0
|
|
|
|
- ;Out.String('ОБНОВЛЕНИЕ');Out.Ln
|
|
|
|
|
|
+ IF ~G.HasEvents() OR forse THEN G.Flip; needFlip := 0
|
|
ELSE INC(needFlip)
|
|
ELSE INC(needFlip)
|
|
- ;Out.String(' отложено');Out.Ln
|
|
|
|
END
|
|
END
|
|
END Flip;
|
|
END Flip;
|
|
|
|
|
|
@@ -421,9 +420,9 @@ BEGIN
|
|
IF p.redraw OR buffer.redrawAll THEN
|
|
IF p.redraw OR buffer.redrawAll THEN
|
|
FOR y := 0 TO p.h - 1 DO
|
|
FOR y := 0 TO p.h - 1 DO
|
|
FOR x := 0 TO p.w - 1 DO
|
|
FOR x := 0 TO p.w - 1 DO
|
|
- IF p.updated[y, x] OR buffer.redrawAll THEN
|
|
|
|
|
|
+ IF buffer.redrawAll OR (p.cells[y, x].updated # 0) THEN
|
|
DrawCell(X + x, Y + y, p.cells[y, x]);
|
|
DrawCell(X + x, Y + y, p.cells[y, x]);
|
|
- p.updated[y, x] := FALSE
|
|
|
|
|
|
+ ClearUpdated(p.cells[y, x])
|
|
END
|
|
END
|
|
END
|
|
END
|
|
END;
|
|
END;
|
|
@@ -465,6 +464,13 @@ BEGIN
|
|
G.ToggleFullscreen(screen)
|
|
G.ToggleFullscreen(screen)
|
|
END ToggleFS;
|
|
END ToggleFS;
|
|
|
|
|
|
|
|
+PROCEDURE ResetCell(VAR cell: Cell);
|
|
|
|
+BEGIN
|
|
|
|
+ cell.ch := emptyCh; cell.fg := 7; cell.bg := 0;
|
|
|
|
+ cell.oldCh := cell.ch; cell.oldFg := cell.fg; cell.oldBg := cell.bg;
|
|
|
|
+ cell.updated := 2
|
|
|
|
+END ResetCell;
|
|
|
|
+
|
|
PROCEDURE NewPart(w, h: INTEGER): Part;
|
|
PROCEDURE NewPart(w, h: INTEGER): Part;
|
|
VAR p: Part;
|
|
VAR p: Part;
|
|
x, y: INTEGER;
|
|
x, y: INTEGER;
|
|
@@ -472,10 +478,7 @@ BEGIN NEW(p); p.redraw := TRUE; p.down := NIL; p.right := NIL;
|
|
p.w := w; p.h := h;
|
|
p.w := w; p.h := h;
|
|
FOR y := 0 TO h - 1 DO
|
|
FOR y := 0 TO h - 1 DO
|
|
FOR x := 0 TO w - 1 DO
|
|
FOR x := 0 TO w - 1 DO
|
|
- p.cells[y, x].ch := emptyCh;
|
|
|
|
- p.cells[y, x].fg := 7;
|
|
|
|
- p.cells[y, x].bg := 0;
|
|
|
|
- p.updated[y, x] := TRUE
|
|
|
|
|
|
+ ResetCell(p.cells[y, x])
|
|
END
|
|
END
|
|
END
|
|
END
|
|
RETURN p END NewPart;
|
|
RETURN p END NewPart;
|
|
@@ -489,7 +492,7 @@ BEGIN p.redraw := TRUE;
|
|
p.cells[y, x].ch := emptyCh;
|
|
p.cells[y, x].ch := emptyCh;
|
|
p.cells[y, x].fg := 7;
|
|
p.cells[y, x].fg := 7;
|
|
p.cells[y, x].bg := 0;
|
|
p.cells[y, x].bg := 0;
|
|
- p.updated[y, x] := TRUE
|
|
|
|
|
|
+ p.cells[y, x].updated := 2
|
|
END
|
|
END
|
|
END;
|
|
END;
|
|
p.w := w; p.h := h
|
|
p.w := w; p.h := h
|
|
@@ -530,15 +533,15 @@ BEGIN
|
|
MoveMouse(event.x, event.y)
|
|
MoveMouse(event.x, event.y)
|
|
END
|
|
END
|
|
ELSIF e.type = G.timer THEN
|
|
ELSIF e.type = G.timer THEN
|
|
- IF e.timer = cursorTimer THEN
|
|
|
|
|
|
+ IF e.timer = flipTimer THEN
|
|
|
|
+ event.type := noEvent;
|
|
|
|
+ IF needFlip # 0 THEN G.Flip; needFlip := 0 END
|
|
|
|
+ ELSIF e.timer = cursorTimer THEN
|
|
event.type := noEvent;
|
|
event.type := noEvent;
|
|
IF curX > 0 THEN
|
|
IF curX > 0 THEN
|
|
cursorShown := ~cursorShown;
|
|
cursorShown := ~cursorShown;
|
|
UpdateCell(curX, curY);
|
|
UpdateCell(curX, curY);
|
|
Flush
|
|
Flush
|
|
- END;
|
|
|
|
- IF needFlip # 0 THEN G.Flip; needFlip := 0
|
|
|
|
- ;Out.String(' По таймеру');Out.Ln
|
|
|
|
END
|
|
END
|
|
ELSE
|
|
ELSE
|
|
event.type := timer
|
|
event.type := timer
|
|
@@ -573,10 +576,7 @@ END ParseEvent;
|
|
PROCEDURE WaitAndParseEvent(VAR event: Event);
|
|
PROCEDURE WaitAndParseEvent(VAR event: Event);
|
|
VAR E: G.Event;
|
|
VAR E: G.Event;
|
|
BEGIN
|
|
BEGIN
|
|
- IF (needFlip # 0) & ~G.PeekEvent(E) THEN
|
|
|
|
- G.Flip; needFlip := 0
|
|
|
|
- ;Out.String(' По ожиданию');Out.Ln
|
|
|
|
- END;
|
|
|
|
|
|
+ IF (needFlip # 0) & ~G.PeekEvent(E) THEN G.Flip; needFlip := 0 END;
|
|
G.WaitEvent(E);
|
|
G.WaitEvent(E);
|
|
ParseEvent(E, event)
|
|
ParseEvent(E, event)
|
|
END WaitAndParseEvent;
|
|
END WaitAndParseEvent;
|
|
@@ -675,11 +675,13 @@ PROCEDURE Size*(VAR width, height: INTEGER);
|
|
BEGIN width := buffer.w; height := buffer.h
|
|
BEGIN width := buffer.w; height := buffer.h
|
|
END Size;
|
|
END Size;
|
|
|
|
|
|
-PROCEDURE GetCell*(x, y: INTEGER; VAR cell: Cell);
|
|
|
|
|
|
+PROCEDURE GetCell*(x, y: INTEGER; VAR ch: CHAR; VAR fg, bg: INTEGER);
|
|
VAR p: Part;
|
|
VAR p: Part;
|
|
|
|
+ cell: Cell;
|
|
BEGIN p := GetPart(buffer, x, y);
|
|
BEGIN p := GetPart(buffer, x, y);
|
|
- IF p # NIL THEN cell := p.cells[y, x]
|
|
|
|
- ELSE cell.ch := emptyCh; cell.fg := 7; cell.bg := 0
|
|
|
|
|
|
+ IF p # NIL THEN cell := p.cells[y, x];
|
|
|
|
+ ch := cell.ch; fg := cell.fg; bg := cell.bg
|
|
|
|
+ ELSE ch := emptyCh; fg := 0; bg := 0
|
|
END
|
|
END
|
|
END GetCell;
|
|
END GetCell;
|
|
|
|
|
|
@@ -803,12 +805,15 @@ BEGIN
|
|
G.StartTimer(userTimer)
|
|
G.StartTimer(userTimer)
|
|
END StartTimer;
|
|
END StartTimer;
|
|
|
|
|
|
-PROCEDURE InitTimer;
|
|
|
|
|
|
+PROCEDURE InitTimers;
|
|
BEGIN
|
|
BEGIN
|
|
cursorShown := TRUE;
|
|
cursorShown := TRUE;
|
|
cursorTimer := G.NewTimer(cursorTickSpeed);
|
|
cursorTimer := G.NewTimer(cursorTickSpeed);
|
|
- G.StartTimer(cursorTimer)
|
|
|
|
-END InitTimer;
|
|
|
|
|
|
+ G.StartTimer(cursorTimer);
|
|
|
|
+
|
|
|
|
+ flipTimer := G.NewTimer(flipSpeed);
|
|
|
|
+ G.StartTimer(flipTimer)
|
|
|
|
+END InitTimers;
|
|
|
|
|
|
PROCEDURE Init*;
|
|
PROCEDURE Init*;
|
|
VAR opt: SET;
|
|
VAR opt: SET;
|
|
@@ -820,7 +825,7 @@ BEGIN Done := FALSE;
|
|
InitScreen;
|
|
InitScreen;
|
|
InitColors;
|
|
InitColors;
|
|
InitBuffer;
|
|
InitBuffer;
|
|
- InitTimer;
|
|
|
|
|
|
+ InitTimers;
|
|
mouseDown := FALSE;
|
|
mouseDown := FALSE;
|
|
needFlip := 0;
|
|
needFlip := 0;
|
|
processingEvent := FALSE;
|
|
processingEvent := FALSE;
|
|
@@ -853,5 +858,5 @@ END SetFontFile;
|
|
BEGIN wantW := stdW; wantH := stdH; wantScaleX := 0.0; wantScaleY := 0.0;
|
|
BEGIN wantW := stdW; wantH := stdH; wantScaleX := 0.0; wantScaleY := 0.0;
|
|
settings := {fullscreen}; Done := FALSE;
|
|
settings := {fullscreen}; Done := FALSE;
|
|
iconFile := 'Data/Images/Icon.png';
|
|
iconFile := 'Data/Images/Icon.png';
|
|
- fontFile := 'Data/Fonts/Main';
|
|
|
|
|
|
+ fontFile := 'Data/Fonts/Main'
|
|
END TermBox.
|
|
END TermBox.
|