Recent

Author Topic: [New Component] ExtTabCtrl - A custom, feature-rich tab control (LGPL)  (Read 6290 times)

wp

  • Hero Member
  • *****
  • Posts: 13630
PageControl could be simply the container for a top-aligned ExtTabCtrl and the tabsheets (headerless), and ExtTabCtrl should be able to use tabsheets as pages (instead of TFrames like in the current page control demo).
I'd prefer a TNotebook because the PageControl appears to be more complex to me and originates from a widget control which may cause problems with custom-painting. It will allow automatic switching to dark mode, but might require some extra code for mouse-over effects.

But basically you are right. I think that besides TExtTabControl there should also be a TExtPageControl which descends from TExtTabControl and houses an internal notebook. The notebook should be linked to the TabControl in a way that any operations made with the tabs will be mirrored with the notebook pages, i.e. when a tab is added a page will be added to the notebook; when another tab is selected the notebook should switch to the corresponding page, etc. My gutfeeling tells me that it would be easier when the notebook is not accessible directly, only via methods of the TExtPageControls.

We could use characters (+, <, >) for the buttons
Great idea, plus #$E2#$9C#$95, or similar, for the cross (provided the font has it) - this would make the FInternalBtnImages obolete and will save some code.

With the distance of a few days I see also that the FInternalTabImages has an issue because it copies the images from the provided imagelist, Images. Having 10 ExtTabCtrls in a project would then mean that there are 10 copies of the original image list. This is not why an imagelist was invented. Only because of the rotated images... Maybe you should return to your original idea of extracting the required image at the required size from the Images list and paint that on the canvas, rather than letting the imagelist itself draw it.

i see that the close button cross will be white - in dark mode only, and only when using the OnDrawTab callback. Before it had been red.
No prob, but i simply won't understand yet why, and if/how one could control that.
I saw that the black button icons were not visible any more in dark mode, and therefore I added a routine to recolor the images by replacing all pixels having alpha <> 0 with some other color. (of course this is useful only for monochrome images) This is done when dark mode is detected. Of course, processing of the red cross could be excluded from this procedure. Alternatively, when you need a specific "close" icon you can provide it always in the Images, an imagelist, and specify its imageindex in the ButtonImages.

d7_2_laz

  • Hero Member
  • *****
  • Posts: 696
Hello wp, thank you for your detailed considerations!
About pagecontrol, notebook & co: i'd agree, but i really didn't intend to propagate tpagecontrol against tnotebook, but simply wanted to mention that's possible to apply the TExtTabCtrl here too,  for one of the typical 'page' containers.

About the (red->white) close button: the new one processed in dark mode doesn't look that bad too, but originally i felt it a bit irritating. No clear definite opinion yet (as oftenly, an option to decide could be nice, but ...). Maybe let's wait what ovidio is thinking about, but at the end i think we'll keep the current one.
« Last Edit: June 15, 2026, 12:45:51 am by d7_2_laz »
Lazarus 4.8  FPC 3.2.2 Win11 64bit

ovidio

  • Jr. Member
  • **
  • Posts: 68
PageControl could be simply the container for a top-aligned ExtTabCtrl and the tabsheets (headerless), and ExtTabCtrl should be able to use tabsheets as pages (instead of TFrames like in the current page control demo).
I'd prefer a TNotebook because the PageControl appears to be more complex to me and originates from a widget control which may cause problems with custom-painting. It will allow automatic switching to dark mode, but might require some extra code for mouse-over effects.

But basically you are right. I think that besides TExtTabControl there should also be a TExtPageControl which descends from TExtTabControl and houses an internal notebook. The notebook should be linked to the TabControl in a way that any operations made with the tabs will be mirrored with the notebook pages, i.e. when a tab is added a page will be added to the notebook; when another tab is selected the notebook should switch to the corresponding page, etc. My gutfeeling tells me that it would be easier when the notebook is not accessible directly, only via methods of the TExtPageControls.

I have also though about doing a TExtPageCtrl with an internal TNotebook, but would like to complete this component first.

