From d09b8c3ec24bef1affd89ee478b94cf0517fa69d Mon Sep 17 00:00:00 2001 From: Ketmar Dark Date: Mon, 28 Aug 2017 11:47:56 +0300 Subject: [PATCH] Holmes UI fixes --- src/game/g_holmes.inc | 73 ++++------- src/game/g_holmes.pas | 7 +- src/game/g_holmes_ui.inc | 268 ++++++++++++++++++++++++++------------- 3 files changed, 208 insertions(+), 140 deletions(-) diff --git a/src/game/g_holmes.inc b/src/game/g_holmes.inc index 27138aa..6ebe034 100644 --- a/src/game/g_holmes.inc +++ b/src/game/g_holmes.inc @@ -118,8 +118,8 @@ begin glBegin(GL_QUADS); glTexCoord2f(0.0, 0.0); glVertex2i(msX, msY); // top-left glTexCoord2f(1.0, 0.0); glVertex2i(msX+curTexWidth, msY); // top-right - glTexCoord2f(1.0, 1.0); glVertex2i(msX+curTexWidth, msY+curHeight); // bottom-right - glTexCoord2f(0.0, 1.0); glVertex2i(msX, msY+curHeight); // bottom-left + glTexCoord2f(1.0, 1.0); glVertex2i(msX+curTexWidth, msY+curTexHeight); // bottom-right + glTexCoord2f(0.0, 1.0); glVertex2i(msX, msY+curTexHeight); // bottom-left glEnd(); Inc(msX, 2); glDisable(GL_BLEND); @@ -492,27 +492,7 @@ end; // ////////////////////////////////////////////////////////////////////////// // procedure drawLine (x1, y1, x2, y2: Integer; r, g, b: Integer; a: Integer=255); - - procedure lcor (var x1, y1, x2, y2: Integer); - begin - if (y2 < y1) then - begin - x1 := x1 xor x2; - x2 := x1 xor x2; - x1 := x1 xor x2; - - y1 := y1 xor y2; - y2 := y1 xor y2; - y1 := y1 xor y2; - end; - - if (x1 < x2) then Inc(X2) else Inc(x1); - Inc(y2); - end; - begin - lcor(x1, y1, x2, y2); - if (a < 0) then a := 0 else if (a > 255) then a := 255; if (r < 0) then r := 0 else if (r > 255) then r := 255; if (g < 0) then g := 0 else if (g > 255) then g := 255; @@ -535,10 +515,17 @@ begin glPointSize(1); glBegin(GL_LINES); - glVertex2i(x1, y1); - glVertex2i(x2, y2); + glVertex2f(x1+0.37, y1+0.37); + glVertex2f(x2+0.37, y2+0.37); glEnd(); + if (x1 <> x2) or (y1 <> y2) then + begin + glBegin(GL_POINTS); + glVertex2f(x2+0.37, y2+0.37); + glEnd(); + end; + glColor4f(1, 1, 1, 1); glDisable(GL_BLEND); end; @@ -547,19 +534,10 @@ end; procedure drawRect (x, y, w, h: Integer; r, g, b: Integer; a: Integer=255); begin if (w < 0) or (h < 0) then exit; - //if (w = 1) and (h = 1) then begin drawLine(x, y, x, y, r, g, b, a); exit; end; if (a < 0) then a := 0 else if (a > 255) then a := 255; if (r < 0) then r := 0 else if (r > 255) then r := 255; if (g < 0) then g := 0 else if (g > 255) then g := 255; if (b < 0) then b := 0 else if (b > 255) then b := 255; - { - Inc(w); - Inc(h); - drawLine(x, y, x+w-1, y, r, g, b, a); - drawLine(x+w-1, y+1, x+w-1, y+h-1, r, g, b, a); - drawLine(x+w-2, y+h-1, x, y+h-1, r, g, b, a); - drawLine(x, y+h-2, x, y+1, r, g, b, a); - } if (a < 255) then begin glEnable(GL_BLEND); @@ -574,20 +552,21 @@ begin glDisable(GL_LINE_SMOOTH); glDisable(GL_POLYGON_SMOOTH); glColor4f(r/255.0, g/255.0, b/255.0, a/255.0); - { - glBegin(GL_LINE_LOOP); - glVertex2f(x+0.37, y+0.37); - glVertex2f(x+w-1+0.37, y+0.37); - glVertex2f(x+w-1+0.37, y+h-1); - glVertex2f(x+0.37, y+h-1+0.37); - glEnd(); - } - glBegin(GL_LINES); - glVertex2i(x, y); glVertex2i(x+w, y); // top - glVertex2i(x, y+h-1); glVertex2i(x+w, y+h-1); // bottom - glVertex2f(x+0.37, y+1); glVertex2f(x+0.37, y+h-1); // left - glVertex2f(x+w-1+0.37, y+1); glVertex2f(x+w-1+0.37, y+h-1); // right - glEnd(); + if (w = 1) and (h = 1) then + begin + glBegin(GL_POINTS); + glVertex2f(x+0.37, y+0.37); + glEnd(); + end + else + begin + glBegin(GL_LINES); + glVertex2i(x, y); glVertex2i(x+w, y); // top + glVertex2i(x, y+h-1); glVertex2i(x+w, y+h-1); // bottom + glVertex2f(x+0.37, y+1); glVertex2f(x+0.37, y+h-1); // left + glVertex2f(x+w-1+0.37, y+1); glVertex2f(x+w-1+0.37, y+h-1); // right + glEnd(); + end; //glRect(x, y, x+w, y+h); glColor4f(1, 1, 1, 1); glDisable(GL_BLEND); diff --git a/src/game/g_holmes.pas b/src/game/g_holmes.pas index 785b311..0fb34c0 100644 --- a/src/game/g_holmes.pas +++ b/src/game/g_holmes.pas @@ -149,7 +149,7 @@ begin llb.appendItem('monster info', @showMonsInfo); llb.appendItem('monster LOS to player', @showMonsLOS2Plr); llb.appendItem('monster cells (SLOW!)', @showAllMonsCells); - llb.appendItem('', nil); + llb.appendItem('WINDOWS', nil); llb.appendItem('layers window', @showLayersWindow); llb.appendItem('outline window', @showOutlineWindow); winOptions := THTopWindow.Create('Holmes Options', 100, 100); @@ -190,10 +190,9 @@ begin llb.appendItem('acid2', @g_ol_rlayer_acid2); llb.appendItem('water', @g_ol_rlayer_water); llb.appendItem('foreground', @g_ol_rlayer_fore); - llb.appendItem('', nil); + llb.appendItem('OPTIONS', nil); llb.appendItem('fill walls', @g_ol_fill_walls); - llb.appendItem('', nil); - llb.appendItem('slow''n''nice', @g_ol_nice); + llb.appendItem('contours', @g_ol_nice); winOutlines := THTopWindow.Create('outlines', 100, 10); winOutlines.escClose := true; winOutlines.appendChild(llb); diff --git a/src/game/g_holmes_ui.inc b/src/game/g_holmes_ui.inc index 5684ab2..f5472e8 100644 --- a/src/game/g_holmes_ui.inc +++ b/src/game/g_holmes_ui.inc @@ -20,6 +20,7 @@ type mParent: THControl; mX, mY: Integer; mWidth, mHeight: Integer; + mFrameWidth, mFrameHeight: Integer; mEnabled: Boolean; mCanFocus: Boolean; mChildren: array of THControl; @@ -27,6 +28,11 @@ type mGrab: THControl; // valid only for top-level controls mEscClose: Boolean; // valid only for top-level controls mEatKeys: Boolean; + mDrawShadow: Boolean; + + private + scallowed: Boolean; + scxywh: array[0..3] of GLint; protected function getEnabled (): Boolean; @@ -46,6 +52,20 @@ type procedure activated (); virtual; procedure blurred (); virtual; + //WARNING! do not call scissor functions outside `.draw*()` API! + // reset scissor to whole control + procedure resetScissor (); + // set scissor to this internal rect (in local coords) + procedure setScissor (lx, ly, lw, lh: Integer); + + // DO NOT USE! + procedure setScissorGLInternal (x, y, w, h: Integer); + + public + // return `false` if destination rect is empty + // modifies rect0 + class function intersectRect (var x0, y0, w0, h0: Integer; const x1, y1, w1, h1: Integer): Boolean; + public constructor Create (ax, ay, aw, ah: Integer; aparent: THControl=nil); destructor Destroy (); override; @@ -75,6 +95,8 @@ type function firstChild (): THControl; inline; function lastChild (): THControl; inline; + procedure appendChild (ctl: THControl); virtual; + public property x0: Integer read mX; property y0: Integer read mY; @@ -100,12 +122,11 @@ type public constructor Create (const atitle: AnsiString; ax, ay: Integer; aw: Integer=-1; ah: Integer=-1); - procedure appendChild (ctl: THControl); - // `sx` and `sy` are screen coordinates procedure drawControl (sx, sy: Integer); override; procedure drawControlPost (sx, sy: Integer); override; + function keyEvent (var ev: THKeyEvent): Boolean; override; // returns `true` if event was eaten function mouseEvent (var ev: THMouseEvent): Boolean; override; // returns `true` if event was eaten end; @@ -256,6 +277,8 @@ begin mY := ay; mWidth := aw; mHeight := ah; + mFrameWidth := 0; + mFrameHeight := 0; mEnabled := true; mCanFocus := true; mChildren := nil; @@ -263,6 +286,8 @@ begin mGrab := nil; mEscClose := false; mEatKeys := false; + scallowed := false; + mDrawShadow := false; end; @@ -543,36 +568,86 @@ begin end; +procedure THControl.appendChild (ctl: THControl); +begin + if (ctl = nil) then exit; + if (ctl.mParent <> nil) then exit; + SetLength(mChildren, Length(mChildren)+1); + mChildren[High(mChildren)] := ctl; + ctl.mParent := self; + Inc(ctl.mX, mFrameWidth); + Inc(ctl.mY, mFrameHeight); + if (ctl.mWidth > 0) and (ctl.mHeight > 0) and + (ctl.mX+ctl.mWidth > mFrameWidth) and (ctl.mY+ctl.mHeight > mFrameHeight) then + begin + if (mWidth+mFrameWidth < ctl.mX+ctl.mWidth) then mWidth := ctl.mX+ctl.mWidth+mFrameWidth; + if (mHeight+mFrameHeight < ctl.mY+ctl.mHeight) then mHeight := ctl.mY+ctl.mHeight+mFrameHeight; + end; + if (mFocused = nil) and ctl.mEnabled and ctl.mCanFocus and (ctl.mWidth > 0) and (ctl.mHeight > 0) then mFocused := ctl; +end; + + +//TODO: overflow checks +class function THControl.intersectRect (var x0, y0, w0, h0: Integer; const x1, y1, w1, h1: Integer): Boolean; +var + ex0, ey0: Integer; +begin + result := false; + if (w0 < 1) or (h0 < 1) or (w1 < 1) or (h1 < 1) then exit; + // check for intersection + if (x0+w0 <= x1) or (y0+h0 <= y1) or (x1+w1 <= x0) or (y1+h1 <= y0) then exit; + if (x0 >= x1+w1) or (y0 >= y1+h1) or (x1 >= x0+h0) or (y1 >= y0+h0) then exit; + // ok, intersects + ex0 := x0+w0; + ey0 := y0+h0; + if (x0 < x1) then x0 := x1; + if (y0 < y1) then y0 := y1; + if (ex0 > x1+w1) then ex0 := x1+w1; + if (ey0 > y1+h1) then ey0 := y1+h1; + w0 := ex0-x0; + h0 := ey0-y0; + result := (w0 > 0) and (h0 > 0); +end; + + +procedure THControl.setScissorGLInternal (x, y, w, h: Integer); +begin + if not scallowed then exit; + y := gWinSizeY-(y+h); + if not intersectRect(x, y, w, h, scxywh[0], scxywh[1], scxywh[2], scxywh[3]) then glScissor(0, 0, 0, 0) else glScissor(x, y, w, h); +end; + + +procedure THControl.resetScissor (); +var + x, y: Integer; +begin + if not scallowed then exit; + x := 0; + y := 0; + toGlobal(x, y); + setScissorGLInternal(x, y, mWidth, mHeight); +end; + + +procedure THControl.setScissor (lx, ly, lw, lh: Integer); +var + x, y: Integer; +begin + if not scallowed then exit; + if not intersectRect(lx, ly, lw, lh, 0, 0, mWidth, mHeight) then begin glScissor(0, 0, 0, 0); exit; end; + x := lx; + y := ly; + toGlobal(x, y); + setScissorGLInternal(x, y, lw, lh); +end; + + procedure THControl.draw (); var f: Integer; x, y: Integer; - scxywh: array[0..3] of GLint; wassc: Boolean; - - procedure setScissor (x, y, w, h: Integer); - var - x1, y1: Integer; - sx0, sy0: Integer; - sx1, sy1: Integer; - begin - if (w < 1) or (h < 1) or (scxywh[2] < 1) or (scxywh[3] < 1) then begin glScissor(0, 0, 0, 0); exit; end; - x1 := x+w-1; - y1 := y+h-1; - sx0 := scxywh[0]; - sy0 := scxywh[1]; - sx1 := sx0+scxywh[2]-1; - sy1 := sy0+scxywh[3]-1; - //conwritefln('0: (%d,%d)-(%d,%d) (%d,%d)-(%d,%d)', [sx0, sy0, sx1, sy1, x, y, x1, y1]); - if (x1 < sx0) or (y1 < sy0) or (x > sx1) or (y > sy1) then begin glScissor(0, 0, 0, 0); exit; end; - if (x < sx0) then x := sx0; - if (y < sy0) then y := sy0; - if (x1 > sx1) then x1 := sx1; - if (y1 > sy1) then y1 := sy1; - //conwritefln('1: (%d,%d)-(%d,%d) (%d,%d)-(%d,%d)', [sx0, sy0, sx1, sy1, x, y, x1, y1]); - glScissor(x, y, x1-x+1, y1-y+1); - end; - begin if (mWidth < 1) or (mHeight < 1) then exit; x := 0; @@ -586,38 +661,38 @@ begin scxywh[3] := 0; wassc := (glIsEnabled(GL_SCISSOR_TEST) <> 0); - if wassc then - begin - glGetIntegerv(GL_SCISSOR_BOX, @scxywh[0]); - end - else - begin - glGetIntegerv(GL_VIEWPORT, @scxywh[0]); - end; + if wassc then glGetIntegerv(GL_SCISSOR_BOX, @scxywh[0]) else glGetIntegerv(GL_VIEWPORT, @scxywh[0]); //conwritefln('(%d,%d)-(%d,%d)', [scxywh[0], scxywh[1], scxywh[2], scxywh[3]]); - glEnable(GL_SCISSOR_TEST); - setScissor(x, gWinSizeY-(y+mHeight-1)-1, mWidth, mHeight); + scallowed := true; + resetScissor(); drawControl(x, y); - if (mParent = nil) then setScissor(x+2, gWinSizeY-(y+mHeight-1-2)-1, mWidth-4, mHeight-14); + if (mFrameWidth <> 0) or (mFrameHeight <> 0) then setScissor(mFrameWidth, mFrameHeight, mWidth-mFrameWidth*2, mHeight-mFrameHeight*2); for f := 0 to High(mChildren) do mChildren[f].draw(); - if (mParent = nil) then setScissor(x, gWinSizeY-(y+mHeight-1)-1, mWidth, mHeight); + if (mFrameWidth <> 0) or (mFrameHeight <> 0) then resetScissor(); drawControlPost(x, y); glScissor(scxywh[0], scxywh[1], scxywh[2], scxywh[3]); + if wassc then glEnable(GL_SCISSOR_TEST) else glDisable(GL_SCISSOR_TEST); + scallowed := false; end; procedure THControl.drawControl (sx, sy: Integer); begin if (mParent = nil) then darkenRect(sx, sy, mWidth, mHeight, 64); - //fillRect(sx, sy, mWidth, mHeight, 0, 0, 255, 120); end; procedure THControl.drawControlPost (sx, sy: Integer); begin + if mDrawShadow and (mWidth > 0) and (mHeight > 0) then + begin + setScissorGLInternal(sx+8, sy+8, mWidth, mHeight); + darkenRect(sx+mWidth, sy+8, 8, mHeight, 128); + darkenRect(sx+8, sy+mHeight, mWidth-8, 8, 128); + end; end; @@ -697,78 +772,51 @@ end; // ////////////////////////////////////////////////////////////////////////// // constructor THTopWindow.Create (const atitle: AnsiString; ax, ay: Integer; aw: Integer=-1; ah: Integer=-1); begin + inherited Create(ax, ay, aw, ah, nil); + mFrameWidth := 8; + mFrameHeight := 8; mTitle := atitle; + if (mWidth < mFrameWidth*2) then mWidth := mFrameWidth*2; + if (mHeight < mFrameHeight*2) then mHeight := mFrameHeight*2; if (Length(mTitle) > 0) then begin - if (ah < 14) then ah := 14; - if (aw < Length(mTitle)*8+4) then aw := Length(mTitle)*8+4; - end - else - begin - if (ah < 4) then ah := 4; - if (aw < 4) then aw := 4; + if (mWidth < Length(mTitle)*8+mFrameWidth*2) then mWidth := Length(mTitle)*8+mFrameWidth*2; end; mDragging := false; - inherited Create(ax, ay, aw, ah, nil); -end; - - -procedure THTopWindow.appendChild (ctl: THControl); -var - myofs: Integer; -begin - if (ctl = nil) then exit; - if (ctl.mParent <> nil) then exit; - if (Length(mTitle) > 0) then myofs := 12 else myofs := 2; - SetLength(mChildren, Length(mChildren)+1); - mChildren[High(mChildren)] := ctl; - ctl.mParent := self; - Inc(ctl.mX, 2); - Inc(ctl.mY, myofs); - if (ctl.mWidth > 0) and (ctl.mHeight > 0) and - (ctl.mX+ctl.mWidth > 2) and (ctl.mY+ctl.mHeight > myofs-2) then - begin - if (mWidth+2 < ctl.mX+ctl.mWidth) then mWidth := ctl.mX+ctl.mWidth+2; - if (mHeight+2 < ctl.mY+ctl.mHeight) then mHeight := ctl.mY+ctl.mHeight+2; - end; - if (mFocused = nil) and ctl.mEnabled and ctl.mCanFocus and (ctl.mWidth > 0) and (ctl.mHeight > 0) then mFocused := ctl; + mDrawShadow := true; end; procedure THTopWindow.drawControl (sx, sy: Integer); begin - //if (mParent = nil) then darkenRect(sx, sy, mWidth, mHeight, 200); fillRect(sx, sy, mWidth, mHeight, 0, 0, 128); end; procedure THTopWindow.drawControlPost (sx, sy: Integer); +const r = 255; +const g = 255; +const b = 255; var - r, g, b: Integer; + tx: Integer; begin - { - if getFocused then + if mDragging then begin - r := 255; - g := 255; - b := 255; + drawRect(mX+4, mY+4, mWidth-8, mHeight-8, r, g, b); end else begin - r := 127; - g := 127; - b := 127; + drawRect(mX+3, mY+3, mWidth-6, mHeight-6, r, g, b); + drawRect(mX+5, mY+5, mWidth-10, mHeight-10, r, g, b); end; - } - r := 255; - g := 255; - b := 255; - drawRect(mX, mY, mWidth, mHeight, r, g, b); if (Length(mTitle) > 0) then begin - fillRect(mX+1, mY+1, mWidth-2, 9, r, g, b); - drawText8(mX+2, mY+1, mTitle, 0, 0, 0); + setScissor(mFrameWidth, 0, mWidth-mFrameWidth*2, 8); + tx := (mWidth-Length(mTitle)*8) div 2; + fillRect(mX+tx-3, mY, Length(mTitle)*8+3+2, 8, 0, 0, 128); + drawText8(mX+tx, mY, mTitle, r, g, b); end; + inherited drawControlPost(sx, sy); end; @@ -779,6 +827,19 @@ begin end; +function THTopWindow.keyEvent (var ev: THKeyEvent): Boolean; +begin + result := inherited keyEvent(ev); + if not getFocused then exit; + if (ev.kstate = ev.ModAlt) and (ev.kind = ev.Press) and (ev.scan = SDL_SCANCODE_F3) then + begin + uiRemoveWindow(self); + result := true; + exit; + end; +end; + + function THTopWindow.mouseEvent (var ev: THMouseEvent): Boolean; var lx, ly: Integer; @@ -804,7 +865,7 @@ begin ly := ev.y; if toLocal(lx, ly) then begin - if ((Length(mTitle) > 0) and (ly < 12)) or ((Length(mTitle) = 0) and (ly < 2)) then + if (ly < 8) then begin mDragging := true; mDragStartX := ev.x; @@ -815,6 +876,21 @@ begin end; end; + if (ev.kind = ev.Press) and (ev.but = ev.Right) then + begin + lx := ev.x; + ly := ev.y; + if toLocal(lx, ly) then + begin + if (ly < 8) then + begin + uiRemoveWindow(self); + result := true; + exit; + end; + end; + end; + result := inherited mouseEvent(ev); end; @@ -851,7 +927,7 @@ end; procedure THCtlCBListBox.drawControl (sx, sy: Integer); var - f: Integer; + f, tx: Integer; begin //fillRect(sx, sy, mWidth, mHeight, 0, 128, 0); Inc(sx, 2); @@ -865,6 +941,20 @@ begin //if mChecks[f]^ then drawText8(sx+6, sy, 'x', 255, 255, 255); if mChecks[f]^ then drawText8(sx, sy, '[x]', 255, 255, 255) else drawText8(sx, sy, '[ ]', 255, 255, 255); drawText8(sx+3*8+2, sy, mItems[f], 255, 255, 0); + end + else if (Length(mItems[f]) > 0) then + begin + tx := sx+(mWidth-Length(mItems[f])*8) div 2; + if (tx-3 > sx+4) then + begin + drawLine(sx+4, sy+3, tx-3, sy+3, 255, 255, 255); + drawLine(tx+Length(mItems[f])*8, sy+3, sx+mWidth-4, sy+3, 255, 255, 255); + end; + drawText8(sx+(mWidth-Length(mItems[f])*8) div 2, sy, mItems[f], 255, 255, 255); + end + else + begin + drawLine(sx+4, sy+3, sx+mWidth-8, sy+3, 255, 255, 255); end; Inc(sy, 8); end; -- 2.29.2