📄 qwindowsxpstyle.cpp
字号:
pIsThemeActive = (PtrIsThemeActive )themeLib.resolve("IsThemeActive"); pGetThemePartSize = (PtrGetThemePartSize )themeLib.resolve("GetThemePartSize"); pOpenThemeData = (PtrOpenThemeData )themeLib.resolve("OpenThemeData"); pCloseThemeData = (PtrCloseThemeData )themeLib.resolve("CloseThemeData"); pDrawThemeBackground = (PtrDrawThemeBackground )themeLib.resolve("DrawThemeBackground"); pDrawThemeBackgroundEx = (PtrDrawThemeBackgroundEx )themeLib.resolve("DrawThemeBackgroundEx"); pGetCurrentThemeName = (PtrGetCurrentThemeName )themeLib.resolve("GetCurrentThemeName"); pGetThemeBool = (PtrGetThemeBool )themeLib.resolve("GetThemeBool"); pGetThemeColor = (PtrGetThemeColor )themeLib.resolve("GetThemeColor"); pGetThemeEnumValue = (PtrGetThemeEnumValue )themeLib.resolve("GetThemeEnumValue"); pGetThemeFilename = (PtrGetThemeFilename )themeLib.resolve("GetThemeFilename"); pGetThemeFont = (PtrGetThemeFont )themeLib.resolve("GetThemeFont"); pGetThemeInt = (PtrGetThemeInt )themeLib.resolve("GetThemeInt"); pGetThemeIntList = (PtrGetThemeIntList )themeLib.resolve("GetThemeIntList"); pGetThemeMargins = (PtrGetThemeMargins )themeLib.resolve("GetThemeMargins"); pGetThemeMetric = (PtrGetThemeMetric )themeLib.resolve("GetThemeMetric"); pGetThemePartSize = (PtrGetThemePartSize )themeLib.resolve("GetThemePartSize"); pGetThemePosition = (PtrGetThemePosition )themeLib.resolve("GetThemePosition"); pGetThemePropertyOrigin = (PtrGetThemePropertyOrigin)themeLib.resolve("GetThemePropertyOrigin"); pGetThemeRect = (PtrGetThemeRect )themeLib.resolve("GetThemeRect"); pGetThemeString = (PtrGetThemeString )themeLib.resolve("GetThemeString"); pGetThemeBackgroundRegion = (PtrGetThemeBackgroundRegion )themeLib.resolve("GetThemeBackgroundRegion"); pGetThemeDocumentationProperty = (PtrGetThemeDocumentationProperty )themeLib.resolve("GetThemeDocumentationProperty"); pIsThemeBackgroundPartiallyTransparent = (PtrIsThemeBackgroundPartiallyTransparent)themeLib.resolve("IsThemeBackgroundPartiallyTransparent"); } } return pIsAppThemed != 0;}/*! \internal Returns a native buffer (DIB section) of at least the size of ( \a x , \a y ). The buffer has a 32 bit depth, to not lose the alpha values on proper alpha-pixmaps.*/HBITMAP QWindowsXPStylePrivate::buffer(int w, int h){ // If we already have a HBITMAP which is of adequate size, just return that if (bufferBitmap) { if (bufferW >= w && bufferH >= h) return bufferBitmap; // Not big enough, discard the old one if (bufferDC && nullBitmap) SelectObject(bufferDC, nullBitmap); DeleteObject(bufferBitmap); bufferBitmap = 0; } w = qMax(bufferW, w); h = qMax(bufferH, h); if (!bufferDC) bufferDC = CreateCompatibleDC(qt_win_display_dc()); // Define the header BITMAPINFO bmi; memset(&bmi, 0, sizeof(bmi)); bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi.bmiHeader.biWidth = w; bmi.bmiHeader.biHeight = -h; bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = 32; bmi.bmiHeader.biCompression = BI_RGB; // Create the pixmap bufferPixels = 0; bufferBitmap = CreateDIBSection(bufferDC, &bmi, DIB_RGB_COLORS, (void **) &bufferPixels, 0, 0); GdiFlush(); nullBitmap = (HBITMAP)SelectObject(bufferDC, bufferBitmap); if (!bufferBitmap) { qErrnoWarning("QWindowsXPStylePrivate::buffer(w,h), failed to create dibsection"); bufferW = 0; bufferH = 0; return 0; } if (!bufferPixels) { qErrnoWarning("QWindowsXPStylePrivate::buffer(w,h), did not allocate pixel data"); bufferW = 0; bufferH = 0; return 0; } bufferW = w; bufferH = h;#ifdef DEBUG_XP_STYLE qDebug("Creating new dib section (%d, %d)", w, h);#endif return bufferBitmap;}/*! \internal Returns true if the part contains any transparency at all. This does not indicate what kind of transparency we're dealing with. It can be - Alpha transparency - Masked transparency*/bool QWindowsXPStylePrivate::isTransparent(XPThemeData &themeData){ return pIsThemeBackgroundPartiallyTransparent(themeData.handle(), themeData.partId, themeData.stateId);}/*! \internal Returns a QRegion of the region of the part*/QRegion QWindowsXPStylePrivate::region(XPThemeData &themeData){ HRGN hRgn = 0; RECT rect = themeData.toRECT(themeData.rect); if (!SUCCEEDED(pGetThemeBackgroundRegion(themeData.handle(), bufferHDC(), themeData.partId, themeData.stateId, &rect, &hRgn))) return QRegion(); QRegion rgn = QRegion(0,0,1,1); const bool success = CombineRgn(rgn.handle(), hRgn, 0, RGN_COPY) != ERROR; DeleteObject(hRgn); if (success) return rgn; return QRegion();}/*! \internal Sets the parts region on a window.*/void QWindowsXPStylePrivate::setTransparency(QWidget *widget, XPThemeData &themeData){ HRGN hrgn = themeData.mask(); if (hrgn && widget) SetWindowRgn(winId(widget), hrgn, true);}/*! \internal Returns true if the native doublebuffer contains a pixel which has a non-0xFF alpha value. Should only be use when its guaranteed that data painted into the buffer wasn't a proper alpha pixmap.*/bool QWindowsXPStylePrivate::hasAnyData(const QRect &rect){ const int startX = rect.left(); const int startY = rect.top(); 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 || painter->opacity() != 1.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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -