The rendering of buttons on our toolbars is pretty dated. In particular, the greying of disabled buttons is using a technique that works best on 4-bit graphics and that may produce ugly and inadequate results for bitmaps with more colours. And overall, the rendering algorithms assume colour-indexed bitmaps with a palette (8-bit or less colour depth) and does not work at all for direct-colour bitmaps without palettes (typically 24-bit "true colour"). We should improve this!
See also:
Bugs: #120
Bugs: #37
Discussion: 6e4ad3ad
Discussion: Transparent bitmaps with TButtonGadget
Discussion: 89cd9b96
Discussion: Tip for nicer gadget buttons
Discussion: TControlBar
Feature Requests: #213
News: 2022/07/owlmaker-build-6160-update
Wiki: OWLNext_Roadmap_and_Prereleases
Anonymous
Support for 24-bit bitmaps has been added on the trunk [r6122], and the revision has been merged into Owlet [r6123].
One of the big problems with the old code was that it did colour mapping — replacing certain colours in the source bitmap by system colours. See TButtonGadget::GetGlyphDib. It calls TDib::MapUIColors, which transforms the given glyph. GetGlyphDib is called behind the scenes by TButtonGadget::BuildCelArray, which in turn is called in TButtonGadget::SysColorChange and TButtonGadget::GetDesiredSize. The latter function is called as part of gadget window initialisation and sizing. So the colour mapping just happened as a side-effect of this — all very obscure!
With regard to rendering proper transparency, the effect of the colour mapping was to replace TColor::LtGray by TColor::Sys3dFace in the given glyph. However, pixels of this colour are not rendered. Instead, a mask is created based on the transformed bitmap with TColor::Sys3dFace as the transparent colour. The mask is then used to finally render the glyph (using GDI function MaskBlt). Using a mask allows the theme-based background to show through transparent areas of the glyph bitmap, as the background is rendered first (see TButtonGadget::PaintBorder). The rendering of the face itself is delegated by TButtonGadget::PaintFace to TUIFace and happens in TUIFace::PaintBm.
Apart from being obscure, the colour mapping using TDib::MapUIColors does not work for 24-bit bitmaps, since this function works on the DIB's palette, and 24-bit bitmaps do not have a palette.
My revision removes the colour mapping altogether. Mapping certain colours in the glyphs to system colours no longer make sense in modern Windows, I would think, but let me know if you see a compatibility problem. Without the mapping, the code is now much clearer about using TColor::LtGray as the transparent colour. However, perhaps we should change this also, and instead use the upper left pixel. The latter is a common convention, I think. For example, it is supported by Windows' own Image Lists (see ImageList_LoadImage).
The other big problem with the rendering was, as mentioned in the ticket description, that it had very poor rendering of disabled buttons. I have hence replaced this part of the code altogether with a new fading routine. It dries and fades the colours in the glyph towards TColor::Sys3dFace. See the revised TUIFace::PaintBm, which now calls the new helper function MakeFadedCopy_.
The new solution should be compatible with bitmaps of all colour depths. I've tested 4-bit, 8-bit and 24-bit, and it seems to all work as intended. But please review and test!
Related
Commit: [r6122]
Commit: [r6123]
Flicker-free rendering in TGadgetWindow::Paint has been added on the trunk [r6149][r6150][r6152][r6154] and merged into Owlet [r6151][r6153][r6155].
Related
Commit: [r6149]
Commit: [r6150]
Commit: [r6151]
Commit: [r6152]
Commit: [r6153]
Commit: [r6154]
Commit: [r6155]