Ignore:
Timestamp:
Oct 29, 2009, 10:11:44 PM (16 years ago)
Author:
Dmitry A. Kuminov
Message:

gui: Only supply one icon when creating a HPOINTER (WinCreatePointerIndirect() ignores the other one anyway) and make sure that the mini icon is used for HPOINTERs sent to the system tray which expects only mini icons.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/gui/image/qpixmap_pm.cpp

    r264 r267  
    102102    icons and pointers (\sa toPmHPOINTER()).
    103103
    104     Note that if the pixmap does neither have a maks nor the alpha channel but
     104    if \a embedRealAlpha is \c true, the real alpha chennel (not the 1bpp mask)
     105    will be embedded in the high 8 bits of the 32-bit pixel value for each pixel
     106    in the created bitmap (which always has 1 plane and the 32-bit depth). This
     107    extra information isn't touched by PM/GPI but may be used by custom drawing
     108    routines to do real alpha blending.
     109
     110    Note that if the pixmap does neither have a mask nor the alpha channel but
    105111    \a mask is not NULL, a NULLHANDLE value will be stored there.
    106112
     
    110116    \warning This function is only available on OS/2.
    111117*/
    112 HBITMAP QPixmap::toPmHBITMAP(HBITMAP *mask) const
     118HBITMAP QPixmap::toPmHBITMAP(HBITMAP *mask) const
    113119{
    114120    if (data->classId() != QPixmapData::RasterClass) {
     
    130136    HBITMAP hbmMask = NULLHANDLE;
    131137
    132     QImage image = d->image.convertToFormat(QImage::Format_ARGB32).mirrored();
     138    // Note that we always use ARGB32 even if embedRealAlpha is false because
     139    // in this case we will use the alpha channel to dither the 1bpp mask
     140    QImage image = d->image.convertToFormat(QImage::Format_ARGB32);
     141    // flip the bitmap top to bottom for PM
     142    image = image.mirrored();
    133143
    134144    // bitmap header + 2 palette entries (for the mask)
     
    148158
    149159    if (mask && hasAlpha()) {
    150         // get the mask. We prefer QImage::createAlphaMask() over QPixmap::mask()
    151         // since the former will dither while the latter will convert any
    152         // non-zero alpha value to an opaque pixel
    153 #if 1
    154         QImage mask = image.createAlphaMask().convertToFormat(QImage::Format_Mono);
    155 
    156         // note: for some strange reason, createAlphaMask() (as opposed to
    157         // mask().toImage()) returns an image already flipped top to bottom,
    158         // so take it into account
    159 
    160         // create the AND mask
    161         mask.invertPixels();
    162         // add the XOR mask (and leave it zeroed)
    163         mask = mask.copy(0, -h, w, h * 2);
    164 
    165 #else
    166         QImage mask = this->mask().toImage().convertToFormat(QImage::Format_Mono);
    167 
    168         // create the AND mask
    169         mask.invertPixels();
    170         // add the XOR mask (and leave it zeroed)
    171         mask = mask.copy(0, 0, w, h * 2);
    172         // flip the bitmap top to bottom for PM
    173         mask = mask.mirrored(false, true);
    174 #endif
     160        // get the mask
     161        QImage mask;
     162        if (!embedRealAlpha) {
     163            // We prefer QImage::createAlphaMask() over QPixmap::mask()
     164            // since the former will dither while the latter will convert any
     165            // non-zero alpha value to an opaque pixel
     166            mask = image.createAlphaMask().convertToFormat(QImage::Format_Mono);
     167
     168            // note: for some strange reason, createAlphaMask() (as opposed to
     169            // mask().toImage()) returns an image already flipped top to bottom,
     170            // so take it into account
     171
     172            // create the AND mask
     173            mask.invertPixels();
     174            // add the XOR mask (and leave it zeroed)
     175            mask = mask.copy(0, -h, w, h * 2);
     176        } else {
     177            // if we embedded real alpha, we still need a mask if we are going
     178            // to create a pointer out of this pixmap (WinCreatePointerIndirect()
     179            // requirement), but we will use QPixmap::mask() because it won't be
     180            // able to destroy the alpha channel of non-fully transparent pixels
     181            // when preparing the color bitmap for masking later. We could also
     182            // skip this prepare step, but well, let's go this way, it won't hurt.
     183            mask = this->mask().toImage().convertToFormat(QImage::Format_Mono);
     184
     185            // create the AND mask
     186            mask.invertPixels();
     187            // add the XOR mask (and leave it zeroed)
     188            mask = mask.copy(0, 0, w, h * 2);
     189            // flip the bitmap top to bottom for PM
     190            mask = mask.mirrored(false, true);
     191        }
    175192
    176193        // create the mask bitmap
     
    192209        POINTL ptls[] = {
    193210            { 0, 0 }, { w - 1, h - 1 },     // dst: inclusive-inclusive
    194             { 0, h }, { w, h * 2 },             // src: inclusive-exclusive
     211            { 0, h }, { w, h * 2 },         // src: inclusive-exclusive
    195212        };
    196213        ptls[0].y -= h;
     
    217234    If \a isPointer is \c true, an icon size closest to the system pointer size
    218235    is chosen, otherwise to the system icon size. \a hotX and \a hotY define the
    219     hot spot.
     236    hot spot. Note is that the size of the resulting pointer will exactly match
     237    the system size no matter what size the matched icon is. Smaller icons will
     238    be centered in a box corresponding to the system size, larger icons will
     239    be scaled down.
     240
     241    If \a embedRealAlpha is \c true, the color bitmap in the pointer will have
     242    the alpha channel embedded in it (see toPmHBITMAP() for details).
     243
     244    Note that due to the bug in WinCreatePointerIndirect(), hbmMiniPointer and
     245    hbmMiniColor field of the POINTERINFO structure are always ignored. For this
     246    reason, the caller must choose what icon size (normal or half-size) he wants
     247    to get using the \a isMini argument. A bitmap of the respective size will be
     248    created and assigned to the hbmColor field.
    220249
    221250    It is the caller's responsibility to free the \c HPOINTER data
     
    226255// static
    227256HPOINTER QPixmap::toPmHPOINTER(const QIcon &icon, bool isPointer,
    228                                int hotX, int hotY)
     257                               int hotX, int hotY, bool embedRealAlpha,
     258                               bool isMini)
    229259{
    230260    if (icon.isNull())
     
    234264    int w = WinQuerySysValue(HWND_DESKTOP, isPointer ? SV_CXPOINTER : SV_CXICON);
    235265    int h = WinQuerySysValue(HWND_DESKTOP, isPointer ? SV_CYPOINTER : SV_CYICON);
    236     int w2 = w / 2;
    237     int h2 = h / 2;
    238 
    239     // obtain the closest (but never larger) icon sizes we have
     266    if (isMini) {
     267        w = w / 2;
     268        h = h / 2;
     269    }
     270
     271    // obtain the closest (but never larger) icon size we have
    240272    QSize size = icon.actualSize(QSize(w, h));
    241     QSize sizeMini = icon.actualSize(QSize(w2, h2));
    242273
    243274    QPixmap pm = icon.pixmap(size);
    244     QPixmap pmMini = icon.pixmap(sizeMini);
    245     if (pm.isNull() && pmMini.isNull())
    246         return NULLHANDLE;
    247 
    248     // if we got smaller pixmaps then center them inside the system sized rect
    249     // instead of letting WinCreatePointerIndirect() scale them (this covers a
    250     // usual case when we got 32 and 16 px pixmaps on a 120 DPI system where the
    251     // icon size is 40 and 20 px respectively): scaling such small images looks
    252     // really ugly.
     275    if (pm.isNull())
     276        return NULLHANDLE;
     277
     278    // if we got a smaller pixmap then center it inside the box matching the
     279    // system size instead of letting WinCreatePointerIndirect() scale (this
     280    // covers a usual case when we get 32/16 px pixmaps on a 120 DPI system
     281    // where the icon size is 40/20 px respectively): scaling such small images
     282    // looks really ugly.
    253283    if (!pm.isNull() && (pm.width() < w || pm.height() < h)) {
    254284        Q_ASSERT(pm.width() <= w && pm.height() <= h);
     
    259289        pm = pmNew;
    260290    }
    261     if (!pmMini.isNull() && (pmMini.width() < w2 || pmMini.height() < h2)) {
    262         Q_ASSERT(pmMini.width() <= w2 && pmMini.height() <= h2);
    263         QPixmap pmNew(w2, h2);
    264         pmNew.fill(Qt::transparent);
    265         QPainter painter(&pmNew);
    266         painter.drawPixmap((w2 - pmMini.width()) / 2, (h2 - pmMini.height()) / 2, pmMini);
    267         pmMini = pmNew;
    268     }
    269 
    270     if (pm.isNull()) {
    271         // if we only have the mini icon, use it as a normal one;
    272         // WinCreatePointerIndirect() will figure that and not scale it
    273         pm = pmMini;
    274         pmMini = QPixmap();
    275     }
    276291
    277292    POINTERINFO info;
     
    279294    info.xHotspot = hotX;
    280295    info.yHotspot = hotY;
    281     info.hbmColor = pm.toPmHBITMAP(&info.hbmPointer);
    282     if (!pmMini.isNull()) {
    283         info.hbmMiniColor = pmMini.toPmHBITMAP(&info.hbmMiniPointer);
    284     } else {
    285         info.hbmMiniPointer = NULLHANDLE;
    286         info.hbmMiniColor = NULLHANDLE;
    287     }
     296    info.hbmColor = pm.toPmHBITMAP(&info.hbmPointer, embedRealAlpha);
     297    info.hbmMiniPointer = NULLHANDLE;
     298    info.hbmMiniColor = NULLHANDLE;
    288299
    289300    HPOINTER hIcon = WinCreatePointerIndirect(HWND_DESKTOP, &info);
     
    291302    GpiDeleteBitmap(info.hbmPointer);
    292303    GpiDeleteBitmap(info.hbmColor);
    293     GpiDeleteBitmap(info.hbmMiniPointer);
    294     GpiDeleteBitmap(info.hbmMiniColor);
    295304
    296305    return hIcon;
Note: See TracChangeset for help on using the changeset viewer.