📄 qwindowsxpstyle.cpp
字号:
const int w = rect.width(); const int h = rect.height(); for (int y = startY; y < h; ++y) { register DWORD *buffer = (DWORD*)bufferPixels + (y * bufferW); for (int x = startX; x < w; ++x, ++buffer) { int alpha = (*buffer) >> 24; if (alpha != 0xFF) // buffer has been touched return true; } } return false;}/*! \internal Returns true if the native doublebuffer contains pixels with varying alpha value.*/bool QWindowsXPStylePrivate::hasAlphaChannel(const QRect &rect){ const int startX = rect.left(); const int startY = rect.top(); const int w = rect.width(); const int h = rect.height(); int firstAlpha = -1; for (int y = startY; y < h/2; ++y) { register DWORD *buffer = (DWORD*)bufferPixels + (y * bufferW); for (int x = startX; x < w; ++x, ++buffer) { int alpha = (*buffer) >> 24; if (firstAlpha == -1) firstAlpha = alpha; else if (alpha != firstAlpha) return true; } } return false;}/*! \internal When the theme engine paints both a true alpha pixmap and a glyph into our buffer, the glyph might not contain a proper alpha value. The rule of thumb for premultiplied pixmaps is that the color values of a pixel can never be higher than the alpha values, so we use this to our advantage here, and fix all instances where this occures.*/bool QWindowsXPStylePrivate::fixAlphaChannel(const QRect &rect){ const int startX = rect.left(); const int startY = rect.top(); const int w = rect.width(); const int h = rect.height(); bool hasFixedAlphaValue = false; for (int y = startY; y < h; ++y) { register DWORD *buffer = (DWORD*)bufferPixels + (y * bufferW); for (register int x = startX; x < w; ++x, ++buffer) { uint pixel = *buffer; int alpha = qAlpha(pixel); if (qRed(pixel) > alpha || qGreen(pixel) > alpha || qBlue(pixel) > alpha) { *buffer |= 0xff000000; hasFixedAlphaValue = true; } } } return hasFixedAlphaValue;}/*! \internal Swaps the alpha values on certain pixels: 0xFF?????? -> 0x00?????? 0x00?????? -> 0xFF?????? Used to determin the mask of a non-alpha transparent pixmap in the native doublebuffer, and swap the alphas so we may paint the image as a Premultiplied QImage with drawImage(), and obtain the mask transparency.*/bool QWindowsXPStylePrivate::swapAlphaChannel(const QRect &rect){ const int startX = rect.left(); const int startY = rect.top(); const int w = rect.width(); const int h = rect.height(); bool valueChange = false; // Flip the alphas, so that 255-alpha pixels are 0, and 0-alpha are 255. for (int y = startY; y < h; ++y) { register DWORD *buffer = (DWORD*)bufferPixels + (y * bufferW); for (register int x = startX; x < w; ++x, ++buffer) { register unsigned int alphaValue = (*buffer) & 0xFF000000; if (alphaValue == 0xFF000000) { *buffer &= 0x00FFFFFF; valueChange = true; } else if (alphaValue == 0) { *buffer |= 0xFF000000; valueChange = true; } } } return valueChange;}/*! \internal Main theme drawing function. Determines the correct lowlevel drawing method depending on several factors. Use drawBackgroundThruNativeBuffer() if: - Painter does not have an HDC - Theme part is flipped (mirrored horizontally) else use drawBackgroundDirectly().*/void QWindowsXPStylePrivate::drawBackground(XPThemeData &themeData){ if (themeData.rect.isEmpty()) return; QPainter *painter = themeData.painter; Q_ASSERT_X(painter != 0, "QWindowsXPStylePrivate::drawBackground()", "Trying to draw a theme part without a painter"); if (!painter) return; painter->save(); QMatrix m = painter->matrix(); bool complexXForm = m.m11() != 1.0 || m.m22() != 1.0 || m.m12() != 0.0 || m.m21() != 0.0; bool useFallback = painter->paintEngine()->getDC() == 0 || themeData.rotate || complexXForm || themeData.mirrorVertically || (themeData.mirrorHorizontally && pDrawThemeBackgroundEx == 0); if (!useFallback) drawBackgroundDirectly(themeData); else drawBackgroundThruNativeBuffer(themeData); painter->restore();}/*! \internal This function draws the theme parts directly to the paintengines HDC. Do not use this if you need to perform other transformations on the resulting data.*/void QWindowsXPStylePrivate::drawBackgroundDirectly(XPThemeData &themeData){ QPainter *painter = themeData.painter; HDC dc = painter->paintEngine()->getDC(); QPoint redirectionDelta(int(painter->deviceMatrix().dx()), int(painter->deviceMatrix().dy())); QRect area = themeData.rect.translated(redirectionDelta); QRegion sysRgn = painter->paintEngine()->systemClip(); if (sysRgn.isEmpty()) sysRgn = area; else sysRgn &= area; if (painter->hasClipping()) sysRgn &= painter->clipRegion().translated(redirectionDelta); SelectClipRgn(dc, sysRgn.handle());#ifdef DEBUG_XP_STYLE printf("---[ DIRECT PAINTING ]------------------> Name(%-10s) Part(%d) State(%d)\n", qPrintable(themeData.name), themeData.partId, themeData.stateId); showProperties(themeData);#endif RECT drawRECT = themeData.toRECT(area); DTBGOPTS drawOptions; drawOptions.dwSize = sizeof(drawOptions); drawOptions.rcClip = themeData.toRECT(sysRgn.boundingRect()); drawOptions.dwFlags = DTBG_CLIPRECT | (themeData.noBorder ? DTBG_OMITBORDER : 0) | (themeData.noContent ? DTBG_OMITCONTENT : 0) | (themeData.mirrorHorizontally ? DTBG_MIRRORDC : 0); if (pDrawThemeBackgroundEx != 0) { pDrawThemeBackgroundEx(themeData.handle(), dc, themeData.partId, themeData.stateId, &(drawRECT), &drawOptions); } else { // We are running on a system where the uxtheme.dll does not have // the DrawThemeBackgroundEx function, so we need to clip away // borders or contents manually. All flips and mirrors uses the // fallback implementation int borderSize = 0; PROPERTYORIGIN origin = PO_NOTFOUND; pGetThemePropertyOrigin(themeData.handle(), themeData.partId, themeData.stateId, TMT_BORDERSIZE, &origin); pGetThemeInt(themeData.handle(), themeData.partId, themeData.stateId, TMT_BORDERSIZE, &borderSize); // Clip away border region QRegion extraClip = sysRgn; if ((origin == PO_CLASS || origin == PO_PART || origin == PO_STATE) && borderSize > 0) { if (themeData.noBorder) { // extraClip &= area is already done drawRECT = themeData.toRECT(area.adjusted(-borderSize, -borderSize, borderSize, borderSize)); } // Clip away content region if (themeData.noContent) { QRegion content = area.adjusted(borderSize, borderSize, -borderSize, -borderSize); extraClip ^= content; } // Set the clip region, if used.. if (themeData.noBorder || themeData.noContent) SelectClipRgn(dc, extraClip.handle()); } pDrawThemeBackground(themeData.handle(), dc, themeData.partId, themeData.stateId, &(drawRECT), &(drawOptions.rcClip)); } SelectClipRgn(dc, 0);}/*! \internal This function uses a secondary Native doublebuffer for painting parts. It should only be used when the painteengine doesn't provide a proper HDC for direct painting (e.g. when doing a grabWidget(), painting to other pixmaps etc), or when special transformations are needed (e.g. flips (horizonal mirroring only, vertical are handled by the theme engine).*/void QWindowsXPStylePrivate::drawBackgroundThruNativeBuffer(XPThemeData &themeData){ QPainter *painter = themeData.painter; QRect rect = themeData.rect; if ((themeData.rotate + 90) % 180 == 0) { // Catch 90,270,etc.. degree flips. rect = QRect(0, 0, rect.height(), rect.width()); } rect.moveTo(0,0); int partId = themeData.partId; int stateId = themeData.stateId; int w = rect.width(); int h = rect.height(); // Values initialized later, either from cached values, or from function calls AlphaChannelType alphaType = UnknownAlpha; bool stateHasData = true; // We assume so; bool hasAlpha = false; bool partIsTransparent; bool inspectData; bool potentialInvalidAlpha; QString pixmapCacheKey = QString("$qt_xp_%1p%2s%3s%4b%5c%6w%7h").arg(themeData.name) .arg(partId).arg(stateId).arg(!themeData.noBorder).arg(!themeData.noContent) .arg(w).arg(h); QPixmap cachedPixmap; ThemeMapKey key(themeData); ThemeMapData data = alphaCache.value(key); bool haveCachedPixmap = false; bool isCached = data.dataValid; if (isCached) { if (!(stateHasData = data.hasAnyData)) return; // Cached NOOP inspectData = data.wasAlphaSwapped; partIsTransparent = data.partIsTransparent; hasAlpha = data.hasAlphaChannel; alphaType = data.alphaType; potentialInvalidAlpha = data.hadInvalidAlpha; haveCachedPixmap = QPixmapCache::find(pixmapCacheKey, cachedPixmap);#ifdef DEBUG_XP_STYLE char buf[25]; ::sprintf(buf, "+ Pixmap(%3d, %3d) ]", w, h); printf("---[ CACHED %s--------> Name(%-10s) Part(%d) State(%d)\n", haveCachedPixmap ? buf : "]-------------------", qPrintable(themeData.name), themeData.partId, themeData.stateId);#endif } else { // Not cached, so get values from Theme Engine BOOL tmt_borderonly = false; COLORREF tmt_transparentcolor = 0x0; PROPERTYORIGIN proporigin = PO_NOTFOUND; pGetThemeBool(themeData.handle(), themeData.partId, themeData.stateId, TMT_BORDERONLY, &tmt_borderonly); pGetThemeColor(themeData.handle(), themeData.partId, themeData.stateId, TMT_TRANSPARENTCOLOR, &tmt_transparentcolor); pGetThemePropertyOrigin(themeData.handle(), themeData.partId, themeData.stateId, TMT_CAPTIONMARGINS, &proporigin); inspectData = (tmt_transparentcolor != 0 || tmt_borderonly || proporigin == PO_PART || proporigin == PO_STATE); partIsTransparent = isTransparent(themeData); potentialInvalidAlpha = false; pGetThemePropertyOrigin(themeData.handle(), themeData.partId, themeData.stateId, TMT_GLYPHTYPE, &proporigin); if (proporigin == PO_PART || proporigin == PO_STATE) { int tmt_glyphtype = GT_NONE; pGetThemeEnumValue(themeData.handle(), themeData.partId, themeData.stateId, TMT_GLYPHTYPE, &tmt_glyphtype); potentialInvalidAlpha = partIsTransparent && !inspectData && tmt_glyphtype == GT_IMAGEGLYPH; }#ifdef DEBUG_XP_STYLE printf("---[ NOT CACHED ]-----------------------> Name(%-10s) Part(%d) State(%d)\n", qPrintable(themeData.name), themeData.partId, themeData.stateId); printf("-->partIsTransparen = %d\n", partIsTransparent); printf("-->inspectData = %d\n", inspectData); printf("-->potentialInvalidAlpha = %d\n", potentialInvalidAlpha); showProperties(themeData);#endif } bool wasAlphaSwapped = false; bool wasAlphaFixed = false; // OLD PSDK Workaround ------------------------------------------------------------------------ // See if we need extra clipping for the older PSDK, which does // not have a DrawThemeBackgroundEx function for DTGB_OMITBORDER // and DTGB_OMITCONTENT bool addBorderContentClipping = false; QRegion extraClip; QRect area = rect; if (themeData.noBorder || themeData.noContent) { extraClip = area; // We are running on a system where the uxtheme.dll does not have // the DrawThemeBackgroundEx function, so we need to clip away // borders or contents manually. int borderSize = 0; PROPERTYORIGIN origin = PO_NOTFOUND; pGetThemePropertyOrigin(themeData.handle(), themeData.partId, themeData.stateId, TMT_BORDERSIZE, &origin); pGetThemeInt(themeData.handle(), themeData.partId, themeData.stateId, TMT_BORDERSIZE, &borderSize); // Clip away border region if ((origin == PO_CLASS || origin == PO_PART || origin == PO_STATE) && borderSize > 0) { if (themeData.noBorder) { extraClip &= area; area = area.adjusted(-borderSize, -borderSize, borderSize, borderSize); } // Clip away content region if (themeData.noContent) { QRegion content = area.adjusted(borderSize, borderSize, -borderSize, -borderSize); extraClip ^= content; } } addBorderContentClipping = (themeData.noBorder | themeData.noContent); } QImage img; if (!haveCachedPixmap) { // If the pixmap is not cached, generate it! ------------------------- buffer(w, h); // Ensure a buffer of at least (w, h) in size HDC dc = bufferHDC(); // Clear the buffer if (alphaType != NoAlpha) { // Consider have separate "memset" function for small chunks for more speedup memset(bufferPixels, inspectData ? 0xFF : 0x00, bufferW * h * 4); } // Difference between area and rect int dx = area.x() - rect.x(); int dy = area.y() - rect.y(); int dr = area.right() - rect.right(); int db = area.bottom() - rect.bottom(); // Adjust so painting rect starts from Origo rect.moveTo(0,0); area.moveTo(dx,dy);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -