Recent

Author Topic: BGRABitmap-RoundRect-Different radius for every corner like CSS Border radius  (Read 1710 times)

ϻαϻɾΣɀО

  • Jr. Member
  • **
  • Posts: 54
  • MaMrEzO
Hi,
I trying to implement CSS Theme based!
I`d done some base classes and the drawing graphic layer is BGRABitmap!
Now I have a problem to draw a round rectangle!

I already knew about TRoundRectangleOptions for the Square corners too.
By default in BGRA draw roundrects with rx/rw parameters, As result, drawn roundRect corners are the same(with [] TRoundRectangleOptions), but I need different radius corners for everyone! like CSS border-radius.

In this way, rx/ry are the same for every corner, and every corner may have a different radius!

Thanks for your reading time and advice.
« Last Edit: October 15, 2019, 06:30:00 pm by ϻαϻɾΣɀО »
Debio-Sql is a new brand of GUI Database tool for the Firebird RDBMS.
http://debio-sql.ariaian.com/

winni

  • Sr. Member
  • ****
  • Posts: 430
Hi!

Strange desire!

Hardrock solution:

Draw 4 different roundrects with the needed radiuses.

Use BGRABitmap.getpart(R: TRect) to cut out the related corners and put them on an empty bitmap.

Not nice but working.

Winni
« Last Edit: October 15, 2019, 06:37:21 pm by winni »

ϻαϻɾΣɀО

  • Jr. Member
  • **
  • Posts: 54
  • MaMrEzO
Strange desire!
8-) I know!

Draw 4 different roundrects with the needed radiuses.
Use BGRABitmap.getpart(R: TRect) to cut out the related corners and put them on an empty bitmap.
It is possible, But the reound rect is not the all, Background may be filled with color/gradient/image/even texture, So in antialiased cases and many other cases, the result comes with poor quality...

But Thanks  :)
Debio-Sql is a new brand of GUI Database tool for the Firebird RDBMS.
http://debio-sql.ariaian.com/

ϻαϻɾΣɀО

  • Jr. Member
  • **
  • Posts: 54
  • MaMrEzO
For have a imagination of what is coding take a look at this code:

Code: Pascal  [Select]
  1.  
  2.   TDCSSSizeKind = (dcskPixel, dcskEM, dcsPrcent);  
  3.  
  4.   { TDCSSSize }
  5.   TDCSSSize = record//
  6.   public
  7.     Kind: TDCSSSizeKind;
  8.     Value: Double;
  9.     class operator = (L, R: TDCSSSize): Boolean;
  10.   end;  
  11.  
  12.   { TDCSSCorner }
  13.  
  14.   TDCSSCorner = record
  15.   public
  16.     //As CSS Order
  17.     TopLeft, TopRight, BottomRight, BottomLeft: TDCSSSize;
  18.     procedure SetValues(ValueForAll: Double; UnitForAll: TDCSSSizeKind);
  19.     class operator = (L, R: TDCSSCorner): Boolean;
  20.   end;  
  21.  
  22.   { TDCSSBorder }
  23.  
  24.   TDCSSBorder = class(TDCSSBase)
  25.   private
  26.     FColor: TDCSSColor;
  27.     FRadius: TDCSSCorner;
  28.     FWidth: TDCSSRect;
  29.     function GetFlatCorners: Boolean;
  30.     procedure SetColor(AValue: TDCSSColor);
  31.     procedure SetRadius(AValue: TDCSSCorner);
  32.     procedure SetWidth(AValue: TDCSSRect);
  33.   public
  34.     property Width: TDCSSRect read FWidth write SetWidth;
  35.     property Color: TDCSSColor read FColor write SetColor;
  36.     property Radius: TDCSSCorner read FRadius write SetRadius;
  37.     property FlatCorners: Boolean read GetFlatCorners;
  38.     procedure Assign(ASource: TDCSSBorder);
  39.   end;
  40.  
  41.   TDBGRABorderInfo = record
  42.     rndOpts: TRoundRectangleOptions;
  43.     rx, ry: Single;
  44.   end;
  45.  
  46. {
  47.   By the now it assumed that all corners have same radius
  48.   But one or more may have Square corner!
  49.  
  50.   So simply find the square ones and get the average of none zero(square) ones!
  51. }
  52. function BorderInfo(ACSSBorder: TDCSSBorder): TDBGRABorderInfo;
  53. var
  54.   val: Double;
  55.   vals: Byte;
  56. begin
  57.   Result.rndOpts := [];
  58.   val := 0.0;
  59.   vals := 0;
  60.  
  61.   if ACSSBorder.Radius.BottomRight.Value > 0 then
  62.   begin
  63.     val += ACSSBorder.Radius.BottomRight.Value;
  64.     vals += 1;
  65.   end
  66.   else
  67.    Result.rndOpts += [rrBottomRightSquare];
  68.  
  69.   if ACSSBorder.Radius.BottomLeft.Value > 0 then
  70.   begin
  71.     val += ACSSBorder.Radius.BottomLeft.Value;
  72.     vals += 1;
  73.   end
  74.   else
  75.     Result.rndOpts += [rrBottomLeftSquare];
  76.  
  77.   if ACSSBorder.Radius.TopLeft.Value > 0 then
  78.   begin
  79.     val += ACSSBorder.Radius.TopLeft.Value;
  80.     vals += 1;
  81.   end
  82.   else
  83.     Result.rndOpts += [rrTopLeftSquare];
  84.  
  85.   if ACSSBorder.Radius.TopRight.Value > 0 then
  86.   begin
  87.     val += ACSSBorder.Radius.TopRight.Value;
  88.     vals += 1;
  89.   end
  90.   else
  91.     Result.rndOpts += [rrTopRightSquare];      
  92.  
  93.   Result.ry := val / vals;
  94.   Result.rx := Result.ry;
  95. end;                                  
  96.  


As you can see I`d to skip the different corers radius.

And something else, There will bew dirrefent line width for every lines of rectangle  %)....
« Last Edit: October 15, 2019, 07:07:01 pm by ϻαϻɾΣɀО »
Debio-Sql is a new brand of GUI Database tool for the Firebird RDBMS.
http://debio-sql.ariaian.com/

winni

  • Sr. Member
  • ****
  • Posts: 430
Hi!

Why and where should it result in poor quality?

Draw all 4 bitmaps on transparent bitmaps.
Take a transparent Bitmap  as final bitmap.
Now the room outside of the rounded rectangle is transparent and every kind of color/gradient/texture shines through.

Winni

ϻαϻɾΣɀО

  • Jr. Member
  • **
  • Posts: 54
  • MaMrEzO
Why and where should it result in poor quality?
May not poor in quality, But poor in performance?

Debio-Sql is a new brand of GUI Database tool for the Firebird RDBMS.
http://debio-sql.ariaian.com/

winni

  • Sr. Member
  • ****
  • Posts: 430
Hi!

Do you need it for animation?

I have made some animations with 10 frames/ sec. And it is astonishing what amount of jobs  BGRA can do in 100 ms. Depends on size and the kind of the routine. It is always the same with graphic: as long as the are not painted they are quick!

Just test it: Do your special roundrect routine 1000 times (or so) and use GetTickCount64 at start and end to measure the time.

Winn

winni

  • Sr. Member
  • ****
  • Posts: 430
Hi!

I made you a simple Demo program. Without extra classes. Just simple.

Graphic and project are attached.

Ουίννι


circular

  • Hero Member
  • *****
  • Posts: 3022
    • Personal webpage
You can improve performance by using a clipping rectangle (ClipRect property) and drawing in each area with a different radius.

Another way would be to use a path (TBGRAPath of BGRAPath unit) and define it according to your wishes using lines and arcs.
Conscience is the debugger of the mind

ps

  • Jr. Member
  • **
  • Posts: 89
Another way would be to use a path (TBGRAPath of BGRAPath unit) and define it according to your wishes using lines and arcs.
Only this is correct way if there is plan to support CSS Borders.  Because each corner can have different width, color, style etc.. https://developer.mozilla.org/en-US/docs/Web/CSS/border

ϻαϻɾΣɀО:
See this example: https://jsfiddle.net/4bLp19q6/ There is 4 "shapes" top left right bottom.
IDE:  Lazarus 1.8 RC3/Trunk, Delphi XE OS:Windows 10, Ubuntu

winni

  • Sr. Member
  • ****
  • Posts: 430
Hi!

In Pascal there is never only "one correct way".

Show me the only correct way to increment an integer???
Code: Pascal  [Select]
  1. i := i +1:
  2. inc(i);
  3. i+=1;

You can easy enhance my corner code with color and linewidth. So that is my "one correct way".

If you think that there is "only one correct way" then you are on a crusade. And not in science. In Pascal. And in the real life.

Winni


sstvmaster

  • Full Member
  • ***
  • Posts: 126
@winni

+1
Lazarus 2.0.4 x32
Lazarus 2.1.0 Trunk x32
OS Win 7 32bit

lainz

  • Hero Member
  • *****
  • Posts: 3276
    • Lainz
In fact in this case yes there is only one way to make it 100% equal to CSS, and is supporting it completely with all his properties, generating the same drawing with the same CSS file like a browser will do.

But is true that to make that goal /any/ combination of code that does the solution will be valid.

Also is true that the browsers implements several CSS engines, so maybe even between them there is not 100% compatible CSS as a final drawing.  :)

circular

  • Hero Member
  • *****
  • Posts: 3022
    • Personal webpage
ϻαϻɾΣɀО:
See this example: https://jsfiddle.net/4bLp19q6/ There is 4 "shapes" top left right bottom.
In this case, if it is only to draw the shape without the various border colors, the ClipRect method would do. Though I would recommand to use a path as it is more elegant and not so complicated.

It remains to draw the border, which could be done in fact by first drawing the border (mostly as if there was no round corners) and then apply a mask of the round rectangle. Apparently the borders can contain a curve as seen in your example, so probably you would not easily avoid using a path here.

To avoid applying a mask, you would need to compute the intersection of the trapezoid of the borders with the rounded corners. That can be done with some trigonometry (arctan of the slope of the trapezoid diagonal). So you could get the actual final path for each part.
Conscience is the debugger of the mind

ϻαϻɾΣɀО

  • Jr. Member
  • **
  • Posts: 54
  • MaMrEzO
Thanks, everyone.
By the now may not urgent to implement this functionality. CSS theme for UI consists of formly rounded with one or two square corners (For example spin buttons, Attached below).
However, I cannot find any example/sample code to use the TBGRAPath!  I`ve read the source code of the mentioned unit, but see no luck to figure out how maybe get work with it.
May someone give me an example how to use it or guide me to documention abut it.

But for detailed graphical modern look like theme, Something especial like the box-shadow, maybe have a higher priority.
I decided to create new topic about it https://forum.lazarus.freepascal.org/index.php/topic,47106.msg336688.html#msg336688
Debio-Sql is a new brand of GUI Database tool for the Firebird RDBMS.
http://debio-sql.ariaian.com/