소스 검색

basic text layout

Johann ELSASS 5 년 전
부모
커밋
03b4a6f123
7개의 변경된 파일99개의 추가작업 그리고 51개의 파일을 삭제
  1. 27 12
      bctools.pas
  2. 10 2
      bctypes.pas
  3. 1 5
      bgracolortheme.pas
  4. 1 3
      bgraimagetheme.pas
  5. 48 26
      bgrasvgtheme.pas
  6. 10 3
      bgratheme.pas
  7. 2 0
      test/test_bgrathemes/umain.pas

+ 27 - 12
bctools.pas

@@ -38,8 +38,11 @@ procedure GetGlyphActualLayout(ACaption: string; AFont: TBCFont;
 // Specify the flag AOldPlacement to have the old (buggy) version
 function ComputeGlyphPosition(var rAvail: TRect;
   AGlyph: TBitmap; AGlyphAlignment: TBCAlignment; AGlyphMargin: integer;
-  ACaption: string; AFont: TBCFont; AOldPlacement: boolean;
-  AGlyphScale: Single = 1): TRect;
+  ACaption: string; AFont: TBCFont; AOldPlacement: boolean = false;
+  AGlyphScale: Single = 1): TRect; overload;
+function ComputeGlyphPosition(var rAvail: TRect;
+  gw, gh: integer; AGlyphAlignment: TBCAlignment; AGlyphMargin: integer;
+  ACaption: string; AFont: TBCFont; AOldPlacement: boolean = false): TRect; overload;
 // This method correct TRect to border width. As far as border width is bigger,
 // BGRA drawing rectangle with offset (half border width)
 procedure CalculateBorderRect(ABorder: TBCBorder; var ARect: TRect);
@@ -75,6 +78,24 @@ implementation
 
 uses BGRAPolygon, BGRAFillInfo, BGRAText, math, BGRAUTF8, LazUTF8;
 
+function ComputeGlyphPosition(var rAvail: TRect; AGlyph: TBitmap;
+  AGlyphAlignment: TBCAlignment; AGlyphMargin: integer; ACaption: string;
+  AFont: TBCFont; AOldPlacement: boolean; AGlyphScale: Single): TRect;
+var gw, gh: integer;
+begin
+  if Assigned(AGlyph) and not AGlyph.Empty then
+  begin
+    gw := round(AGlyph.Width * AGlyphScale);
+    gh := round(AGlyph.Height * AGlyphScale);
+  end else
+  begin
+    gw := 0;
+    gh := 0;
+  end;
+  result := ComputeGlyphPosition(rAvail, gw, gh, AGlyphAlignment, AGlyphMargin, ACaption,
+    AFont, AOldPlacement);
+end;
+
 procedure CalculateBorderRect(ABorder: TBCBorder; var ARect: TRect);
 var w: integer;
 begin
@@ -443,11 +464,10 @@ begin
 end;
 
 function ComputeGlyphPosition(var rAvail: TRect;
-  AGlyph: TBitmap; AGlyphAlignment: TBCAlignment; AGlyphMargin: integer;
-  ACaption: string; AFont: TBCFont; AOldPlacement: boolean;
-  AGlyphScale: Single = 1): TRect;
+  gw, gh: integer; AGlyphAlignment: TBCAlignment; AGlyphMargin: integer;
+  ACaption: string; AFont: TBCFont; AOldPlacement: boolean): TRect;
 var
-  gw,gh, w, h, w2,h2, glyphHorzMargin, glyphVertMargin: integer;
+  w, h, w2,h2, glyphHorzMargin, glyphVertMargin: integer;
   horizAlign, relHorizAlign: TAlignment;
   vertAlign, relVertAlign: TTextLayout;
   rText, rAll, rGlyph: TRect;
@@ -469,12 +489,7 @@ var
   end;
 
 begin
-  if Assigned(AGlyph) and not AGlyph.Empty then
-  begin
-    gw := round(AGlyph.Width * AGlyphScale);
-    gh := round(AGlyph.Height * AGlyphScale);
-  end
-  else exit(EmptyRect);
+  if (gw = 0) or (gh = 0) then exit(EmptyRect);
 
   if AOldPlacement then
   begin

+ 10 - 2
bctypes.pas

@@ -872,8 +872,16 @@ begin
     FPaddingBottom:= TBCFont(Source).PaddingBottom;
 
     Change;
