X-Git-Url: https://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fgx%2Fgh_ui.pas;h=be597b0dfbb75b933b1ed816eca27470b6d1eb10;hb=e4b651a876eccee3cdc7f96cef3203db81db369b;hp=4f4133f84d38bcf13ae95ea22a2f367f0f55ce29;hpb=007b3a8fcfe260417aa379da9e6b4e84ddc028d4;p=d2df-sdl.git diff --git a/src/gx/gh_ui.pas b/src/gx/gh_ui.pas index 4f4133f..be597b0 100644 --- a/src/gx/gh_ui.pas +++ b/src/gx/gh_ui.pas @@ -1,4 +1,5 @@ -(* Copyright (C) DooM 2D:Forever Developers +(* coded by Ketmar // Invisible Vector + * Understanding is not required. Only obedience. * * 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 @@ -11,7 +12,7 @@ * 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 . + * along with this program. If not, see . *) {$INCLUDE ../shared/a_modes.inc} {$M+} @@ -23,37 +24,58 @@ uses SysUtils, Classes, GL, GLExt, SDL2, gh_ui_common, + gh_ui_style, sdlcarcass, glgfx, xparser; // ////////////////////////////////////////////////////////////////////////// // type - THControlClass = class of THControl; + TUIControlClass = class of TUIControl; - THControl = class + TUIControl = class public - type TActionCB = procedure (me: THControl; uinfo: Integer); + type TActionCB = procedure (me: TUIControl; uinfo: Integer); + + public + const ClrIdxActive = 0; + const ClrIdxDisabled = 1; + const ClrIdxInactive = 2; + const ClrIdxMax = 2; private - mParent: THControl; + mParent: TUIControl; mId: AnsiString; + mStyleId: AnsiString; mX, mY: Integer; mWidth, mHeight: Integer; mFrameWidth, mFrameHeight: Integer; mEnabled: Boolean; mCanFocus: Boolean; - mChildren: array of THControl; - mFocused: THControl; // valid only for top-level controls - mGrab: THControl; // valid only for top-level controls + mChildren: array of TUIControl; + mFocused: TUIControl; // valid only for top-level controls + mGrab: TUIControl; // valid only for top-level controls mEscClose: Boolean; // valid only for top-level controls mEatKeys: Boolean; mDrawShadow: Boolean; + // colors + mCtl4Style: AnsiString; + mBackColor: array[0..ClrIdxMax] of TGxRGBA; + mTextColor: array[0..ClrIdxMax] of TGxRGBA; + mFrameColor: array[0..ClrIdxMax] of TGxRGBA; + mFrameTextColor: array[0..ClrIdxMax] of TGxRGBA; + mFrameIconColor: array[0..ClrIdxMax] of TGxRGBA; + mDarken: array[0..ClrIdxMax] of Integer; // -1: none private scis: TScissorSave; scallowed: Boolean; + protected + procedure updateStyle (); virtual; + procedure cacheStyle (root: TUIStyle); virtual; + function getColorIndex (): Integer; inline; + protected function getEnabled (): Boolean; procedure setEnabled (v: Boolean); inline; @@ -61,13 +83,13 @@ type function getFocused (): Boolean; inline; procedure setFocused (v: Boolean); inline; - function isMyChild (ctl: THControl): Boolean; + function isMyChild (ctl: TUIControl): Boolean; - function findFirstFocus (): THControl; - function findLastFocus (): THControl; + function findFirstFocus (): TUIControl; + function findLastFocus (): TUIControl; - function findNextFocus (cur: THControl): THControl; - function findPrevFocus (cur: THControl): THControl; + function findNextFocus (cur: TUIControl): TUIControl; + function findPrevFocus (cur: TUIControl): TUIControl; procedure activated (); virtual; procedure blurred (); virtual; @@ -145,6 +167,7 @@ type function parseAnyAlign (par: TTextParser): Integer; function parseHAlign (par: TTextParser): Integer; function parseVAlign (par: TTextParser): Integer; + function parseOrientation (const prname: AnsiString; par: TTextParser): Boolean; procedure parseTextAlign (par: TTextParser; var h, v: Integer); procedure parseChildren (par: TTextParser); // par should be on '{'; final '}' is eaten @@ -172,7 +195,7 @@ type procedure draw (); virtual; - function topLevel (): THControl; inline; + function topLevel (): TUIControl; inline; // returns `true` if global coords are inside this control function toLocal (var x, y: Integer): Boolean; @@ -181,33 +204,34 @@ type procedure toGlobal (lx, ly: Integer; out x, y: Integer); inline; // x and y are global coords - function controlAtXY (x, y: Integer): THControl; + function controlAtXY (x, y: Integer): TUIControl; function mouseEvent (var ev: THMouseEvent): Boolean; virtual; // returns `true` if event was eaten function keyEvent (var ev: THKeyEvent): Boolean; virtual; // returns `true` if event was eaten - function prevSibling (): THControl; - function nextSibling (): THControl; - function firstChild (): THControl; inline; - function lastChild (): THControl; inline; + function prevSibling (): TUIControl; + function nextSibling (): TUIControl; + function firstChild (): TUIControl; inline; + function lastChild (): TUIControl; inline; - procedure appendChild (ctl: THControl); virtual; + procedure appendChild (ctl: TUIControl); virtual; public property id: AnsiString read mId; + property styleId: AnsiString read mStyleId; property x0: Integer read mX; property y0: Integer read mY; property height: Integer read mHeight; property width: Integer read mWidth; property enabled: Boolean read getEnabled write setEnabled; - property parent: THControl read mParent; + property parent: TUIControl read mParent; property focused: Boolean read getFocused write setFocused; property escClose: Boolean read mEscClose write mEscClose; property eatKeys: Boolean read mEatKeys write mEatKeys; end; - THTopWindow = class(THControl) + TUITopWindow = class(TUIControl) private mTitle: AnsiString; mDragging: Boolean; @@ -215,8 +239,13 @@ type mWaitingClose: Boolean; mInClose: Boolean; mFreeOnClose: Boolean; // default: false + mDoCenter: Boolean; // after layouting + + protected + procedure cacheStyle (root: TUIStyle); override; protected + procedure activated (); override; procedure blurred (); override; public @@ -225,6 +254,8 @@ type public constructor Create (const atitle: AnsiString; ax, ay: Integer; aw: Integer=-1; ah: Integer=-1); + procedure AfterConstruction (); override; // so it will be correctly initialized when created from parser + function parseProperty (const prname: AnsiString; par: TTextParser): Boolean; override; procedure centerInScreen (); @@ -241,7 +272,7 @@ type end; - THCtlSimpleText = class(THControl) + TUISimpleText = class(TUIControl) private type PItem = ^TItem; @@ -266,7 +297,7 @@ type end; - THCtlCBListBox = class(THControl) + TUICBListBox = class(TUIControl) private type PItem = ^TItem; @@ -292,7 +323,7 @@ type end; // ////////////////////////////////////////////////////////////////////// // - THCtlBox = class(THControl) + TUIBox = class(TUIControl) private mHasFrame: Boolean; mCaption: AnsiString; @@ -300,6 +331,8 @@ type public constructor Create (ahoriz: Boolean); + procedure AfterConstruction (); override; // so it will be correctly initialized when created from parser + function parseProperty (const prname: AnsiString; par: TTextParser): Boolean; override; procedure drawControl (gx, gy: Integer); override; @@ -308,21 +341,29 @@ type function keyEvent (var ev: THKeyEvent): Boolean; override; end; - THCtlHBox = class(THCtlBox) + TUIHBox = class(TUIBox) public procedure AfterConstruction (); override; // so it will be correctly initialized when created from parser end; - THCtlVBox = class(THCtlBox) + TUIVBox = class(TUIBox) public procedure AfterConstruction (); override; // so it will be correctly initialized when created from parser end; // ////////////////////////////////////////////////////////////////////// // - THCtlSpan = class(THControl) + TUISpan = class(TUIControl) public - constructor Create (); + procedure AfterConstruction (); override; // so it will be correctly initialized when created from parser + function parseProperty (const prname: AnsiString; par: TTextParser): Boolean; override; + + procedure drawControl (gx, gy: Integer); override; + end; + + // ////////////////////////////////////////////////////////////////////// // + TUILine = class(TUIControl) + public procedure AfterConstruction (); override; // so it will be correctly initialized when created from parser function parseProperty (const prname: AnsiString; par: TTextParser): Boolean; override; @@ -330,8 +371,18 @@ type procedure drawControl (gx, gy: Integer); override; end; + TUIHLine = class(TUILine) + public + procedure AfterConstruction (); override; // so it will be correctly initialized when created from parser + end; + + TUIVLine = class(TUILine) + public + procedure AfterConstruction (); override; // so it will be correctly initialized when created from parser + end; + // ////////////////////////////////////////////////////////////////////// // - THCtlTextLabel = class(THControl) + TUITextLabel = class(TUIControl) private mText: AnsiString; mHAlign: Integer; // -1: left; 0: center; 1: right; default: left @@ -339,7 +390,8 @@ type public constructor Create (const atext: AnsiString); - //destructor Destroy (); override; + + procedure AfterConstruction (); override; // so it will be correctly initialized when created from parser function parseProperty (const prname: AnsiString; par: TTextParser): Boolean; override; @@ -357,14 +409,16 @@ procedure uiDraw (); // ////////////////////////////////////////////////////////////////////////// // -procedure uiAddWindow (ctl: THControl); -procedure uiRemoveWindow (ctl: THControl); // will free window if `mFreeOnClose` is `true` -function uiVisibleWindow (ctl: THControl): Boolean; +procedure uiAddWindow (ctl: TUIControl); +procedure uiRemoveWindow (ctl: TUIControl); // will free window if `mFreeOnClose` is `true` +function uiVisibleWindow (ctl: TUIControl): Boolean; + +procedure uiUpdateStyles (); // ////////////////////////////////////////////////////////////////////////// // // do layouting -procedure uiLayoutCtl (ctl: THControl); +procedure uiLayoutCtl (ctl: TUIControl); // ////////////////////////////////////////////////////////////////////////// // @@ -382,12 +436,12 @@ uses // ////////////////////////////////////////////////////////////////////////// // var knownCtlClasses: array of record - klass: THControlClass; + klass: TUIControlClass; name: AnsiString; end = nil; -procedure registerCtlClass (aklass: THControlClass; const aname: AnsiString); +procedure registerCtlClass (aklass: TUIControlClass; const aname: AnsiString); begin assert(aklass <> nil); assert(Length(aname) > 0); @@ -397,7 +451,7 @@ begin end; -function findCtlClass (const aname: AnsiString): THControlClass; +function findCtlClass (const aname: AnsiString): TUIControlClass; var f: Integer; begin @@ -415,9 +469,9 @@ end; // ////////////////////////////////////////////////////////////////////////// // type - TFlexLayouter = specialize TFlexLayouterBase; + TFlexLayouter = specialize TFlexLayouterBase; -procedure uiLayoutCtl (ctl: THControl); +procedure uiLayoutCtl (ctl: TUIControl); var lay: TFlexLayouter; begin @@ -445,6 +499,11 @@ begin lay.layout(); //writeln('=== final ==='); lay.dump(); + if (ctl.mParent = nil) and (ctl is TUITopWindow) and (TUITopWindow(ctl).mDoCenter) then + begin + TUITopWindow(ctl).centerInScreen(); + end; + finally FreeAndNil(lay); end; @@ -453,14 +512,22 @@ end; // ////////////////////////////////////////////////////////////////////////// // var - uiTopList: array of THControl = nil; + uiTopList: array of TUIControl = nil; + + +procedure uiUpdateStyles (); +var + ctl: TUIControl; +begin + for ctl in uiTopList do ctl.updateStyle(); +end; function uiMouseEvent (ev: THMouseEvent): Boolean; var f, c: Integer; lx, ly: Integer; - ctmp: THControl; + ctmp: TUIControl; begin ev.x := trunc(ev.x/gh_ui_scale); ev.y := trunc(ev.y/gh_ui_scale); @@ -502,8 +569,8 @@ end; procedure uiDraw (); var - f: Integer; - ctl: THControl; + f, cidx: Integer; + ctl: TUIControl; begin glMatrixMode(GL_MODELVIEW); glPushMatrix(); @@ -514,7 +581,9 @@ begin begin ctl := uiTopList[f]; ctl.draw(); - if (f <> High(uiTopList)) then darkenRect(ctl.x0, ctl.y0, ctl.width, ctl.height, 128); + cidx := ctl.getColorIndex; + //if (f <> High(uiTopList)) then darkenRect(ctl.x0, ctl.y0, ctl.width, ctl.height, 128); + if (ctl.mDarken[cidx] > 0) then darkenRect(ctl.x0, ctl.y0, ctl.width, ctl.height, ctl.mDarken[cidx]); end; finally glMatrixMode(GL_MODELVIEW); @@ -523,13 +592,13 @@ begin end; -procedure uiAddWindow (ctl: THControl); +procedure uiAddWindow (ctl: TUIControl); var f, c: Integer; begin if (ctl = nil) then exit; ctl := ctl.topLevel; - if not (ctl is THTopWindow) then exit; // alas + if not (ctl is TUITopWindow) then exit; // alas for f := 0 to High(uiTopList) do begin if (uiTopList[f] = ctl) then @@ -547,17 +616,18 @@ begin if (Length(uiTopList) > 0) then uiTopList[High(uiTopList)].blurred(); SetLength(uiTopList, Length(uiTopList)+1); uiTopList[High(uiTopList)] := ctl; + ctl.updateStyle(); ctl.activated(); end; -procedure uiRemoveWindow (ctl: THControl); +procedure uiRemoveWindow (ctl: TUIControl); var f, c: Integer; begin if (ctl = nil) then exit; ctl := ctl.topLevel; - if not (ctl is THTopWindow) then exit; // alas + if not (ctl is TUITopWindow) then exit; // alas for f := 0 to High(uiTopList) do begin if (uiTopList[f] = ctl) then @@ -565,12 +635,12 @@ begin ctl.blurred(); for c := f+1 to High(uiTopList) do uiTopList[c-1] := uiTopList[c]; SetLength(uiTopList, Length(uiTopList)-1); - if (ctl is THTopWindow) then + if (ctl is TUITopWindow) then begin try - if assigned(THTopWindow(ctl).closeCB) then THTopWindow(ctl).closeCB(ctl, 0); + if assigned(TUITopWindow(ctl).closeCB) then TUITopWindow(ctl).closeCB(ctl, 0); finally - if (THTopWindow(ctl).mFreeOnClose) then FreeAndNil(ctl); + if (TUITopWindow(ctl).mFreeOnClose) then FreeAndNil(ctl); end; end; exit; @@ -579,14 +649,14 @@ begin end; -function uiVisibleWindow (ctl: THControl): Boolean; +function uiVisibleWindow (ctl: TUIControl): Boolean; var f: Integer; begin result := false; if (ctl = nil) then exit; ctl := ctl.topLevel; - if not (ctl is THTopWindow) then exit; // alas + if not (ctl is TUITopWindow) then exit; // alas for f := 0 to High(uiTopList) do begin if (uiTopList[f] = ctl) then begin result := true; exit; end; @@ -595,9 +665,10 @@ end; // ////////////////////////////////////////////////////////////////////////// // -constructor THControl.Create (); +constructor TUIControl.Create (); begin mParent := nil; + mId := ''; mX := 0; mY := 0; mWidth := 64; @@ -624,12 +695,14 @@ begin mLineStart := false; mHGroup := ''; mVGroup := ''; + mStyleId := ''; + mCtl4Style := ''; mAlign := -1; // left/top mExpand := false; end; -constructor THControl.Create (ax, ay, aw, ah: Integer); +constructor TUIControl.Create (ax, ay, aw, ah: Integer); begin Create(); mX := ax; @@ -639,7 +712,7 @@ begin end; -destructor THControl.Destroy (); +destructor TUIControl.Destroy (); var f, c: Integer; begin @@ -664,31 +737,88 @@ begin end; +function TUIControl.getColorIndex (): Integer; inline; +begin + if (not mEnabled) then begin result := ClrIdxDisabled; exit; end; + if (getFocused) then begin result := ClrIdxActive; exit; end; + result := ClrIdxInactive; +end; + +procedure TUIControl.updateStyle (); +var + stl: TUIStyle = nil; + ctl: TUIControl; +begin + ctl := self; + while (ctl <> nil) do + begin + if (Length(ctl.mStyleId) <> 0) then begin stl := uiFindStyle(ctl.mStyleId); break; end; + ctl := ctl.mParent; + end; + if (stl = nil) then stl := uiFindStyle(''); // default + cacheStyle(stl); + for ctl in mChildren do ctl.updateStyle(); +end; + +procedure TUIControl.cacheStyle (root: TUIStyle); +var + cst: AnsiString = ''; +begin + //writeln('caching style for <', className, '> (', mCtl4Style, ')...'); + if (Length(mCtl4Style) > 0) then + begin + cst := mCtl4Style; + if (cst[1] <> '@') then cst := '@'+cst; + end; + // active + mBackColor[ClrIdxActive] := root['back-color'+cst].asRGBADef(TGxRGBA.Create(0, 0, 128)); + mTextColor[ClrIdxActive] := root['text-color'+cst].asRGBADef(TGxRGBA.Create(255, 255, 255)); + mFrameColor[ClrIdxActive] := root['frame-color'+cst].asRGBADef(TGxRGBA.Create(255, 255, 255)); + mFrameTextColor[ClrIdxActive] := root['frame-text-color'+cst].asRGBADef(TGxRGBA.Create(255, 255, 255)); + mFrameIconColor[ClrIdxActive] := root['frame-icon-color'+cst].asRGBADef(TGxRGBA.Create(0, 255, 0)); + mDarken[ClrIdxActive] := root['darken'+cst].asIntDef(-1); + // disabled + mBackColor[ClrIdxDisabled] := root['back-color#disabled'+cst].asRGBADef(TGxRGBA.Create(0, 0, 128)); + mTextColor[ClrIdxDisabled] := root['text-color#disabled'+cst].asRGBADef(TGxRGBA.Create(127, 127, 127)); + mFrameColor[ClrIdxDisabled] := root['frame-color#disabled'+cst].asRGBADef(TGxRGBA.Create(127, 127, 127)); + mFrameTextColor[ClrIdxDisabled] := root['frame-text-color#disabled'+cst].asRGBADef(TGxRGBA.Create(127, 127, 127)); + mFrameIconColor[ClrIdxDisabled] := root['frame-icon-color#disabled'+cst].asRGBADef(TGxRGBA.Create(0, 127, 0)); + mDarken[ClrIdxDisabled] := root['darken#disabled'+cst].asIntDef(128); + // inactive + mBackColor[ClrIdxInactive] := root['back-color#inactive'+cst].asRGBADef(TGxRGBA.Create(0, 0, 128)); + mTextColor[ClrIdxInactive] := root['text-color#inactive'+cst].asRGBADef(TGxRGBA.Create(255, 255, 255)); + mFrameColor[ClrIdxInactive] := root['frame-color#inactive'+cst].asRGBADef(TGxRGBA.Create(255, 255, 255)); + mFrameTextColor[ClrIdxInactive] := root['frame-text-color#inactive'+cst].asRGBADef(TGxRGBA.Create(255, 255, 255)); + mFrameIconColor[ClrIdxInactive] := root['frame-icon-color#inactive'+cst].asRGBADef(TGxRGBA.Create(0, 255, 0)); + mDarken[ClrIdxInactive] := root['darken#inactive'+cst].asIntDef(128); +end; + + // ////////////////////////////////////////////////////////////////////////// // -function THControl.getDefSize (): TLaySize; inline; begin result := mLayDefSize; end; -function THControl.getMaxSize (): TLaySize; inline; begin result := mLayMaxSize; end; -function THControl.getFlex (): Integer; inline; begin result := mFlex; end; -function THControl.isHorizBox (): Boolean; inline; begin result := mHoriz; end; -procedure THControl.setHorizBox (v: Boolean); inline; begin mHoriz := v; end; -function THControl.canWrap (): Boolean; inline; begin result := mCanWrap; end; -procedure THControl.setCanWrap (v: Boolean); inline; begin mCanWrap := v; end; -function THControl.isLineStart (): Boolean; inline; begin result := mLineStart; end; -procedure THControl.setLineStart (v: Boolean); inline; begin mLineStart := v; end; -function THControl.getAlign (): Integer; inline; begin result := mAlign; end; -procedure THControl.setAlign (v: Integer); inline; begin mAlign := v; end; -function THControl.getExpand (): Boolean; inline; begin result := mExpand; end; -procedure THControl.setExpand (v: Boolean); inline; begin mExpand := v; end; -function THControl.getHGroup (): AnsiString; inline; begin result := mHGroup; end; -procedure THControl.setHGroup (const v: AnsiString); inline; begin mHGroup := v; end; -function THControl.getVGroup (): AnsiString; inline; begin result := mVGroup; end; -procedure THControl.setVGroup (const v: AnsiString); inline; begin mVGroup := v; end; - -function THControl.getMargins (): TLayMargins; inline; +function TUIControl.getDefSize (): TLaySize; inline; begin result := mLayDefSize; end; +function TUIControl.getMaxSize (): TLaySize; inline; begin result := mLayMaxSize; end; +function TUIControl.getFlex (): Integer; inline; begin result := mFlex; end; +function TUIControl.isHorizBox (): Boolean; inline; begin result := mHoriz; end; +procedure TUIControl.setHorizBox (v: Boolean); inline; begin mHoriz := v; end; +function TUIControl.canWrap (): Boolean; inline; begin result := mCanWrap; end; +procedure TUIControl.setCanWrap (v: Boolean); inline; begin mCanWrap := v; end; +function TUIControl.isLineStart (): Boolean; inline; begin result := mLineStart; end; +procedure TUIControl.setLineStart (v: Boolean); inline; begin mLineStart := v; end; +function TUIControl.getAlign (): Integer; inline; begin result := mAlign; end; +procedure TUIControl.setAlign (v: Integer); inline; begin mAlign := v; end; +function TUIControl.getExpand (): Boolean; inline; begin result := mExpand; end; +procedure TUIControl.setExpand (v: Boolean); inline; begin mExpand := v; end; +function TUIControl.getHGroup (): AnsiString; inline; begin result := mHGroup; end; +procedure TUIControl.setHGroup (const v: AnsiString); inline; begin mHGroup := v; end; +function TUIControl.getVGroup (): AnsiString; inline; begin result := mVGroup; end; +procedure TUIControl.setVGroup (const v: AnsiString); inline; begin mVGroup := v; end; + +function TUIControl.getMargins (): TLayMargins; inline; begin result := TLayMargins.Create(mFrameHeight, mFrameWidth, mFrameHeight, mFrameWidth); end; -procedure THControl.setActualSizePos (constref apos: TLayPos; constref asize: TLaySize); inline; begin +procedure TUIControl.setActualSizePos (constref apos: TLayPos; constref asize: TLaySize); inline; begin //writeln(self.className, '; pos=', apos.toString, '; size=', asize.toString); if (mParent <> nil) then begin @@ -699,7 +829,7 @@ procedure THControl.setActualSizePos (constref apos: TLayPos; constref asize: TL mHeight := asize.h; end; -procedure THControl.layPrepare (); +procedure TUIControl.layPrepare (); begin mLayDefSize := mDefSize; mLayMaxSize := mMaxSize; @@ -709,7 +839,7 @@ end; // ////////////////////////////////////////////////////////////////////////// // -function THControl.parsePos (par: TTextParser): TLayPos; +function TUIControl.parsePos (par: TTextParser): TLayPos; var ech: AnsiChar = ')'; begin @@ -721,7 +851,7 @@ begin par.expectDelim(ech); end; -function THControl.parseSize (par: TTextParser): TLaySize; +function TUIControl.parseSize (par: TTextParser): TLaySize; var ech: AnsiChar = ')'; begin @@ -733,95 +863,95 @@ begin par.expectDelim(ech); end; -function THControl.parseBool (par: TTextParser): Boolean; +function TUIControl.parseBool (par: TTextParser): Boolean; begin result := - par.eatIdOrStr('true', false) or - par.eatIdOrStr('yes', false) or - par.eatIdOrStr('tan', false); + par.eatIdOrStrCI('true') or + par.eatIdOrStrCI('yes') or + par.eatIdOrStrCI('tan'); if not result then begin - if (not par.eatIdOrStr('false', false)) and (not par.eatIdOrStr('no', false)) and (not par.eatIdOrStr('ona', false)) then + if (not par.eatIdOrStrCI('false')) and (not par.eatIdOrStrCI('no')) and (not par.eatIdOrStrCI('ona')) then begin par.error('boolean value expected'); end; end; end; -function THControl.parseAnyAlign (par: TTextParser): Integer; +function TUIControl.parseAnyAlign (par: TTextParser): Integer; begin - if (par.eatIdOrStr('left', false)) or (par.eatIdOrStr('top', false)) then result := -1 - else if (par.eatIdOrStr('right', false)) or (par.eatIdOrStr('bottom', false)) then result := 1 - else if (par.eatIdOrStr('center', false)) then result := 0 + if (par.eatIdOrStrCI('left')) or (par.eatIdOrStrCI('top')) then result := -1 + else if (par.eatIdOrStrCI('right')) or (par.eatIdOrStrCI('bottom')) then result := 1 + else if (par.eatIdOrStrCI('center')) then result := 0 else par.error('invalid align value'); end; -function THControl.parseHAlign (par: TTextParser): Integer; +function TUIControl.parseHAlign (par: TTextParser): Integer; begin - if (par.eatIdOrStr('left', false)) then result := -1 - else if (par.eatIdOrStr('right', false)) then result := 1 - else if (par.eatIdOrStr('center', false)) then result := 0 + if (par.eatIdOrStrCI('left')) then result := -1 + else if (par.eatIdOrStrCI('right')) then result := 1 + else if (par.eatIdOrStrCI('center')) then result := 0 else par.error('invalid horizontal align value'); end; -function THControl.parseVAlign (par: TTextParser): Integer; +function TUIControl.parseVAlign (par: TTextParser): Integer; begin - if (par.eatIdOrStr('top', false)) then result := -1 - else if (par.eatIdOrStr('bottom', false)) then result := 1 - else if (par.eatIdOrStr('center', false)) then result := 0 + if (par.eatIdOrStrCI('top')) then result := -1 + else if (par.eatIdOrStrCI('bottom')) then result := 1 + else if (par.eatIdOrStrCI('center')) then result := 0 else par.error('invalid vertical align value'); end; -procedure THControl.parseTextAlign (par: TTextParser; var h, v: Integer); +procedure TUIControl.parseTextAlign (par: TTextParser; var h, v: Integer); var wasH: Boolean = false; wasV: Boolean = false; begin while true do begin - if (par.eatIdOrStr('left', false)) then + if (par.eatIdOrStrCI('left')) then begin if wasH then par.error('too many align directives'); wasH := true; h := -1; continue; end; - if (par.eatIdOrStr('right', false)) then + if (par.eatIdOrStrCI('right')) then begin if wasH then par.error('too many align directives'); wasH := true; h := 1; continue; end; - if (par.eatIdOrStr('hcenter', false)) then + if (par.eatIdOrStrCI('hcenter')) then begin if wasH then par.error('too many align directives'); wasH := true; h := 0; continue; end; - if (par.eatIdOrStr('top', false)) then + if (par.eatIdOrStrCI('top')) then begin if wasV then par.error('too many align directives'); wasV := true; v := -1; continue; end; - if (par.eatIdOrStr('bottom', false)) then + if (par.eatIdOrStrCI('bottom')) then begin if wasV then par.error('too many align directives'); wasV := true; v := 1; continue; end; - if (par.eatIdOrStr('vcenter', false)) then + if (par.eatIdOrStrCI('vcenter')) then begin if wasV then par.error('too many align directives'); wasV := true; v := 0; continue; end; - if (par.eatIdOrStr('center', false)) then + if (par.eatIdOrStrCI('center')) then begin if wasV or wasH then par.error('too many align directives'); wasV := true; @@ -835,8 +965,23 @@ begin if not wasV and not wasH then par.error('invalid align value'); end; +function TUIControl.parseOrientation (const prname: AnsiString; par: TTextParser): Boolean; +begin + if (strEquCI1251(prname, 'orientation')) or (strEquCI1251(prname, 'orient')) then + begin + if (par.eatIdOrStrCI('horizontal')) or (par.eatIdOrStrCI('horiz')) then mHoriz := true + else if (par.eatIdOrStrCI('vertical')) or (par.eatIdOrStrCI('vert')) then mHoriz := false + else par.error('`horizontal` or `vertical` expected'); + result := true; + end + else + begin + result := false; + end; +end; + // par should be on '{'; final '}' is eaten -procedure THControl.parseProperties (par: TTextParser); +procedure TUIControl.parseProperties (par: TTextParser); var pn: AnsiString; begin @@ -853,10 +998,10 @@ begin end; // par should be on '{' -procedure THControl.parseChildren (par: TTextParser); +procedure TUIControl.parseChildren (par: TTextParser); var - cc: THControlClass; - ctl: THControl; + cc: TUIControlClass; + ctl: TUIControl; begin par.expectDelim('{'); while (not par.eatDelim('}')) do @@ -882,10 +1027,11 @@ begin end; -function THControl.parseProperty (const prname: AnsiString; par: TTextParser): Boolean; +function TUIControl.parseProperty (const prname: AnsiString; par: TTextParser): Boolean; begin result := true; - if (strEquCI1251(prname, 'id')) then begin mId := par.expectStrOrId(true); exit; end; // allow empty strings + if (strEquCI1251(prname, 'id')) then begin mId := par.expectIdOrStr(true); exit; end; // allow empty strings + if (strEquCI1251(prname, 'style')) then begin mStyleId := par.expectIdOrStr(); exit; end; // no empty strings if (strEquCI1251(prname, 'flex')) then begin flex := par.expectInt(); exit; end; // sizes if (strEquCI1251(prname, 'defsize')) or (strEquCI1251(prname, 'size')) then begin mDefSize := parseSize(par); exit; end; @@ -900,8 +1046,8 @@ begin if (strEquCI1251(prname, 'expand')) then begin mExpand := parseBool(par); exit; end; // align if (strEquCI1251(prname, 'align')) then begin mAlign := parseAnyAlign(par); exit; end; - if (strEquCI1251(prname, 'hgroup')) then begin mHGroup := par.expectStrOrId(true); exit; end; // allow empty strings - if (strEquCI1251(prname, 'vgroup')) then begin mVGroup := par.expectStrOrId(true); exit; end; // allow empty strings + if (strEquCI1251(prname, 'hgroup')) then begin mHGroup := par.expectIdOrStr(true); exit; end; // allow empty strings + if (strEquCI1251(prname, 'vgroup')) then begin mVGroup := par.expectIdOrStr(true); exit; end; // allow empty strings // other if (strEquCI1251(prname, 'canfocus')) then begin mCanFocus := parseBool(par); exit; end; if (strEquCI1251(prname, 'enabled')) then begin mEnabled := parseBool(par); exit; end; @@ -913,27 +1059,27 @@ end; // ////////////////////////////////////////////////////////////////////////// // -procedure THControl.activated (); +procedure TUIControl.activated (); begin end; -procedure THControl.blurred (); +procedure TUIControl.blurred (); begin mGrab := nil; end; -function THControl.topLevel (): THControl; inline; +function TUIControl.topLevel (): TUIControl; inline; begin result := self; while (result.mParent <> nil) do result := result.mParent; end; -function THControl.getEnabled (): Boolean; +function TUIControl.getEnabled (): Boolean; var - ctl: THControl; + ctl: TUIControl; begin result := false; if (not mEnabled) or (mWidth < 1) or (mHeight < 1) then exit; @@ -947,7 +1093,7 @@ begin end; -procedure THControl.setEnabled (v: Boolean); inline; +procedure TUIControl.setEnabled (v: Boolean); inline; begin if (mEnabled = v) then exit; mEnabled := v; @@ -955,15 +1101,23 @@ begin end; -function THControl.getFocused (): Boolean; inline; +function TUIControl.getFocused (): Boolean; inline; begin - if (mParent = nil) then result := (Length(uiTopList) > 0) and (uiTopList[High(uiTopList)] = self) else result := (topLevel.mFocused = self); + if (mParent = nil) then + begin + result := (Length(uiTopList) > 0) and (uiTopList[High(uiTopList)] = self); + end + else + begin + result := (topLevel.mFocused = self); + if (result) then result := (Length(uiTopList) > 0) and (uiTopList[High(uiTopList)] = topLevel); + end; end; -procedure THControl.setFocused (v: Boolean); inline; +procedure TUIControl.setFocused (v: Boolean); inline; var - tl: THControl; + tl: TUIControl; begin tl := topLevel; if not v then @@ -979,7 +1133,7 @@ begin if (not mEnabled) or (not mCanFocus) then exit; if (tl.mFocused <> self) then begin - tl.mFocused.blurred(); + if (tl.mFocused <> nil) then tl.mFocused.blurred(); tl.mFocused := self; if (tl.mGrab <> self) then tl.mGrab := nil; activated(); @@ -987,7 +1141,7 @@ begin end; -function THControl.isMyChild (ctl: THControl): Boolean; +function TUIControl.isMyChild (ctl: TUIControl): Boolean; begin result := true; while (ctl <> nil) do @@ -1000,9 +1154,9 @@ end; // returns `true` if global coords are inside this control -function THControl.toLocal (var x, y: Integer): Boolean; +function TUIControl.toLocal (var x, y: Integer): Boolean; var - ctl: THControl; + ctl: TUIControl; begin ctl := self; while (ctl <> nil) do @@ -1014,16 +1168,16 @@ begin result := (x >= 0) and (y >= 0) and (x < mWidth) and (y < mHeight); end; -function THControl.toLocal (gx, gy: Integer; out x, y: Integer): Boolean; inline; +function TUIControl.toLocal (gx, gy: Integer; out x, y: Integer): Boolean; inline; begin x := gx; y := gy; result := toLocal(x, y); end; -procedure THControl.toGlobal (var x, y: Integer); +procedure TUIControl.toGlobal (var x, y: Integer); var - ctl: THControl; + ctl: TUIControl; begin ctl := self; while (ctl <> nil) do @@ -1034,7 +1188,7 @@ begin end; end; -procedure THControl.toGlobal (lx, ly: Integer; out x, y: Integer); inline; +procedure TUIControl.toGlobal (lx, ly: Integer; out x, y: Integer); inline; begin x := lx; y := ly; @@ -1043,7 +1197,7 @@ end; // x and y are global coords -function THControl.controlAtXY (x, y: Integer): THControl; +function TUIControl.controlAtXY (x, y: Integer): TUIControl; var lx, ly: Integer; f: Integer; @@ -1060,7 +1214,7 @@ begin end; -function THControl.prevSibling (): THControl; +function TUIControl.prevSibling (): TUIControl; var f: Integer; begin @@ -1074,7 +1228,7 @@ begin result := nil; end; -function THControl.nextSibling (): THControl; +function TUIControl.nextSibling (): TUIControl; var f: Integer; begin @@ -1088,18 +1242,18 @@ begin result := nil; end; -function THControl.firstChild (): THControl; inline; +function TUIControl.firstChild (): TUIControl; inline; begin if (Length(mChildren) <> 0) then result := mChildren[0] else result := nil; end; -function THControl.lastChild (): THControl; inline; +function TUIControl.lastChild (): TUIControl; inline; begin if (Length(mChildren) <> 0) then result := mChildren[High(mChildren)] else result := nil; end; -function THControl.findFirstFocus (): THControl; +function TUIControl.findFirstFocus (): TUIControl; var f: Integer; begin @@ -1116,7 +1270,7 @@ begin end; -function THControl.findLastFocus (): THControl; +function TUIControl.findLastFocus (): TUIControl; var f: Integer; begin @@ -1133,7 +1287,7 @@ begin end; -function THControl.findNextFocus (cur: THControl): THControl; +function TUIControl.findNextFocus (cur: TUIControl): TUIControl; begin result := nil; if enabled then @@ -1154,7 +1308,7 @@ begin end; -function THControl.findPrevFocus (cur: THControl): THControl; +function TUIControl.findPrevFocus (cur: TUIControl): TUIControl; begin result := nil; if enabled then @@ -1176,7 +1330,7 @@ begin end; -procedure THControl.appendChild (ctl: THControl); +procedure TUIControl.appendChild (ctl: TUIControl); begin if (ctl = nil) then exit; if (ctl.mParent <> nil) then exit; @@ -1191,12 +1345,12 @@ 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; + //if (mFocused = nil) and ctl.mEnabled and ctl.mCanFocus and (ctl.mWidth > 0) and (ctl.mHeight > 0) then mFocused := ctl; end; // ////////////////////////////////////////////////////////////////////////// // -procedure THControl.setScissorGLInternal (x, y, w, h: Integer); +procedure TUIControl.setScissorGLInternal (x, y, w, h: Integer); begin if not scallowed then exit; x := trunc(x*gh_ui_scale); @@ -1206,7 +1360,7 @@ begin scis.combineRect(x, y, w, h); end; -procedure THControl.setScissor (lx, ly, lw, lh: Integer); +procedure TUIControl.setScissor (lx, ly, lw, lh: Integer); var gx, gy: Integer; //ox, oy, ow, oh: Integer; @@ -1223,7 +1377,7 @@ begin setScissorGLInternal(gx, gy, lw, lh); end; -procedure THControl.resetScissor (fullArea: Boolean); inline; +procedure TUIControl.resetScissor (fullArea: Boolean); inline; begin if not scallowed then exit; if (fullArea) then @@ -1238,7 +1392,7 @@ end; // ////////////////////////////////////////////////////////////////////////// // -procedure THControl.draw (); +procedure TUIControl.draw (); var f: Integer; gx, gy: Integer; @@ -1262,12 +1416,12 @@ begin end; end; -procedure THControl.drawControl (gx, gy: Integer); +procedure TUIControl.drawControl (gx, gy: Integer); begin - if (mParent = nil) then darkenRect(gx, gy, mWidth, mHeight, 64); + //if (mParent = nil) then darkenRect(gx, gy, mWidth, mHeight, 64); end; -procedure THControl.drawControlPost (gx, gy: Integer); +procedure TUIControl.drawControlPost (gx, gy: Integer); begin // shadow if mDrawShadow and (mWidth > 0) and (mHeight > 0) then @@ -1280,9 +1434,9 @@ end; // ////////////////////////////////////////////////////////////////////////// // -function THControl.mouseEvent (var ev: THMouseEvent): Boolean; +function TUIControl.mouseEvent (var ev: THMouseEvent): Boolean; var - ctl: THControl; + ctl: TUIControl; begin result := false; if not mEnabled then exit; @@ -1309,9 +1463,9 @@ begin end; -function THControl.keyEvent (var ev: THKeyEvent): Boolean; +function TUIControl.keyEvent (var ev: THKeyEvent): Boolean; var - ctl: THControl; + ctl: TUIControl; begin result := false; if not mEnabled then exit; @@ -1352,12 +1506,17 @@ end; // ////////////////////////////////////////////////////////////////////////// // -constructor THTopWindow.Create (const atitle: AnsiString; ax, ay: Integer; aw: Integer=-1; ah: Integer=-1); +constructor TUITopWindow.Create (const atitle: AnsiString; ax, ay: Integer; aw: Integer=-1; ah: Integer=-1); begin inherited Create(ax, ay, aw, ah); mFrameWidth := 8; mFrameHeight := 8; mTitle := atitle; +end; + +procedure TUITopWindow.AfterConstruction (); +begin + inherited AfterConstruction(); if (mWidth < mFrameWidth*2+3*8) then mWidth := mFrameWidth*2+3*8; if (mHeight < mFrameHeight*2) then mHeight := mFrameHeight*2; if (Length(mTitle) > 0) then @@ -1369,14 +1528,15 @@ begin mWaitingClose := false; mInClose := false; closeCB := nil; + mCtl4Style := ''; end; -function THTopWindow.parseProperty (const prname: AnsiString; par: TTextParser): Boolean; +function TUITopWindow.parseProperty (const prname: AnsiString; par: TTextParser): Boolean; begin if (strEquCI1251(prname, 'title')) or (strEquCI1251(prname, 'caption')) then begin - mTitle := par.expectStrOrId(true); + mTitle := par.expectIdOrStr(true); result := true; exit; end; @@ -1386,19 +1546,26 @@ begin result := true; exit; end; - if (strEquCI1251(prname, 'orientation')) or (strEquCI1251(prname, 'orient')) then + if (strEquCI1251(prname, 'position')) then begin - if (par.eatIdOrStr('horizontal', false)) or (par.eatIdOrStr('horiz', false)) then mHoriz := true - else if (par.eatIdOrStr('vertical', false)) or (par.eatIdOrStr('vert', false)) then mHoriz := false - else par.error('`horizontal` or `vertical` expected'); + if (par.eatIdOrStrCI('default')) then mDoCenter := false + else if (par.eatIdOrStrCI('center')) then mDoCenter := true + else par.error('`center` or `default` expected'); result := true; exit; end; + if (parseOrientation(prname, par)) then begin result := true; exit; end; result := inherited parseProperty(prname, par); end; -procedure THTopWindow.centerInScreen (); +procedure TUITopWindow.cacheStyle (root: TUIStyle); +begin + inherited cacheStyle(root); +end; + + +procedure TUITopWindow.centerInScreen (); begin if (mWidth > 0) and (mHeight > 0) then begin @@ -1408,45 +1575,55 @@ begin end; -procedure THTopWindow.drawControl (gx, gy: Integer); +procedure TUITopWindow.drawControl (gx, gy: Integer); begin - fillRect(gx, gy, mWidth, mHeight, 0, 0, 128); + fillRect(gx, gy, mWidth, mHeight, mBackColor[getColorIndex]); end; -procedure THTopWindow.drawControlPost (gx, gy: Integer); -const r = 255; -const g = 255; -const b = 255; +procedure TUITopWindow.drawControlPost (gx, gy: Integer); var + cidx: Integer; tx: Integer; begin + cidx := getColorIndex; if mDragging then begin - drawRectUI(mX+4, mY+4, mWidth-8, mHeight-8, r, g, b); + drawRectUI(mX+4, mY+4, mWidth-8, mHeight-8, mFrameColor[cidx]); end else begin - drawRectUI(mX+3, mY+3, mWidth-6, mHeight-6, r, g, b); - drawRectUI(mX+5, mY+5, mWidth-10, mHeight-10, r, g, b); + drawRectUI(mX+3, mY+3, mWidth-6, mHeight-6, mFrameColor[cidx]); + drawRectUI(mX+5, mY+5, mWidth-10, mHeight-10, mFrameColor[cidx]); setScissor(mFrameWidth, 0, 3*8, 8); - fillRect(mX+mFrameWidth, mY, 3*8, 8, 0, 0, 128); - drawText8(mX+mFrameWidth, mY, '[ ]', r, g, b); - if mInClose then drawText8(mX+mFrameWidth+7, mY, '#', 0, 255, 0) - else drawText8(mX+mFrameWidth+7, mY, '*', 0, 255, 0); + fillRect(mX+mFrameWidth, mY, 3*8, 8, mBackColor[cidx]); + drawText8(mX+mFrameWidth, mY, '[ ]', mFrameColor[cidx]); + if mInClose then drawText8(mX+mFrameWidth+7, mY, '#', mFrameIconColor[cidx]) + else drawText8(mX+mFrameWidth+7, mY, '*', mFrameIconColor[cidx]); end; if (Length(mTitle) > 0) then begin setScissor(mFrameWidth+3*8, 0, mWidth-mFrameWidth*2-3*8, 8); tx := (mX+3*8)+((mWidth-3*8)-Length(mTitle)*8) div 2; - fillRect(tx-3, mY, Length(mTitle)*8+3+2, 8, 0, 0, 128); - drawText8(tx, mY, mTitle, r, g, b); + fillRect(tx-3, mY, Length(mTitle)*8+3+2, 8, mBackColor[cidx]); + drawText8(tx, mY, mTitle, mFrameTextColor[cidx]); end; inherited drawControlPost(gx, gy); end; -procedure THTopWindow.blurred (); +procedure TUITopWindow.activated (); +begin + if (mFocused = nil) or (mFocused = self) then + begin + mFocused := findFirstFocus(); + if (mFocused <> nil) and (mFocused <> self) then mFocused.activated(); + end; + inherited; +end; + + +procedure TUITopWindow.blurred (); begin mDragging := false; mWaitingClose := false; @@ -1455,7 +1632,7 @@ begin end; -function THTopWindow.keyEvent (var ev: THKeyEvent): Boolean; +function TUITopWindow.keyEvent (var ev: THKeyEvent): Boolean; begin result := inherited keyEvent(ev); if not getFocused then exit; @@ -1468,7 +1645,7 @@ begin end; -function THTopWindow.mouseEvent (var ev: THMouseEvent): Boolean; +function TUITopWindow.mouseEvent (var ev: THMouseEvent): Boolean; var lx, ly: Integer; begin @@ -1551,21 +1728,21 @@ end; // ////////////////////////////////////////////////////////////////////////// // -constructor THCtlSimpleText.Create (ax, ay: Integer); +constructor TUISimpleText.Create (ax, ay: Integer); begin mItems := nil; inherited Create(ax, ay, 4, 4); end; -destructor THCtlSimpleText.Destroy (); +destructor TUISimpleText.Destroy (); begin mItems := nil; inherited; end; -procedure THCtlSimpleText.appendItem (const atext: AnsiString; acentered: Boolean=false; ahline: Boolean=false); +procedure TUISimpleText.appendItem (const atext: AnsiString; acentered: Boolean=false; ahline: Boolean=false); var it: PItem; begin @@ -1579,7 +1756,7 @@ begin end; -procedure THCtlSimpleText.drawControl (gx, gy: Integer); +procedure TUISimpleText.drawControl (gx, gy: Integer); var f, tx: Integer; it: PItem; @@ -1598,21 +1775,21 @@ begin b := 255; if (Length(it.title) = 0) then begin - drawHLine(gx+4, gy+3, mWidth-8, r, g, b); + drawHLine(gx+4, gy+3, mWidth-8, TGxRGBA.Create(r, g, b)); end else if (tx-3 > gx+4) then begin - drawHLine(gx+4, gy+3, tx-3-(gx+3), r, g, b); - drawHLine(tx+Length(it.title)*8, gy+3, mWidth-4, r, g, b); + drawHLine(gx+4, gy+3, tx-3-(gx+3), TGxRGBA.Create(r, g, b)); + drawHLine(tx+Length(it.title)*8, gy+3, mWidth-4, TGxRGBA.Create(r, g, b)); end; end; - drawText8(tx, gy, it.title, r, g, b); + drawText8(tx, gy, it.title, TGxRGBA.Create(r, g, b)); Inc(gy, 8); end; end; -function THCtlSimpleText.mouseEvent (var ev: THMouseEvent): Boolean; +function TUISimpleText.mouseEvent (var ev: THMouseEvent): Boolean; var lx, ly: Integer; begin @@ -1624,14 +1801,14 @@ begin end; -function THCtlSimpleText.keyEvent (var ev: THKeyEvent): Boolean; +function TUISimpleText.keyEvent (var ev: THKeyEvent): Boolean; begin result := inherited keyEvent(ev); end; // ////////////////////////////////////////////////////////////////////////// // -constructor THCtlCBListBox.Create (ax, ay: Integer); +constructor TUICBListBox.Create (ax, ay: Integer); begin mItems := nil; mCurIndex := -1; @@ -1639,14 +1816,14 @@ begin end; -destructor THCtlCBListBox.Destroy (); +destructor TUICBListBox.Destroy (); begin mItems := nil; inherited; end; -procedure THCtlCBListBox.appendItem (const atext: AnsiString; bv: PBoolean; aaction: TActionCB=nil); +procedure TUICBListBox.appendItem (const atext: AnsiString; bv: PBoolean; aaction: TActionCB=nil); var it: PItem; begin @@ -1661,7 +1838,7 @@ begin end; -procedure THCtlCBListBox.drawControl (gx, gy: Integer); +procedure TUICBListBox.drawControl (gx, gy: Integer); var f, tx: Integer; it: PItem; @@ -1669,32 +1846,32 @@ begin for f := 0 to High(mItems) do begin it := @mItems[f]; - if (mCurIndex = f) then fillRect(gx, gy, mWidth, 8, 0, 128, 0); + if (mCurIndex = f) then fillRect(gx, gy, mWidth, 8, TGxRGBA.Create(0, 128, 0)); if (it.varp <> nil) then begin - if it.varp^ then drawText8(gx, gy, '[x]', 255, 255, 255) else drawText8(gx, gy, '[ ]', 255, 255, 255); - drawText8(gx+3*8+2, gy, it.title, 255, 255, 0); + if it.varp^ then drawText8(gx, gy, '[x]', TGxRGBA.Create(255, 255, 255)) else drawText8(gx, gy, '[ ]', TGxRGBA.Create(255, 255, 255)); + drawText8(gx+3*8+2, gy, it.title, TGxRGBA.Create(255, 255, 0)); end else if (Length(it.title) > 0) then begin tx := gx+(mWidth-Length(it.title)*8) div 2; if (tx-3 > gx+4) then begin - drawHLine(gx+4, gy+3, tx-3-(gx+3), 255, 255, 255); - drawHLine(tx+Length(it.title)*8, gy+3, mWidth-4, 255, 255, 255); + drawHLine(gx+4, gy+3, tx-3-(gx+3), TGxRGBA.Create(255, 255, 255)); + drawHLine(tx+Length(it.title)*8, gy+3, mWidth-4, TGxRGBA.Create(255, 255, 255)); end; - drawText8(tx, gy, it.title, 255, 255, 255); + drawText8(tx, gy, it.title, TGxRGBA.Create(255, 255, 255)); end else begin - drawHLine(gx+4, gy+3, mWidth-8, 255, 255, 255); + drawHLine(gx+4, gy+3, mWidth-8, TGxRGBA.Create(255, 255, 255)); end; Inc(gy, 8); end; end; -function THCtlCBListBox.mouseEvent (var ev: THMouseEvent): Boolean; +function TUICBListBox.mouseEvent (var ev: THMouseEvent): Boolean; var lx, ly: Integer; it: PItem; @@ -1722,7 +1899,7 @@ begin end; -function THCtlCBListBox.keyEvent (var ev: THKeyEvent): Boolean; +function TUICBListBox.keyEvent (var ev: THKeyEvent): Boolean; var it: PItem; begin @@ -1788,23 +1965,24 @@ end; // ////////////////////////////////////////////////////////////////////////// // -constructor THCtlBox.Create (ahoriz: Boolean); +constructor TUIBox.Create (ahoriz: Boolean); begin inherited Create(); mHoriz := ahoriz; end; -function THCtlBox.parseProperty (const prname: AnsiString; par: TTextParser): Boolean; +procedure TUIBox.AfterConstruction (); begin - if (strEquCI1251(prname, 'orientation')) or (strEquCI1251(prname, 'orient')) then - begin - if (par.eatIdOrStr('horizontal', false)) or (par.eatIdOrStr('horiz', false)) then mHoriz := true - else if (par.eatIdOrStr('vertical', false)) or (par.eatIdOrStr('vert', false)) then mHoriz := false - else par.error('`horizontal` or `vertical` expected'); - result := true; - exit; - end; + inherited AfterConstruction(); + mCanFocus := false; + mCtl4Style := 'box'; +end; + + +function TUIBox.parseProperty (const prname: AnsiString; par: TTextParser): Boolean; +begin + if (parseOrientation(prname, par)) then begin result := true; exit; end; if (strEquCI1251(prname, 'frame')) then begin mHasFrame := parseBool(par); @@ -1814,7 +1992,7 @@ begin end; if (strEquCI1251(prname, 'title')) or (strEquCI1251(prname, 'caption')) then begin - mCaption := par.expectStrOrId(true); + mCaption := par.expectIdOrStr(true); mDefSize := TLaySize.Create(Length(mCaption)*8+3, 8); result := true; exit; @@ -1829,29 +2007,30 @@ begin end; -procedure THCtlBox.drawControl (gx, gy: Integer); +procedure TUIBox.drawControl (gx, gy: Integer); var - r, g, b: Integer; + cidx: Integer; tx: Integer; begin - if focused then begin r := 255; g := 255; b := 255; end else begin r := 255; g := 255; b := 0; end; + cidx := getColorIndex; + fillRect(gx, gy, mWidth, mHeight, mBackColor[cidx]); if mHasFrame then begin // draw frame - drawRectUI(gx+3, gy+3, mWidth-6, mHeight-6, r, g, b); + drawRectUI(gx+3, gy+3, mWidth-6, mHeight-6, mFrameColor[cidx]); end; // draw caption if (Length(mCaption) > 0) then begin setScissor(mFrameWidth+1, 0, mWidth-mFrameWidth-2, 8); tx := gx+((mWidth-Length(mCaption)*8) div 2); - if mHasFrame then fillRect(tx-2, gy, Length(mCaption)*8+3, 8, 0, 0, 128); - drawText8(tx, gy, mCaption, r, g, b); + if mHasFrame then fillRect(tx-2, gy, Length(mCaption)*8+3, 8, mBackColor[cidx]); + drawText8(tx, gy, mCaption, mFrameTextColor[cidx]); end; end; -function THCtlBox.mouseEvent (var ev: THMouseEvent): Boolean; +function TUIBox.mouseEvent (var ev: THMouseEvent): Boolean; var lx, ly: Integer; begin @@ -1864,14 +2043,14 @@ end; //TODO: navigation with arrow keys, according to box orientation -function THCtlBox.keyEvent (var ev: THKeyEvent): Boolean; +function TUIBox.keyEvent (var ev: THKeyEvent): Boolean; begin result := inherited keyEvent(ev); end; // ////////////////////////////////////////////////////////////////////////// // -procedure THCtlHBox.AfterConstruction (); +procedure TUIHBox.AfterConstruction (); begin inherited AfterConstruction(); mHoriz := true; @@ -1879,7 +2058,7 @@ end; // ////////////////////////////////////////////////////////////////////////// // -procedure THCtlVBox.AfterConstruction (); +procedure TUIVBox.AfterConstruction (); begin inherited AfterConstruction(); mHoriz := false; @@ -1887,54 +2066,103 @@ end; // ////////////////////////////////////////////////////////////////////////// // -constructor THCtlSpan.Create (); +procedure TUISpan.AfterConstruction (); begin - inherited Create(); + inherited AfterConstruction(); mExpand := true; + mCanFocus := false; + mCtl4Style := 'span'; end; -function THCtlSpan.parseProperty (const prname: AnsiString; par: TTextParser): Boolean; + +function TUISpan.parseProperty (const prname: AnsiString; par: TTextParser): Boolean; begin - if (strEquCI1251(prname, 'orientation')) or (strEquCI1251(prname, 'orient')) then - begin - if (par.eatIdOrStr('horizontal', false)) or (par.eatIdOrStr('horiz', false)) then mHoriz := true - else if (par.eatIdOrStr('vertical', false)) or (par.eatIdOrStr('vert', false)) then mHoriz := false - else par.error('`horizontal` or `vertical` expected'); - result := true; - exit; - end; + if (parseOrientation(prname, par)) then begin result := true; exit; end; result := inherited parseProperty(prname, par); end; -procedure THCtlSpan.drawControl (gx, gy: Integer); + +procedure TUISpan.drawControl (gx, gy: Integer); begin end; -procedure THCtlSpan.AfterConstruction (); +// ////////////////////////////////////////////////////////////////////// // +procedure TUILine.AfterConstruction (); begin inherited AfterConstruction(); - //mDefSize := TLaySize.Create(0, 8); mExpand := true; + mCanFocus := false; + mCtl4Style := 'line'; +end; + + +function TUILine.parseProperty (const prname: AnsiString; par: TTextParser): Boolean; +begin + if (parseOrientation(prname, par)) then begin result := true; exit; end; + result := inherited parseProperty(prname, par); +end; + + +procedure TUILine.drawControl (gx, gy: Integer); +var + cidx: Integer; +begin + cidx := getColorIndex; + if mHoriz then + begin + drawHLine(gx, gy+(mHeight div 2), mWidth, mTextColor[cidx]); + end + else + begin + drawVLine(gx+(mWidth div 2), gy, mHeight, mTextColor[cidx]); + end; end; // ////////////////////////////////////////////////////////////////////////// // -constructor THCtlTextLabel.Create (const atext: AnsiString); +procedure TUIHLine.AfterConstruction (); +begin + inherited AfterConstruction(); + mHoriz := true; + mDefSize.h := 1; +end; + + +// ////////////////////////////////////////////////////////////////////////// // +procedure TUIVLine.AfterConstruction (); +begin + inherited AfterConstruction(); + mHoriz := false; + mDefSize.w := 1; +end; + + +// ////////////////////////////////////////////////////////////////////////// // +constructor TUITextLabel.Create (const atext: AnsiString); begin inherited Create(); - mHAlign := -1; - mVAlign := 0; mText := atext; mDefSize := TLaySize.Create(Length(atext)*8, 8); end; -function THCtlTextLabel.parseProperty (const prname: AnsiString; par: TTextParser): Boolean; +procedure TUITextLabel.AfterConstruction (); +begin + inherited AfterConstruction(); + mHAlign := -1; + mVAlign := 0; + mCanFocus := false; + if (mDefSize.h <= 0) then mDefSize.h := 8; + mCtl4Style := 'label'; +end; + + +function TUITextLabel.parseProperty (const prname: AnsiString; par: TTextParser): Boolean; begin if (strEquCI1251(prname, 'title')) or (strEquCI1251(prname, 'caption')) then begin - mText := par.expectStrOrId(true); + mText := par.expectIdOrStr(true); mDefSize := TLaySize.Create(Length(mText)*8, 8); result := true; exit; @@ -1949,14 +2177,13 @@ begin end; -procedure THCtlTextLabel.drawControl (gx, gy: Integer); +procedure TUITextLabel.drawControl (gx, gy: Integer); var xpos, ypos: Integer; + cidx: Integer; begin - // debug - fillRect(gx, gy, mWidth, mHeight, 96, 96, 0); - drawRectUI(gx, gy, mWidth, mHeight, 96, 96, 96); - + cidx := getColorIndex; + fillRect(gx, gy, mWidth, mHeight, mBackColor[cidx]); if (Length(mText) > 0) then begin if (mHAlign < 0) then xpos := 0 @@ -1967,12 +2194,12 @@ begin else if (mVAlign > 0) then ypos := mHeight-8 else ypos := (mHeight-8) div 2; - drawText8(gx+xpos, gy+ypos, mText, 255, 255, 255); + drawText8(gx+xpos, gy+ypos, mText, mTextColor[cidx]); end; end; -function THCtlTextLabel.mouseEvent (var ev: THMouseEvent): Boolean; +function TUITextLabel.mouseEvent (var ev: THMouseEvent): Boolean; var lx, ly: Integer; begin @@ -1984,16 +2211,17 @@ begin end; -function THCtlTextLabel.keyEvent (var ev: THKeyEvent): Boolean; +function TUITextLabel.keyEvent (var ev: THKeyEvent): Boolean; begin result := inherited keyEvent(ev); end; initialization - registerCtlClass(THCtlBox, 'box'); - registerCtlClass(THCtlHBox, 'hbox'); - registerCtlClass(THCtlVBox, 'vbox'); - registerCtlClass(THCtlSpan, 'span'); - registerCtlClass(THCtlTextLabel, 'label'); + registerCtlClass(TUIHBox, 'hbox'); + registerCtlClass(TUIVBox, 'vbox'); + registerCtlClass(TUISpan, 'span'); + registerCtlClass(TUIHLine, 'hline'); + registerCtlClass(TUIVLine, 'vline'); + registerCtlClass(TUITextLabel, 'label'); end.