From 345e116f73d0e4b11593a94bee7d18b9e64572eb Mon Sep 17 00:00:00 2001 From: Ketmar Dark Date: Mon, 25 Sep 2017 00:18:39 +0300 Subject: [PATCH] HolmesUI: ui parser fixes; vbox layouter fixes (centering control); scissoring fixes --- src/gx/gh_flexlay.pas | 13 ++++--- src/gx/gh_ui.pas | 77 ++++++++++++++++++++++-------------------- src/gx/glgfx.pas | 22 ++++++++---- src/shared/xparser.pas | 8 +++++ 4 files changed, 73 insertions(+), 47 deletions(-) diff --git a/src/gx/gh_flexlay.pas b/src/gx/gh_flexlay.pas index f948702..79c6a5c 100644 --- a/src/gx/gh_flexlay.pas +++ b/src/gx/gh_flexlay.pas @@ -502,6 +502,7 @@ var grp: PLayGroup; maxsz: Integer; cidx: LayControlIdx; + ct: PLayControl; mr: TLayMargins; begin // reset all 'laywrap' flags for controls, set initial 'startsize' @@ -527,15 +528,17 @@ begin for c := 0 to High(grp.ctls) do begin cidx := grp.ctls[c]; - if (maxsz < ctlist[cidx].startsize[gtype]) then maxsz := ctlist[cidx].startsize[gtype]; + ct := @ctlist[cidx]; + if (maxsz < ct.startsize[gtype]) then maxsz := ct.startsize[gtype]; end; for c := 0 to High(grp.ctls) do begin cidx := grp.ctls[c]; - if (maxsz <> ctlist[cidx].startsize[gtype]) then + ct := @ctlist[cidx]; + if (maxsz <> ct.startsize[gtype]) then begin needRecalcMaxSize := true; - ctlist[cidx].startsize[gtype] := maxsz; + ct.startsize[gtype] := maxsz; end; end; end; @@ -731,7 +734,7 @@ begin // expand or align if (lc.expand) then lc.desiredsize.w := nmin(lc.maxsize.w, me.desiredsize.w-me.margins.vert) // expand else if (lc.aligndir > 0) then lc.desiredpos.x := me.desiredsize.w-me.margins.right-lc.desiredsize.w // right align - else if (lc.aligndir = 0) then lc.desiredpos.x := (me.desiredsize.w-me.margins.horiz-lc.desiredsize.w) div 2; // center + else if (lc.aligndir = 0) then lc.desiredpos.x := (me.desiredsize.w-lc.desiredsize.w) div 2; // center if (not osz.equals(lc.desiredsize)) then begin if (lc.inGroup) then groupElementChanged := true; @@ -833,7 +836,7 @@ begin end; for c := 0 to 1 do begin - if (ct.maxsize[c] <= 0) then continue; + if (ct.maxsize[c] < 0) then continue; if (ct.desiredsize[c] > ct.maxsize[c]) then begin //writeln('ctl #', f, '; dimension #', c, ': desired=', ctlist[f].desiredsize[c], '; max=', ctlist[f].maxsize[c]); diff --git a/src/gx/gh_ui.pas b/src/gx/gh_ui.pas index a8593ad..a467408 100644 --- a/src/gx/gh_ui.pas +++ b/src/gx/gh_ui.pas @@ -37,6 +37,7 @@ type private mParent: THControl; + mId: AnsiString; mX, mY: Integer; mWidth, mHeight: Integer; mFrameWidth, mFrameHeight: Integer; @@ -159,8 +160,7 @@ type public constructor Create (); - constructor Create (aparent: THControl); - constructor Create (ax, ay, aw, ah: Integer; aparent: THControl=nil); + constructor Create (ax, ay, aw, ah: Integer); destructor Destroy (); override; // `sx` and `sy` are screen coordinates @@ -191,6 +191,7 @@ type procedure appendChild (ctl: THControl); virtual; public + property id: AnsiString read mId; property x0: Integer read mX; property y0: Integer read mY; property height: Integer read mHeight; @@ -250,7 +251,7 @@ type mItems: array of TItem; public - constructor Create (ax, ay: Integer; aparent: THControl=nil); + constructor Create (ax, ay: Integer); destructor Destroy (); override; procedure appendItem (const atext: AnsiString; acentered: Boolean=false; ahline: Boolean=false); @@ -276,7 +277,7 @@ type mCurIndex: Integer; public - constructor Create (ax, ay: Integer; aparent: THControl=nil); + constructor Create (ax, ay: Integer); destructor Destroy (); override; procedure appendItem (const atext: AnsiString; bv: PBoolean; aaction: TActionCB=nil); @@ -294,8 +295,7 @@ type mCaption: AnsiString; public - constructor Create (ahoriz: Boolean; aparent: THControl=nil); - //destructor Destroy (); override; + constructor Create (ahoriz: Boolean); function parseProperty (const prname: AnsiString; par: TTextParser): Boolean; override; @@ -307,12 +307,12 @@ type THCtlHBox = class(THCtlBox) public - constructor Create (aparent: THControl=nil); + procedure AfterConstruction (); override; // so it will be correctly initialized when created from parser end; THCtlVBox = class(THCtlBox) public - constructor Create (aparent: THControl=nil); + procedure AfterConstruction (); override; // so it will be correctly initialized when created from parser end; @@ -323,7 +323,7 @@ type mVAlign: Integer; // -1: top; 0: center; 1: bottom; default: center public - constructor Create (const atext: AnsiString; aparent: THControl=nil); + constructor Create (const atext: AnsiString); //destructor Destroy (); override; function parseProperty (const prname: AnsiString; par: TTextParser): Boolean; override; @@ -618,9 +618,9 @@ begin end; -constructor THControl.Create (ax, ay, aw, ah: Integer; aparent: THControl=nil); +constructor THControl.Create (ax, ay, aw, ah: Integer); begin - Create(aparent); + Create(); mX := ax; mY := ay; mWidth := aw; @@ -628,13 +628,6 @@ begin end; -constructor THControl.Create (aparent: THControl); -begin - Create(); - mParent := aparent; -end; - - destructor THControl.Destroy (); var f, c: Integer; @@ -685,6 +678,7 @@ begin end; procedure THControl.setActualSizePos (constref apos: TLayPos; constref asize: TLaySize); inline; begin + //writeln(self.className, '; pos=', apos.toString, '; size=', asize.toString); if (mParent <> nil) then begin mX := apos.x; @@ -838,7 +832,7 @@ begin if (not par.eatDelim('{')) then exit; while (not par.eatDelim('}')) do begin - if (par.tokType <> par.TTId) and (par.tokType <> par.TTStr) then par.error('property name expected'); + if (not par.isIdOrStr) then par.error('property name expected'); pn := par.tokStr; par.skipToken(); par.eatDelim(':'); // optional @@ -856,13 +850,14 @@ begin par.expectDelim('{'); while (not par.eatDelim('}')) do begin - if (par.tokType <> par.TTId) then par.error('control name expected'); + if (not par.isIdOrStr) then par.error('control name expected'); cc := findCtlClass(par.tokStr); if (cc = nil) then par.errorfmt('unknown control name: ''%s''', [par.tokStr]); //writeln('children for <', par.tokStr, '>: <', cc.className, '>'); par.skipToken(); par.eatDelim(':'); // optional - ctl := cc.Create(nil); + ctl := cc.Create(); + //writeln(' mHoriz=', ctl.mHoriz); try ctl.parseProperties(par); except @@ -879,6 +874,7 @@ end; function THControl.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, 'flex')) then begin flex := par.expectInt(); exit; end; // sizes if (strEquCI1251(prname, 'defsize')) then begin mDefSize := parseSize(par); exit; end; @@ -1179,8 +1175,7 @@ begin y := trunc(y*gh_ui_scale); w := trunc(w*gh_ui_scale); h := trunc(h*gh_ui_scale); - //y := gWinSizeY-(y+h); - scis.setRect(x, y, w, h); + scis.combineRect(x, y, w, h); end; @@ -1199,9 +1194,16 @@ end; procedure THControl.setScissor (lx, ly, lw, lh: Integer); var x, y: Integer; + //ox, oy, ow, oh: 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; + //ox := lx; oy := ly; ow := lw; oh := lh; + if not intersectRect(lx, ly, lw, lh, 0, 0, mWidth, mHeight) then + begin + //writeln('oops: <', self.className, '>: old=(', ox, ',', oy, ')-[', ow, ',', oh, ']'); + glScissor(0, 0, 0, 0); + exit; + end; x := lx; y := ly; toGlobal(x, y); @@ -1245,6 +1247,7 @@ end; procedure THControl.drawControlPost (sx, sy: Integer); begin + // shadow if mDrawShadow and (mWidth > 0) and (mHeight > 0) then begin setScissorGLInternal(sx+8, sy+8, mWidth, mHeight); @@ -1328,7 +1331,7 @@ end; // ////////////////////////////////////////////////////////////////////////// // constructor THTopWindow.Create (const atitle: AnsiString; ax, ay: Integer; aw: Integer=-1; ah: Integer=-1); begin - inherited Create(ax, ay, aw, ah, nil); + inherited Create(ax, ay, aw, ah); mFrameWidth := 8; mFrameHeight := 8; mTitle := atitle; @@ -1527,7 +1530,7 @@ end; // ////////////////////////////////////////////////////////////////////////// // -constructor THCtlSimpleText.Create (ax, ay: Integer; aparent: THControl=nil); +constructor THCtlSimpleText.Create (ax, ay: Integer); begin mItems := nil; inherited Create(ax, ay, 4, 4); @@ -1609,7 +1612,7 @@ end; // ////////////////////////////////////////////////////////////////////////// // -constructor THCtlCBListBox.Create (ax, ay: Integer; aparent: THControl=nil); +constructor THCtlCBListBox.Create (ax, ay: Integer); begin mItems := nil; mCurIndex := -1; @@ -1768,9 +1771,9 @@ end; // ////////////////////////////////////////////////////////////////////////// // -constructor THCtlBox.Create (ahoriz: Boolean; aparent: THControl=nil); +constructor THCtlBox.Create (ahoriz: Boolean); begin - inherited Create(aparent); + inherited Create(); mHoriz := ahoriz; end; @@ -1829,6 +1832,7 @@ begin end; end; + function THCtlBox.mouseEvent (var ev: THMouseEvent): Boolean; var lx, ly: Integer; @@ -1851,23 +1855,24 @@ end; // ////////////////////////////////////////////////////////////////////////// // -constructor THCtlHBox.Create (aparent: THControl=nil); +procedure THCtlHBox.AfterConstruction (); begin - inherited Create(true, aparent); + inherited AfterConstruction(); + mHoriz := true; end; // ////////////////////////////////////////////////////////////////////////// // -constructor THCtlVBox.Create (aparent: THControl=nil); +procedure THCtlVBox.AfterConstruction (); begin - inherited Create(false, aparent); + inherited AfterConstruction(); + mHoriz := false; end; - // ////////////////////////////////////////////////////////////////////////// // -constructor THCtlTextLabel.Create (const atext: AnsiString; aparent: THControl=nil); +constructor THCtlTextLabel.Create (const atext: AnsiString); begin - inherited Create(aparent); + inherited Create(); mHAlign := -1; mVAlign := 0; mText := atext; diff --git a/src/gx/glgfx.pas b/src/gx/glgfx.pas index d6f8763..61fa5f6 100644 --- a/src/gx/glgfx.pas +++ b/src/gx/glgfx.pas @@ -119,7 +119,7 @@ type procedure restore (); // set new scissor rect, bounded by the saved scissor rect - procedure setRect (x, y, w, h: Integer); + procedure combineRect (x, y, w, h: Integer); end; @@ -1072,11 +1072,21 @@ begin if wassc then glEnable(GL_SCISSOR_TEST) else glDisable(GL_SCISSOR_TEST); end; -procedure TScissorSave.setRect (x, y, w, h: Integer); +procedure TScissorSave.combineRect (x, y, w, h: Integer); +//var ox, oy, ow, oh: Integer; begin if (w < 1) or (h < 1) then begin glScissor(0, 0, 0, 0); exit; end; y := gScrHeight-(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); + //ox := x; oy := y; ow := w; oh := h; + if not intersectRect(x, y, w, h, scxywh[0], scxywh[1], scxywh[2], scxywh[3]) then + begin + //writeln('oops: COMBINE: old=(', ox, ',', oy, ')-(', ox+ow-1, ',', oy+oh-1, '); sci: (', scxywh[0], ',', scxywh[1], ')-(', scxywh[0]+scxywh[2]-1, ',', scxywh[1]+scxywh[3]-1, ')'); + glScissor(0, 0, 0, 0); + end + else + begin + glScissor(x, y, w, h); + end; end; //TODO: overflow checks @@ -1087,11 +1097,11 @@ 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 (ex0 <= x1) or (ey0 <= y1) or (x1+w1 <= x0) or (y1+h1 <= y0) then exit; + if (x0 >= x1+w1) or (y0 >= y1+h1) or (x1 >= ex0) or (y1 >= ey0) then exit; + // ok, intersects if (x0 < x1) then x0 := x1; if (y0 < y1) then y0 := y1; if (ex0 > x1+w1) then ex0 := x1+w1; diff --git a/src/shared/xparser.pas b/src/shared/xparser.pas index b985f1a..0f2c2ec 100644 --- a/src/shared/xparser.pas +++ b/src/shared/xparser.pas @@ -106,6 +106,8 @@ type function skipToken1 (): Boolean; {$ENDIF} + function isIdOrStr (): Boolean; inline; + function expectId (): AnsiString; procedure expectId (const aid: AnsiString; caseSens: Boolean=true); function eatId (const aid: AnsiString; caseSens: Boolean=true): Boolean; @@ -650,6 +652,12 @@ begin end; +function TTextParser.isIdOrStr (): Boolean; inline; +begin + result := (mTokType = TTId) or (mTokType = TTStr); +end; + + function TTextParser.expectId (): AnsiString; begin if (mTokType <> TTId) then raise Exception.Create('identifier expected'); -- 2.29.2