-  end
-  else
+  end else
+  if Source is TFont then
+  begin
+    FColor := TFont(Source).Color;
+    FHeight := -TFont(Source).Height;
+    FName := TFont(Source).Name;
+    FStyle:= TFont(Source).Style;
+
+    Change;
+  end else
     inherited Assign(Source);
 end;
 

+ 1 - 5
bgracolortheme.pas

@@ -126,12 +126,10 @@ begin
 
     if Caption <> '' then
     begin
+      fillchar(Style, sizeof(Style), 0);
       Style.Alignment := taCenter;
       Style.Layout := tlCenter;
       Style.Wordbreak := True;
-      Style.SystemFont := False;
-      Style.Clipping := True;
-      Style.Opaque := False;
       if ColorText <> clDefault then
         DestCanvas.Font.Color := ColorText;
       DestCanvas.TextRect(ARect, 0, 0, Caption, Style);
@@ -144,7 +142,6 @@ procedure TBGRAColorTheme.DrawRadioButton(Caption: string;
   ARect: TRect; ASurface: TBGRAThemeSurface);
 var
   Style: TTextStyle;
-  Bitmap: TBGRABitmap;
   Color: TBGRAPixel;
 begin
   with ASurface do
@@ -191,7 +188,6 @@ procedure TBGRAColorTheme.DrawCheckBox(Caption: string;
   ARect: TRect; ASurface: TBGRAThemeSurface);
 var
   Style: TTextStyle;
-  Bitmap: TBGRABitmap;
   Color: TBGRAPixel;
   aleft, atop, aright, abottom: integer;
 begin

+ 1 - 3
bgraimagetheme.pas

@@ -94,12 +94,10 @@ begin
 
     if Caption <> '' then
     begin
+      fillchar(Style, sizeof(Style), 0);
       Style.Alignment := taCenter;
       Style.Layout := tlCenter;
       Style.Wordbreak := True;
-      Style.SystemFont := False;
-      Style.Clipping := True;
-      Style.Opaque := False;
       DestCanvas.TextRect(ARect, 0, 0, Caption, Style);
     end;
   end;

+ 48 - 26
bgrasvgtheme.pas

@@ -12,6 +12,7 @@ uses
 const
   DEFAULT_CHECKBOX_TEXT_SPACING = 2;
   DEFAULT_GLYPH_TEXT_SPACING = 6;
+  DEFAULT_BUTTON_TEXT_SPACING = 6;
 
 type
 
@@ -19,6 +20,7 @@ type
 
   TBGRASVGTheme = class(TBGRATheme)
   private
+    FButtonTextSpacing: integer;
     FCheckboxTextSpacing: integer;
     FColorizeActiveOp: TBlendOperation;
     FColorizeDisabledOp: TBlendOperation;
@@ -48,6 +50,7 @@ type
     procedure SetButtonSliceScalingLeft(AValue: integer);
     procedure SetButtonSliceScalingRight(AValue: integer);
     procedure SetButtonSliceScalingTop(AValue: integer);
+    procedure SetButtonTextSpacing(AValue: integer);
     procedure SetCheckBoxChecked(AValue: TStringList);
     procedure SetCheckboxTextSpacing(AValue: integer);
     procedure SetCheckBoxUnchecked(AValue: TStringList);
@@ -129,6 +132,8 @@ type
       read FButtonSliceScalingBottom write SetButtonSliceScalingBottom;
     // Spacing between glyph and its text (in 96 DPI)
     property GlyphTextSpacing: integer read FGlyphTextSpacing write SetGlyphTextSpacing default DEFAULT_GLYPH_TEXT_SPACING;
+    // Spacing between text and button border (in 96 DPI)
+    property ButtonTextSpacing: integer read FButtonTextSpacing write SetButtonTextSpacing default DEFAULT_BUTTON_TEXT_SPACING;
     // CSS Color to tint the normal states, use rgba(0,0,0,0) to disable
     property ColorizeNormal: string read FColorizeNormal write SetColorizeNormal;
     property ColorizeNormalOp: TBlendOperation read FColorizeNormalOp write SetColorizeNormalOp default boTransparent;
@@ -169,6 +174,8 @@ procedure Register;
 
 implementation
 
