123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524 |
- MODULE Gui; (* My GUI Module *)
- IMPORT Out, G := Graph;
- CONST
- charW = 8; charH = 16;
-
- (* redrawState *)
- redrawNone* = 0;
- redrawAll* = 1;
- redrawSome* = 2;
- TYPE
- Method* = POINTER TO MethodDesc;
- Component* = POINTER TO ComponentDesc;
- Container* = POINTER TO ContainerDesc;
- Form* = POINTER TO FormDesc;
- Button* = POINTER TO ButtonDesc;
- Edit* = POINTER TO EditDesc;
- Circle* = POINTER TO CircleDesc;
- (* Handler Procedures *)
- OnDrawHandler = PROCEDURE (c: Component; bmp: G.Bitmap; x0, y0: INTEGER);
- OnMouseDownHandler = PROCEDURE (c: Component; x, y, btn: INTEGER);
- OnKeyDownHandler = PROCEDURE (c: Component; key: INTEGER);
-
- MethodDesc* = RECORD
- draw*: OnDrawHandler;
- mouseDown*: OnMouseDownHandler;
- keyDown*: OnKeyDownHandler;
- add*: PROCEDURE (c, toAdd: Component);
- updated*: PROCEDURE (c: Component; moved: BOOLEAN);
- redraw*: PROCEDURE (c: Component; bmp: G.Bitmap; x0, y0: INTEGER);
- (* Setters *)
- setX*: PROCEDURE (c: Component; x: INTEGER);
- setY*: PROCEDURE (c: Component; y: INTEGER);
- setW*: PROCEDURE (c: Component; w: INTEGER);
- setH*: PROCEDURE (c: Component; h: INTEGER);
- setBounds*: PROCEDURE (c: Component; x, y, w, h: INTEGER);
- setVisible*: PROCEDURE (c: Component; visible: BOOLEAN);
- (* Event Handler Setters *)
- setOnDraw*: PROCEDURE (c: Component; hn: OnDrawHandler);
- setOnMouseDown*: PROCEDURE (c: Component; hn: OnMouseDownHandler);
- setOnKeyDown*: PROCEDURE (c: Component; hn: OnKeyDownHandler);
- END;
- ComponentDesc* = RECORD
- x-, y-, w-, h-: INTEGER;
- visible-: BOOLEAN;
- redrawState-: INTEGER; (* see constants with prefix 'redraw' *)
- do*: Method;
- onDraw-: OnDrawHandler;
- onMouseDown-: OnMouseDownHandler;
- onKeyDown-: OnKeyDownHandler;
- parent*: Component;
- next*: Component
- END;
- ContainerDesc* = RECORD(ComponentDesc)
- first*: Component
- END;
- FormDesc* = RECORD(ContainerDesc)
- bgColor*: INTEGER
- END;
- ButtonDesc* = RECORD(ComponentDesc)
- caption-: ARRAY 100 OF CHAR
- END;
- EditDesc* = RECORD(ComponentDesc)
- text-: ARRAY 4096 OF CHAR;
- selStart-: INTEGER;
- selLen-: INTEGER
- END;
- CircleDesc* = RECORD(ComponentDesc)
- color*: INTEGER
- END;
-
- VAR
- screen: G.Bitmap;
- font: G.Font;
- needFlip: BOOLEAN;
- (* Methods *)
- method, formMethod, buttonMethod, circleMethod, editMethod: Method;
- form: Form;
- btnHello: Button;
- circle: Circle;
- edit: Edit;
- (* Component *)
- PROCEDURE InitComponent*(c: Component);
- BEGIN
- c.x := 0; c.y := 0; c.w := 0; c.h := 0;
- c.visible := TRUE;
- c.redrawState := redrawNone;
- c.do := method; c.next := NIL; c.parent := NIL;
- c.onDraw := NIL; c.onMouseDown := NIL
- END InitComponent;
- PROCEDURE UpdatedComponent*(c: Component; moved: BOOLEAN);
- BEGIN
- IF c.redrawState # redrawAll THEN
- c.redrawState := redrawAll;
- c := c.parent;
- IF moved & (c # NIL) & (c.redrawState # redrawAll) THEN
- c.redrawState := redrawAll;
- c := c.parent
- END;
- WHILE (c # NIL) & (c.redrawState = redrawNone) DO
- c.redrawState := redrawSome;
- c := c.parent
- END
- END
- END UpdatedComponent;
- PROCEDURE RedrawComponent*(c: Component; bmp: G.Bitmap; x0, y0: INTEGER);
- BEGIN
- IF (c.redrawState = redrawAll) & c.visible THEN
- c.do.draw(c, bmp, x0, y0);
- needFlip := TRUE
- END;
- c.redrawState := redrawNone
- END RedrawComponent;
- PROCEDURE ComponentSetX(c: Component; x: INTEGER);
- BEGIN c.x := x; c.do.updated(c, TRUE)
- END ComponentSetX;
- PROCEDURE ComponentSetY(c: Component; y: INTEGER);
- BEGIN c.y := y; c.do.updated(c, TRUE)
- END ComponentSetY;
- PROCEDURE ComponentSetW(c: Component; w: INTEGER);
- BEGIN c.w := w; c.do.updated(c, TRUE)
- END ComponentSetW;
- PROCEDURE ComponentSetH(c: Component; h: INTEGER);
- BEGIN c.h := h; c.do.updated(c, TRUE)
- END ComponentSetH;
- PROCEDURE ComponentSetBounds(c: Component; x, y, w, h: INTEGER);
- BEGIN c.x := x; c.y := y; c.w := w; c.h := h; c.do.updated(c, TRUE)
- END ComponentSetBounds;
- PROCEDURE ComponentSetVisible(c: Component; visible: BOOLEAN);
- BEGIN
- IF c.visible # visible THEN
- c.visible := visible;
- c.do.updated(c, ~visible)
- END
- END ComponentSetVisible;
- PROCEDURE ComponentSetOnDraw(c: Component; hn: OnDrawHandler);
- BEGIN c.onDraw := hn
- END ComponentSetOnDraw;
- PROCEDURE ComponentSetOnMouseDown(c: Component; hn: OnMouseDownHandler);
- BEGIN c.onMouseDown := hn
- END ComponentSetOnMouseDown;
- PROCEDURE ComponentSetOnKeyDown(c: Component; hn: OnKeyDownHandler);
- BEGIN c.onKeyDown := hn
- END ComponentSetOnKeyDown;
- (* Container *)
- PROCEDURE InitContainer*(c: Container);
- BEGIN
- InitComponent(c);
- c.first := NIL
- END InitContainer;
- PROCEDURE RedrawContainer*(c: Component; bmp: G.Bitmap; x0, y0: INTEGER);
- VAR x: Component;
- BEGIN
- IF c.visible THEN
- IF c.redrawState = redrawAll THEN
- c.do.draw(c, bmp, x0, y0);
- needFlip := TRUE
- ELSIF c.redrawState = redrawSome THEN
- INC(x0, c.x); INC(y0, c.y);
- x := c(Container).first;
- WHILE x # NIL DO
- IF x.redrawState # redrawNone THEN
- x.do.redraw(x, bmp, x0, y0)
- END;
- x := x.next
- END;
- needFlip := TRUE
- END
- END;
- c.redrawState := redrawNone
- END RedrawContainer;
- PROCEDURE DrawContainerChildren(c: Component; bmp: G.Bitmap; x0, y0: INTEGER);
- VAR d: Component;
- BEGIN
- INC(x0, c.x); INC(y0, c.y);
- d := c(Container).first;
- WHILE d # NIL DO
- IF d.visible THEN d.do.draw(d, bmp, x0, y0) END;
- d.redrawState := redrawNone;
- d := d.next
- END
- END DrawContainerChildren;
- PROCEDURE MouseDownContainer(c: Component; x, y, btn: INTEGER);
- VAR d: Component;
- BEGIN
- d := c(Container).first;
- WHILE (d # NIL) &
- ~(d.visible &
- (x >= d.x) & (x < d.x + d.w) &
- (y >= d.y) & (y < d.y + d.h))
- DO d := d.next
- END;
- IF d # NIL THEN d.do.mouseDown(d, x - d.x, y - d.y, btn) END
- END MouseDownContainer;
- PROCEDURE AddToContainer(c, toAdd: Component);
- BEGIN
- toAdd.next := c(Container).first;
- c(Container).first := toAdd;
- toAdd.parent := c;
- toAdd.do.updated(c, TRUE)
- END AddToContainer;
- (* Form *)
- PROCEDURE InitForm*(f: Form);
- BEGIN
- InitContainer(f);
- f.do := formMethod;
- f.bgColor := G.MakeCol(180, 180, 180)
- END InitForm;
- PROCEDURE NewForm*(): Form;
- VAR f: Form;
- BEGIN
- NEW(f); InitForm(f); RETURN f
- END NewForm;
- PROCEDURE DrawForm(c: Component; bmp: G.Bitmap; x0, y0: INTEGER);
- VAR x, y: INTEGER;
- BEGIN
- x := x0 + c.x; y := y0 + c.y;
- G.RectFill(bmp, x, y, x + c.w - 1, y + c.h - 1, c(Form).bgColor);
- DrawContainerChildren(c, bmp, x0, y0)
- END DrawForm;
- (* Button *)
- PROCEDURE InitButton*(b: Button; caption: ARRAY OF CHAR);
- BEGIN
- InitComponent(b);
- b.do := buttonMethod;
- b.caption := caption
- END InitButton;
- PROCEDURE NewButton*(caption: ARRAY OF CHAR): Button;
- VAR b: Button;
- BEGIN
- NEW(b); InitButton(b, caption); RETURN b
- END NewButton;
- PROCEDURE DrawButton(c: Component; bmp: G.Bitmap; x0, y0: INTEGER);
- VAR i, len, c1, c2, c3: INTEGER;
- BEGIN
- INC(x0, c.x); INC(y0, c.y);
- c1 := G.MakeCol(255, 255, 255);
- c2 := G.MakeCol(160, 160, 160);
- c3 := G.MakeCol(100, 100, 100);
- len := 0; WHILE c(Button).caption[len] # 0X DO INC(len) END;
- G.RectFill(bmp, x0 + 1, y0 + 1, x0 + c.w - 3, y0 + c.h - 3,
- G.MakeCol(200, 200, 200));
- G.HLine(bmp, x0, y0, x0 + c.w - 2, c1);
- G.VLine(bmp, x0, y0, y0 + c.h - 2, c1);
- G.HLine(bmp, x0 + 1, y0 + c.h - 2, x0 + c.w - 3, c2);
- G.VLine(bmp, x0 + c.w - 2, y0 + 1, y0 + c.h - 2, c2);
- G.HLine(bmp, x0, y0 + c.h - 1, x0 + c.w - 1, c3);
- G.VLine(bmp, x0 + c.w - 1, y0, y0 + c.h - 2, c3);
- FOR i := 0 TO len - 1 DO
- G.DrawCharacter(screen, font, x0 + (c.w - charW * len) DIV 2,
- y0 + (c.h - charH) DIV 2, c(Button).caption[i],
- G.MakeCol(0, 0, 0));
- INC(x0, charW)
- END
- END DrawButton;
- PROCEDURE MouseDownButton(c: Component; x, y, btn: INTEGER);
- BEGIN
- IF c.onMouseDown # NIL THEN c.onMouseDown(c, x, y, btn) END
- END MouseDownButton;
- (* Edit *)
- PROCEDURE InitEdit*(e: Edit);
- BEGIN
- InitComponent(e);
- e.do := editMethod;
- e.text[0] := 0X;
- e.selStart := 0;
- e.selLen := 0
- END InitEdit;
- PROCEDURE NewEdit*(): Edit;
- VAR e: Edit;
- BEGIN
- NEW(e); InitEdit(e); RETURN e
- END NewEdit;
- PROCEDURE DrawEdit(c: Component; bmp: G.Bitmap; x0, y0: INTEGER);
- VAR i, len, c1, c2, c3: INTEGER;
- BEGIN
- INC(x0, c.x); INC(y0, c.y);
- c1 := G.MakeCol(255, 255, 255);
- c2 := G.MakeCol(160, 160, 160);
- c3 := G.MakeCol(100, 100, 100);
- len := 0; WHILE c(Edit).text[len] # 0X DO INC(len) END;
- G.RectFill(bmp, x0 + 1, y0 + 1, x0 + c.w - 3, y0 + c.h - 3,
- G.MakeCol(200, 200, 200));
- G.HLine(bmp, x0, y0, x0 + c.w - 2, c1);
- G.VLine(bmp, x0, y0, y0 + c.h - 2, c1);
- G.HLine(bmp, x0 + 1, y0 + c.h - 2, x0 + c.w - 3, c2);
- G.VLine(bmp, x0 + c.w - 2, y0 + 1, y0 + c.h - 2, c2);
- G.HLine(bmp, x0, y0 + c.h - 1, x0 + c.w - 1, c3);
- G.VLine(bmp, x0 + c.w - 1, y0, y0 + c.h - 2, c3);
- FOR i := 0 TO len - 1 DO
- G.DrawCharacter(screen, font, x0 + (c.w - charW * len) DIV 2,
- y0 + (c.h - charH) DIV 2, c(Edit).text[i],
- G.MakeCol(0, 0, 0));
- INC(x0, charW)
- END
- END DrawEdit;
- PROCEDURE MouseDownEdit(c: Component; x, y, btn: INTEGER);
- BEGIN
- IF c.onMouseDown # NIL THEN c.onMouseDown(c, x, y, btn) END
- END MouseDownEdit;
- PROCEDURE KeyDownEdit(c: Component; key: INTEGER);
- BEGIN
- IF c.onKeyDown # NIL THEN c.onKeyDown(c, key) END
- END KeyDownEdit;
- (* Circle *)
- PROCEDURE InitCircle*(c: Circle);
- BEGIN
- InitComponent(c);
- c.do := circleMethod;
- c.color := G.MakeCol(0, 0, 0)
- END InitCircle;
- PROCEDURE NewCircle*(): Circle;
- VAR c: Circle;
- BEGIN
- NEW(c); InitCircle(c); RETURN c
- END NewCircle;
- PROCEDURE DrawCircle(c: Component; bmp: G.Bitmap; x0, y0: INTEGER);
- VAR r, x, y, err, color: INTEGER;
- BEGIN
- INC(x0, c.x); INC(y0, c.y);
- IF c.w <= c.h THEN r := (c.w - 1) DIV 2 ELSE r := (c.h - 1) DIV 2 END;
- IF r > 0 THEN
- INC(x0, c.w DIV 2); INC(y0, c.h DIV 2);
- x := 0; y := r; err := 3 - 2 * r; color := c(Circle).color;
- WHILE y >= x DO
- G.PutPixel(screen, x0 + x, y0 + y, color);
- G.PutPixel(screen, x0 + y, y0 + x, color);
- G.PutPixel(screen, x0 - y, y0 + x, color);
- G.PutPixel(screen, x0 - x, y0 + y, color);
- G.PutPixel(screen, x0 - x, y0 - y, color);
- G.PutPixel(screen, x0 - y, y0 - x, color);
- G.PutPixel(screen, x0 + y, y0 - x, color);
- G.PutPixel(screen, x0 + x, y0 - y, color);
- IF err < 0 THEN INC(err, 4 * x + 6); INC(x, 1)
- ELSE INC(err, 4 * (x - y)); INC(x); DEC(y)
- END
- END
- END
- END DrawCircle;
- PROCEDURE MouseDownCircle(c: Component; x, y, btn: INTEGER);
- BEGIN
- c(Circle).color := G.MakeCol(G.Random(256), G.Random(256), G.Random(256));
- DEC(c.x); DEC(c.w);
- c.do.updated(c, TRUE)
- END MouseDownCircle;
- (* Other *)
- PROCEDURE btnHelloMouseDown(c: Component; x, y, btn: INTEGER);
- VAR i: INTEGER;
- BEGIN
- c(Button).caption[1] := CHR(33 + (ORD(c(Button).caption[1]) + y * c.w + x) MOD 64);
- i := 0; WHILE c(Button).caption[i] # 0X DO INC(i) END;
- IF i < LEN(c(Button).caption) - 1 THEN
- c(Button).caption[i] := CHR(i+ORD('0')); c(Button).caption[i+1] := 0X
- END;
- IF c.next # NIL THEN c.next.do.setVisible(c.next, ~c.next.visible) END;
- c.do.setX(c, c.x + 1)
- END btnHelloMouseDown;
- PROCEDURE Act;
- BEGIN
- form.do.redraw(form, screen, 0, 0);
- IF needFlip THEN G.Flip; needFlip := FALSE ELSE G.RepeatFlip END
- END Act;
- PROCEDURE Run;
- VAR e: G.Event;
- quit: BOOLEAN;
- BEGIN
- quit := FALSE;
- REPEAT
- G.WaitEvents(50);
- WHILE G.PollEvent(e) DO
- CASE e.type OF
- G.quit: quit := TRUE
- | G.keyDown: IF e.key.code = G.kEsc THEN quit := TRUE END
- | G.mouseDown: form.do.mouseDown(form, e.x, e.y, e.button)
- | G.mouseMove: needFlip := TRUE
- ELSE
- END
- END;
- Act
- UNTIL quit
- END Run;
- PROCEDURE Init;
- VAR i: INTEGER;
- BEGIN
- form := NewForm();
- form.w := screen.w;
- form.h := screen.h;
- FOR i := 0 TO 4 DO
- btnHello := NewButton('Hello');
- btnHello.x := 10;
- btnHello.y := 1 + i * 21;
- btnHello.w := 70;
- btnHello.h := 20;
- btnHello.onMouseDown := btnHelloMouseDown;
- btnHello.visible := i MOD 2 = 0;
- form.do.add(form, btnHello)
- END;
- FOR i := 1 TO G.Random(10) + 10 DO
- circle := NewCircle();
- circle.w := 10 + G.Random(100);
- circle.h := circle.w;
- circle.x := 100 + G.Random(screen.w - circle.w - 101);
- circle.y := G.Random(screen.h - 1 - circle.h);
- form.do.add(form, circle)
- END;
-
- edit := NewEdit();
- edit.do.setBounds(edit, 10, screen.h - 30, 80, 20);
- edit.text := 'World';
- form.do.add(form, edit);
-
- G.ClearScreen;
- needFlip := TRUE
- END Init;
- BEGIN
- NEW(method);
- method.draw := NIL;
- method.mouseDown := NIL;
- method.keyDown := NIL;
- method.add := NIL;
- method.updated := UpdatedComponent;
- method.redraw := RedrawComponent;
- method.setX := ComponentSetX;
- method.setY := ComponentSetY;
- method.setW := ComponentSetW;
- method.setH := ComponentSetH;
- method.setBounds := ComponentSetBounds;
- method.setVisible := ComponentSetVisible;
- method.setOnDraw := ComponentSetOnDraw;
- method.setOnMouseDown := ComponentSetOnMouseDown;
- method.setOnKeyDown := ComponentSetOnKeyDown;
-
- NEW(formMethod);
- formMethod^ := method^;
- formMethod.draw := DrawForm;
- formMethod.mouseDown := MouseDownContainer;
- formMethod.add := AddToContainer;
- formMethod.redraw := RedrawContainer;
- NEW(buttonMethod);
- buttonMethod^ := method^;
- buttonMethod.draw := DrawButton;
- buttonMethod.mouseDown := MouseDownButton;
-
- NEW (editMethod);
- editMethod^ := method^;
- editMethod.draw := DrawEdit;
- editMethod.mouseDown := MouseDownEdit;
- editMethod.keyDown := KeyDownEdit;
- NEW(circleMethod);
- circleMethod^ := method^;
- circleMethod.draw := DrawCircle;
- circleMethod.mouseDown := MouseDownCircle;
- circleMethod.add := NIL;
- circleMethod.updated := UpdatedComponent;
- circleMethod.redraw := RedrawComponent;
- G.Settings(320, 200, {G.fullscreen, G.spread, G.sharpPixels, G.initMouse});
- (* G.Settings(640, 480, {G.fullscreen, G.spread, G.sharpPixels, G.initMouse});*)
- screen := G.Init();
- IF screen # NIL THEN
- font := G.LoadFont('data/images/font.bmp', charW, charH);
- IF font # NIL THEN
- Init;
- Run
- ELSE
- Out.String('Could not load font.'); Out.Ln
- END
- ELSE Out.String('Graphics init failed.'); Out.Ln
- END;
- G.Close()
- END Gui.
|