📄 qwindowsxpstyle.cpp
字号:
// 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::fromLatin1("$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); DTBGOPTS drawOptions; drawOptions.dwSize = sizeof(drawOptions); drawOptions.rcClip = themeData.toRECT(rect); drawOptions.dwFlags = DTBG_CLIPRECT | (themeData.noBorder ? DTBG_OMITBORDER : 0) | (themeData.noContent ? DTBG_OMITCONTENT : 0); // Drawing the part into the backing store if (pDrawThemeBackgroundEx != 0) { RECT rect(themeData.toRECT(area)); pDrawThemeBackgroundEx(themeData.handle(), dc, themeData.partId, themeData.stateId, &rect, &drawOptions); } else { // Set the clip region, if used.. if (addBorderContentClipping) { SelectClipRgn(dc, extraClip.handle()); // Compensate for the noBorder area difference (noContent has the same area) drawOptions.rcClip = themeData.toRECT(rect.adjusted(dx, dy, dr, db)); } pDrawThemeBackground(themeData.handle(), dc, themeData.partId, themeData.stateId, &(drawOptions.rcClip), 0); if (addBorderContentClipping) SelectClipRgn(dc, 0); } // If not cached, analyze the buffer data to figure // out alpha type, and if it contains data if (!isCached) { if (inspectData) stateHasData = hasAnyData(rect); // SHORTCUT: If the part's state has no data, cache it for NOOP later if (!stateHasData) { memset(&data, 0, sizeof(data)); data.dataValid = true; alphaCache.insert(key, data); return; } hasAlpha = hasAlphaChannel(rect); if (!hasAlpha && partIsTransparent) potentialInvalidAlpha = true;#if defined(DEBUG_XP_STYLE) && 1 dumpNativeDIB(w, h);#endif } // Swap alpha values, if needed if (inspectData) wasAlphaSwapped = swapAlphaChannel(rect); // Fix alpha values, if needed if (potentialInvalidAlpha) wasAlphaFixed = fixAlphaChannel(rect); QImage::Format format; if ((partIsTransparent && !wasAlphaSwapped) || (!partIsTransparent && hasAlpha)) { format = QImage::Format_ARGB32_Premultiplied; alphaType = RealAlpha; } else if (wasAlphaSwapped) { format = QImage::Format_ARGB32_Premultiplied; alphaType = MaskAlpha; } else { format = QImage::Format_RGB32; alphaType = NoAlpha; }#if defined(DEBUG_XP_STYLE) && 1 printf("Image format is: %s\n", alphaType == RealAlpha ? "Real Alpha" : alphaType == MaskAlpha ? "Masked Alpha" : "No Alpha");#endif img = QImage(bufferPixels, bufferW, bufferH, format); } // Blitting backing store bool useRegion = partIsTransparent && !hasAlpha && !wasAlphaSwapped; QRegion newRegion; QRegion oldRegion; if (useRegion) { newRegion = region(themeData); oldRegion = painter->clipRegion(); painter->setClipRegion(newRegion);#if defined(DEBUG_XP_STYLE) && 0 printf("Using region:\n"); QVector<QRect> rects = newRegion.rects(); for (int i = 0; i < rects.count(); ++i) { const QRect &r = rects.at(i); printf(" (%d, %d, %d, %d)\n", r.x(), r.y(), r.right(), r.bottom()); }#endif } if (addBorderContentClipping) painter->setClipRegion(extraClip, Qt::IntersectClip); if (!themeData.mirrorHorizontally && !themeData.mirrorVertically && !themeData.rotate) { if (!haveCachedPixmap) painter->drawImage(themeData.rect, img, rect); else painter->drawPixmap(themeData.rect, cachedPixmap); } else { // This is _slow_! // Make a copy containing only the necessary data, and mirror // on all wanted axes. Then draw the copy. // If cached, the normal pixmap is cached, instead of caching // all possible orientations for each part and state. QImage imgCopy; if (!haveCachedPixmap) imgCopy = img.copy(rect); else imgCopy = cachedPixmap.toImage(); if (themeData.rotate) { QMatrix rotMatrix; rotMatrix.rotate(themeData.rotate); imgCopy = imgCopy.transformed(rotMatrix); } if (themeData.mirrorHorizontally || themeData.mirrorVertically) { imgCopy = imgCopy.mirrored(themeData.mirrorHorizontally, themeData.mirrorVertically); } painter->drawImage(themeData.rect, imgCopy); } if (useRegion || addBorderContentClipping) { if (oldRegion.isEmpty()) painter->setClipping(false); else painter->setClipRegion(oldRegion); } // Cache the pixmap to avoid expensive swapAlphaChannel() calls if (!haveCachedPixmap && ((w * h) < 2000) && w && h) { QPixmap pix = QPixmap::fromImage(img).copy(rect); QPixmapCache::insert(pixmapCacheKey, pix);#ifdef DEBUG_XP_STYLE printf("+++Adding pixmap to cache, size(%d, %d), wasAlphaSwapped(%d), wasAlphaFixed(%d), name(%s)\n", w, h, wasAlphaSwapped, wasAlphaFixed, qPrintable(pixmapCacheKey));#endif } // Add to theme part cache if (!isCached) { memset(&data, 0, sizeof(data)); data.dataValid = true; data.partIsTransparent = partIsTransparent; data.alphaType = alphaType; data.hasAlphaChannel = hasAlpha; data.hasAnyData = stateHasData; data.wasAlphaSwapped = wasAlphaSwapped; data.hadInvalidAlpha = wasAlphaFixed; alphaCache.insert(key, data); }}// ------------------------------------------------------------------------------------------------/*! \class QWindowsXPStyle \brief The QWindowsXPStyle class provides a Microsoft Windows XP-like look and feel. \ingroup appearance \warning This style is only available on the Windows XP platform because it makes use of Windows XP's style engine. Most of the functions are documented in the base classes
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -