Recent

Author Topic: TArrow component supplement  (Read 4397 times)

wittbo

  • Full Member
  • ***
  • Posts: 151
TArrow component supplement
« on: August 20, 2020, 06:01:30 pm »
this time I don't have a problem or question, but a solution for a problem right away, which most Lazarus programmers don't have, because they program under Windows or Linux.

I develop under macOS, but always create a Windows version of my programs. Therefore it is important for me to create the same look & feel for both the macOS and Windows version with one program version. I like to use the TUpDown component for a fast control of TAChart graphics. Up to Lazarus 2.0.2 the macOS and Windows TUpDown components were identical and uniform to use. In the course of further development for the Cocoa Widgetset, TUpDown on the Mac has been switched to a native macOS component. Unfortunately, this component has a single standard size and cannot be further customized. I have described this in this thread: https://forum.lazarus.freepascal.org/index.php/topic,46648.msg332955.html#msg332955

By chance I came across the component TArrow from the Tab Misc. With little effort I was able to extend it (resize the arrow, button style behavior, transparency) so that two TArrow components can be used in combination like today's WIndows and the earlier macOS version.

The source code of my customized TArrow component (TArrowNew) is included here. I would like to suggest to include the extensions in the Lazarus LCL standard. Who can I contact for this?
-wittbo-
MBAir M2 with MacOS 14.4.1 / Lazarus  3.2.2
MacStudio M1 Max with MacOS 14.4.1 / Lazarus 3.2.2

wp

  • Hero Member
  • *****
  • Posts: 12459
Re: TArrow component supplement
« Reply #1 on: August 20, 2020, 10:16:16 pm »
Therefore it is important for me to create the same look & feel for both the macOS and Windows version with one program version.
This is against the Lazarus paradigm: applications should take the look and feel of the native applications of an OS. When macOS decides to draw UpDown buttons in its own way Lazarus will accept it. Look at a TPageControl: completely different in macOS than in Windows. If you really want to give your applications the same look in macOS and Windows you must use a custom-drawn widgetset.

The source code of my customized TArrow component (TArrowNew) is included here. I would like to suggest to include the extensions in the Lazarus LCL standard. Who can I contact for this?
The official way for a feature request is to write a report to the bug tracker (link at the left of the forum site).

I don't want to disappoint you, but my personal opinion is that a second TArrow component will not be accepted. I even wonder why the standard TArrow is included in the distribution: it is neither needed by Lazarus, nor is it contained in Delphi. It can be emulated by a TSpeedbutton with an arrow icon easily. I guess that it will be moved to CCR sooner or later. So then, why should there be even a second TArrow?

Regarding the component itself: You duplicate much of the code of TArrow. The classical OOP way would be to inherit TArrowNew from TArrow. But if I'd have to decide about inclusion of your component I'd favor a simple addition to TArrow (instead of adding a new component). Modify the TArrow code directly and add the new color properties and extend the Paint routine since having MouseOver/MouseDown effects in TArrow does make some sense. Create a diff file relative to the current trunk version and add it to the bug report. You should also add a demo program (with run-time created extended arrow) that shows the new features.

The component should not use "explicit" colors such as clBlack for the arrow. "Dark mode" has become very popular these days, and you can imagine what your button will look like when the user decides to switch from bright mode to dark mode.

On the other hand: Why don't you use a TSpeedButton (or TBitBtn) instead of the arrow and give it a nicely-drawn, anti-aliased arrow icon? This way you would get the MouseDown and MouseOver effects for free.

« Last Edit: August 20, 2020, 10:24:42 pm by wp »

wittbo

  • Full Member
  • ***
  • Posts: 151
Re: TArrow component supplement
« Reply #2 on: August 21, 2020, 12:24:39 pm »
Quote
This is against the Lazarus paradigm: applications should take the look and feel of the native applications of an OS. When macOS decides to draw UpDown buttons in its own way Lazarus will accept it. Look at a TPageControl: completely different in macOS than in Windows. If you really want to give your applications the same look in macOS and Windows you must use a custom-drawn widgetset.
I understand that. I originally decided to use the TUpDown control because it could be used both vertically and horizontally, its size is adjustable, very easy. And under Windows this is still the case. Then I really have to look for another control.
Quote
I don't want to disappoint you, but my personal opinion is that a second TArrow component will not be accepted.
That wasn't my intention either. I understood it as an "upgrade" of the existing TArrow control, because it is very easy to handle.
Quote
Why don't you use a TSpeedButton?
That is indeed a very good question. In the beginning I was looking for a replacement for the TUpDown control and found TArrow by chance and two TArrows are like a TUpDown.
TSpeedbutton, right, is like a little mystery. I've read the specification (https://lazarus-ccr.sourceforge.io/docs/lcl/buttons/tspeedbutton.html) more than once, I always don't quite understand it:
- which states are there?
- how can I get the current state?
- can I change the state in the program?
- how do the possible glyphs correspond to the possible states?
- there is a glyph property and an image list property; do both work together or which control is behind it?