Great idea, plus #$E2#$9C#$95, or similar, for the cross (provided the font has it) - this would make the FInternalBtnImages obolete and will save some code.

With the distance of a few days I see also that the FInternalTabImages has an issue because it copies the images from the provided imagelist, Images. Having 10 ExtTabCtrls in a project would then mean that there are 10 copies of the original image list. This is not why an imagelist was invented. Only because of the rotated images... Maybe you should return to your original idea of extracting the required image at the required size from the Images list and paint that on the canvas, rather than letting the imagelist itself draw it.

I have now switched to custom drawn images. What do you think? I do have realized a problem, with the cross for the close button, when I make it right for macOS it is asymmetric on Windows, and viceversa. Will check how to fix it. In addition, now the images can be seen in either light or dark modes.

EDIT: I have modified how the close button is drawn, and now it is always symmetric.

I saw that the black button icons were not visible any more in dark mode, and therefore I added a routine to recolor the images by replacing all pixels having alpha <> 0 with some other color. (of course this is useful only for monochrome images) This is done when dark mode is detected. Of course, processing of the red cross could be excluded from this procedure. Alternatively, when you need a specific "close" icon you can provide it always in the Images, an imagelist, and specify its imageindex in the ButtonImages.

Now they don't change colors when switching modes, since this color can be seen well on both modes.
« Last Edit: June 15, 2026, 12:50:19 pm by ovidio »

wp

  • Hero Member
  • *****
  • Posts: 13630
Looked at your current code:
  • Although you had re-added the removed code which I thought was responsible for my observed hangs at high-dpi this is working fine now. Great.
  • But: The custom-drawn speedbuttons do not look nice at high dpi. They are pixelated and seem to be scaled twice: Well, the first scale is due to your "sz := Scale(16)" which is correct because the image must be larger at higher dpi. But the second scale seems to be done by the Speedbutton itself, because it always assumes that images assigned to the Glyph property are for 96ppi (but you already has painted the bitmap for your resolution). I don't know if or how this feature can be disabled, but I think it would be easier to paint the speedbutton icon yourself, too: there is an OnPaintEvent where you can either create the bitmap or where you can draw the previously-created bitmap. Of course, the Glyph property then must be kept empty. Alternatively you could skip the speed buttons altogether and draw the icons directly on the ExtTabCtlr's canvas, maybe with some ThemeServices calls for the background to mimic the presence of a speedbutton.
  • The "Rotate Add Tab" checkbox in my demo has no functionality any more. Probably because the new speedbutton code does not take care of the external imagelist where the "BtnAdd" icon can be found as well.
  • In the Windows dark mode the border lines of the tabs are barely visible. You use clBtnShadow for the pen here - I think this color does not become brighter in darkmode. Maybe you must detect dark mode (IsDarkMode) and select a darkmode-specific color here.
  • I don't like the name "ButtonImages" - it indicates that it refers to an imagelist, but it only refers to a sub-component with image indexes for the buttons. Why not "ButtonImageIndexes" or similar? This would avoid the confusion.I already had renamed it in my fork, but did not publish the new name because it would break your code in existing demos and test projects.
« Last Edit: June 15, 2026, 11:00:30 pm by wp »

ovidio

  • Jr. Member
  • **
  • Posts: 68
Looked at your current code:
  • Although you had re-added the removed code which I thought was responsible for my observed hangs at high-dpi this is working fine now. Great.
  • But: The custom-drawn speedbuttons do not look nice at high dpi. They are pixelated and seem to be scaled twice: Well, the first scale is due to your "sz := Scale(16)" which is correct because the image must be larger at higher dpi. But the second scale seems to be done by the Speedbutton itself, because it always assumes that images assigned to the Glyph property are for 96ppi (but you already has painted the bitmap for your resolution). I don't know if or how this feature can be disabled, but I think it would be easier to paint the speedbutton icon yourself, too: there is an OnPaintEvent where you can either create the bitmap or where you can draw the previously-created bitmap. Of course, the Glyph property then must be kept empty. Alternatively you could skip the speed buttons altogether and draw the icons directly on the ExtTabCtlr's canvas, maybe with some ThemeServices calls for the background to mimic the presence of a speedbutton.
  • The "Rotate Add Tab" checkbox in my demo has no functionality any more. Probably because the new speedbutton code does not take care of the external imagelist where the "BtnAdd" icon can be found as well.
  • In the Windows dark mode the border lines of the tabs are barely visible. You use clBtnShadow for the pen here - I think this color does not become brighter in darkmode. Maybe you must detect dark mode (IsDarkMode) and select a darkmode-specific color here.

