|
@@ -15,14 +15,23 @@ unit Fresnel.CSSStyleInspector;
|
|
|
interface
|
|
|
|
|
|
uses
|
|
|
- Classes, SysUtils, FPImage, fpCSSTree, fpCSSResParser, fpCSSResolver,
|
|
|
+ Classes, SysUtils, Math, FPImage, fpCSSTree, fpCSSResParser, fpCSSResolver,
|
|
|
Fresnel.DOM, Fresnel.Classes, Fresnel.Controls, Fresnel.Events, FCL.Events;
|
|
|
|
|
|
type
|
|
|
|
|
|
- { TCSSInspBoxModell }
|
|
|
+ { TCSSInspDropArrow }
|
|
|
|
|
|
- TCSSInspBoxModell = class(TDiv)
|
|
|
+ TCSSInspDropArrow = class(TSpan)
|
|
|
+ protected
|
|
|
+ procedure DoRender(aRenderer: IFresnelRenderer); override;
|
|
|
+ public
|
|
|
+ procedure ComputeCSSLayoutFinished; override;
|
|
|
+ end;
|
|
|
+
|
|
|
+ { TCSSInspBoxModel }
|
|
|
+
|
|
|
+ TCSSInspBoxModel = class(TDiv)
|
|
|
private
|
|
|
FBorderColor: TFPColor;
|
|
|
FContentColor: TFPColor;
|
|
@@ -49,7 +58,7 @@ type
|
|
|
|
|
|
TCSSStyleInspector = class(TDiv)
|
|
|
private
|
|
|
- FBoxModellDiv: TCSSInspBoxModell;
|
|
|
+ FBoxModelDiv: TCSSInspBoxModel;
|
|
|
FRulesDiv: TDiv;
|
|
|
FLock: integer;
|
|
|
FInspectNeeded: boolean;
|
|
@@ -61,8 +70,11 @@ type
|
|
|
procedure ShowNothingSelected;
|
|
|
procedure UpdateRule(Row: integer; Selectors, Origin: TCSSString; RuleEl: TCSSRuleElement);
|
|
|
procedure UpdateDeclaration(RuleDiv: TDiv; Row: integer; DeclEl: TCSSDeclarationElement);
|
|
|
- function UpdateDeclaration(DeclDiv: TDIv; DeclEl: TCSSDeclarationElement; var Index: integer): boolean;
|
|
|
- procedure UpdateLabel(DeclDiv: TDiv; Index: integer; aClass, aCaption: string);
|
|
|
+ function UpdateDeclaration(DeclDiv: TDiv; DeclEl: TCSSDeclarationElement; var Index: integer): boolean;
|
|
|
+ procedure UpdateLongHand(AttrID: TCSSNumericalID; aValue: string; DeclDiv: TDiv; Index: integer);
|
|
|
+ function UpdateElement(DeclDiv: TDiv; Index: integer; ElClass: TFresnelElementClass; const aCSSClass: string): TFresnelElement;
|
|
|
+ procedure UpdateLabel(DeclDiv: TDiv; Index: integer; const aClass, aCaption: string);
|
|
|
+ procedure UpdateArrow(DeclDiv: TDiv; Index: integer; const aClass: string);
|
|
|
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
|
|
|
public
|
|
|
const
|
|
@@ -77,10 +89,12 @@ type
|
|
|
DeclDivClass = 'CSSStyleInspDecl';
|
|
|
DeclKeyLabelClass = 'CSSStyleInspKey';
|
|
|
DeclColonLabelClass = 'CSSStyleInspColon';
|
|
|
+ DeclDropArrowLabelClass = 'CSSStyleInspDropArrow';
|
|
|
DeclValueLabelClass = 'CSSStyleInspValue';
|
|
|
DeclSemicolonLabelClass = 'CSSStyleInspSemicolon';
|
|
|
+ DeclLonghandDivClass = 'CSSStyleInspLonghand';
|
|
|
SkippedClass = 'CSSStyleInspSkipped';
|
|
|
- BoxModellDivClass = 'CSSStyleInspBoxModell';
|
|
|
+ BoxModelDivClass = 'CSSStyleInspBoxModel';
|
|
|
//
|
|
|
ElementStyleCaption = 'Element.Style';
|
|
|
public
|
|
@@ -91,28 +105,59 @@ type
|
|
|
procedure EndUpdate;
|
|
|
property Target: TFresnelElement read FTarget write SetTarget;
|
|
|
property RulesDiv: TDiv read FRulesDiv;
|
|
|
- property BoxModellDiv: TCSSInspBoxModell read FBoxModellDiv;
|
|
|
+ property BoxModellDiv: TCSSInspBoxModel read FBoxModelDiv;
|
|
|
end;
|
|
|
|
|
|
implementation
|
|
|
|
|
|
-{ TCSSInspBoxModell }
|
|
|
+{ TCSSInspDropArrow }
|
|
|
|
|
|
-procedure TCSSInspBoxModell.SetMarginColor(AValue: TFPColor);
|
|
|
+procedure TCSSInspDropArrow.DoRender(aRenderer: IFresnelRenderer);
|
|
|
+var
|
|
|
+ R: TFresnelRect;
|
|
|
+ Points: TFresnelPointArray;
|
|
|
+ w, h: TFresnelLength;
|
|
|
+begin
|
|
|
+ R:=UsedContentBox;
|
|
|
+ writeln('AAA3 TCSSInspDropArrow.Render ',R.ToString);
|
|
|
+
|
|
|
+ h:=Min(R.Width,R.Height);
|
|
|
+ w:=h*0.66;
|
|
|
+
|
|
|
+ SetLength(Points,3);
|
|
|
+ Points[0].X:=R.Left+(r.Width-w)/2;
|
|
|
+ Points[0].Y:=R.Top+(r.Height-h)/2;
|
|
|
+ Points[1].X:=Points[0].X+w;
|
|
|
+ Points[1].Y:=(R.Top+R.Bottom)/2;
|
|
|
+ Points[2].X:=Points[0].X;
|
|
|
+ Points[2].Y:=R.Bottom-(r.Height-h)/2;
|
|
|
+
|
|
|
+ aRenderer.Polygon(colWhite,@Points[0],3);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TCSSInspDropArrow.ComputeCSSLayoutFinished;
|
|
|
+begin
|
|
|
+ inherited ComputeCSSLayoutFinished;
|
|
|
+ writeln('TCSSInspDropArrow.ComputeCSSLayoutFinished ',UsedBorderBox.ToString);
|
|
|
+end;
|
|
|
+
|
|
|
+{ TCSSInspBoxModel }
|
|
|
+
|
|
|
+procedure TCSSInspBoxModel.SetMarginColor(AValue: TFPColor);
|
|
|
begin
|
|
|
if FMarginColor=AValue then Exit;
|
|
|
FMarginColor:=AValue;
|
|
|
Invalidate;
|
|
|
end;
|
|
|
|
|
|
-procedure TCSSInspBoxModell.SetPaddingColor(AValue: TFPColor);
|
|
|
+procedure TCSSInspBoxModel.SetPaddingColor(AValue: TFPColor);
|
|
|
begin
|
|
|
if FPaddingColor=AValue then Exit;
|
|
|
FPaddingColor:=AValue;
|
|
|
Invalidate;
|
|
|
end;
|
|
|
|
|
|
-function TCSSInspBoxModell.FloatToCaption(f: TFresnelLength): string;
|
|
|
+function TCSSInspBoxModel.FloatToCaption(f: TFresnelLength): string;
|
|
|
var
|
|
|
p, EndP: SizeInt;
|
|
|
begin
|
|
@@ -129,21 +174,21 @@ begin
|
|
|
end;
|
|
|
end;
|
|
|
|
|
|
-procedure TCSSInspBoxModell.SetBorderColor(AValue: TFPColor);
|
|
|
+procedure TCSSInspBoxModel.SetBorderColor(AValue: TFPColor);
|
|
|
begin
|
|
|
if FBorderColor=AValue then Exit;
|
|
|
FBorderColor:=AValue;
|
|
|
Invalidate;
|
|
|
end;
|
|
|
|
|
|
-procedure TCSSInspBoxModell.SetContentColor(AValue: TFPColor);
|
|
|
+procedure TCSSInspBoxModel.SetContentColor(AValue: TFPColor);
|
|
|
begin
|
|
|
if FContentColor=AValue then Exit;
|
|
|
FContentColor:=AValue;
|
|
|
Invalidate;
|
|
|
end;
|
|
|
|
|
|
-procedure TCSSInspBoxModell.DoRender(aRenderer: IFresnelRenderer);
|
|
|
+procedure TCSSInspBoxModel.DoRender(aRenderer: IFresnelRenderer);
|
|
|
var
|
|
|
MarginRect, BorderRect, PaddingRect, ContentRect: TFresnelRect;
|
|
|
L, T, W, cx, cy: TFresnelLength;
|
|
@@ -170,7 +215,7 @@ begin
|
|
|
L:=UsedClientBox.Left;
|
|
|
T:=UsedClientBox.Top;
|
|
|
W:=UsedClientBox.Width;
|
|
|
- writeln('TFresnelBoxModell.DoRender ',UsedClientBox.ToString);
|
|
|
+ //writeln('TFresnelBoxModell.DoRender ',UsedClientBox.ToString);
|
|
|
F:=Font;
|
|
|
Size0:=F.TextSize('0');
|
|
|
TextCol:=colWhite;
|
|
@@ -257,7 +302,7 @@ begin
|
|
|
aRenderer.TextOut(cx-MarginBottomSize.X*0.5,MarginRect.Bottom-Size0.Y*1.2,F,TextCol,MarginBottomCaption);
|
|
|
end;
|
|
|
|
|
|
-constructor TCSSInspBoxModell.Create(AOwner: TComponent);
|
|
|
+constructor TCSSInspBoxModel.Create(AOwner: TComponent);
|
|
|
begin
|
|
|
inherited Create(AOwner);
|
|
|
FMarginColor:=FPColor($bbbb,$bbbb,0);
|
|
@@ -476,13 +521,9 @@ end;
|
|
|
procedure TCSSStyleInspector.UpdateDeclaration(RuleDiv: TDiv; Row: integer;
|
|
|
DeclEl: TCSSDeclarationElement);
|
|
|
var
|
|
|
- KeyEl: TCSSElement;
|
|
|
- ResolvedKeyEl: TCSSResolvedIdentifierElement;
|
|
|
ValueTxt, KeyTxt, ValueCaption: String;
|
|
|
i, Index: Integer;
|
|
|
DeclDiv: TDiv;
|
|
|
- KeyData: TCSSAttributeKeyData;
|
|
|
- TargetResolver: TCSSResolver;
|
|
|
begin
|
|
|
// add or update div
|
|
|
if Row<RuleDiv.NodeCount-1 then // -1 for the footer
|
|
@@ -527,7 +568,7 @@ begin
|
|
|
DeclDiv.Nodes[DeclDiv.NodeCount-1].Free;
|
|
|
end;
|
|
|
|
|
|
-function TCSSStyleInspector.UpdateDeclaration(DeclDiv: TDIv;
|
|
|
+function TCSSStyleInspector.UpdateDeclaration(DeclDiv: TDiv;
|
|
|
DeclEl: TCSSDeclarationElement; var Index: integer): boolean;
|
|
|
var
|
|
|
KeyEl: TCSSElement;
|
|
@@ -538,6 +579,8 @@ var
|
|
|
ValueTxt, ValueCaption: String;
|
|
|
i: Integer;
|
|
|
KeyTxt: TCSSString;
|
|
|
+ AttrIDs: TCSSNumericalIDArray;
|
|
|
+ Values: TCSSStringArray;
|
|
|
begin
|
|
|
Result:=false;
|
|
|
if (DeclEl.KeyCount<>1) then
|
|
@@ -578,49 +621,102 @@ begin
|
|
|
UpdateLabel(DeclDiv,Index,DeclColonLabelClass,':');
|
|
|
inc(Index);
|
|
|
|
|
|
-
|
|
|
+ if length(Desc.CompProps)>0 then
|
|
|
+ begin
|
|
|
+ // shorthand
|
|
|
+ UpdateArrow(DeclDiv,Index,DeclDropArrowLabelClass);
|
|
|
+ inc(Index);
|
|
|
+ end;
|
|
|
|
|
|
UpdateLabel(DeclDiv,Index,DeclValueLabelClass,ValueCaption);
|
|
|
inc(Index);
|
|
|
UpdateLabel(DeclDiv,Index,DeclSemicolonLabelClass,';');
|
|
|
inc(Index);
|
|
|
|
|
|
+ if (length(Desc.CompProps)>0) and Assigned(Desc.OnSplitShorthand) then
|
|
|
+ begin
|
|
|
+ // shorthand: add longhands
|
|
|
+ TargetResolver.InitParseAttr(Desc,nil,ValueTxt);
|
|
|
+ AttrIDs:=[];
|
|
|
+ Values:=[];
|
|
|
+ Desc.OnSplitShorthand(TargetResolver,AttrIDs,Values);
|
|
|
+
|
|
|
+ for i:=0 to length(AttrIDs)-1 do
|
|
|
+ begin
|
|
|
+ UpdateLongHand(AttrIDs[i],Values[i],DeclDiv,Index);
|
|
|
+ inc(Index);
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+
|
|
|
// todo: split shorthands
|
|
|
// todo: check if overriden
|
|
|
end;
|
|
|
|
|
|
-procedure TCSSStyleInspector.UpdateLabel(DeclDiv: TDiv; Index: integer; aClass, aCaption: string);
|
|
|
+procedure TCSSStyleInspector.UpdateLongHand(AttrID: TCSSNumericalID;
|
|
|
+ aValue: string; DeclDiv: TDiv; Index: integer);
|
|
|
+var
|
|
|
+ LHDiv: TDiv;
|
|
|
+ SubIndex: Integer;
|
|
|
+ Desc: TCSSAttributeDesc;
|
|
|
+begin
|
|
|
+ Desc:=Target.Resolver.GetAttributeDesc(AttrID);
|
|
|
+
|
|
|
+ LHDiv:=TDiv(UpdateElement(DeclDiv,Index,TDiv,DeclLonghandDivClass));
|
|
|
+ SubIndex:=0;
|
|
|
+ UpdateLabel(LHDiv,SubIndex,DeclKeyLabelClass,Desc.Name);
|
|
|
+ inc(SubIndex);
|
|
|
+ UpdateLabel(LHDiv,SubIndex,DeclColonLabelClass,':');
|
|
|
+ inc(SubIndex);
|
|
|
+ UpdateLabel(LHDiv,SubIndex,DeclValueLabelClass,aValue);
|
|
|
+ inc(SubIndex);
|
|
|
+ UpdateLabel(LHDiv,SubIndex,DeclSemicolonLabelClass,';');
|
|
|
+ inc(SubIndex);
|
|
|
+end;
|
|
|
+
|
|
|
+function TCSSStyleInspector.UpdateElement(DeclDiv: TDiv; Index: integer;
|
|
|
+ ElClass: TFresnelElementClass; const aCSSClass: string): TFresnelElement;
|
|
|
var
|
|
|
- aLabel: TLabel;
|
|
|
El: TFresnelElement;
|
|
|
begin
|
|
|
- //writeln('TCSSStyleInspector.UpdateLabel ',Index,' "',aClass,'" "',aCaption,'"');
|
|
|
if Index=DeclDiv.NodeCount then
|
|
|
begin
|
|
|
// add
|
|
|
- aLabel:=TLabel.Create(Self);
|
|
|
- aLabel.CSSClasses.Text:=aClass;
|
|
|
- aLabel.Caption:=aCaption;
|
|
|
- aLabel.Parent:=DeclDiv;
|
|
|
+ Result:=ElClass.Create(Self);
|
|
|
+ Result.CSSClasses.Text:=aCSSClass;
|
|
|
+ Result.Parent:=DeclDiv;
|
|
|
end else begin
|
|
|
// update
|
|
|
El:=DeclDiv.Nodes[Index];
|
|
|
- if El is TLabel then
|
|
|
+ if El is ElClass then
|
|
|
begin
|
|
|
- // update label
|
|
|
- aLabel:=TLabel(El);
|
|
|
- aLabel.CSSClasses.Text:=aClass;
|
|
|
- aLabel.Caption:=aCaption;
|
|
|
+ // update
|
|
|
+ Result:=El;
|
|
|
+ Result.CSSClasses.Text:=aCSSClass;
|
|
|
end else begin
|
|
|
- // insert label
|
|
|
- aLabel:=TLabel.Create(Self);
|
|
|
- aLabel.CSSClasses.Text:=aClass;
|
|
|
- aLabel.Caption:=aCaption;
|
|
|
- DeclDiv.InsertBefore(aLabel,El);
|
|
|
+ // insert
|
|
|
+ Result:=ElClass.Create(Self);
|
|
|
+ Result.CSSClasses.Text:=aCSSClass;
|
|
|
+ DeclDiv.InsertBefore(Result,El);
|
|
|
end;
|
|
|
end;
|
|
|
end;
|
|
|
|
|
|
+procedure TCSSStyleInspector.UpdateLabel(DeclDiv: TDiv; Index: integer;
|
|
|
+ const aClass, aCaption: string);
|
|
|
+var
|
|
|
+ aLabel: TLabel;
|
|
|
+begin
|
|
|
+ aLabel:=TLabel(UpdateElement(DeclDiv,Index,TLabel,aClass));
|
|
|
+ aLabel.Caption:=aCaption;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TCSSStyleInspector.UpdateArrow(DeclDiv: TDiv; Index: integer;
|
|
|
+ const aClass: string);
|
|
|
+begin
|
|
|
+ writeln('AAA2 TCSSStyleInspector.UpdateArrow ');
|
|
|
+ UpdateElement(DeclDiv,Index,TCSSInspDropArrow,aClass);
|
|
|
+end;
|
|
|
+
|
|
|
procedure TCSSStyleInspector.Notification(AComponent: TComponent; Operation: TOperation);
|
|
|
begin
|
|
|
inherited Notification(AComponent, Operation);
|
|
@@ -641,9 +737,9 @@ begin
|
|
|
Parent:=Self;
|
|
|
end;
|
|
|
|
|
|
- FBoxModellDiv:=TCSSInspBoxModell.Create(Self);
|
|
|
+ FBoxModelDiv:=TCSSInspBoxModel.Create(Self);
|
|
|
with BoxModellDiv do begin
|
|
|
- CSSClasses.Text:=BoxModellDivClass;
|
|
|
+ CSSClasses.Text:=BoxModelDivClass;
|
|
|
Parent:=Self;
|
|
|
end;
|
|
|
|
|
@@ -666,10 +762,12 @@ begin
|
|
|
+'.'+DeclDivClass+' { margin-left: 2ch; }'+LineEnding
|
|
|
+'.'+DeclKeyLabelClass+' { color: cyan; }'+LineEnding
|
|
|
+'.'+DeclColonLabelClass+' { margin-right: 1ch; }'+LineEnding
|
|
|
+ +'.'+DeclDropArrowLabelClass+' { display: inline block; width: 0.8em; height: 0.8em; }'+LineEnding
|
|
|
+'.'+DeclValueLabelClass+' { color: #d8e; }'+LineEnding
|
|
|
//+'.'+DeclSemicolonLabelClass+' { font-weight: bold; }'+LineEnding
|
|
|
+ +'.'+DeclLonghandDivClass+' { margin-left: 2ch; }'+LineEnding
|
|
|
+'.'+SkippedClass+' { color: #aaa; }'+LineEnding
|
|
|
- +'.'+BoxModellDivClass+' { color: #fff; font-size: 10px; background-color: #222; padding: 6px; height: 12em; }'+LineEnding
|
|
|
+ +'.'+BoxModelDivClass+' { color: #fff; font-size: 10px; background-color: #222; padding: 6px; height: 12em; }'+LineEnding
|
|
|
;
|
|
|
end;
|
|
|
|