Shaped Icons on a CTabCtrl... nearly impossible...
CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 9 of 9

Thread: Shaped Icons on a CTabCtrl... nearly impossible...

  1. #1
    Join Date
    May 2013
    Posts
    14

    Question Shaped Icons on a CTabCtrl... nearly impossible...

    I have a dialog window with a CTabCtrl. The following code is successful in showing an icon along with the text name on each of 16 tabs. The icons are 16x16 pixel squares, 4-bit, that I made with Visual Studio 2008's resource editor.

    The icons to have transparent pixels (the first pixel of the color map), so that I can "shape" them to be circles, etc., instead of squares.

    However, the transparency works ONLY IF I use ILC_COLOR8 instead of ILC_COLOR4, and use LR_LOADMAP3DCOLORS. (Neither of these are documented as being related.) If I don't have LR_LOADMAP3DCOLORS, or if I use ILC_COLOR4, the "transparent" parts of the icon are colored white instead.

    Although my code now works, can anyone explain why? I'm really a Unix guy and would love to understand Windows better than I do.



    // Configure the Tab control.

    CTabCtrl* ptab = (CTabCtrl*) GetDlgItem( IDC_TAB1 );

    static CImageList* pil = NULL;

    if ( ! pil ) {
    pil = new CImageList;

    // There's no documentation on the entire internet of this, but if I specify
    // ILC_COLOR4, the first color in the icon is turned to white, not the actual
    // COLOR_WINDOW.

    pil->Create( 16, 16, ILC_COLOR8, 4, 4 );

    // The help for CImageList doesn't explain what this background color is for.
    // I've tried the following to see if it controls the color used for transparency
    // of the images in the image list (with LOADTRANSPARENT) but it doesn't
    // seem to be used for that.
    // pil->SetBkColor( CLR_NONE );
    // pil->SetBkColor( GetSysColor( COLOR_WINDOW ) );

    // This worked fine, except it doesn't support transparencies.

    // HICON hiMyIcon = LoadIcon( AfxGetInstanceHandle(), MAKEINTRESOURCE( IDI_OK ) );

    // LR_LOADTRANSPARENT is documented to turn "the first color" in the icon to the
    // window background color, in effect making it transparent. However, without
    // LR_LOADMAP3DCOLORS it instead is just turning that portion of the icon to white.

    HICON hiMyIcon = (HICON) LoadImage( AfxGetInstanceHandle(),
    MAKEINTRESOURCE( IDI_PATCH_STATUS_OK ),
    IMAGE_ICON, 16, 16,
    LR_LOADTRANSPARENT | LR_LOADMAP3DCOLORS );

    pil->Add( hiMyIcon );

    // The discussion of OverlayImage mentions transparency, but I can't figure out
    // how to try this. But not needed once I start using LR_LOADMAP3DCOLORS.

    // pil->SetOverlayImage( iIndex, 1 );
    }

    ptab->SetImageList( pil );



    // Make 16 tabs. Label each tab with the OK icon and the tab number.

    for ( int i = 0; i < 16; i++ ) {
    char szBuf[ 200 ];

    AKsnprintf( szBuf, sizeof( szBuf ), "%d", i + 1 );
    ptab->InsertItem( i, szBuf, 0 );
    }

  2. #2
    Join Date
    Apr 2000
    Location
    Belgium (Europe)
    Posts
    3,652

    Re: Shaped Icons on a CTabCtrl... nearly impossible...

    you create an 8bit icon. This doesn't say anything about the actual image being available, if you do nothing, you'll just get an empty image.

    Loadmap3Dcolors doesn't actually make a transparent bitmap. it merely takes an image and maps (recolors) some fixed colors to variable colors.
    so a gray of 128,128,128 will get mapped(recolored) to whatever color your 3D front face color is set to. similarly pure black, and pure white will be mapped as well, as well as the dark 3d effect (which is a gray 64,64,64 iirc).

    this remapping can result in really messy looking icons if you use a "reverse" windows display setting where the page color is black (instead of white) and window text is white (instead of black). This is common in the "high contrast" display settings.

    If you want real transparency, you should use truecolor icons with alphachanel. This will however restrict your app to running properly to vista and later (partial support on XP SP3).

  3. #3
    Join Date
    May 2013
    Posts
    14

    Re: Shaped Icons on a CTabCtrl... nearly impossible...

    Hi OReubens,

    Thank you so much for your time and expertise.

    My question was perhaps not quite clear.

    Yes, I understand there's no actual transparency; the icon continues to be a square, with some pixels merely changed to be (eg) the window's background color. Since I'm using the icons on CTabCtrl tabs it doesn't matter.

    Your explanation of the 3D effect matches the understanding I got from the VC2008 docs for LR_LOADMAP3DCOLORS. However, in fact I am NOT using this functionality. My icons are simply red, green, yellow, black.

    My goal, AND what is working (for some reason that I'd like to understand), is instead the "pixel change" to turn the FIRST CELL IN THE COLOR MAP to match background color. This cell needn't be black, 64/64/64 etc. In fact I set it to hot pink to make it stand out (and made another color map cell black as I needed black).

    I understand your point about reverse window colors. However, the problems I have are occuring even with "typical" window colors. (And since my icons aren't attempting a 3D look, they'd probably work pretty well in reverse.)
    So my questions really are:

    1) LR_LOADTRANSPARENT claims to remap first cell in the color map to background color. But this DOESN'T WORK with pil->Create( 16, 16, ILC_COLOR4, 4, 4 ); It needs ILC_COLOR8. Why is that? (BTW the icon is 16-color, although I've edited the colors.)

    2) AND, it doesn't work unless I specify LR_LOADMAP3DCOLORS as well. Why is that?

  4. #4
    Join Date
    Apr 2000
    Location
    Belgium (Europe)
    Posts
    3,652

    Re: Shaped Icons on a CTabCtrl... nearly impossible...

    1) This is probably due to a difference in the icon you create (either as 16color with ILC_COLOR4 or 256 color with ILC_COLOR8) and the image being loaded.
    If you crate an icon as ILC_COLOR4 but your actual image being loaded is not 16 color with using the default windows palette, then all colors will be remapped to the closest matching base 16 windows colors. When this happens, the transparency effect is lost.

    2) If you then use LOADMAP3DCOLORS as well, this will fix things. but not really for the reasons you think, but probably because of the unexpected matching it did in the previous stage.



    If your image is an actual icon file rather than an image, then LOADTRANSPARENT does nothing, the mask in the icon takes precedence. remapping colors can still occur in an actual icon. What color your paint program uses to visualize the "transparent pixels" on an icon is actually irrelevant here.

    THe bottom line really is... if your image is 16 color (as in it's actually maximum 16, not an 8bpp image that only contains 16 unique colors), load it as ILC_COLOR4 otherwise load it as appropriate ILC_COLOR8 or higher.

  5. #5
    Join Date
    May 2013
    Posts
    14

    Re: Shaped Icons on a CTabCtrl... nearly impossible...

    Thanks, I feel that I'm slowly learning something. The icons were 4-bit, 16-color ones made with the VC2008 resource editor. I MAY have also changed the pixel values for ssome of the pixels, not sure. But you seem to be saying (and it makes sense) that since I created a 4-bit CImageList, it specifically tried to use the old 16 colors from 1984 PC's, right? Then, the "LOADTRANSPARENT" did its thing, turning color map entry #0 (which WAS black) to match the light greenish-grey window color I have... but since that color wasn't in the old 16 color map, it went ahead and used white, which I think was probably the closest match among the 16 colors?

    If that were the whole story, then using an 8-bit CImageList, which was able to hold any color it wanted (up to a limit of 256 colors of course), should have been able to display the exact light greenish-grey. But it STILL didn't, until I also had LOADMAP3DCOLORS. I don't understand that.

  6. #6
    Join Date
    Apr 2000
    Location
    Belgium (Europe)
    Posts
    3,652

    Re: Shaped Icons on a CTabCtrl... nearly impossible...

    actually... no...
    if you pre-create the imagelist to a certain size, you get the size and a default palette.
    adding individual images, will get remapped with the palette the imagelist is set to. So if you have set colors that don't appear in the default palette, then those colors will be remapped to the closest approximation in the current palette of the imagelist.

    if you want the imagelist to have a certain palette, you need to explicitely enforce this, or create the imagelist by loading an image rather than creating an empty one and filling it up yourself.

    These type of color remaps happen all the time when you take an image from one DC to another or depending on itf it's a DIB or a DDB that's being backed. And sometime unexpected side effects happen because of this remapping.

    There is a reason why a decision was made to stop fully supporting 16 (not enough colors) and 256 color modes (too much hassle with palette changes) in fvour of truecolor modes. Many new programs don't even function well under those conditions.

    At the opposite side, if you deal with 16 color images, make sure they're using the default 16 base colors and no other, if they are using different colors, then it should be treated as a 256 color image (that only uses 16 unique colors).
    When dealing with Windows API's, avoid 8bit palette based DIB's and DCs unless you're prepared to support them properly. Either set your DC/DIB to monochrome, 16 color (assuming the default 16 base colors), or truecolor (16, 24 or 32 bit color). For most modern videocards, 16 bit color modes don't get hardware accelleration so it's also usually a bad idea these days.
    Last edited by OReubens; May 23rd, 2013 at 09:20 AM.

  7. #7
    Join Date
    May 2013
    Posts
    14

    Re: Shaped Icons on a CTabCtrl... nearly impossible...

    Thanks again OReubens.

    This code as presented works. If I remove the 3D flag OR if I create the CImageList with ILC_COLOR4 instead of ILC_COLOR8, it does NOT work. In both cases of course I'm using the same icons, which happen to be color-edited 16-color icons.

    I think your explanation lays to rest the case of ILC_COLOR4. I see now thanks to your explanation that this clearly cannot work as the colormap is full at creation time, and even though the icons themselves may not be using non-standard-4-bit-colors, the window BACKGROUND is non standard, so that the TRANSPARENT flag simply won't work.

    But lets take the case where I make used ILC_COLOR8. LoadIcon() can apparently allocate the needed color, as it does so with the 3D flag. It simply doesn't do what the manual pages say TRANSPARENT will WITHOUT the 3D flag. Is this just a manual oversight perhaps? Does "non-3D" default to the idea of a white background, for instance, because before 3D, before Win95, the background was white and non-changable? (I don't even remember, I only used older windows about 100 hours.)

  8. #8
    Join Date
    Apr 2000
    Location
    Belgium (Europe)
    Posts
    3,652

    Re: Shaped Icons on a CTabCtrl... nearly impossible...

    the thing is... you really have to see ILC_COLOR4 as meaning "The 16 base windows colors" and not "Whichever 16 colors I want".
    While you certainly can achieve the 2nd, it'll require quite a bit of hassle and messing around to make it consistently work that way. So much so that the majority of programs don't bother anyway, and even guides and books tend to discard it as a viable option.

    Similarly with ILC_COLOR8, 256 color and it's whole palette mess will tend to mean "the default windows 256 color palette", this case in particular is even a slight bit harder to work around than the ILC_COLOR4 because it has a more complex/slower mapping to/from.



    transparent and 3D do different things. and in the case of an imagelist, the effects of those are different yet again.


    In the case of an imagelist, the only way to achieve actual transparency is with either creating the imagelist with a mask (ILC_MASK) or with ILC_COLOR32 and using an alphachannel (with an optional mask).
    You're making the imageslist without a mask, so you get images 'as is' without an actual transparent information.

    So... using that info.
    loading the image with LR_TRANSPARENT, loads the image replacing the first pixel value with COLOR_WINDOW (=usually white). Which is exactly what you say you get. This image with the "white" pixels is then added "as is" as an image without mask into the imagelist. so when you draw this image from the imagelist, you get the original image with the first pixel color all replaced by white.
    If this doesn't work well with ILC_COLOR4 and does with ILC_COLOR8 this simply means you didn't get what you expected in the loading phase when the colors were being remapped to the 16 base windows colors.


    the 3D mapping simply does additional color remapping for the 3D button effects. It doesn't in any way shape or form affect actual transparency. In a extreme case, it will override the color_window effect of the previous step if you happen to have your window color set to a 3D color.


    "transparent" in windows tends to be a myth for the most part.
    The only true transparency is in the API's that support alphablending and you properly use an alphachannel. (rejoice, imagelist is one of them)
    The next best thing is using a mask. (again, bonus if you use an imagelist this this is supported)
    everything else is just a poor mans attempt by having an image where some colors in the bitmap happen to have the same colors as the area you will be painting on top of. A lot of the time this just barely works, sometimes it doesn't.



    your simple way out is changing the image to truecolor and using an alphachannel. changing the imagelist to ILC_COLOR32
    your next best thing is making an image for the entire image list and creating the imagelist based on the image with the colorkey enabled. (this will automatically create a mask from the color key).
    the harder thing is sticking to what you have and generating a mask of the image based on a color key from the image through code, then add the image and it's mask to a masked imagelist.
    Other than that, the 3Dmapping and transparent effects won't work in your case since you aren't using the imagelist on top of color_window but on a dialog/control.

  9. #9
    Join Date
    May 2013
    Posts
    14

    Re: Shaped Icons on a CTabCtrl... nearly impossible...

    I agree (and at this point, know, thanks to your previous notes) everything up to this point:



    the 3D mapping simply does additional color remapping for the 3D button effects. It doesn't in any way shape or form affect actual transparency. In a extreme case, it will override the color_window effect of the previous step if you happen to have your window color set to a 3D color.

    Not true.

    With an 8-bit image list, TRANSPARENT|3D can map the first pixel in the color map to background color, as I needed. So I KNOW the COLOR8 image list itself can get the color.

    If I remove the |3D, then it does NOT map the first pixel in the color map to background color.

    The docs (and nothing else on the internet) says the 3D flag should be necessary for TRANSPARENT to work.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  


Azure Activities Information Page

Windows Mobile Development Center


Click Here to Expand Forum to Full Width

This is a CodeGuru survey question.


Featured


HTML5 Development Center