Now the images are drawn directly on the TSpeedButton canvas. On my Windows, they work OK with high DPI. Please, can you check that it works for you too?

I will check your other comments Tomorrow.

wp

  • Hero Member
  • *****
  • Posts: 13630
Now the images are drawn directly on the TSpeedButton canvas. On my Windows, they work OK with high DPI. Please, can you check that it works for you too?
Yes, nice quality now. To my eyes, however, the + button appears a bit to large compared to the others - shrink the lines by 1 or 2 pixels on each side (to keep symmetry) - but this is only my personal impression.

ovidio

  • Jr. Member
  • **
  • Posts: 68
I have corrected some bugs and addressed some comments, including:
  • Changed the color of the border on dark mode, to make it more visible
  • Changed the color of inactive tabs, to avoid that they look as disabled
  • Fixed a bug with the hints (buttons would show the hint of the last tab when they had no hint defined)
  • Custom buttons change color of border/fill when switching modes
  • Removed obsolete/unused code
  • Increased the text indent when there was no image on the tab
  • Images are instantly updated when toRotateAddImage is selected/deselected
  • Renamed TButtonImages to TButtonImageIndexes
  • Reduced the thickness of the + image

I believe that most of the suggestions have been implemented now. What do you think?

wp

  • Hero Member
  • *****
  • Posts: 13630
Yes, good.

Maybe just this: In dark mode, the border color of the tabs appears a bit too aggressive to me now, I'd prefer a bit more decent gray, similar to the border of the standard TPageControl or TGroupbox (see screenshot). But anyway, just my taste...

I think let's wait a few more days for more comments, and then we can think about adding the control to OPM.

d7_2_laz

  • Hero Member
  • *****
  • Posts: 696