+uses BCTypes, BCTools;
+
 const
   RES_CHECKBOXUNCHECKED =
     '<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M19 5v14H5V5h14m0-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z"/></svg>';
@@ -411,6 +418,7 @@ begin
   FButtonSliceScalingRight := 10;
   FButtonSliceScalingBottom := 10;
   FGlyphTextSpacing := DEFAULT_GLYPH_TEXT_SPACING;
+  FButtonTextSpacing := DEFAULT_BUTTON_TEXT_SPACING;
   FColorizeNormal := RES_COLORIZENORMAL;
   FColorizeHover := RES_COLORIZEHOVER;
   FColorizeActive := RES_COLORIZEACTIVE;
@@ -434,6 +442,7 @@ begin
     FButtonSliceScalingRight := XMLConf.GetValue('Button/SliceScaling/Right', 10);
     FButtonSliceScalingTop := XMLConf.GetValue('Button/SliceScaling/Top', 10);
     FGlyphTextSpacing := XMLConf.GetValue('Button/GlyphSpacing', DEFAULT_GLYPH_TEXT_SPACING);
+    FButtonTextSpacing := XMLConf.GetValue('Button/TextSpacing', DEFAULT_BUTTON_TEXT_SPACING);
     // CheckBox
     FCheckBoxChecked.Text := XMLConf.GetValue('CheckBox/Checked/SVG',
       RES_CHECKBOXCHECKED){%H-};
@@ -471,6 +480,7 @@ begin
   XMLConf.SetValue('Button/SliceScaling/Right', FButtonSliceScalingRight);
   XMLConf.SetValue('Button/SliceScaling/Top', FButtonSliceScalingTop);
   XMLConf.SetValue('Button/GlyphSpacing', FGlyphTextSpacing);
+  XMLConf.SetValue('Button/TextSpacing', FButtonTextSpacing);
   // CheckBox
   XMLConf.SetValue('CheckBox/Checked/SVG', FCheckBoxChecked.Text{%H-});
   XMLConf.SetValue('CheckBox/Unchecked/SVG', FCheckBoxUnchecked.Text{%H-});
@@ -616,10 +626,11 @@ var
   svg: TBGRASVG;
   svgCode: String;
   gs: TSize;
-  gw, tw, gx: integer;
-  style: TTextStyle;
-  r: TRect;
+  bcFont: TBCFont;
+  actualCaption: string;
+  r, rGlyph: TRect;
   drawText: boolean = True;
+
 begin
   with ASurface do
   begin
@@ -645,22 +656,36 @@ begin
       FButtonSliceScalingRight, FButtonSliceScalingBottom, Bitmap,
       BitmapDPI);
     svg.Free;
-    gw := 0;
-    tw := DestCanvas.TextWidth(Caption);
+
     if Assigned(AImageList) and (AImageIndex > -1) and (AImageIndex < AImageList.Count) then
     begin
       gs := AImageList.GetScaledSize(BitmapDPI);
-      gw := gs.cx + ScaleForBitmap(GlyphTextSpacing);
-      gx := (Bitmap.Width - ScaleForBitmap(tw, DestCanvasDPI) - gw) div 2;
-      if (gx < ScaleForBitmap(GlyphTextSpacing*3)) then
-      begin
-        gx := (Bitmap.Width - gs.Width) div 2;
-        drawText := False;
-      end;
-      AImageList.Draw(AImageIndex, Bitmap,
-        RectWithSizeF(gx, (Bitmap.Height - gs.cy) div 2, gs.cx, gs.cy));
-      gw := ScaleForCanvas(gw, BitmapDPI);
-    end;
+      if ARect.Width - gs.cx < ScaleForBitmap(GlyphTextSpacing + 2*ButtonTextSpacing) then
+        drawText := false;
+    end
+      else gs := TSize.Create(0, 0);
+
+    bcFont := TBCFont.Create(nil);
+    bcFont.Assign(DestCanvas.Font);
+    bcFont.Scale(BitmapDPI / DestCanvasDPI, false);
+    bcFont.WordBreak := true;
+    bcFont.PaddingBottom:= ScaleForBitmap(ButtonTextSpacing);
+    bcFont.PaddingTop:= ScaleForBitmap(ButtonTextSpacing);
+    bcFont.PaddingRight:= ScaleForBitmap(ButtonTextSpacing);
+    bcFont.PaddingLeft:= ScaleForBitmap(ButtonTextSpacing);
+    bcFont.TextAlignment:= bcaCenter;
+
+    if drawText then
+      actualCaption := Caption
+      else actualCaption:= '';
+
+    r := ScaleForBitmap(ARect, DestCanvasDPI);
+    rGlyph := ComputeGlyphPosition(r, gs.cx, gs.cy, bcaCenter,
+      ScaleForBitmap(GlyphTextSpacing), actualCaption, bcFont);
+    if not rGlyph.IsEmpty then
+      AImageList.Draw(AImageIndex, Bitmap, RectF(rGlyph));
+    RenderText(r, bcFont, actualCaption, Bitmap);
+
     ColorizeSurface(ASurface, State);
     DrawBitmap;
 