The only documentation I found was from Embarcadero 2014 (http://docwiki.embarcadero.com/Libraries/Sydney/en/Vcl.Buttons.TSpeedButton.Glyph)and concerns states and glyph properties. I don't know, as of which TSpeedbutton in Lazarus also applies.

Nevertheless, I will try to realize my solution with TSpeedbutton.

BTW, under Windows, Speedbutton has such a nice mouse-over background effect; many versions ago, the same thing happened on the Mac. Unfortunately nothing happens now when I move the mouse over the button. It's probably Apple standard, Mac applications don't do that (anymore). I still think it is a nice "responsive design".
-wittbo-
MBAir M2 with MacOS 14.4.1 / Lazarus  3.2.2
MacStudio M1 Max with MacOS 14.4.1 / Lazarus 3.2.2

Blaazen

  • Hero Member
  • *****
  • Posts: 3241
  • POKE 54296,15
    • Eye-Candy Controls
Re: TArrow component supplement
« Reply #3 on: August 21, 2020, 12:48:20 pm »
TSpeedbutton is like TButton or TBitBtn, except it cannot have focus and cannot be reached by Tab key.

If you have more than one TSpeedbutton and you set their GroupIndex to the same non-zero value, you join these buttons to radiogroup. You can control their state by properties Down and AllowAllUp.
Lazarus 2.3.0 (rev main-2_3-2863...) FPC 3.3.1 x86_64-linux-qt Chakra, Qt 4.8.7/5.13.2, Plasma 5.17.3
Lazarus 1.8.2 r57369 FPC 3.0.4 i386-win32-win32/win64 Wine 3.21

Try Eye-Candy Controls: https://sourceforge.net/projects/eccontrols/files/

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: TArrow component supplement
« Reply #4 on: August 21, 2020, 04:23:18 pm »
Regarding Images and Glyph, IIRC (I might not, it has been some time since I used it) Images is used if NumGlyphs is bigger than zero, otherwise the single Glyph (or none) is used.

I don't quite remember how changing the glyph according to the button's state was acomplished but I seem to recall it was done manually by changing ImageIndex inside handlers for the various OnMouseXXX and other state-changing events

Note that most of this info comes from my recollection of old Delphi (v3 to v8) and conversion of those projects (which I'm not now in charge of) to Lazarus quite some years ago so it might not apply anymore ...  :-[
« Last Edit: August 21, 2020, 04:25:18 pm by lucamar »
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

wp

  • Hero Member
  • *****
  • Posts: 12459
Re: TArrow component supplement
« Reply #5 on: August 21, 2020, 07:22:55 pm »
Look at attached demo for a simple demonstration of using 4 arrow speedbuttons for moving an object.

A glyph can contain 4 states:
- normal
- disabled
- clicked (i.e. mouse over button and mouse down)
- down (i.e. permanently down, useful when several speedbuttons are grouped like radiobuttons, or when a button acts like a checkbox)

In the left button group a standard, single png image is assigned to each speedbutton.Glyph (NumGlyphs=1). The three missing images are auto-generated from the provided glyphs. Depending on widgetsets "clicked" and "down" images hardly change from the normal image, but the disabled image is always grayed in some way.

In the right button group custom-drawn versions for disabled and hot states were combined with the normal state image. These image form a strip, 1 image high, 3 images wide, or 16x48 pixels (width x height). Here the disabled images are redrawn and look more distinct than the simple gray-scale images of the left button group. And also the hot images appear to stand out more clearly.

Note that the free icon libraries found in the internet usually do not contain images of the other states. The project here uses the commercial icon set Axialis Ribbon Toolbar Basic (

I should also mention that there is another way to provide images to the speedbutton. Instead of assigning an image to the Glyph property of a button (and repeating this for all other buttons needing the same images on other forms or for other occasions) it is also possible in Laz 2.0 to assign an image list to the corresponding property of the button. There is an ImageIndex property which selects the image needed for this particular button from the image list. One advantage of reusing the same images at several places is that the new ImageList can contain images at several sizes ("resolution"), and when the "Scaled" property of the ImageList is checked the image size is selected according to the screen resolution.

I am not 100% sure, but i think that the image stips with the state images are not separated here.

wittbo

  • Full Member
  • ***
  • Posts: 151
Re: TArrow component supplement
« Reply #6 on: August 31, 2020, 11:41:05 am »
@WP: thank you for your example. I have done some more experiments with SpeedButton and bitmap images in the past days; you can find my project in the appendix. Very interesting and also a bit mystical is the behaviour of the Speedbutton with the properties Flat and Transparent.

It is clear that the set background color is only visible when Transparent=False. But that it is only visible if Flat=False is set at the same time does not seem logical to me.

I copied a speed button from your example, wp, and put it in comparison to my own speed button. The difference is that the glyph of the right Speedbutton is apparently stored as PNG, while the glyph of the left Speedbutton is dynamically generated from a bitmap at runtime. Although the transparent properties of the bitmap are set correctly in my understanding, the bitmap is not transparent on the background of the Speedbutton.

BTW: The Down property of the Speedbutton can only be set if GroupIndex > 0.
-wittbo-
MBAir M2 with MacOS 14.4.1 / Lazarus  3.2.2
MacStudio M1 Max with MacOS 14.4.1 / Lazarus 3.2.2

wp

  • Hero Member
  • *****
  • Posts: 12459
Re: TArrow component supplement
« Reply #7 on: August 31, 2020, 12:46:53 pm »
I agree: "Flat" and "Transparent" are counter-intuitive. They were correct in ancient Win95, but nowadays with theme-support many things lost their old meaning.

I also confess that usually I never get the old color-transparency of Delphi to work. It looks so easy: define a "transparent color" and set Transparent to true -- but mostly it does not work. What I do now is to use real alpha-channel transparency as used in png images. Once you know how to do that yourself it is easy:

Code: Pascal  [Select][+][-]
  1. uses
  2.   FPImage, IntfGraphics, LazCanvas;  
  3.  
  4. function TForm1.MakeArrow (iWidth, iHeight: Integer; ArrowType: TArrowType): TBitmap;
  5. const
  6.   cInnerOffset = 8;
  7. var
  8.   BM        : TBitmap;
  9.   FR        : TRect;
  10.   FT        : array[1 .. 3] of TPoint;
  11.   midY, midX: integer;
  12.   ratioNeed : double;
  13.   size      : TSize;
  14.   intfImg: TLazIntfImage;
  15.   cnv: TLazCanvas;
  16. begin
  17.    BM                  := TTBitmap.Create;
  18.    BM.PixelFormat      := pf32Bit;                        // IMPORTANT !!!
  19.    {
  20.    BM.Transparent      := true;
  21.    BM.TransparentColor := clFuchsia;
  22.    BM.TransparentMode  := tmFixed;
  23.    }
  24.  
  25.    // your calculations here unchanged...
  26.  
  27.   // Now, instead of ...
  28.   {
  29.    BM.Canvas.Brush.Color := clFuchsia;
  30.    BM.Canvas.FillRect(BM.Canvas.ClipRect);
  31.  
  32.    BM.Canvas.Pen.Color   := clGray;
  33.    BM.Canvas.Brush.Color := clGray;
  34.    BM.Canvas.Polygon (FT);
  35.    }
  36.  
  37.   // ... use a TLazIntfImage with alpha-channel transparency
  38.    intfImg := BM.CreateIntfImage;
  39.    try
  40.      cnv := TLazCanvas.Create(intfImg);
  41.      try
  42.        cnv.Brush.FPColor := colTransparent;                         // Do a real alpha-channel transparent fill
  43.        cnv.FillRect(0, 0, intfImg.Width, intfImg.Height);
  44.        cnv.Brush.FPColor := colGray;
  45.        cnv.Pen.FPColor := colGray;
  46.        cnv.Polygon(FT);
  47.      finally
  48.        cnv.Free;
  49.      end;
  50.      BM.LoadFromIntfImage(intfImg);
  51.    finally
  52.      intfImg.Free;
  53.    end;
  54.    
  55.    Result := BM;
  56. end;


jamie

  • Hero Member
  • *****
  • Posts: 6735
Re: TArrow component supplement
« Reply #8 on: August 31, 2020, 02:21:33 pm »
speaking of Transparent colors, in Delphi it use to be the lower left corner of the image that dictated the transparent color if it was set for Auto, otherwise you specified it.

 This was basically the action taken for transparent glyphs and the likes..

has all of this changed ?
The only true wisdom is knowing you know nothing

wittbo

  • Full Member
  • ***
  • Posts: 151
Re: TArrow component supplement
« Reply #9 on: August 31, 2020, 03:54:51 pm »
@wp:  Great solution!
It works.
Tested on Win10, Mac Mojave.
BTW: On the mac with macOS High Sierra (maybe also lower OS versions) transparency does not work. This seems to be a problem of older macOS, not Lazarus. Copy the program to macOS Mojave without recompile, transparency works.
-wittbo-
MBAir M2 with MacOS 14.4.1 / Lazarus  3.2.2
MacStudio M1 Max with MacOS 14.4.1 / Lazarus 3.2.2

wp

  • Hero Member
  • *****
  • Posts: 12459
Re: TArrow component supplement
« Reply #10 on: August 31, 2020, 05:22:20 pm »
Here is an example with two speedbuttons using bitmap color-transparency. My intention was to demonstrate that it works with file bitmaps, but not with run-time created bitmaps like in wittbo's code. But I was wrong -- both cases are working. The run-time created code is essentially the same as in wittbo's reply #6. Who understands this?

This is annoying: sometimes color-transparency works, sometimes it does not. This was similar in Delphi. Why would the Jedi components have had all these routines like "DrawTransparentBitmap" etc. Probably there is a reason behind it. I just have not idea.

With Lazarus having easy access to png, I decided to switch to alpha-channel transparency, and all these issues were gone.

wittbo

  • Full Member
  • ***
  • Posts: 151
Re: TArrow component supplement
« Reply #11 on: September 03, 2020, 03:13:58 pm »
Me too, wp.

The TBitmap behaves different depending whether transparent of the speedbutton is set or not. If speedbutton.transparent = false the bitmap isn't transparent either, even if transparency of the bitmap is explicitly set to true. So alpha channel transparency is really the best solution.

Nevertheless there remain some unexplainable things with coloring the speedbutton itself. If speedbutton.color is explicitly set to some color mybe clRed, a clRed colored speedbutton is only drawn, if speedbutton.flat = true (and transparent=false of course); if flat is set to false there is a thin clRed border around the speedbutton, while the main speedbutton area is light gray, mybe clDefault. More than that, if flat = false and transparent is set to true, the speedbutton is not transparent, nearly the same as with flat=false and transparent=false, but in this case the thin borderline hat a dark gray color.

So my conclusion for speedbuttons is:
1. Alway set flat property true.
2. If you have predefined glyphs, always use PNG format graphics files.
3. If you are working with runtime created glyphs, always use alpha channel graphics as described by wp (Reply #7, see above).

Thank you so much for this discussion and your hints.
-wittbo-
MBAir M2 with MacOS 14.4.1 / Lazarus  3.2.2
MacStudio M1 Max with MacOS 14.4.1 / Lazarus 3.2.2

wittbo

  • Full Member
  • ***
  • Posts: 151
Re: TArrow component supplement
« Reply #12 on: September 03, 2020, 07:09:20 pm »
A little addition to the alpha channel solution described by wp and a very nice bug in the component TCustomImage (?):

To get the bitmap displayed, you have to define its size: intfImg.SetSize (myWidth, myHeight)

If myWidth is exactly twice as large as myHeight and really only in this special case, the displayed Bitmap has a square area with width = height = myHeight. Nice Bug isn't it?
« Last Edit: September 03, 2020, 07:12:25 pm by wittbo »
-wittbo-
MBAir M2 with MacOS 14.4.1 / Lazarus  3.2.2
MacStudio M1 Max with MacOS 14.4.1 / Lazarus 3.2.2

wp

  • Hero Member
  • *****
  • Posts: 12459
Re: TArrow component supplement
« Reply #13 on: September 03, 2020, 07:39:17 pm »
Can you work out a simple compilable demonstration and post it here?
« Last Edit: September 03, 2020, 07:41:01 pm by wp »

wittbo

  • Full Member
  • ***
  • Posts: 151
Re: TArrow component supplement
« Reply #14 on: September 04, 2020, 12:46:16 pm »
Here it is.

The app starts with a rectangle 80 * 45. By means of the UpDown you can change the height.
So, if you step down to 41,  everything works as expected.
When you step down from 41 to 40, the red rectangle flips to a square 40 * 40,
when you reduce the height, 39, 38, ... everything Ok.

This effect always occurs when width = 2*height.
-wittbo-
MBAir M2 with MacOS 14.4.1 / Lazarus  3.2.2
MacStudio M1 Max with MacOS 14.4.1 / Lazarus 3.2.2

 

TinyPortal © 2005-2018