In sum very good changes!
- Bug with the hints: yes, had noticed this too (and circumvented); appeared to be fixed.
- Previously as being disabled looking passive tabs: yes, is improved.
- Text indentation in tabs having no image: yes, better now!
- Add button changed color when switching modes: is corrected.
- (Renamed TButtonImages to TButtonImageIndexes -> i don't know yet the background of this topic)

- Border color in dark mode changed, to make it more visible:
  My first thought: great! Then: as wp said, the border color appears to be too dominant.
  Then, after comparing previous vs. now - see attached image -, the feeling: i'd like it somehow more to see it as before, either appealing 'without' border or with a much more decent border color. Typical matter of taste or for an option (yes i know, options are unpopular). My preference would be to be somehow to be able to control the border color.

I'd have additionally two minor subtopics for the scenario 'scrolling needed' (see image).
- Imo a bit more indendation for the 'scroll next' button would be good. When testing, i'd sometimes achieved an 'add' when having intended to do a scroll. The distance between the buttons is so small. Don't know if others might feel similar.
- That tabs may appear truncated is by nature. If they should appear if that doesn't make sense (because one cannot identiy anything on the tab), or if there maybe measures against, might be a question. I would it let as it is, but only to mention this little aspect.

« Last Edit: June 16, 2026, 04:20:23 pm by d7_2_laz »
Lazarus 4.8  FPC 3.2.2 Win11 64bit

wp

  • Hero Member
  • *****
  • Posts: 13630
- (Renamed TButtonImages to TButtonImageIndexes -> i don't know yet the background of this topic)
You can replace all or some of the +, <, > and x images by your own icons by putting those into an ImageList and attaching that to the Images property of to the TExtTabCtrl (you can mix button and tab images in the same imagelist), and in ButtonImageIndex you can specify the ImageIndex for each of these buttons (or leave it at -1 to keept the built-in image).
« Last Edit: June 16, 2026, 05:10:27 pm by wp »

ovidio

  • Jr. Member
  • **
  • Posts: 68
- Border color in dark mode changed, to make it more visible:
  My first thought: great! Then: as wp said, the border color appears to be too dominant.
  Then, after comparing previous vs. now - see attached image -, the feeling: i'd like it somehow more to see it as before, either appealing 'without' border or with a much more decent border color. Typical matter of taste or for an option (yes i know, options are unpopular). My preference would be to be somehow to be able to control the border color.

I have tried to make the color more subtle. It is hard to get a good balance, because the color is different on macOS and on Windows. What do you think of this color?

I'd have additionally two minor subtopics for the scenario 'scrolling needed' (see image).
- Imo a bit more indendation for the 'scroll next' button would be good. When testing, i'd sometimes achieved an 'add' when having intended to do a scroll. The distance between the buttons is so small. Don't know if others might feel similar.
- That tabs may appear truncated is by nature. If they should appear if that doesn't make sense (because one cannot identiy anything on the tab), or if there maybe measures against, might be a question. I would it let as it is, but only to mention this little aspect.

I will look into it Tomorrow.

ovidio

  • Jr. Member
  • **
  • Posts: 68
Maybe just this: In dark mode, the border color of the tabs appears a bit too aggressive to me now, I'd prefer a bit more decent gray, similar to the border of the standard TPageControl or TGroupbox (see screenshot). But anyway, just my taste...

Do you like this (more subtle color)? Or, it is too subtle?

I think let's wait a few more days for more comments, and then we can think about adding the control to OPM.

Ok, in the meantime I will continue hunting bugs.

By the way, I don't know how to handle design time clicks. With the patched Lazarus, it works perfectly but for many users it will look buggy (of course, people will blame the component, not Lazarus for the strange behavior). So the question is, should I leave it as is or disable it until Lazarus 4.10 or 5.0 comes out?

Antek

  • New Member
  • *
  • Posts: 15
I just tested the demo from  current repository .
  • Win 11 24h2
  • laz 4.8 ; fpc 3.2 fixes

Tested
100%/175%/225% scaling
with and w/o darkmode/metadark ( demo highdp ,notebook , simple (w/o metadark))

So far everything is working fine.
Great work!!

ovidio

  • Jr. Member
  • **
  • Posts: 68
I just tested the demo from  current repository .
  • Win 11 24h2
  • laz 4.8 ; fpc 3.2 fixes

Tested
100%/175%/225% scaling
with and w/o darkmode/metadark ( demo highdp ,notebook , simple (w/o metadark))

So far everything is working fine.
Great work!!

Great! Thank you for testing it.

wp

  • Hero Member
  • *****
  • Posts: 13630
Do you like this (more subtle color)? Or, it is too subtle?
Hmm, maybe a bit difficult to see, at least on my monitor. Maybe blending factor 0.2 or 0.25 - see screenshots. But there could be another issue. The color basically depends on clBtnShadow. What if Microsoft decides in one of its many updates to make this system color much darker, or brighter? Or when the user selects a tab color equal to the border color? Therefore, I agree with d7_2_laz that once there is a user setting for the tab color there should also be a user setting for the border color.

By the way, I don't know how to handle design time clicks. With the patched Lazarus, it works perfectly but for many users it will look buggy (of course, people will blame the component, not Lazarus for the strange behavior). So the question is, should I leave it as is or disable it until Lazarus 4.10 or 5.0 comes out?
I think it's not worth the effort to find a work-around. Releasing v5.0 is being discussed, and the first RC is not too far away. There are many more components which work at designtime only in a limited way, and when you mention that the bug preventing the desired behaviour has been fixed in the development version of Lazarus and in the upcoming v5.0, nobody will blame the component.

 

TinyPortal © 2005-2018