@@ -677,16 +702,6 @@ begin
       DestCanvas.Rectangle(r);
       DestCanvas.Pen.Style := psSolid;
     end;
-
-    if (Caption <> '') and drawText then
-    begin
-      fillchar(style, sizeof(style), 0);
-      style.Alignment := taCenter;
-      style.Layout := tlCenter;
-      style.Wordbreak := True;
-      inc(ARect.Left, gw);
-      DestCanvas.TextRect(ARect, 0, 0, Caption, style);
-    end;
   end;
 end;
 
@@ -802,6 +817,13 @@ begin
   InvalidateThemedControls;
 end;
 
+procedure TBGRASVGTheme.SetButtonTextSpacing(AValue: integer);
+begin
+  if FButtonTextSpacing=AValue then Exit;
+  FButtonTextSpacing:=AValue;
+  InvalidateThemedControls;
+end;
+
 procedure TBGRASVGTheme.DrawCheckBox(Caption: string; State: TBGRAThemeButtonState;
   Focused: boolean; Checked: boolean; ARect: TRect; ASurface: TBGRAThemeSurface);
 var

+ 10 - 3
bgratheme.pas

@@ -33,6 +33,7 @@ type
     procedure BitmapColorOverlay(AColor: TBGRAPixel; AOperation: TBlendOperation = boTransparent); overload;
     function ScaleForCanvas(AValue: integer; AFromDPI: integer = 96): integer;
     function ScaleForBitmap(AValue: integer; AFromDPI: integer = 96): integer;
+    function ScaleForBitmap(const ARect: TRect; AFromDPI: integer = 96): TRect;
     property DestCanvas: TCanvas read FDestCanvas;
     property DestCanvasDPI: integer read FLclDPI;
     property Bitmap: TBGRABitmap read GetBitmap;
@@ -193,6 +194,14 @@ begin
   result := MulDiv(AValue, BitmapDPI, AFromDPI);
 end;
 
+function TBGRAThemeSurface.ScaleForBitmap(const ARect: TRect; AFromDPI: integer): TRect;
+begin
+  result.Left := ScaleForBitmap(ARect.Left, AFromDPI);
+  result.Top := ScaleForBitmap(ARect.Top, AFromDPI);
+  result.Right := ScaleForBitmap(ARect.Right, AFromDPI);
+  result.Bottom := ScaleForBitmap(ARect.Bottom, AFromDPI);
+end;
+
 { TBGRATheme }
 
 function TBGRATheme.GetThemedControl(AIndex: integer): TBGRAThemeControl;
@@ -266,12 +275,10 @@ begin
 
     if Caption <> '' then
     begin
+      fillchar(Style, sizeof(Style), 0);
       Style.Alignment := taCenter;
       Style.Layout := tlCenter;
       Style.Wordbreak := True;
-      Style.SystemFont := False;
-      Style.Clipping := True;
-      Style.Opaque := False;
       DestCanvas.TextRect(ARect, 0, 0, Caption, Style);
     end;
   end;

+ 2 - 0
test/test_bgrathemes/umain.pas

@@ -49,6 +49,8 @@ implementation
 procedure TfrmBGRAThemesButton.FormCreate(Sender: TObject);
 begin
   BGRAImageTheme1.LoadResources('theme.ini');
+  BGRAThemeButton1.Caption := 'This button is clickable';
+  BGRAThemeButton2.Caption := 'This one may be disabled';
 end;
 
 procedure TfrmBGRAThemesButton.BGRAThemeCheckBox1Change(Sender: TObject);