Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /* -*- Mode: C++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | |
michael@0 | 6 | #include "nsNativeThemeWin.h" |
michael@0 | 7 | #include "mozilla/EventStates.h" |
michael@0 | 8 | #include "mozilla/WindowsVersion.h" |
michael@0 | 9 | #include "nsRenderingContext.h" |
michael@0 | 10 | #include "nsRect.h" |
michael@0 | 11 | #include "nsSize.h" |
michael@0 | 12 | #include "nsTransform2D.h" |
michael@0 | 13 | #include "nsThemeConstants.h" |
michael@0 | 14 | #include "nsIPresShell.h" |
michael@0 | 15 | #include "nsPresContext.h" |
michael@0 | 16 | #include "nsIContent.h" |
michael@0 | 17 | #include "nsIFrame.h" |
michael@0 | 18 | #include "nsNameSpaceManager.h" |
michael@0 | 19 | #include "nsIDOMHTMLInputElement.h" |
michael@0 | 20 | #include "nsLookAndFeel.h" |
michael@0 | 21 | #include "nsMenuFrame.h" |
michael@0 | 22 | #include "nsGkAtoms.h" |
michael@0 | 23 | #include <malloc.h> |
michael@0 | 24 | #include "nsWindow.h" |
michael@0 | 25 | #include "nsIComboboxControlFrame.h" |
michael@0 | 26 | #include "prinrval.h" |
michael@0 | 27 | #include "WinUtils.h" |
michael@0 | 28 | |
michael@0 | 29 | #include "gfxPlatform.h" |
michael@0 | 30 | #include "gfxContext.h" |
michael@0 | 31 | #include "gfxWindowsPlatform.h" |
michael@0 | 32 | #include "gfxWindowsSurface.h" |
michael@0 | 33 | #include "gfxWindowsNativeDrawing.h" |
michael@0 | 34 | |
michael@0 | 35 | #include "nsUXThemeData.h" |
michael@0 | 36 | #include "nsUXThemeConstants.h" |
michael@0 | 37 | #include <algorithm> |
michael@0 | 38 | |
michael@0 | 39 | using mozilla::IsVistaOrLater; |
michael@0 | 40 | using namespace mozilla; |
michael@0 | 41 | using namespace mozilla::widget; |
michael@0 | 42 | |
michael@0 | 43 | #ifdef PR_LOGGING |
michael@0 | 44 | extern PRLogModuleInfo* gWindowsLog; |
michael@0 | 45 | #endif |
michael@0 | 46 | |
michael@0 | 47 | NS_IMPL_ISUPPORTS_INHERITED(nsNativeThemeWin, nsNativeTheme, nsITheme) |
michael@0 | 48 | |
michael@0 | 49 | nsNativeThemeWin::nsNativeThemeWin() : |
michael@0 | 50 | mProgressDeterminateTimeStamp(TimeStamp::Now()), |
michael@0 | 51 | mProgressIndeterminateTimeStamp(TimeStamp::Now()) |
michael@0 | 52 | { |
michael@0 | 53 | // If there is a relevant change in forms.css for windows platform, |
michael@0 | 54 | // static widget style variables (e.g. sButtonBorderSize) should be |
michael@0 | 55 | // reinitialized here. |
michael@0 | 56 | } |
michael@0 | 57 | |
michael@0 | 58 | nsNativeThemeWin::~nsNativeThemeWin() |
michael@0 | 59 | { |
michael@0 | 60 | nsUXThemeData::Invalidate(); |
michael@0 | 61 | } |
michael@0 | 62 | |
michael@0 | 63 | static int32_t |
michael@0 | 64 | GetTopLevelWindowActiveState(nsIFrame *aFrame) |
michael@0 | 65 | { |
michael@0 | 66 | // Get the widget. nsIFrame's GetNearestWidget walks up the view chain |
michael@0 | 67 | // until it finds a real window. |
michael@0 | 68 | nsIWidget* widget = aFrame->GetNearestWidget(); |
michael@0 | 69 | nsWindowBase * window = static_cast<nsWindowBase*>(widget); |
michael@0 | 70 | if (!window) |
michael@0 | 71 | return mozilla::widget::themeconst::FS_INACTIVE; |
michael@0 | 72 | if (widget && !window->IsTopLevelWidget() && |
michael@0 | 73 | !(window = window->GetParentWindowBase(false))) |
michael@0 | 74 | return mozilla::widget::themeconst::FS_INACTIVE; |
michael@0 | 75 | |
michael@0 | 76 | if (window->GetWindowHandle() == ::GetActiveWindow()) |
michael@0 | 77 | return mozilla::widget::themeconst::FS_ACTIVE; |
michael@0 | 78 | return mozilla::widget::themeconst::FS_INACTIVE; |
michael@0 | 79 | } |
michael@0 | 80 | |
michael@0 | 81 | static int32_t |
michael@0 | 82 | GetWindowFrameButtonState(nsIFrame* aFrame, EventStates eventState) |
michael@0 | 83 | { |
michael@0 | 84 | if (GetTopLevelWindowActiveState(aFrame) == |
michael@0 | 85 | mozilla::widget::themeconst::FS_INACTIVE) { |
michael@0 | 86 | if (eventState.HasState(NS_EVENT_STATE_HOVER)) |
michael@0 | 87 | return mozilla::widget::themeconst::BS_HOT; |
michael@0 | 88 | return mozilla::widget::themeconst::BS_INACTIVE; |
michael@0 | 89 | } |
michael@0 | 90 | |
michael@0 | 91 | if (eventState.HasState(NS_EVENT_STATE_HOVER)) { |
michael@0 | 92 | if (eventState.HasState(NS_EVENT_STATE_ACTIVE)) |
michael@0 | 93 | return mozilla::widget::themeconst::BS_PUSHED; |
michael@0 | 94 | return mozilla::widget::themeconst::BS_HOT; |
michael@0 | 95 | } |
michael@0 | 96 | return mozilla::widget::themeconst::BS_NORMAL; |
michael@0 | 97 | } |
michael@0 | 98 | |
michael@0 | 99 | static int32_t |
michael@0 | 100 | GetClassicWindowFrameButtonState(EventStates eventState) |
michael@0 | 101 | { |
michael@0 | 102 | if (eventState.HasState(NS_EVENT_STATE_ACTIVE) && |
michael@0 | 103 | eventState.HasState(NS_EVENT_STATE_HOVER)) |
michael@0 | 104 | return DFCS_BUTTONPUSH|DFCS_PUSHED; |
michael@0 | 105 | return DFCS_BUTTONPUSH; |
michael@0 | 106 | } |
michael@0 | 107 | |
michael@0 | 108 | static bool |
michael@0 | 109 | IsTopLevelMenu(nsIFrame *aFrame) |
michael@0 | 110 | { |
michael@0 | 111 | bool isTopLevel(false); |
michael@0 | 112 | nsMenuFrame *menuFrame = do_QueryFrame(aFrame); |
michael@0 | 113 | if (menuFrame) { |
michael@0 | 114 | isTopLevel = menuFrame->IsOnMenuBar(); |
michael@0 | 115 | } |
michael@0 | 116 | return isTopLevel; |
michael@0 | 117 | } |
michael@0 | 118 | |
michael@0 | 119 | static MARGINS |
michael@0 | 120 | GetCheckboxMargins(HANDLE theme, HDC hdc) |
michael@0 | 121 | { |
michael@0 | 122 | MARGINS checkboxContent = {0}; |
michael@0 | 123 | GetThemeMargins(theme, hdc, MENU_POPUPCHECK, MCB_NORMAL, |
michael@0 | 124 | TMT_CONTENTMARGINS, nullptr, &checkboxContent); |
michael@0 | 125 | return checkboxContent; |
michael@0 | 126 | } |
michael@0 | 127 | |
michael@0 | 128 | static SIZE |
michael@0 | 129 | GetCheckboxBGSize(HANDLE theme, HDC hdc) |
michael@0 | 130 | { |
michael@0 | 131 | SIZE checkboxSize; |
michael@0 | 132 | GetThemePartSize(theme, hdc, MENU_POPUPCHECK, MC_CHECKMARKNORMAL, |
michael@0 | 133 | nullptr, TS_TRUE, &checkboxSize); |
michael@0 | 134 | |
michael@0 | 135 | MARGINS checkboxMargins = GetCheckboxMargins(theme, hdc); |
michael@0 | 136 | |
michael@0 | 137 | int leftMargin = checkboxMargins.cxLeftWidth; |
michael@0 | 138 | int rightMargin = checkboxMargins.cxRightWidth; |
michael@0 | 139 | int topMargin = checkboxMargins.cyTopHeight; |
michael@0 | 140 | int bottomMargin = checkboxMargins.cyBottomHeight; |
michael@0 | 141 | |
michael@0 | 142 | int width = leftMargin + checkboxSize.cx + rightMargin; |
michael@0 | 143 | int height = topMargin + checkboxSize.cy + bottomMargin; |
michael@0 | 144 | SIZE ret; |
michael@0 | 145 | ret.cx = width; |
michael@0 | 146 | ret.cy = height; |
michael@0 | 147 | return ret; |
michael@0 | 148 | } |
michael@0 | 149 | |
michael@0 | 150 | static SIZE |
michael@0 | 151 | GetCheckboxBGBounds(HANDLE theme, HDC hdc) |
michael@0 | 152 | { |
michael@0 | 153 | MARGINS checkboxBGSizing = {0}; |
michael@0 | 154 | MARGINS checkboxBGContent = {0}; |
michael@0 | 155 | GetThemeMargins(theme, hdc, MENU_POPUPCHECKBACKGROUND, MCB_NORMAL, |
michael@0 | 156 | TMT_SIZINGMARGINS, nullptr, &checkboxBGSizing); |
michael@0 | 157 | GetThemeMargins(theme, hdc, MENU_POPUPCHECKBACKGROUND, MCB_NORMAL, |
michael@0 | 158 | TMT_CONTENTMARGINS, nullptr, &checkboxBGContent); |
michael@0 | 159 | |
michael@0 | 160 | #define posdx(d) ((d) > 0 ? d : 0) |
michael@0 | 161 | |
michael@0 | 162 | int dx = posdx(checkboxBGContent.cxRightWidth - |
michael@0 | 163 | checkboxBGSizing.cxRightWidth) + |
michael@0 | 164 | posdx(checkboxBGContent.cxLeftWidth - |
michael@0 | 165 | checkboxBGSizing.cxLeftWidth); |
michael@0 | 166 | int dy = posdx(checkboxBGContent.cyTopHeight - |
michael@0 | 167 | checkboxBGSizing.cyTopHeight) + |
michael@0 | 168 | posdx(checkboxBGContent.cyBottomHeight - |
michael@0 | 169 | checkboxBGSizing.cyBottomHeight); |
michael@0 | 170 | |
michael@0 | 171 | #undef posdx |
michael@0 | 172 | |
michael@0 | 173 | SIZE ret(GetCheckboxBGSize(theme, hdc)); |
michael@0 | 174 | ret.cx += dx; |
michael@0 | 175 | ret.cy += dy; |
michael@0 | 176 | return ret; |
michael@0 | 177 | } |
michael@0 | 178 | |
michael@0 | 179 | static SIZE |
michael@0 | 180 | GetGutterSize(HANDLE theme, HDC hdc) |
michael@0 | 181 | { |
michael@0 | 182 | SIZE gutterSize; |
michael@0 | 183 | GetThemePartSize(theme, hdc, MENU_POPUPGUTTER, 0, nullptr, TS_TRUE, &gutterSize); |
michael@0 | 184 | |
michael@0 | 185 | SIZE checkboxBGSize(GetCheckboxBGBounds(theme, hdc)); |
michael@0 | 186 | |
michael@0 | 187 | SIZE itemSize; |
michael@0 | 188 | GetThemePartSize(theme, hdc, MENU_POPUPITEM, MPI_NORMAL, nullptr, TS_TRUE, &itemSize); |
michael@0 | 189 | |
michael@0 | 190 | // Figure out how big the menuitem's icon will be (if present) at current DPI |
michael@0 | 191 | double scaleFactor = nsIWidget::DefaultScaleOverride(); |
michael@0 | 192 | if (scaleFactor <= 0.0) { |
michael@0 | 193 | scaleFactor = gfxWindowsPlatform::GetPlatform()->GetDPIScale(); |
michael@0 | 194 | } |
michael@0 | 195 | int iconDevicePixels = NSToIntRound(16 * scaleFactor); |
michael@0 | 196 | SIZE iconSize = { |
michael@0 | 197 | iconDevicePixels, iconDevicePixels |
michael@0 | 198 | }; |
michael@0 | 199 | // Not really sure what margins should be used here, but this seems to work in practice... |
michael@0 | 200 | MARGINS margins = {0}; |
michael@0 | 201 | GetThemeMargins(theme, hdc, MENU_POPUPCHECKBACKGROUND, MCB_NORMAL, |
michael@0 | 202 | TMT_CONTENTMARGINS, nullptr, &margins); |
michael@0 | 203 | iconSize.cx += margins.cxLeftWidth + margins.cxRightWidth; |
michael@0 | 204 | iconSize.cy += margins.cyTopHeight + margins.cyBottomHeight; |
michael@0 | 205 | |
michael@0 | 206 | int width = std::max(itemSize.cx, std::max(iconSize.cx, checkboxBGSize.cx) + gutterSize.cx); |
michael@0 | 207 | int height = std::max(itemSize.cy, std::max(iconSize.cy, checkboxBGSize.cy)); |
michael@0 | 208 | |
michael@0 | 209 | SIZE ret; |
michael@0 | 210 | ret.cx = width; |
michael@0 | 211 | ret.cy = height; |
michael@0 | 212 | return ret; |
michael@0 | 213 | } |
michael@0 | 214 | |
michael@0 | 215 | /* DrawThemeBGRTLAware - render a theme part based on rtl state. |
michael@0 | 216 | * Some widgets are not direction-neutral and need to be drawn reversed for |
michael@0 | 217 | * RTL. Windows provides a way to do this with SetLayout, but this reverses |
michael@0 | 218 | * the entire drawing area of a given device context, which means that its |
michael@0 | 219 | * use will also affect the positioning of the widget. There are two ways |
michael@0 | 220 | * to work around this: |
michael@0 | 221 | * |
michael@0 | 222 | * Option 1: Alter the position of the rect that we send so that we cancel |
michael@0 | 223 | * out the positioning effects of SetLayout |
michael@0 | 224 | * Option 2: Create a memory DC with the widgetRect's dimensions, draw onto |
michael@0 | 225 | * that, and then transfer the results back to our DC |
michael@0 | 226 | * |
michael@0 | 227 | * This function tries to implement option 1, under the assumption that the |
michael@0 | 228 | * correct way to reverse the effects of SetLayout is to translate the rect |
michael@0 | 229 | * such that the offset from the DC bitmap's left edge to the old rect's |
michael@0 | 230 | * left edge is equal to the offset from the DC bitmap's right edge to the |
michael@0 | 231 | * new rect's right edge. In other words, |
michael@0 | 232 | * (oldRect.left + vpOrg.x) == ((dcBMP.width - vpOrg.x) - newRect.right) |
michael@0 | 233 | */ |
michael@0 | 234 | static HRESULT |
michael@0 | 235 | DrawThemeBGRTLAware(HANDLE aTheme, HDC aHdc, int aPart, int aState, |
michael@0 | 236 | const RECT *aWidgetRect, const RECT *aClipRect, |
michael@0 | 237 | bool aIsRtl) |
michael@0 | 238 | { |
michael@0 | 239 | NS_ASSERTION(aTheme, "Bad theme handle."); |
michael@0 | 240 | NS_ASSERTION(aHdc, "Bad hdc."); |
michael@0 | 241 | NS_ASSERTION(aWidgetRect, "Bad rect."); |
michael@0 | 242 | NS_ASSERTION(aClipRect, "Bad clip rect."); |
michael@0 | 243 | |
michael@0 | 244 | if (!aIsRtl) { |
michael@0 | 245 | return DrawThemeBackground(aTheme, aHdc, aPart, aState, |
michael@0 | 246 | aWidgetRect, aClipRect); |
michael@0 | 247 | } |
michael@0 | 248 | |
michael@0 | 249 | HGDIOBJ hObj = GetCurrentObject(aHdc, OBJ_BITMAP); |
michael@0 | 250 | BITMAP bitmap; |
michael@0 | 251 | POINT vpOrg; |
michael@0 | 252 | |
michael@0 | 253 | if (hObj && GetObject(hObj, sizeof(bitmap), &bitmap) && |
michael@0 | 254 | GetViewportOrgEx(aHdc, &vpOrg)) { |
michael@0 | 255 | RECT newWRect(*aWidgetRect); |
michael@0 | 256 | newWRect.left = bitmap.bmWidth - (aWidgetRect->right + 2*vpOrg.x); |
michael@0 | 257 | newWRect.right = bitmap.bmWidth - (aWidgetRect->left + 2*vpOrg.x); |
michael@0 | 258 | |
michael@0 | 259 | RECT newCRect; |
michael@0 | 260 | RECT *newCRectPtr = nullptr; |
michael@0 | 261 | |
michael@0 | 262 | if (aClipRect) { |
michael@0 | 263 | newCRect.top = aClipRect->top; |
michael@0 | 264 | newCRect.bottom = aClipRect->bottom; |
michael@0 | 265 | newCRect.left = bitmap.bmWidth - (aClipRect->right + 2*vpOrg.x); |
michael@0 | 266 | newCRect.right = bitmap.bmWidth - (aClipRect->left + 2*vpOrg.x); |
michael@0 | 267 | newCRectPtr = &newCRect; |
michael@0 | 268 | } |
michael@0 | 269 | |
michael@0 | 270 | SetLayout(aHdc, LAYOUT_RTL); |
michael@0 | 271 | HRESULT hr = DrawThemeBackground(aTheme, aHdc, aPart, aState, &newWRect, |
michael@0 | 272 | newCRectPtr); |
michael@0 | 273 | SetLayout(aHdc, 0); |
michael@0 | 274 | if (SUCCEEDED(hr)) { |
michael@0 | 275 | return hr; |
michael@0 | 276 | } |
michael@0 | 277 | } |
michael@0 | 278 | return DrawThemeBackground(aTheme, aHdc, aPart, aState, |
michael@0 | 279 | aWidgetRect, aClipRect); |
michael@0 | 280 | } |
michael@0 | 281 | |
michael@0 | 282 | /* |
michael@0 | 283 | * Caption button padding data - 'hot' button padding. |
michael@0 | 284 | * These areas are considered hot, in that they activate |
michael@0 | 285 | * a button when hovered or clicked. The button graphic |
michael@0 | 286 | * is drawn inside the padding border. Unrecognized themes |
michael@0 | 287 | * are treated as their recognized counterparts for now. |
michael@0 | 288 | * left top right bottom |
michael@0 | 289 | * classic min 1 2 0 1 |
michael@0 | 290 | * classic max 0 2 1 1 |
michael@0 | 291 | * classic close 1 2 2 1 |
michael@0 | 292 | * |
michael@0 | 293 | * aero basic min 1 2 0 2 |
michael@0 | 294 | * aero basic max 0 2 1 2 |
michael@0 | 295 | * aero basic close 1 2 1 2 |
michael@0 | 296 | * |
michael@0 | 297 | * xp theme min 0 2 0 2 |
michael@0 | 298 | * xp theme max 0 2 1 2 |
michael@0 | 299 | * xp theme close 1 2 2 2 |
michael@0 | 300 | * |
michael@0 | 301 | * 'cold' button padding - generic button padding, should |
michael@0 | 302 | * be handled in css. |
michael@0 | 303 | * left top right bottom |
michael@0 | 304 | * classic min 0 0 0 0 |
michael@0 | 305 | * classic max 0 0 0 0 |
michael@0 | 306 | * classic close 0 0 0 0 |
michael@0 | 307 | * |
michael@0 | 308 | * aero basic min 0 0 1 0 |
michael@0 | 309 | * aero basic max 1 0 0 0 |
michael@0 | 310 | * aero basic close 0 0 0 0 |
michael@0 | 311 | * |
michael@0 | 312 | * xp theme min 0 0 1 0 |
michael@0 | 313 | * xp theme max 1 0 0 0 |
michael@0 | 314 | * xp theme close 0 0 0 0 |
michael@0 | 315 | */ |
michael@0 | 316 | |
michael@0 | 317 | enum CaptionDesktopTheme { |
michael@0 | 318 | CAPTION_CLASSIC = 0, |
michael@0 | 319 | CAPTION_BASIC, |
michael@0 | 320 | CAPTION_XPTHEME, |
michael@0 | 321 | }; |
michael@0 | 322 | |
michael@0 | 323 | enum CaptionButton { |
michael@0 | 324 | CAPTIONBUTTON_MINIMIZE = 0, |
michael@0 | 325 | CAPTIONBUTTON_RESTORE, |
michael@0 | 326 | CAPTIONBUTTON_CLOSE, |
michael@0 | 327 | }; |
michael@0 | 328 | |
michael@0 | 329 | struct CaptionButtonPadding { |
michael@0 | 330 | RECT hotPadding[3]; |
michael@0 | 331 | }; |
michael@0 | 332 | |
michael@0 | 333 | // RECT: left, top, right, bottom |
michael@0 | 334 | static CaptionButtonPadding buttonData[3] = { |
michael@0 | 335 | { |
michael@0 | 336 | { { 1, 2, 0, 1 }, { 0, 2, 1, 1 }, { 1, 2, 2, 1 } } |
michael@0 | 337 | }, |
michael@0 | 338 | { |
michael@0 | 339 | { { 1, 2, 0, 2 }, { 0, 2, 1, 2 }, { 1, 2, 2, 2 } } |
michael@0 | 340 | }, |
michael@0 | 341 | { |
michael@0 | 342 | { { 0, 2, 0, 2 }, { 0, 2, 1, 2 }, { 1, 2, 2, 2 } } |
michael@0 | 343 | } |
michael@0 | 344 | }; |
michael@0 | 345 | |
michael@0 | 346 | // Adds "hot" caption button padding to minimum widget size. |
michael@0 | 347 | static void |
michael@0 | 348 | AddPaddingRect(nsIntSize* aSize, CaptionButton button) { |
michael@0 | 349 | if (!aSize) |
michael@0 | 350 | return; |
michael@0 | 351 | RECT offset; |
michael@0 | 352 | if (!IsAppThemed()) |
michael@0 | 353 | offset = buttonData[CAPTION_CLASSIC].hotPadding[button]; |
michael@0 | 354 | else if (!IsVistaOrLater()) |
michael@0 | 355 | offset = buttonData[CAPTION_XPTHEME].hotPadding[button]; |
michael@0 | 356 | else |
michael@0 | 357 | offset = buttonData[CAPTION_BASIC].hotPadding[button]; |
michael@0 | 358 | aSize->width += offset.left + offset.right; |
michael@0 | 359 | aSize->height += offset.top + offset.bottom; |
michael@0 | 360 | } |
michael@0 | 361 | |
michael@0 | 362 | // If we've added padding to the minimum widget size, offset |
michael@0 | 363 | // the area we draw into to compensate. |
michael@0 | 364 | static void |
michael@0 | 365 | OffsetBackgroundRect(RECT& rect, CaptionButton button) { |
michael@0 | 366 | RECT offset; |
michael@0 | 367 | if (!IsAppThemed()) |
michael@0 | 368 | offset = buttonData[CAPTION_CLASSIC].hotPadding[button]; |
michael@0 | 369 | else if (!IsVistaOrLater()) |
michael@0 | 370 | offset = buttonData[CAPTION_XPTHEME].hotPadding[button]; |
michael@0 | 371 | else |
michael@0 | 372 | offset = buttonData[CAPTION_BASIC].hotPadding[button]; |
michael@0 | 373 | rect.left += offset.left; |
michael@0 | 374 | rect.top += offset.top; |
michael@0 | 375 | rect.right -= offset.right; |
michael@0 | 376 | rect.bottom -= offset.bottom; |
michael@0 | 377 | } |
michael@0 | 378 | |
michael@0 | 379 | /* |
michael@0 | 380 | * Notes on progress track and meter part constants: |
michael@0 | 381 | * xp and up: |
michael@0 | 382 | * PP_BAR(_VERT) - base progress track |
michael@0 | 383 | * PP_TRANSPARENTBAR(_VERT) - transparent progress track. this only works if |
michael@0 | 384 | * the underlying surface supports alpha. otherwise |
michael@0 | 385 | * theme lib's DrawThemeBackground falls back on |
michael@0 | 386 | * opaque PP_BAR. we currently don't use this. |
michael@0 | 387 | * PP_CHUNK(_VERT) - xp progress meter. this does not draw an xp style |
michael@0 | 388 | * progress w/chunks, it draws fill using the chunk |
michael@0 | 389 | * graphic. |
michael@0 | 390 | * vista and up: |
michael@0 | 391 | * PP_FILL(_VERT) - progress meter. these have four states/colors. |
michael@0 | 392 | * PP_PULSEOVERLAY(_VERT) - white reflection - an overlay, not sure what this |
michael@0 | 393 | * is used for. |
michael@0 | 394 | * PP_MOVEOVERLAY(_VERT) - green pulse - the pulse effect overlay on |
michael@0 | 395 | * determined progress bars. we also use this for |
michael@0 | 396 | * indeterminate chunk. |
michael@0 | 397 | * |
michael@0 | 398 | * Notes on state constants: |
michael@0 | 399 | * PBBS_NORMAL - green progress |
michael@0 | 400 | * PBBVS_PARTIAL/PBFVS_ERROR - red error progress |
michael@0 | 401 | * PBFS_PAUSED - yellow paused progress |
michael@0 | 402 | * |
michael@0 | 403 | * There is no common controls style indeterminate part on vista and up. |
michael@0 | 404 | */ |
michael@0 | 405 | |
michael@0 | 406 | /* |
michael@0 | 407 | * Progress bar related constants. These values are found by experimenting and |
michael@0 | 408 | * comparing against native widgets used by the system. They are very unlikely |
michael@0 | 409 | * exact but try to not be too wrong. |
michael@0 | 410 | */ |
michael@0 | 411 | // The amount of time we animate progress meters parts across the frame. |
michael@0 | 412 | static const double kProgressDeterminateTimeSpan = 3.0; |
michael@0 | 413 | static const double kProgressIndeterminateTimeSpan = 5.0; |
michael@0 | 414 | // The width of the overlay used to animate the horizontal progress bar (Vista and later). |
michael@0 | 415 | static const int32_t kProgressHorizontalVistaOverlaySize = 120; |
michael@0 | 416 | // The width of the overlay used for the horizontal indeterminate progress bars on XP. |
michael@0 | 417 | static const int32_t kProgressHorizontalXPOverlaySize = 55; |
michael@0 | 418 | // The height of the overlay used to animate the vertical progress bar (Vista and later). |
michael@0 | 419 | static const int32_t kProgressVerticalOverlaySize = 45; |
michael@0 | 420 | // The height of the overlay used for the vertical indeterminate progress bar (Vista and later). |
michael@0 | 421 | static const int32_t kProgressVerticalIndeterminateOverlaySize = 60; |
michael@0 | 422 | // The width of the overlay used to animate the indeterminate progress bar (Windows Classic). |
michael@0 | 423 | static const int32_t kProgressClassicOverlaySize = 40; |
michael@0 | 424 | |
michael@0 | 425 | /* |
michael@0 | 426 | * GetProgressOverlayStyle - returns the proper overlay part for themed |
michael@0 | 427 | * progress bars based on os and orientation. |
michael@0 | 428 | */ |
michael@0 | 429 | static int32_t |
michael@0 | 430 | GetProgressOverlayStyle(bool aIsVertical) |
michael@0 | 431 | { |
michael@0 | 432 | if (aIsVertical) { |
michael@0 | 433 | if (IsVistaOrLater()) { |
michael@0 | 434 | return PP_MOVEOVERLAYVERT; |
michael@0 | 435 | } |
michael@0 | 436 | return PP_CHUNKVERT; |
michael@0 | 437 | } else { |
michael@0 | 438 | if (IsVistaOrLater()) { |
michael@0 | 439 | return PP_MOVEOVERLAY; |
michael@0 | 440 | } |
michael@0 | 441 | return PP_CHUNK; |
michael@0 | 442 | } |
michael@0 | 443 | } |
michael@0 | 444 | |
michael@0 | 445 | /* |
michael@0 | 446 | * GetProgressOverlaySize - returns the minimum width or height for themed |
michael@0 | 447 | * progress bar overlays. This includes the width of indeterminate chunks |
michael@0 | 448 | * and vista pulse overlays. |
michael@0 | 449 | */ |
michael@0 | 450 | static int32_t |
michael@0 | 451 | GetProgressOverlaySize(bool aIsVertical, bool aIsIndeterminate) |
michael@0 | 452 | { |
michael@0 | 453 | if (IsVistaOrLater()) { |
michael@0 | 454 | if (aIsVertical) { |
michael@0 | 455 | return aIsIndeterminate ? kProgressVerticalIndeterminateOverlaySize |
michael@0 | 456 | : kProgressVerticalOverlaySize; |
michael@0 | 457 | } |
michael@0 | 458 | return kProgressHorizontalVistaOverlaySize; |
michael@0 | 459 | } |
michael@0 | 460 | return kProgressHorizontalXPOverlaySize; |
michael@0 | 461 | } |
michael@0 | 462 | |
michael@0 | 463 | /* |
michael@0 | 464 | * IsProgressMeterFilled - Determines if a progress meter is at 100% fill based |
michael@0 | 465 | * on a comparison of the current value and maximum. |
michael@0 | 466 | */ |
michael@0 | 467 | static bool |
michael@0 | 468 | IsProgressMeterFilled(nsIFrame* aFrame) |
michael@0 | 469 | { |
michael@0 | 470 | NS_ENSURE_TRUE(aFrame, false); |
michael@0 | 471 | nsIFrame* parentFrame = aFrame->GetParent(); |
michael@0 | 472 | NS_ENSURE_TRUE(parentFrame, false); |
michael@0 | 473 | return nsNativeTheme::GetProgressValue(parentFrame) == |
michael@0 | 474 | nsNativeTheme::GetProgressMaxValue(parentFrame); |
michael@0 | 475 | } |
michael@0 | 476 | |
michael@0 | 477 | /* |
michael@0 | 478 | * CalculateProgressOverlayRect - returns the padded overlay animation rect |
michael@0 | 479 | * used in rendering progress bars. Resulting rects are used in rendering |
michael@0 | 480 | * vista+ pulse overlays and indeterminate progress meters. Graphics should |
michael@0 | 481 | * be rendered at the origin. |
michael@0 | 482 | */ |
michael@0 | 483 | RECT |
michael@0 | 484 | nsNativeThemeWin::CalculateProgressOverlayRect(nsIFrame* aFrame, |
michael@0 | 485 | RECT* aWidgetRect, |
michael@0 | 486 | bool aIsVertical, |
michael@0 | 487 | bool aIsIndeterminate, |
michael@0 | 488 | bool aIsClassic) |
michael@0 | 489 | { |
michael@0 | 490 | NS_ASSERTION(aFrame, "bad frame pointer"); |
michael@0 | 491 | NS_ASSERTION(aWidgetRect, "bad rect pointer"); |
michael@0 | 492 | |
michael@0 | 493 | int32_t frameSize = aIsVertical ? aWidgetRect->bottom - aWidgetRect->top |
michael@0 | 494 | : aWidgetRect->right - aWidgetRect->left; |
michael@0 | 495 | |
michael@0 | 496 | // Recycle a set of progress pulse timers - these timers control the position |
michael@0 | 497 | // of all progress overlays and indeterminate chunks that get rendered. |
michael@0 | 498 | double span = aIsIndeterminate ? kProgressIndeterminateTimeSpan |
michael@0 | 499 | : kProgressDeterminateTimeSpan; |
michael@0 | 500 | TimeDuration period; |
michael@0 | 501 | if (!aIsIndeterminate) { |
michael@0 | 502 | if (TimeStamp::Now() > (mProgressDeterminateTimeStamp + |
michael@0 | 503 | TimeDuration::FromSeconds(span))) { |
michael@0 | 504 | mProgressDeterminateTimeStamp = TimeStamp::Now(); |
michael@0 | 505 | } |
michael@0 | 506 | period = TimeStamp::Now() - mProgressDeterminateTimeStamp; |
michael@0 | 507 | } else { |
michael@0 | 508 | if (TimeStamp::Now() > (mProgressIndeterminateTimeStamp + |
michael@0 | 509 | TimeDuration::FromSeconds(span))) { |
michael@0 | 510 | mProgressIndeterminateTimeStamp = TimeStamp::Now(); |
michael@0 | 511 | } |
michael@0 | 512 | period = TimeStamp::Now() - mProgressIndeterminateTimeStamp; |
michael@0 | 513 | } |
michael@0 | 514 | |
michael@0 | 515 | double percent = period / TimeDuration::FromSeconds(span); |
michael@0 | 516 | |
michael@0 | 517 | if (!aIsVertical && IsFrameRTL(aFrame)) |
michael@0 | 518 | percent = 1 - percent; |
michael@0 | 519 | |
michael@0 | 520 | RECT overlayRect = *aWidgetRect; |
michael@0 | 521 | int32_t overlaySize; |
michael@0 | 522 | if (!aIsClassic) { |
michael@0 | 523 | overlaySize = GetProgressOverlaySize(aIsVertical, aIsIndeterminate); |
michael@0 | 524 | } else { |
michael@0 | 525 | overlaySize = kProgressClassicOverlaySize; |
michael@0 | 526 | } |
michael@0 | 527 | |
michael@0 | 528 | // Calculate a bounds that is larger than the meters frame such that the |
michael@0 | 529 | // overlay starts and ends completely off the edge of the frame: |
michael@0 | 530 | // [overlay][frame][overlay] |
michael@0 | 531 | // This also yields a nice delay on rotation. Use overlaySize as the minimum |
michael@0 | 532 | // size for [overlay] based on the graphics dims. If [frame] is larger, use |
michael@0 | 533 | // the frame size instead. |
michael@0 | 534 | int trackWidth = frameSize > overlaySize ? frameSize : overlaySize; |
michael@0 | 535 | if (!aIsVertical) { |
michael@0 | 536 | int xPos = aWidgetRect->left - trackWidth; |
michael@0 | 537 | xPos += (int)ceil(((double)(trackWidth*2) * percent)); |
michael@0 | 538 | overlayRect.left = xPos; |
michael@0 | 539 | overlayRect.right = xPos + overlaySize; |
michael@0 | 540 | } else { |
michael@0 | 541 | int yPos = aWidgetRect->bottom + trackWidth; |
michael@0 | 542 | yPos -= (int)ceil(((double)(trackWidth*2) * percent)); |
michael@0 | 543 | overlayRect.bottom = yPos; |
michael@0 | 544 | overlayRect.top = yPos - overlaySize; |
michael@0 | 545 | } |
michael@0 | 546 | return overlayRect; |
michael@0 | 547 | } |
michael@0 | 548 | |
michael@0 | 549 | /* |
michael@0 | 550 | * DrawChunkProgressMeter - renders an xp style chunked progress meter. Called |
michael@0 | 551 | * by DrawProgressMeter. |
michael@0 | 552 | * |
michael@0 | 553 | * @param aTheme progress theme handle |
michael@0 | 554 | * @param aHdc hdc returned by gfxWindowsNativeDrawing |
michael@0 | 555 | * @param aPart the PP_X progress part |
michael@0 | 556 | * @param aState the theme state |
michael@0 | 557 | * @param aFrame the elements frame |
michael@0 | 558 | * @param aWidgetRect bounding rect for the widget |
michael@0 | 559 | * @param aClipRect dirty rect that needs drawing. |
michael@0 | 560 | * @param aAppUnits app units per device pixel |
michael@0 | 561 | * @param aIsIndeterm is an indeterminate progress? |
michael@0 | 562 | * @param aIsVertical render a vertical progress? |
michael@0 | 563 | * @param aIsRtl direction is rtl |
michael@0 | 564 | */ |
michael@0 | 565 | static void |
michael@0 | 566 | DrawChunkProgressMeter(HTHEME aTheme, HDC aHdc, int aPart, |
michael@0 | 567 | int aState, nsIFrame* aFrame, RECT* aWidgetRect, |
michael@0 | 568 | RECT* aClipRect, gfxFloat aAppUnits, bool aIsIndeterm, |
michael@0 | 569 | bool aIsVertical, bool aIsRtl) |
michael@0 | 570 | { |
michael@0 | 571 | NS_ASSERTION(aTheme, "Bad theme."); |
michael@0 | 572 | NS_ASSERTION(aHdc, "Bad hdc."); |
michael@0 | 573 | NS_ASSERTION(aWidgetRect, "Bad rect."); |
michael@0 | 574 | NS_ASSERTION(aClipRect, "Bad clip rect."); |
michael@0 | 575 | NS_ASSERTION(aFrame, "Bad frame."); |
michael@0 | 576 | |
michael@0 | 577 | // For horizontal meters, the theme lib paints the right graphic but doesn't |
michael@0 | 578 | // paint the chunks, so we do that manually. For vertical meters, the theme |
michael@0 | 579 | // library draws everything correctly. |
michael@0 | 580 | if (aIsVertical) { |
michael@0 | 581 | DrawThemeBackground(aTheme, aHdc, aPart, aState, aWidgetRect, aClipRect); |
michael@0 | 582 | return; |
michael@0 | 583 | } |
michael@0 | 584 | |
michael@0 | 585 | // query for the proper chunk metrics |
michael@0 | 586 | int chunkSize, spaceSize; |
michael@0 | 587 | if (FAILED(GetThemeMetric(aTheme, aHdc, aPart, aState, |
michael@0 | 588 | TMT_PROGRESSCHUNKSIZE, &chunkSize)) || |
michael@0 | 589 | FAILED(GetThemeMetric(aTheme, aHdc, aPart, aState, |
michael@0 | 590 | TMT_PROGRESSSPACESIZE, &spaceSize))) { |
michael@0 | 591 | DrawThemeBackground(aTheme, aHdc, aPart, aState, aWidgetRect, aClipRect); |
michael@0 | 592 | return; |
michael@0 | 593 | } |
michael@0 | 594 | |
michael@0 | 595 | // render chunks |
michael@0 | 596 | if (!aIsRtl || aIsIndeterm) { |
michael@0 | 597 | for (int chunk = aWidgetRect->left; chunk <= aWidgetRect->right; |
michael@0 | 598 | chunk += (chunkSize+spaceSize)) { |
michael@0 | 599 | if (!aIsIndeterm && ((chunk + chunkSize) > aWidgetRect->right)) { |
michael@0 | 600 | // aWidgetRect->right represents the end of the meter. Partial blocks |
michael@0 | 601 | // don't get rendered with one exception, so exit here if we don't have |
michael@0 | 602 | // a full chunk to draw. |
michael@0 | 603 | // The above is true *except* when the meter is at 100% fill, in which |
michael@0 | 604 | // case Windows renders any remaining partial block. Query the parent |
michael@0 | 605 | // frame to find out if we're at 100%. |
michael@0 | 606 | if (!IsProgressMeterFilled(aFrame)) { |
michael@0 | 607 | break; |
michael@0 | 608 | } |
michael@0 | 609 | } |
michael@0 | 610 | RECT bounds = |
michael@0 | 611 | { chunk, aWidgetRect->top, chunk + chunkSize, aWidgetRect->bottom }; |
michael@0 | 612 | DrawThemeBackground(aTheme, aHdc, aPart, aState, &bounds, aClipRect); |
michael@0 | 613 | } |
michael@0 | 614 | } else { |
michael@0 | 615 | // rtl needs to grow in the opposite direction to look right. |
michael@0 | 616 | for (int chunk = aWidgetRect->right; chunk >= aWidgetRect->left; |
michael@0 | 617 | chunk -= (chunkSize+spaceSize)) { |
michael@0 | 618 | if ((chunk - chunkSize) < aWidgetRect->left) { |
michael@0 | 619 | if (!IsProgressMeterFilled(aFrame)) { |
michael@0 | 620 | break; |
michael@0 | 621 | } |
michael@0 | 622 | } |
michael@0 | 623 | RECT bounds = |
michael@0 | 624 | { chunk - chunkSize, aWidgetRect->top, chunk, aWidgetRect->bottom }; |
michael@0 | 625 | DrawThemeBackground(aTheme, aHdc, aPart, aState, &bounds, aClipRect); |
michael@0 | 626 | } |
michael@0 | 627 | } |
michael@0 | 628 | } |
michael@0 | 629 | |
michael@0 | 630 | /* |
michael@0 | 631 | * DrawProgressMeter - render an appropriate progress meter based on progress |
michael@0 | 632 | * meter style, orientation, and os. Note, this does not render the underlying |
michael@0 | 633 | * progress track. |
michael@0 | 634 | * |
michael@0 | 635 | * @param aFrame the widget frame |
michael@0 | 636 | * @param aWidgetType type of widget |
michael@0 | 637 | * @param aTheme progress theme handle |
michael@0 | 638 | * @param aHdc hdc returned by gfxWindowsNativeDrawing |
michael@0 | 639 | * @param aPart the PP_X progress part |
michael@0 | 640 | * @param aState the theme state |
michael@0 | 641 | * @param aWidgetRect bounding rect for the widget |
michael@0 | 642 | * @param aClipRect dirty rect that needs drawing. |
michael@0 | 643 | * @param aAppUnits app units per device pixel |
michael@0 | 644 | */ |
michael@0 | 645 | void |
michael@0 | 646 | nsNativeThemeWin::DrawThemedProgressMeter(nsIFrame* aFrame, int aWidgetType, |
michael@0 | 647 | HANDLE aTheme, HDC aHdc, |
michael@0 | 648 | int aPart, int aState, |
michael@0 | 649 | RECT* aWidgetRect, RECT* aClipRect, |
michael@0 | 650 | gfxFloat aAppUnits) |
michael@0 | 651 | { |
michael@0 | 652 | if (!aFrame || !aTheme || !aHdc) |
michael@0 | 653 | return; |
michael@0 | 654 | |
michael@0 | 655 | NS_ASSERTION(aWidgetRect, "bad rect pointer"); |
michael@0 | 656 | NS_ASSERTION(aClipRect, "bad clip rect pointer"); |
michael@0 | 657 | |
michael@0 | 658 | RECT adjWidgetRect, adjClipRect; |
michael@0 | 659 | adjWidgetRect = *aWidgetRect; |
michael@0 | 660 | adjClipRect = *aClipRect; |
michael@0 | 661 | if (!IsVistaOrLater()) { |
michael@0 | 662 | // Adjust clipping out by one pixel. XP progress meters are inset, |
michael@0 | 663 | // Vista+ are not. |
michael@0 | 664 | InflateRect(&adjWidgetRect, 1, 1); |
michael@0 | 665 | InflateRect(&adjClipRect, 1, 1); |
michael@0 | 666 | } |
michael@0 | 667 | |
michael@0 | 668 | nsIFrame* parentFrame = aFrame->GetParent(); |
michael@0 | 669 | if (!parentFrame) { |
michael@0 | 670 | // We have no parent to work with, just bail. |
michael@0 | 671 | NS_WARNING("No parent frame for progress rendering. Can't paint."); |
michael@0 | 672 | return; |
michael@0 | 673 | } |
michael@0 | 674 | |
michael@0 | 675 | EventStates eventStates = GetContentState(parentFrame, aWidgetType); |
michael@0 | 676 | bool vertical = IsVerticalProgress(parentFrame) || |
michael@0 | 677 | aWidgetType == NS_THEME_PROGRESSBAR_CHUNK_VERTICAL; |
michael@0 | 678 | bool indeterminate = IsIndeterminateProgress(parentFrame, eventStates); |
michael@0 | 679 | bool animate = indeterminate; |
michael@0 | 680 | |
michael@0 | 681 | if (IsVistaOrLater()) { |
michael@0 | 682 | // Vista and up progress meter is fill style, rendered here. We render |
michael@0 | 683 | // the pulse overlay in the follow up section below. |
michael@0 | 684 | DrawThemeBackground(aTheme, aHdc, aPart, aState, |
michael@0 | 685 | &adjWidgetRect, &adjClipRect); |
michael@0 | 686 | if (!IsProgressMeterFilled(aFrame)) { |
michael@0 | 687 | animate = true; |
michael@0 | 688 | } |
michael@0 | 689 | } else if (!indeterminate) { |
michael@0 | 690 | // XP progress meters are 'chunk' style. |
michael@0 | 691 | DrawChunkProgressMeter(aTheme, aHdc, aPart, aState, aFrame, |
michael@0 | 692 | &adjWidgetRect, &adjClipRect, aAppUnits, |
michael@0 | 693 | indeterminate, vertical, IsFrameRTL(aFrame)); |
michael@0 | 694 | } |
michael@0 | 695 | |
michael@0 | 696 | if (animate) { |
michael@0 | 697 | // Indeterminate rendering |
michael@0 | 698 | int32_t overlayPart = GetProgressOverlayStyle(vertical); |
michael@0 | 699 | RECT overlayRect = |
michael@0 | 700 | CalculateProgressOverlayRect(aFrame, &adjWidgetRect, vertical, |
michael@0 | 701 | indeterminate, false); |
michael@0 | 702 | if (IsVistaOrLater()) { |
michael@0 | 703 | DrawThemeBackground(aTheme, aHdc, overlayPart, aState, &overlayRect, |
michael@0 | 704 | &adjClipRect); |
michael@0 | 705 | } else { |
michael@0 | 706 | DrawChunkProgressMeter(aTheme, aHdc, overlayPart, aState, aFrame, |
michael@0 | 707 | &overlayRect, &adjClipRect, aAppUnits, |
michael@0 | 708 | indeterminate, vertical, IsFrameRTL(aFrame)); |
michael@0 | 709 | } |
michael@0 | 710 | |
michael@0 | 711 | if (!QueueAnimatedContentForRefresh(aFrame->GetContent(), 60)) { |
michael@0 | 712 | NS_WARNING("unable to animate progress widget!"); |
michael@0 | 713 | } |
michael@0 | 714 | } |
michael@0 | 715 | } |
michael@0 | 716 | |
michael@0 | 717 | HANDLE |
michael@0 | 718 | nsNativeThemeWin::GetTheme(uint8_t aWidgetType) |
michael@0 | 719 | { |
michael@0 | 720 | if (!IsVistaOrLater()) { |
michael@0 | 721 | // On XP or earlier, render dropdowns as textfields; |
michael@0 | 722 | // doing it the right way works fine with the MS themes, |
michael@0 | 723 | // but breaks on a lot of custom themes (presumably because MS |
michael@0 | 724 | // apps do the textfield border business as well). |
michael@0 | 725 | if (aWidgetType == NS_THEME_DROPDOWN) |
michael@0 | 726 | aWidgetType = NS_THEME_TEXTFIELD; |
michael@0 | 727 | } |
michael@0 | 728 | |
michael@0 | 729 | switch (aWidgetType) { |
michael@0 | 730 | case NS_THEME_BUTTON: |
michael@0 | 731 | case NS_THEME_RADIO: |
michael@0 | 732 | case NS_THEME_CHECKBOX: |
michael@0 | 733 | case NS_THEME_GROUPBOX: |
michael@0 | 734 | return nsUXThemeData::GetTheme(eUXButton); |
michael@0 | 735 | case NS_THEME_NUMBER_INPUT: |
michael@0 | 736 | case NS_THEME_TEXTFIELD: |
michael@0 | 737 | case NS_THEME_TEXTFIELD_MULTILINE: |
michael@0 | 738 | return nsUXThemeData::GetTheme(eUXEdit); |
michael@0 | 739 | case NS_THEME_TOOLTIP: |
michael@0 | 740 | // XP/2K3 should force a classic treatment of tooltips |
michael@0 | 741 | return !IsVistaOrLater() ? |
michael@0 | 742 | nullptr : nsUXThemeData::GetTheme(eUXTooltip); |
michael@0 | 743 | case NS_THEME_TOOLBOX: |
michael@0 | 744 | return nsUXThemeData::GetTheme(eUXRebar); |
michael@0 | 745 | case NS_THEME_WIN_MEDIA_TOOLBOX: |
michael@0 | 746 | return nsUXThemeData::GetTheme(eUXMediaRebar); |
michael@0 | 747 | case NS_THEME_WIN_COMMUNICATIONS_TOOLBOX: |
michael@0 | 748 | return nsUXThemeData::GetTheme(eUXCommunicationsRebar); |
michael@0 | 749 | case NS_THEME_WIN_BROWSER_TAB_BAR_TOOLBOX: |
michael@0 | 750 | return nsUXThemeData::GetTheme(eUXBrowserTabBarRebar); |
michael@0 | 751 | case NS_THEME_TOOLBAR: |
michael@0 | 752 | case NS_THEME_TOOLBAR_BUTTON: |
michael@0 | 753 | case NS_THEME_TOOLBAR_SEPARATOR: |
michael@0 | 754 | return nsUXThemeData::GetTheme(eUXToolbar); |
michael@0 | 755 | case NS_THEME_PROGRESSBAR: |
michael@0 | 756 | case NS_THEME_PROGRESSBAR_VERTICAL: |
michael@0 | 757 | case NS_THEME_PROGRESSBAR_CHUNK: |
michael@0 | 758 | case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL: |
michael@0 | 759 | return nsUXThemeData::GetTheme(eUXProgress); |
michael@0 | 760 | case NS_THEME_TAB: |
michael@0 | 761 | case NS_THEME_TAB_PANEL: |
michael@0 | 762 | case NS_THEME_TAB_PANELS: |
michael@0 | 763 | return nsUXThemeData::GetTheme(eUXTab); |
michael@0 | 764 | case NS_THEME_SCROLLBAR: |
michael@0 | 765 | case NS_THEME_SCROLLBAR_SMALL: |
michael@0 | 766 | case NS_THEME_SCROLLBAR_TRACK_VERTICAL: |
michael@0 | 767 | case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL: |
michael@0 | 768 | case NS_THEME_SCROLLBAR_BUTTON_UP: |
michael@0 | 769 | case NS_THEME_SCROLLBAR_BUTTON_DOWN: |
michael@0 | 770 | case NS_THEME_SCROLLBAR_BUTTON_LEFT: |
michael@0 | 771 | case NS_THEME_SCROLLBAR_BUTTON_RIGHT: |
michael@0 | 772 | case NS_THEME_SCROLLBAR_THUMB_VERTICAL: |
michael@0 | 773 | case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL: |
michael@0 | 774 | return nsUXThemeData::GetTheme(eUXScrollbar); |
michael@0 | 775 | case NS_THEME_RANGE: |
michael@0 | 776 | case NS_THEME_RANGE_THUMB: |
michael@0 | 777 | case NS_THEME_SCALE_HORIZONTAL: |
michael@0 | 778 | case NS_THEME_SCALE_VERTICAL: |
michael@0 | 779 | case NS_THEME_SCALE_THUMB_HORIZONTAL: |
michael@0 | 780 | case NS_THEME_SCALE_THUMB_VERTICAL: |
michael@0 | 781 | return nsUXThemeData::GetTheme(eUXTrackbar); |
michael@0 | 782 | case NS_THEME_SPINNER_UP_BUTTON: |
michael@0 | 783 | case NS_THEME_SPINNER_DOWN_BUTTON: |
michael@0 | 784 | return nsUXThemeData::GetTheme(eUXSpin); |
michael@0 | 785 | case NS_THEME_STATUSBAR: |
michael@0 | 786 | case NS_THEME_STATUSBAR_PANEL: |
michael@0 | 787 | case NS_THEME_STATUSBAR_RESIZER_PANEL: |
michael@0 | 788 | case NS_THEME_RESIZER: |
michael@0 | 789 | return nsUXThemeData::GetTheme(eUXStatus); |
michael@0 | 790 | case NS_THEME_DROPDOWN: |
michael@0 | 791 | case NS_THEME_DROPDOWN_BUTTON: |
michael@0 | 792 | return nsUXThemeData::GetTheme(eUXCombobox); |
michael@0 | 793 | case NS_THEME_TREEVIEW_HEADER_CELL: |
michael@0 | 794 | case NS_THEME_TREEVIEW_HEADER_SORTARROW: |
michael@0 | 795 | return nsUXThemeData::GetTheme(eUXHeader); |
michael@0 | 796 | case NS_THEME_LISTBOX: |
michael@0 | 797 | case NS_THEME_LISTBOX_LISTITEM: |
michael@0 | 798 | case NS_THEME_TREEVIEW: |
michael@0 | 799 | case NS_THEME_TREEVIEW_TWISTY_OPEN: |
michael@0 | 800 | case NS_THEME_TREEVIEW_TREEITEM: |
michael@0 | 801 | return nsUXThemeData::GetTheme(eUXListview); |
michael@0 | 802 | case NS_THEME_MENUBAR: |
michael@0 | 803 | case NS_THEME_MENUPOPUP: |
michael@0 | 804 | case NS_THEME_MENUITEM: |
michael@0 | 805 | case NS_THEME_CHECKMENUITEM: |
michael@0 | 806 | case NS_THEME_RADIOMENUITEM: |
michael@0 | 807 | case NS_THEME_MENUCHECKBOX: |
michael@0 | 808 | case NS_THEME_MENURADIO: |
michael@0 | 809 | case NS_THEME_MENUSEPARATOR: |
michael@0 | 810 | case NS_THEME_MENUARROW: |
michael@0 | 811 | case NS_THEME_MENUIMAGE: |
michael@0 | 812 | case NS_THEME_MENUITEMTEXT: |
michael@0 | 813 | return nsUXThemeData::GetTheme(eUXMenu); |
michael@0 | 814 | case NS_THEME_WINDOW_TITLEBAR: |
michael@0 | 815 | case NS_THEME_WINDOW_TITLEBAR_MAXIMIZED: |
michael@0 | 816 | case NS_THEME_WINDOW_FRAME_LEFT: |
michael@0 | 817 | case NS_THEME_WINDOW_FRAME_RIGHT: |
michael@0 | 818 | case NS_THEME_WINDOW_FRAME_BOTTOM: |
michael@0 | 819 | case NS_THEME_WINDOW_BUTTON_CLOSE: |
michael@0 | 820 | case NS_THEME_WINDOW_BUTTON_MINIMIZE: |
michael@0 | 821 | case NS_THEME_WINDOW_BUTTON_MAXIMIZE: |
michael@0 | 822 | case NS_THEME_WINDOW_BUTTON_RESTORE: |
michael@0 | 823 | case NS_THEME_WINDOW_BUTTON_BOX: |
michael@0 | 824 | case NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED: |
michael@0 | 825 | case NS_THEME_WIN_GLASS: |
michael@0 | 826 | case NS_THEME_WIN_BORDERLESS_GLASS: |
michael@0 | 827 | return nsUXThemeData::GetTheme(eUXWindowFrame); |
michael@0 | 828 | } |
michael@0 | 829 | return nullptr; |
michael@0 | 830 | } |
michael@0 | 831 | |
michael@0 | 832 | int32_t |
michael@0 | 833 | nsNativeThemeWin::StandardGetState(nsIFrame* aFrame, uint8_t aWidgetType, |
michael@0 | 834 | bool wantFocused) |
michael@0 | 835 | { |
michael@0 | 836 | EventStates eventState = GetContentState(aFrame, aWidgetType); |
michael@0 | 837 | if (eventState.HasAllStates(NS_EVENT_STATE_HOVER | NS_EVENT_STATE_ACTIVE)) |
michael@0 | 838 | return TS_ACTIVE; |
michael@0 | 839 | if (eventState.HasState(NS_EVENT_STATE_HOVER)) |
michael@0 | 840 | return TS_HOVER; |
michael@0 | 841 | if (wantFocused && eventState.HasState(NS_EVENT_STATE_FOCUS)) |
michael@0 | 842 | return TS_FOCUSED; |
michael@0 | 843 | |
michael@0 | 844 | return TS_NORMAL; |
michael@0 | 845 | } |
michael@0 | 846 | |
michael@0 | 847 | bool |
michael@0 | 848 | nsNativeThemeWin::IsMenuActive(nsIFrame *aFrame, uint8_t aWidgetType) |
michael@0 | 849 | { |
michael@0 | 850 | nsIContent* content = aFrame->GetContent(); |
michael@0 | 851 | if (content->IsXUL() && |
michael@0 | 852 | content->NodeInfo()->Equals(nsGkAtoms::richlistitem)) |
michael@0 | 853 | return CheckBooleanAttr(aFrame, nsGkAtoms::selected); |
michael@0 | 854 | |
michael@0 | 855 | return CheckBooleanAttr(aFrame, nsGkAtoms::menuactive); |
michael@0 | 856 | } |
michael@0 | 857 | |
michael@0 | 858 | /** |
michael@0 | 859 | * aPart is filled in with the UXTheme part code. On return, values > 0 |
michael@0 | 860 | * are the actual UXTheme part code; -1 means the widget will be drawn by |
michael@0 | 861 | * us; 0 means that we should use part code 0, which isn't a real part code |
michael@0 | 862 | * but elicits some kind of default behaviour from UXTheme when drawing |
michael@0 | 863 | * (but isThemeBackgroundPartiallyTransparent may not work). |
michael@0 | 864 | */ |
michael@0 | 865 | nsresult |
michael@0 | 866 | nsNativeThemeWin::GetThemePartAndState(nsIFrame* aFrame, uint8_t aWidgetType, |
michael@0 | 867 | int32_t& aPart, int32_t& aState) |
michael@0 | 868 | { |
michael@0 | 869 | if (!IsVistaOrLater()) { |
michael@0 | 870 | // See GetTheme |
michael@0 | 871 | if (aWidgetType == NS_THEME_DROPDOWN) |
michael@0 | 872 | aWidgetType = NS_THEME_TEXTFIELD; |
michael@0 | 873 | } |
michael@0 | 874 | |
michael@0 | 875 | switch (aWidgetType) { |
michael@0 | 876 | case NS_THEME_BUTTON: { |
michael@0 | 877 | aPart = BP_BUTTON; |
michael@0 | 878 | if (!aFrame) { |
michael@0 | 879 | aState = TS_NORMAL; |
michael@0 | 880 | return NS_OK; |
michael@0 | 881 | } |
michael@0 | 882 | |
michael@0 | 883 | EventStates eventState = GetContentState(aFrame, aWidgetType); |
michael@0 | 884 | if (IsDisabled(aFrame, eventState)) { |
michael@0 | 885 | aState = TS_DISABLED; |
michael@0 | 886 | return NS_OK; |
michael@0 | 887 | } else if (IsOpenButton(aFrame) || |
michael@0 | 888 | IsCheckedButton(aFrame)) { |
michael@0 | 889 | aState = TS_ACTIVE; |
michael@0 | 890 | return NS_OK; |
michael@0 | 891 | } |
michael@0 | 892 | |
michael@0 | 893 | aState = StandardGetState(aFrame, aWidgetType, true); |
michael@0 | 894 | |
michael@0 | 895 | // Check for default dialog buttons. These buttons should always look |
michael@0 | 896 | // focused. |
michael@0 | 897 | if (aState == TS_NORMAL && IsDefaultButton(aFrame)) |
michael@0 | 898 | aState = TS_FOCUSED; |
michael@0 | 899 | return NS_OK; |
michael@0 | 900 | } |
michael@0 | 901 | case NS_THEME_CHECKBOX: |
michael@0 | 902 | case NS_THEME_RADIO: { |
michael@0 | 903 | bool isCheckbox = (aWidgetType == NS_THEME_CHECKBOX); |
michael@0 | 904 | aPart = isCheckbox ? BP_CHECKBOX : BP_RADIO; |
michael@0 | 905 | |
michael@0 | 906 | enum InputState { |
michael@0 | 907 | UNCHECKED = 0, CHECKED, INDETERMINATE |
michael@0 | 908 | }; |
michael@0 | 909 | InputState inputState = UNCHECKED; |
michael@0 | 910 | bool isXULCheckboxRadio = false; |
michael@0 | 911 | |
michael@0 | 912 | if (!aFrame) { |
michael@0 | 913 | aState = TS_NORMAL; |
michael@0 | 914 | } else { |
michael@0 | 915 | if (GetCheckedOrSelected(aFrame, !isCheckbox)) { |
michael@0 | 916 | inputState = CHECKED; |
michael@0 | 917 | } if (isCheckbox && GetIndeterminate(aFrame)) { |
michael@0 | 918 | inputState = INDETERMINATE; |
michael@0 | 919 | } |
michael@0 | 920 | |
michael@0 | 921 | EventStates eventState = |
michael@0 | 922 | GetContentState(isXULCheckboxRadio ? aFrame->GetParent() : aFrame, |
michael@0 | 923 | aWidgetType); |
michael@0 | 924 | if (IsDisabled(aFrame, eventState)) { |
michael@0 | 925 | aState = TS_DISABLED; |
michael@0 | 926 | } else { |
michael@0 | 927 | aState = StandardGetState(aFrame, aWidgetType, false); |
michael@0 | 928 | } |
michael@0 | 929 | } |
michael@0 | 930 | |
michael@0 | 931 | // 4 unchecked states, 4 checked states, 4 indeterminate states. |
michael@0 | 932 | aState += inputState * 4; |
michael@0 | 933 | return NS_OK; |
michael@0 | 934 | } |
michael@0 | 935 | case NS_THEME_GROUPBOX: { |
michael@0 | 936 | aPart = BP_GROUPBOX; |
michael@0 | 937 | aState = TS_NORMAL; |
michael@0 | 938 | // Since we don't support groupbox disabled and GBS_DISABLED looks the |
michael@0 | 939 | // same as GBS_NORMAL don't bother supporting GBS_DISABLED. |
michael@0 | 940 | return NS_OK; |
michael@0 | 941 | } |
michael@0 | 942 | case NS_THEME_NUMBER_INPUT: |
michael@0 | 943 | case NS_THEME_TEXTFIELD: |
michael@0 | 944 | case NS_THEME_TEXTFIELD_MULTILINE: { |
michael@0 | 945 | EventStates eventState = GetContentState(aFrame, aWidgetType); |
michael@0 | 946 | |
michael@0 | 947 | if (IsVistaOrLater()) { |
michael@0 | 948 | /* Note: the NOSCROLL type has a rounded corner in each |
michael@0 | 949 | * corner. The more specific HSCROLL, VSCROLL, HVSCROLL types |
michael@0 | 950 | * have side and/or top/bottom edges rendered as straight |
michael@0 | 951 | * horizontal lines with sharp corners to accommodate a |
michael@0 | 952 | * scrollbar. However, the scrollbar gets rendered on top of |
michael@0 | 953 | * this for us, so we don't care, and can just use NOSCROLL |
michael@0 | 954 | * here. |
michael@0 | 955 | */ |
michael@0 | 956 | aPart = TFP_EDITBORDER_NOSCROLL; |
michael@0 | 957 | |
michael@0 | 958 | if (!aFrame) { |
michael@0 | 959 | aState = TFS_EDITBORDER_NORMAL; |
michael@0 | 960 | } else if (IsDisabled(aFrame, eventState)) { |
michael@0 | 961 | aState = TFS_EDITBORDER_DISABLED; |
michael@0 | 962 | } else if (IsReadOnly(aFrame)) { |
michael@0 | 963 | /* no special read-only state */ |
michael@0 | 964 | aState = TFS_EDITBORDER_NORMAL; |
michael@0 | 965 | } else { |
michael@0 | 966 | nsIContent* content = aFrame->GetContent(); |
michael@0 | 967 | |
michael@0 | 968 | /* XUL textboxes don't get focused themselves, because they have child |
michael@0 | 969 | * html:input.. but we can check the XUL focused attributes on them |
michael@0 | 970 | */ |
michael@0 | 971 | if (content && content->IsXUL() && IsFocused(aFrame)) |
michael@0 | 972 | aState = TFS_EDITBORDER_FOCUSED; |
michael@0 | 973 | else if (eventState.HasAtLeastOneOfStates(NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_FOCUS)) |
michael@0 | 974 | aState = TFS_EDITBORDER_FOCUSED; |
michael@0 | 975 | else if (eventState.HasState(NS_EVENT_STATE_HOVER)) |
michael@0 | 976 | aState = TFS_EDITBORDER_HOVER; |
michael@0 | 977 | else |
michael@0 | 978 | aState = TFS_EDITBORDER_NORMAL; |
michael@0 | 979 | } |
michael@0 | 980 | } else { |
michael@0 | 981 | aPart = TFP_TEXTFIELD; |
michael@0 | 982 | |
michael@0 | 983 | if (!aFrame) |
michael@0 | 984 | aState = TS_NORMAL; |
michael@0 | 985 | else if (IsDisabled(aFrame, eventState)) |
michael@0 | 986 | aState = TS_DISABLED; |
michael@0 | 987 | else if (IsReadOnly(aFrame)) |
michael@0 | 988 | aState = TFS_READONLY; |
michael@0 | 989 | else |
michael@0 | 990 | aState = StandardGetState(aFrame, aWidgetType, true); |
michael@0 | 991 | } |
michael@0 | 992 | |
michael@0 | 993 | return NS_OK; |
michael@0 | 994 | } |
michael@0 | 995 | case NS_THEME_TOOLTIP: { |
michael@0 | 996 | aPart = TTP_STANDARD; |
michael@0 | 997 | aState = TS_NORMAL; |
michael@0 | 998 | return NS_OK; |
michael@0 | 999 | } |
michael@0 | 1000 | case NS_THEME_PROGRESSBAR: |
michael@0 | 1001 | case NS_THEME_PROGRESSBAR_VERTICAL: { |
michael@0 | 1002 | // Note IsVerticalProgress only tests for orient css attrribute, |
michael@0 | 1003 | // NS_THEME_PROGRESSBAR_VERTICAL is dedicated to -moz-appearance: |
michael@0 | 1004 | // progressbar-vertical. |
michael@0 | 1005 | bool vertical = IsVerticalProgress(aFrame) || |
michael@0 | 1006 | aWidgetType == NS_THEME_PROGRESSBAR_VERTICAL; |
michael@0 | 1007 | aPart = vertical ? PP_BARVERT : PP_BAR; |
michael@0 | 1008 | aState = PBBS_NORMAL; |
michael@0 | 1009 | return NS_OK; |
michael@0 | 1010 | } |
michael@0 | 1011 | case NS_THEME_PROGRESSBAR_CHUNK: |
michael@0 | 1012 | case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL: { |
michael@0 | 1013 | nsIFrame* parentFrame = aFrame->GetParent(); |
michael@0 | 1014 | EventStates eventStates = GetContentState(parentFrame, aWidgetType); |
michael@0 | 1015 | if (aWidgetType == NS_THEME_PROGRESSBAR_CHUNK_VERTICAL || |
michael@0 | 1016 | IsVerticalProgress(parentFrame)) { |
michael@0 | 1017 | aPart = IsVistaOrLater() ? |
michael@0 | 1018 | PP_FILLVERT : PP_CHUNKVERT; |
michael@0 | 1019 | } else { |
michael@0 | 1020 | aPart = IsVistaOrLater() ? |
michael@0 | 1021 | PP_FILL : PP_CHUNK; |
michael@0 | 1022 | } |
michael@0 | 1023 | |
michael@0 | 1024 | aState = PBBVS_NORMAL; |
michael@0 | 1025 | return NS_OK; |
michael@0 | 1026 | } |
michael@0 | 1027 | case NS_THEME_TOOLBAR_BUTTON: { |
michael@0 | 1028 | aPart = BP_BUTTON; |
michael@0 | 1029 | if (!aFrame) { |
michael@0 | 1030 | aState = TS_NORMAL; |
michael@0 | 1031 | return NS_OK; |
michael@0 | 1032 | } |
michael@0 | 1033 | |
michael@0 | 1034 | EventStates eventState = GetContentState(aFrame, aWidgetType); |
michael@0 | 1035 | if (IsDisabled(aFrame, eventState)) { |
michael@0 | 1036 | aState = TS_DISABLED; |
michael@0 | 1037 | return NS_OK; |
michael@0 | 1038 | } |
michael@0 | 1039 | if (IsOpenButton(aFrame)) { |
michael@0 | 1040 | aState = TS_ACTIVE; |
michael@0 | 1041 | return NS_OK; |
michael@0 | 1042 | } |
michael@0 | 1043 | |
michael@0 | 1044 | if (eventState.HasAllStates(NS_EVENT_STATE_HOVER | NS_EVENT_STATE_ACTIVE)) |
michael@0 | 1045 | aState = TS_ACTIVE; |
michael@0 | 1046 | else if (eventState.HasState(NS_EVENT_STATE_HOVER)) { |
michael@0 | 1047 | if (IsCheckedButton(aFrame)) |
michael@0 | 1048 | aState = TB_HOVER_CHECKED; |
michael@0 | 1049 | else |
michael@0 | 1050 | aState = TS_HOVER; |
michael@0 | 1051 | } |
michael@0 | 1052 | else { |
michael@0 | 1053 | if (IsCheckedButton(aFrame)) |
michael@0 | 1054 | aState = TB_CHECKED; |
michael@0 | 1055 | else |
michael@0 | 1056 | aState = TS_NORMAL; |
michael@0 | 1057 | } |
michael@0 | 1058 | |
michael@0 | 1059 | return NS_OK; |
michael@0 | 1060 | } |
michael@0 | 1061 | case NS_THEME_TOOLBAR_SEPARATOR: { |
michael@0 | 1062 | aPart = TP_SEPARATOR; |
michael@0 | 1063 | aState = TS_NORMAL; |
michael@0 | 1064 | return NS_OK; |
michael@0 | 1065 | } |
michael@0 | 1066 | case NS_THEME_SCROLLBAR_BUTTON_UP: |
michael@0 | 1067 | case NS_THEME_SCROLLBAR_BUTTON_DOWN: |
michael@0 | 1068 | case NS_THEME_SCROLLBAR_BUTTON_LEFT: |
michael@0 | 1069 | case NS_THEME_SCROLLBAR_BUTTON_RIGHT: { |
michael@0 | 1070 | aPart = SP_BUTTON; |
michael@0 | 1071 | aState = (aWidgetType - NS_THEME_SCROLLBAR_BUTTON_UP)*4; |
michael@0 | 1072 | EventStates eventState = GetContentState(aFrame, aWidgetType); |
michael@0 | 1073 | if (!aFrame) |
michael@0 | 1074 | aState += TS_NORMAL; |
michael@0 | 1075 | else if (IsDisabled(aFrame, eventState)) |
michael@0 | 1076 | aState += TS_DISABLED; |
michael@0 | 1077 | else { |
michael@0 | 1078 | nsIFrame *parent = aFrame->GetParent(); |
michael@0 | 1079 | EventStates parentState = |
michael@0 | 1080 | GetContentState(parent, parent->StyleDisplay()->mAppearance); |
michael@0 | 1081 | if (eventState.HasAllStates(NS_EVENT_STATE_HOVER | NS_EVENT_STATE_ACTIVE)) |
michael@0 | 1082 | aState += TS_ACTIVE; |
michael@0 | 1083 | else if (eventState.HasState(NS_EVENT_STATE_HOVER)) |
michael@0 | 1084 | aState += TS_HOVER; |
michael@0 | 1085 | else if (IsVistaOrLater() && |
michael@0 | 1086 | parentState.HasState(NS_EVENT_STATE_HOVER)) |
michael@0 | 1087 | aState = (aWidgetType - NS_THEME_SCROLLBAR_BUTTON_UP) + SP_BUTTON_IMPLICIT_HOVER_BASE; |
michael@0 | 1088 | else |
michael@0 | 1089 | aState += TS_NORMAL; |
michael@0 | 1090 | } |
michael@0 | 1091 | return NS_OK; |
michael@0 | 1092 | } |
michael@0 | 1093 | case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL: |
michael@0 | 1094 | case NS_THEME_SCROLLBAR_TRACK_VERTICAL: { |
michael@0 | 1095 | aPart = (aWidgetType == NS_THEME_SCROLLBAR_TRACK_HORIZONTAL) ? |
michael@0 | 1096 | SP_TRACKSTARTHOR : SP_TRACKSTARTVERT; |
michael@0 | 1097 | aState = TS_NORMAL; |
michael@0 | 1098 | return NS_OK; |
michael@0 | 1099 | } |
michael@0 | 1100 | case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL: |
michael@0 | 1101 | case NS_THEME_SCROLLBAR_THUMB_VERTICAL: { |
michael@0 | 1102 | aPart = (aWidgetType == NS_THEME_SCROLLBAR_THUMB_HORIZONTAL) ? |
michael@0 | 1103 | SP_THUMBHOR : SP_THUMBVERT; |
michael@0 | 1104 | EventStates eventState = GetContentState(aFrame, aWidgetType); |
michael@0 | 1105 | if (!aFrame) |
michael@0 | 1106 | aState = TS_NORMAL; |
michael@0 | 1107 | else if (IsDisabled(aFrame, eventState)) |
michael@0 | 1108 | aState = TS_DISABLED; |
michael@0 | 1109 | else { |
michael@0 | 1110 | if (eventState.HasState(NS_EVENT_STATE_ACTIVE)) // Hover is not also a requirement for |
michael@0 | 1111 | // the thumb, since the drag is not canceled |
michael@0 | 1112 | // when you move outside the thumb. |
michael@0 | 1113 | aState = TS_ACTIVE; |
michael@0 | 1114 | else if (eventState.HasState(NS_EVENT_STATE_HOVER)) |
michael@0 | 1115 | aState = TS_HOVER; |
michael@0 | 1116 | else |
michael@0 | 1117 | aState = TS_NORMAL; |
michael@0 | 1118 | } |
michael@0 | 1119 | return NS_OK; |
michael@0 | 1120 | } |
michael@0 | 1121 | case NS_THEME_RANGE: |
michael@0 | 1122 | case NS_THEME_SCALE_HORIZONTAL: |
michael@0 | 1123 | case NS_THEME_SCALE_VERTICAL: { |
michael@0 | 1124 | if (aWidgetType == NS_THEME_SCALE_HORIZONTAL || |
michael@0 | 1125 | (aWidgetType == NS_THEME_RANGE && |
michael@0 | 1126 | IsRangeHorizontal(aFrame))) { |
michael@0 | 1127 | aPart = TKP_TRACK; |
michael@0 | 1128 | aState = TRS_NORMAL; |
michael@0 | 1129 | } else { |
michael@0 | 1130 | aPart = TKP_TRACKVERT; |
michael@0 | 1131 | aState = TRVS_NORMAL; |
michael@0 | 1132 | } |
michael@0 | 1133 | return NS_OK; |
michael@0 | 1134 | } |
michael@0 | 1135 | case NS_THEME_RANGE_THUMB: |
michael@0 | 1136 | case NS_THEME_SCALE_THUMB_HORIZONTAL: |
michael@0 | 1137 | case NS_THEME_SCALE_THUMB_VERTICAL: { |
michael@0 | 1138 | if (aWidgetType == NS_THEME_RANGE_THUMB) { |
michael@0 | 1139 | if (IsRangeHorizontal(aFrame)) { |
michael@0 | 1140 | aPart = TKP_THUMBBOTTOM; |
michael@0 | 1141 | } else { |
michael@0 | 1142 | aPart = IsFrameRTL(aFrame) ? TKP_THUMBLEFT : TKP_THUMBRIGHT; |
michael@0 | 1143 | } |
michael@0 | 1144 | } else { |
michael@0 | 1145 | aPart = (aWidgetType == NS_THEME_SCALE_THUMB_HORIZONTAL) ? |
michael@0 | 1146 | TKP_THUMB : TKP_THUMBVERT; |
michael@0 | 1147 | } |
michael@0 | 1148 | EventStates eventState = GetContentState(aFrame, aWidgetType); |
michael@0 | 1149 | if (!aFrame) |
michael@0 | 1150 | aState = TS_NORMAL; |
michael@0 | 1151 | else if (IsDisabled(aFrame, eventState)) { |
michael@0 | 1152 | aState = TKP_DISABLED; |
michael@0 | 1153 | } |
michael@0 | 1154 | else { |
michael@0 | 1155 | if (eventState.HasState(NS_EVENT_STATE_ACTIVE)) // Hover is not also a requirement for |
michael@0 | 1156 | // the thumb, since the drag is not canceled |
michael@0 | 1157 | // when you move outside the thumb. |
michael@0 | 1158 | aState = TS_ACTIVE; |
michael@0 | 1159 | else if (eventState.HasState(NS_EVENT_STATE_FOCUS)) |
michael@0 | 1160 | aState = TKP_FOCUSED; |
michael@0 | 1161 | else if (eventState.HasState(NS_EVENT_STATE_HOVER)) |
michael@0 | 1162 | aState = TS_HOVER; |
michael@0 | 1163 | else |
michael@0 | 1164 | aState = TS_NORMAL; |
michael@0 | 1165 | } |
michael@0 | 1166 | return NS_OK; |
michael@0 | 1167 | } |
michael@0 | 1168 | case NS_THEME_SPINNER_UP_BUTTON: |
michael@0 | 1169 | case NS_THEME_SPINNER_DOWN_BUTTON: { |
michael@0 | 1170 | aPart = (aWidgetType == NS_THEME_SPINNER_UP_BUTTON) ? |
michael@0 | 1171 | SPNP_UP : SPNP_DOWN; |
michael@0 | 1172 | EventStates eventState = GetContentState(aFrame, aWidgetType); |
michael@0 | 1173 | if (!aFrame) |
michael@0 | 1174 | aState = TS_NORMAL; |
michael@0 | 1175 | else if (IsDisabled(aFrame, eventState)) |
michael@0 | 1176 | aState = TS_DISABLED; |
michael@0 | 1177 | else |
michael@0 | 1178 | aState = StandardGetState(aFrame, aWidgetType, false); |
michael@0 | 1179 | return NS_OK; |
michael@0 | 1180 | } |
michael@0 | 1181 | case NS_THEME_TOOLBOX: |
michael@0 | 1182 | case NS_THEME_WIN_MEDIA_TOOLBOX: |
michael@0 | 1183 | case NS_THEME_WIN_COMMUNICATIONS_TOOLBOX: |
michael@0 | 1184 | case NS_THEME_WIN_BROWSER_TAB_BAR_TOOLBOX: |
michael@0 | 1185 | case NS_THEME_STATUSBAR: |
michael@0 | 1186 | case NS_THEME_SCROLLBAR: |
michael@0 | 1187 | case NS_THEME_SCROLLBAR_SMALL: { |
michael@0 | 1188 | aState = 0; |
michael@0 | 1189 | if (IsVistaOrLater()) { |
michael@0 | 1190 | // On vista, they have a part |
michael@0 | 1191 | aPart = RP_BACKGROUND; |
michael@0 | 1192 | } else { |
michael@0 | 1193 | // Otherwise, they don't. (But I bet |
michael@0 | 1194 | // RP_BACKGROUND would work here, too); |
michael@0 | 1195 | aPart = 0; |
michael@0 | 1196 | } |
michael@0 | 1197 | return NS_OK; |
michael@0 | 1198 | } |
michael@0 | 1199 | case NS_THEME_TOOLBAR: { |
michael@0 | 1200 | // Use -1 to indicate we don't wish to have the theme background drawn |
michael@0 | 1201 | // for this item. We will pass any nessessary information via aState, |
michael@0 | 1202 | // and will render the item using separate code. |
michael@0 | 1203 | aPart = -1; |
michael@0 | 1204 | aState = 0; |
michael@0 | 1205 | if (aFrame) { |
michael@0 | 1206 | nsIContent* content = aFrame->GetContent(); |
michael@0 | 1207 | nsIContent* parent = content->GetParent(); |
michael@0 | 1208 | // XXXzeniko hiding the first toolbar will result in an unwanted margin |
michael@0 | 1209 | if (parent && parent->GetFirstChild() == content) { |
michael@0 | 1210 | aState = 1; |
michael@0 | 1211 | } |
michael@0 | 1212 | } |
michael@0 | 1213 | return NS_OK; |
michael@0 | 1214 | } |
michael@0 | 1215 | case NS_THEME_STATUSBAR_PANEL: |
michael@0 | 1216 | case NS_THEME_STATUSBAR_RESIZER_PANEL: |
michael@0 | 1217 | case NS_THEME_RESIZER: { |
michael@0 | 1218 | aPart = (aWidgetType - NS_THEME_STATUSBAR_PANEL) + 1; |
michael@0 | 1219 | aState = TS_NORMAL; |
michael@0 | 1220 | return NS_OK; |
michael@0 | 1221 | } |
michael@0 | 1222 | case NS_THEME_TREEVIEW: |
michael@0 | 1223 | case NS_THEME_LISTBOX: { |
michael@0 | 1224 | aPart = TREEVIEW_BODY; |
michael@0 | 1225 | aState = TS_NORMAL; |
michael@0 | 1226 | return NS_OK; |
michael@0 | 1227 | } |
michael@0 | 1228 | case NS_THEME_TAB_PANELS: { |
michael@0 | 1229 | aPart = TABP_PANELS; |
michael@0 | 1230 | aState = TS_NORMAL; |
michael@0 | 1231 | return NS_OK; |
michael@0 | 1232 | } |
michael@0 | 1233 | case NS_THEME_TAB_PANEL: { |
michael@0 | 1234 | aPart = TABP_PANEL; |
michael@0 | 1235 | aState = TS_NORMAL; |
michael@0 | 1236 | return NS_OK; |
michael@0 | 1237 | } |
michael@0 | 1238 | case NS_THEME_TAB: { |
michael@0 | 1239 | aPart = TABP_TAB; |
michael@0 | 1240 | if (!aFrame) { |
michael@0 | 1241 | aState = TS_NORMAL; |
michael@0 | 1242 | return NS_OK; |
michael@0 | 1243 | } |
michael@0 | 1244 | |
michael@0 | 1245 | EventStates eventState = GetContentState(aFrame, aWidgetType); |
michael@0 | 1246 | if (IsDisabled(aFrame, eventState)) { |
michael@0 | 1247 | aState = TS_DISABLED; |
michael@0 | 1248 | return NS_OK; |
michael@0 | 1249 | } |
michael@0 | 1250 | |
michael@0 | 1251 | if (IsSelectedTab(aFrame)) { |
michael@0 | 1252 | aPart = TABP_TAB_SELECTED; |
michael@0 | 1253 | aState = TS_ACTIVE; // The selected tab is always "pressed". |
michael@0 | 1254 | } |
michael@0 | 1255 | else |
michael@0 | 1256 | aState = StandardGetState(aFrame, aWidgetType, true); |
michael@0 | 1257 | |
michael@0 | 1258 | return NS_OK; |
michael@0 | 1259 | } |
michael@0 | 1260 | case NS_THEME_TREEVIEW_HEADER_SORTARROW: { |
michael@0 | 1261 | // XXX Probably will never work due to a bug in the Luna theme. |
michael@0 | 1262 | aPart = 4; |
michael@0 | 1263 | aState = 1; |
michael@0 | 1264 | return NS_OK; |
michael@0 | 1265 | } |
michael@0 | 1266 | case NS_THEME_TREEVIEW_HEADER_CELL: { |
michael@0 | 1267 | aPart = 1; |
michael@0 | 1268 | if (!aFrame) { |
michael@0 | 1269 | aState = TS_NORMAL; |
michael@0 | 1270 | return NS_OK; |
michael@0 | 1271 | } |
michael@0 | 1272 | |
michael@0 | 1273 | aState = StandardGetState(aFrame, aWidgetType, true); |
michael@0 | 1274 | |
michael@0 | 1275 | return NS_OK; |
michael@0 | 1276 | } |
michael@0 | 1277 | case NS_THEME_DROPDOWN: { |
michael@0 | 1278 | nsIContent* content = aFrame->GetContent(); |
michael@0 | 1279 | bool isHTML = content && content->IsHTML(); |
michael@0 | 1280 | bool useDropBorder = isHTML || IsMenuListEditable(aFrame); |
michael@0 | 1281 | EventStates eventState = GetContentState(aFrame, aWidgetType); |
michael@0 | 1282 | |
michael@0 | 1283 | /* On Vista/Win7, we use CBP_DROPBORDER instead of DROPFRAME for HTML |
michael@0 | 1284 | * content or for editable menulists; this gives us the thin outline, |
michael@0 | 1285 | * instead of the gradient-filled background */ |
michael@0 | 1286 | if (useDropBorder) |
michael@0 | 1287 | aPart = CBP_DROPBORDER; |
michael@0 | 1288 | else |
michael@0 | 1289 | aPart = CBP_DROPFRAME; |
michael@0 | 1290 | |
michael@0 | 1291 | if (IsDisabled(aFrame, eventState)) { |
michael@0 | 1292 | aState = TS_DISABLED; |
michael@0 | 1293 | } else if (IsReadOnly(aFrame)) { |
michael@0 | 1294 | aState = TS_NORMAL; |
michael@0 | 1295 | } else if (IsOpenButton(aFrame)) { |
michael@0 | 1296 | aState = TS_ACTIVE; |
michael@0 | 1297 | } else { |
michael@0 | 1298 | if (useDropBorder && (eventState.HasState(NS_EVENT_STATE_FOCUS) || IsFocused(aFrame))) |
michael@0 | 1299 | aState = TS_ACTIVE; |
michael@0 | 1300 | else if (eventState.HasAllStates(NS_EVENT_STATE_HOVER | NS_EVENT_STATE_ACTIVE)) |
michael@0 | 1301 | aState = TS_ACTIVE; |
michael@0 | 1302 | else if (eventState.HasState(NS_EVENT_STATE_HOVER)) |
michael@0 | 1303 | aState = TS_HOVER; |
michael@0 | 1304 | else |
michael@0 | 1305 | aState = TS_NORMAL; |
michael@0 | 1306 | } |
michael@0 | 1307 | |
michael@0 | 1308 | return NS_OK; |
michael@0 | 1309 | } |
michael@0 | 1310 | case NS_THEME_DROPDOWN_BUTTON: { |
michael@0 | 1311 | bool isHTML = IsHTMLContent(aFrame); |
michael@0 | 1312 | nsIFrame* parentFrame = aFrame->GetParent(); |
michael@0 | 1313 | bool isMenulist = !isHTML && parentFrame->GetType() == nsGkAtoms::menuFrame; |
michael@0 | 1314 | bool isOpen = false; |
michael@0 | 1315 | |
michael@0 | 1316 | // HTML select and XUL menulist dropdown buttons get state from the parent. |
michael@0 | 1317 | if (isHTML || isMenulist) |
michael@0 | 1318 | aFrame = parentFrame; |
michael@0 | 1319 | |
michael@0 | 1320 | EventStates eventState = GetContentState(aFrame, aWidgetType); |
michael@0 | 1321 | aPart = IsVistaOrLater() ? |
michael@0 | 1322 | CBP_DROPMARKER_VISTA : CBP_DROPMARKER; |
michael@0 | 1323 | |
michael@0 | 1324 | // For HTML controls with author styling, we should fall |
michael@0 | 1325 | // back to the old dropmarker style to avoid clashes with |
michael@0 | 1326 | // author-specified backgrounds and borders (bug #441034) |
michael@0 | 1327 | if (isHTML && IsWidgetStyled(aFrame->PresContext(), aFrame, NS_THEME_DROPDOWN)) |
michael@0 | 1328 | aPart = CBP_DROPMARKER; |
michael@0 | 1329 | |
michael@0 | 1330 | if (IsDisabled(aFrame, eventState)) { |
michael@0 | 1331 | aState = TS_DISABLED; |
michael@0 | 1332 | return NS_OK; |
michael@0 | 1333 | } |
michael@0 | 1334 | |
michael@0 | 1335 | if (isHTML) { |
michael@0 | 1336 | nsIComboboxControlFrame* ccf = do_QueryFrame(aFrame); |
michael@0 | 1337 | isOpen = (ccf && ccf->IsDroppedDown()); |
michael@0 | 1338 | } |
michael@0 | 1339 | else |
michael@0 | 1340 | isOpen = IsOpenButton(aFrame); |
michael@0 | 1341 | |
michael@0 | 1342 | if (IsVistaOrLater()) { |
michael@0 | 1343 | if (isHTML || IsMenuListEditable(aFrame)) { |
michael@0 | 1344 | if (isOpen) { |
michael@0 | 1345 | /* Hover is propagated, but we need to know whether we're |
michael@0 | 1346 | * hovering just the combobox frame, not the dropdown frame. |
michael@0 | 1347 | * But, we can't get that information, since hover is on the |
michael@0 | 1348 | * content node, and they share the same content node. So, |
michael@0 | 1349 | * instead, we cheat -- if the dropdown is open, we always |
michael@0 | 1350 | * show the hover state. This looks fine in practice. |
michael@0 | 1351 | */ |
michael@0 | 1352 | aState = TS_HOVER; |
michael@0 | 1353 | return NS_OK; |
michael@0 | 1354 | } |
michael@0 | 1355 | } else { |
michael@0 | 1356 | /* On Vista, the dropdown indicator on a menulist button in |
michael@0 | 1357 | * chrome is not given a hover effect. When the frame isn't |
michael@0 | 1358 | * isn't HTML content, we cheat and force the dropdown state |
michael@0 | 1359 | * to be normal. (Bug 430434) |
michael@0 | 1360 | */ |
michael@0 | 1361 | aState = TS_NORMAL; |
michael@0 | 1362 | return NS_OK; |
michael@0 | 1363 | } |
michael@0 | 1364 | } |
michael@0 | 1365 | |
michael@0 | 1366 | aState = TS_NORMAL; |
michael@0 | 1367 | |
michael@0 | 1368 | // Dropdown button active state doesn't need :hover. |
michael@0 | 1369 | if (eventState.HasState(NS_EVENT_STATE_ACTIVE)) { |
michael@0 | 1370 | if (isOpen && (isHTML || isMenulist)) { |
michael@0 | 1371 | // XXX Button should look active until the mouse is released, but |
michael@0 | 1372 | // without making it look active when the popup is clicked. |
michael@0 | 1373 | return NS_OK; |
michael@0 | 1374 | } |
michael@0 | 1375 | aState = TS_ACTIVE; |
michael@0 | 1376 | } |
michael@0 | 1377 | else if (eventState.HasState(NS_EVENT_STATE_HOVER)) { |
michael@0 | 1378 | // No hover effect for XUL menulists and autocomplete dropdown buttons |
michael@0 | 1379 | // while the dropdown menu is open. |
michael@0 | 1380 | if (isOpen) { |
michael@0 | 1381 | // XXX HTML select dropdown buttons should have the hover effect when |
michael@0 | 1382 | // hovering the combobox frame, but not the popup frame. |
michael@0 | 1383 | return NS_OK; |
michael@0 | 1384 | } |
michael@0 | 1385 | aState = TS_HOVER; |
michael@0 | 1386 | } |
michael@0 | 1387 | return NS_OK; |
michael@0 | 1388 | } |
michael@0 | 1389 | case NS_THEME_MENUPOPUP: { |
michael@0 | 1390 | aPart = MENU_POPUPBACKGROUND; |
michael@0 | 1391 | aState = MB_ACTIVE; |
michael@0 | 1392 | return NS_OK; |
michael@0 | 1393 | } |
michael@0 | 1394 | case NS_THEME_MENUITEM: |
michael@0 | 1395 | case NS_THEME_CHECKMENUITEM: |
michael@0 | 1396 | case NS_THEME_RADIOMENUITEM: { |
michael@0 | 1397 | bool isTopLevel = false; |
michael@0 | 1398 | bool isOpen = false; |
michael@0 | 1399 | bool isHover = false; |
michael@0 | 1400 | nsMenuFrame *menuFrame = do_QueryFrame(aFrame); |
michael@0 | 1401 | EventStates eventState = GetContentState(aFrame, aWidgetType); |
michael@0 | 1402 | |
michael@0 | 1403 | isTopLevel = IsTopLevelMenu(aFrame); |
michael@0 | 1404 | |
michael@0 | 1405 | if (menuFrame) |
michael@0 | 1406 | isOpen = menuFrame->IsOpen(); |
michael@0 | 1407 | |
michael@0 | 1408 | isHover = IsMenuActive(aFrame, aWidgetType); |
michael@0 | 1409 | |
michael@0 | 1410 | if (isTopLevel) { |
michael@0 | 1411 | aPart = MENU_BARITEM; |
michael@0 | 1412 | |
michael@0 | 1413 | if (isOpen) |
michael@0 | 1414 | aState = MBI_PUSHED; |
michael@0 | 1415 | else if (isHover) |
michael@0 | 1416 | aState = MBI_HOT; |
michael@0 | 1417 | else |
michael@0 | 1418 | aState = MBI_NORMAL; |
michael@0 | 1419 | |
michael@0 | 1420 | // the disabled states are offset by 3 |
michael@0 | 1421 | if (IsDisabled(aFrame, eventState)) |
michael@0 | 1422 | aState += 3; |
michael@0 | 1423 | } else { |
michael@0 | 1424 | aPart = MENU_POPUPITEM; |
michael@0 | 1425 | |
michael@0 | 1426 | if (isHover) |
michael@0 | 1427 | aState = MPI_HOT; |
michael@0 | 1428 | else |
michael@0 | 1429 | aState = MPI_NORMAL; |
michael@0 | 1430 | |
michael@0 | 1431 | // the disabled states are offset by 2 |
michael@0 | 1432 | if (IsDisabled(aFrame, eventState)) |
michael@0 | 1433 | aState += 2; |
michael@0 | 1434 | } |
michael@0 | 1435 | |
michael@0 | 1436 | return NS_OK; |
michael@0 | 1437 | } |
michael@0 | 1438 | case NS_THEME_MENUSEPARATOR: |
michael@0 | 1439 | aPart = MENU_POPUPSEPARATOR; |
michael@0 | 1440 | aState = 0; |
michael@0 | 1441 | return NS_OK; |
michael@0 | 1442 | case NS_THEME_MENUARROW: |
michael@0 | 1443 | { |
michael@0 | 1444 | aPart = MENU_POPUPSUBMENU; |
michael@0 | 1445 | EventStates eventState = GetContentState(aFrame, aWidgetType); |
michael@0 | 1446 | aState = IsDisabled(aFrame, eventState) ? MSM_DISABLED : MSM_NORMAL; |
michael@0 | 1447 | return NS_OK; |
michael@0 | 1448 | } |
michael@0 | 1449 | case NS_THEME_MENUCHECKBOX: |
michael@0 | 1450 | case NS_THEME_MENURADIO: |
michael@0 | 1451 | { |
michael@0 | 1452 | bool isChecked; |
michael@0 | 1453 | EventStates eventState = GetContentState(aFrame, aWidgetType); |
michael@0 | 1454 | |
michael@0 | 1455 | // NOTE: we can probably use NS_EVENT_STATE_CHECKED |
michael@0 | 1456 | isChecked = CheckBooleanAttr(aFrame, nsGkAtoms::checked); |
michael@0 | 1457 | |
michael@0 | 1458 | aPart = MENU_POPUPCHECK; |
michael@0 | 1459 | aState = MC_CHECKMARKNORMAL; |
michael@0 | 1460 | |
michael@0 | 1461 | // Radio states are offset by 2 |
michael@0 | 1462 | if (aWidgetType == NS_THEME_MENURADIO) |
michael@0 | 1463 | aState += 2; |
michael@0 | 1464 | |
michael@0 | 1465 | // the disabled states are offset by 1 |
michael@0 | 1466 | if (IsDisabled(aFrame, eventState)) |
michael@0 | 1467 | aState += 1; |
michael@0 | 1468 | |
michael@0 | 1469 | return NS_OK; |
michael@0 | 1470 | } |
michael@0 | 1471 | case NS_THEME_MENUITEMTEXT: |
michael@0 | 1472 | case NS_THEME_MENUIMAGE: |
michael@0 | 1473 | aPart = -1; |
michael@0 | 1474 | aState = 0; |
michael@0 | 1475 | return NS_OK; |
michael@0 | 1476 | |
michael@0 | 1477 | case NS_THEME_WINDOW_TITLEBAR: |
michael@0 | 1478 | aPart = mozilla::widget::themeconst::WP_CAPTION; |
michael@0 | 1479 | aState = GetTopLevelWindowActiveState(aFrame); |
michael@0 | 1480 | return NS_OK; |
michael@0 | 1481 | case NS_THEME_WINDOW_TITLEBAR_MAXIMIZED: |
michael@0 | 1482 | aPart = mozilla::widget::themeconst::WP_MAXCAPTION; |
michael@0 | 1483 | aState = GetTopLevelWindowActiveState(aFrame); |
michael@0 | 1484 | return NS_OK; |
michael@0 | 1485 | case NS_THEME_WINDOW_FRAME_LEFT: |
michael@0 | 1486 | aPart = mozilla::widget::themeconst::WP_FRAMELEFT; |
michael@0 | 1487 | aState = GetTopLevelWindowActiveState(aFrame); |
michael@0 | 1488 | return NS_OK; |
michael@0 | 1489 | case NS_THEME_WINDOW_FRAME_RIGHT: |
michael@0 | 1490 | aPart = mozilla::widget::themeconst::WP_FRAMERIGHT; |
michael@0 | 1491 | aState = GetTopLevelWindowActiveState(aFrame); |
michael@0 | 1492 | return NS_OK; |
michael@0 | 1493 | case NS_THEME_WINDOW_FRAME_BOTTOM: |
michael@0 | 1494 | aPart = mozilla::widget::themeconst::WP_FRAMEBOTTOM; |
michael@0 | 1495 | aState = GetTopLevelWindowActiveState(aFrame); |
michael@0 | 1496 | return NS_OK; |
michael@0 | 1497 | case NS_THEME_WINDOW_BUTTON_CLOSE: |
michael@0 | 1498 | aPart = mozilla::widget::themeconst::WP_CLOSEBUTTON; |
michael@0 | 1499 | aState = GetWindowFrameButtonState(aFrame, GetContentState(aFrame, aWidgetType)); |
michael@0 | 1500 | return NS_OK; |
michael@0 | 1501 | case NS_THEME_WINDOW_BUTTON_MINIMIZE: |
michael@0 | 1502 | aPart = mozilla::widget::themeconst::WP_MINBUTTON; |
michael@0 | 1503 | aState = GetWindowFrameButtonState(aFrame, GetContentState(aFrame, aWidgetType)); |
michael@0 | 1504 | return NS_OK; |
michael@0 | 1505 | case NS_THEME_WINDOW_BUTTON_MAXIMIZE: |
michael@0 | 1506 | aPart = mozilla::widget::themeconst::WP_MAXBUTTON; |
michael@0 | 1507 | aState = GetWindowFrameButtonState(aFrame, GetContentState(aFrame, aWidgetType)); |
michael@0 | 1508 | return NS_OK; |
michael@0 | 1509 | case NS_THEME_WINDOW_BUTTON_RESTORE: |
michael@0 | 1510 | aPart = mozilla::widget::themeconst::WP_RESTOREBUTTON; |
michael@0 | 1511 | aState = GetWindowFrameButtonState(aFrame, GetContentState(aFrame, aWidgetType)); |
michael@0 | 1512 | return NS_OK; |
michael@0 | 1513 | case NS_THEME_WINDOW_BUTTON_BOX: |
michael@0 | 1514 | case NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED: |
michael@0 | 1515 | case NS_THEME_WIN_GLASS: |
michael@0 | 1516 | case NS_THEME_WIN_BORDERLESS_GLASS: |
michael@0 | 1517 | aPart = -1; |
michael@0 | 1518 | aState = 0; |
michael@0 | 1519 | return NS_OK; |
michael@0 | 1520 | } |
michael@0 | 1521 | |
michael@0 | 1522 | aPart = 0; |
michael@0 | 1523 | aState = 0; |
michael@0 | 1524 | return NS_ERROR_FAILURE; |
michael@0 | 1525 | } |
michael@0 | 1526 | |
michael@0 | 1527 | static bool |
michael@0 | 1528 | AssumeThemePartAndStateAreTransparent(int32_t aPart, int32_t aState) |
michael@0 | 1529 | { |
michael@0 | 1530 | if (aPart == MENU_POPUPITEM && aState == MBI_NORMAL) { |
michael@0 | 1531 | return true; |
michael@0 | 1532 | } |
michael@0 | 1533 | return false; |
michael@0 | 1534 | } |
michael@0 | 1535 | |
michael@0 | 1536 | NS_IMETHODIMP |
michael@0 | 1537 | nsNativeThemeWin::DrawWidgetBackground(nsRenderingContext* aContext, |
michael@0 | 1538 | nsIFrame* aFrame, |
michael@0 | 1539 | uint8_t aWidgetType, |
michael@0 | 1540 | const nsRect& aRect, |
michael@0 | 1541 | const nsRect& aDirtyRect) |
michael@0 | 1542 | { |
michael@0 | 1543 | HANDLE theme = GetTheme(aWidgetType); |
michael@0 | 1544 | if (!theme) |
michael@0 | 1545 | return ClassicDrawWidgetBackground(aContext, aFrame, aWidgetType, aRect, aDirtyRect); |
michael@0 | 1546 | |
michael@0 | 1547 | // ^^ without the right sdk, assume xp theming and fall through. |
michael@0 | 1548 | if (nsUXThemeData::CheckForCompositor()) { |
michael@0 | 1549 | switch (aWidgetType) { |
michael@0 | 1550 | case NS_THEME_WINDOW_TITLEBAR: |
michael@0 | 1551 | case NS_THEME_WINDOW_TITLEBAR_MAXIMIZED: |
michael@0 | 1552 | case NS_THEME_WINDOW_FRAME_LEFT: |
michael@0 | 1553 | case NS_THEME_WINDOW_FRAME_RIGHT: |
michael@0 | 1554 | case NS_THEME_WINDOW_FRAME_BOTTOM: |
michael@0 | 1555 | // Nothing to draw, these areas are glass. Minimum dimensions |
michael@0 | 1556 | // should be set, so xul content should be layed out correctly. |
michael@0 | 1557 | return NS_OK; |
michael@0 | 1558 | break; |
michael@0 | 1559 | case NS_THEME_WINDOW_BUTTON_CLOSE: |
michael@0 | 1560 | case NS_THEME_WINDOW_BUTTON_MINIMIZE: |
michael@0 | 1561 | case NS_THEME_WINDOW_BUTTON_MAXIMIZE: |
michael@0 | 1562 | case NS_THEME_WINDOW_BUTTON_RESTORE: |
michael@0 | 1563 | // Not conventional bitmaps, can't be retrieved. If we fall |
michael@0 | 1564 | // through here and call the theme library we'll get aero |
michael@0 | 1565 | // basic bitmaps. |
michael@0 | 1566 | return NS_OK; |
michael@0 | 1567 | break; |
michael@0 | 1568 | case NS_THEME_WIN_GLASS: |
michael@0 | 1569 | case NS_THEME_WIN_BORDERLESS_GLASS: |
michael@0 | 1570 | // Nothing to draw, this is the glass background. |
michael@0 | 1571 | return NS_OK; |
michael@0 | 1572 | case NS_THEME_WINDOW_BUTTON_BOX: |
michael@0 | 1573 | case NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED: |
michael@0 | 1574 | // We handle these through nsIWidget::UpdateThemeGeometries |
michael@0 | 1575 | return NS_OK; |
michael@0 | 1576 | break; |
michael@0 | 1577 | } |
michael@0 | 1578 | } |
michael@0 | 1579 | |
michael@0 | 1580 | int32_t part, state; |
michael@0 | 1581 | nsresult rv = GetThemePartAndState(aFrame, aWidgetType, part, state); |
michael@0 | 1582 | if (NS_FAILED(rv)) |
michael@0 | 1583 | return rv; |
michael@0 | 1584 | |
michael@0 | 1585 | if (AssumeThemePartAndStateAreTransparent(part, state)) { |
michael@0 | 1586 | return NS_OK; |
michael@0 | 1587 | } |
michael@0 | 1588 | |
michael@0 | 1589 | gfxFloat p2a = gfxFloat(aContext->AppUnitsPerDevPixel()); |
michael@0 | 1590 | RECT widgetRect; |
michael@0 | 1591 | RECT clipRect; |
michael@0 | 1592 | gfxRect tr(aRect.x, aRect.y, aRect.width, aRect.height), |
michael@0 | 1593 | dr(aDirtyRect.x, aDirtyRect.y, aDirtyRect.width, aDirtyRect.height); |
michael@0 | 1594 | |
michael@0 | 1595 | tr.ScaleInverse(p2a); |
michael@0 | 1596 | dr.ScaleInverse(p2a); |
michael@0 | 1597 | |
michael@0 | 1598 | nsRefPtr<gfxContext> ctx = aContext->ThebesContext(); |
michael@0 | 1599 | |
michael@0 | 1600 | gfxWindowsNativeDrawing nativeDrawing(ctx, dr, GetWidgetNativeDrawingFlags(aWidgetType)); |
michael@0 | 1601 | |
michael@0 | 1602 | RENDER_AGAIN: |
michael@0 | 1603 | |
michael@0 | 1604 | HDC hdc = nativeDrawing.BeginNativeDrawing(); |
michael@0 | 1605 | if (!hdc) |
michael@0 | 1606 | return NS_ERROR_FAILURE; |
michael@0 | 1607 | |
michael@0 | 1608 | nativeDrawing.TransformToNativeRect(tr, widgetRect); |
michael@0 | 1609 | nativeDrawing.TransformToNativeRect(dr, clipRect); |
michael@0 | 1610 | |
michael@0 | 1611 | #if 0 |
michael@0 | 1612 | { |
michael@0 | 1613 | PR_LOG(gWindowsLog, PR_LOG_ERROR, |
michael@0 | 1614 | (stderr, "xform: %f %f %f %f [%f %f]\n", m.xx, m.yx, m.xy, m.yy, |
michael@0 | 1615 | m.x0, m.y0)); |
michael@0 | 1616 | PR_LOG(gWindowsLog, PR_LOG_ERROR, |
michael@0 | 1617 | (stderr, "tr: [%d %d %d %d]\ndr: [%d %d %d %d]\noff: [%f %f]\n", |
michael@0 | 1618 | tr.x, tr.y, tr.width, tr.height, dr.x, dr.y, dr.width, dr.height, |
michael@0 | 1619 | offset.x, offset.y)); |
michael@0 | 1620 | } |
michael@0 | 1621 | #endif |
michael@0 | 1622 | |
michael@0 | 1623 | if (aWidgetType == NS_THEME_WINDOW_TITLEBAR) { |
michael@0 | 1624 | // Clip out the left and right corners of the frame, all we want in |
michael@0 | 1625 | // is the middle section. |
michael@0 | 1626 | widgetRect.left -= GetSystemMetrics(SM_CXFRAME); |
michael@0 | 1627 | widgetRect.right += GetSystemMetrics(SM_CXFRAME); |
michael@0 | 1628 | } else if (aWidgetType == NS_THEME_WINDOW_TITLEBAR_MAXIMIZED) { |
michael@0 | 1629 | // The origin of the window is off screen when maximized and windows |
michael@0 | 1630 | // doesn't compensate for this in rendering the background. Push the |
michael@0 | 1631 | // top of the bitmap down by SM_CYFRAME so we get the full graphic. |
michael@0 | 1632 | widgetRect.top += GetSystemMetrics(SM_CYFRAME); |
michael@0 | 1633 | } else if (aWidgetType == NS_THEME_TAB) { |
michael@0 | 1634 | // For left edge and right edge tabs, we need to adjust the widget |
michael@0 | 1635 | // rects and clip rects so that the edges don't get drawn. |
michael@0 | 1636 | bool isLeft = IsLeftToSelectedTab(aFrame); |
michael@0 | 1637 | bool isRight = !isLeft && IsRightToSelectedTab(aFrame); |
michael@0 | 1638 | |
michael@0 | 1639 | if (isLeft || isRight) { |
michael@0 | 1640 | // HACK ALERT: There appears to be no way to really obtain this value, so we're forced |
michael@0 | 1641 | // to just use the default value for Luna (which also happens to be correct for |
michael@0 | 1642 | // all the other skins I've tried). |
michael@0 | 1643 | int32_t edgeSize = 2; |
michael@0 | 1644 | |
michael@0 | 1645 | // Armed with the size of the edge, we now need to either shift to the left or to the |
michael@0 | 1646 | // right. The clip rect won't include this extra area, so we know that we're |
michael@0 | 1647 | // effectively shifting the edge out of view (such that it won't be painted). |
michael@0 | 1648 | if (isLeft) |
michael@0 | 1649 | // The right edge should not be drawn. Extend our rect by the edge size. |
michael@0 | 1650 | widgetRect.right += edgeSize; |
michael@0 | 1651 | else |
michael@0 | 1652 | // The left edge should not be drawn. Move the widget rect's left coord back. |
michael@0 | 1653 | widgetRect.left -= edgeSize; |
michael@0 | 1654 | } |
michael@0 | 1655 | } |
michael@0 | 1656 | else if (aWidgetType == NS_THEME_WINDOW_BUTTON_MINIMIZE) { |
michael@0 | 1657 | OffsetBackgroundRect(widgetRect, CAPTIONBUTTON_MINIMIZE); |
michael@0 | 1658 | } |
michael@0 | 1659 | else if (aWidgetType == NS_THEME_WINDOW_BUTTON_MAXIMIZE || |
michael@0 | 1660 | aWidgetType == NS_THEME_WINDOW_BUTTON_RESTORE) { |
michael@0 | 1661 | OffsetBackgroundRect(widgetRect, CAPTIONBUTTON_RESTORE); |
michael@0 | 1662 | } |
michael@0 | 1663 | else if (aWidgetType == NS_THEME_WINDOW_BUTTON_CLOSE) { |
michael@0 | 1664 | OffsetBackgroundRect(widgetRect, CAPTIONBUTTON_CLOSE); |
michael@0 | 1665 | } |
michael@0 | 1666 | |
michael@0 | 1667 | // widgetRect is the bounding box for a widget, yet the scale track is only |
michael@0 | 1668 | // a small portion of this size, so the edges of the scale need to be |
michael@0 | 1669 | // adjusted to the real size of the track. |
michael@0 | 1670 | if (aWidgetType == NS_THEME_RANGE || |
michael@0 | 1671 | aWidgetType == NS_THEME_SCALE_HORIZONTAL || |
michael@0 | 1672 | aWidgetType == NS_THEME_SCALE_VERTICAL) { |
michael@0 | 1673 | RECT contentRect; |
michael@0 | 1674 | GetThemeBackgroundContentRect(theme, hdc, part, state, &widgetRect, &contentRect); |
michael@0 | 1675 | |
michael@0 | 1676 | SIZE siz; |
michael@0 | 1677 | GetThemePartSize(theme, hdc, part, state, &widgetRect, TS_TRUE, &siz); |
michael@0 | 1678 | |
michael@0 | 1679 | // When rounding is necessary, we round the position of the track |
michael@0 | 1680 | // away from the chevron of the thumb to make it look better. |
michael@0 | 1681 | if (aWidgetType == NS_THEME_SCALE_HORIZONTAL || |
michael@0 | 1682 | (aWidgetType == NS_THEME_RANGE && IsRangeHorizontal(aFrame))) { |
michael@0 | 1683 | contentRect.top += (contentRect.bottom - contentRect.top - siz.cy) / 2; |
michael@0 | 1684 | contentRect.bottom = contentRect.top + siz.cy; |
michael@0 | 1685 | } |
michael@0 | 1686 | else { |
michael@0 | 1687 | if (!IsFrameRTL(aFrame)) { |
michael@0 | 1688 | contentRect.left += (contentRect.right - contentRect.left - siz.cx) / 2; |
michael@0 | 1689 | contentRect.right = contentRect.left + siz.cx; |
michael@0 | 1690 | } else { |
michael@0 | 1691 | contentRect.right -= (contentRect.right - contentRect.left - siz.cx) / 2; |
michael@0 | 1692 | contentRect.left = contentRect.right - siz.cx; |
michael@0 | 1693 | } |
michael@0 | 1694 | } |
michael@0 | 1695 | |
michael@0 | 1696 | DrawThemeBackground(theme, hdc, part, state, &contentRect, &clipRect); |
michael@0 | 1697 | } |
michael@0 | 1698 | else if (aWidgetType == NS_THEME_MENUCHECKBOX || aWidgetType == NS_THEME_MENURADIO) |
michael@0 | 1699 | { |
michael@0 | 1700 | bool isChecked = false; |
michael@0 | 1701 | isChecked = CheckBooleanAttr(aFrame, nsGkAtoms::checked); |
michael@0 | 1702 | |
michael@0 | 1703 | if (isChecked) |
michael@0 | 1704 | { |
michael@0 | 1705 | int bgState = MCB_NORMAL; |
michael@0 | 1706 | EventStates eventState = GetContentState(aFrame, aWidgetType); |
michael@0 | 1707 | |
michael@0 | 1708 | // the disabled states are offset by 1 |
michael@0 | 1709 | if (IsDisabled(aFrame, eventState)) |
michael@0 | 1710 | bgState += 1; |
michael@0 | 1711 | |
michael@0 | 1712 | SIZE checkboxBGSize(GetCheckboxBGSize(theme, hdc)); |
michael@0 | 1713 | |
michael@0 | 1714 | RECT checkBGRect = widgetRect; |
michael@0 | 1715 | if (IsFrameRTL(aFrame)) { |
michael@0 | 1716 | checkBGRect.left = checkBGRect.right-checkboxBGSize.cx; |
michael@0 | 1717 | } else { |
michael@0 | 1718 | checkBGRect.right = checkBGRect.left+checkboxBGSize.cx; |
michael@0 | 1719 | } |
michael@0 | 1720 | |
michael@0 | 1721 | // Center the checkbox background vertically in the menuitem |
michael@0 | 1722 | checkBGRect.top += (checkBGRect.bottom - checkBGRect.top)/2 - checkboxBGSize.cy/2; |
michael@0 | 1723 | checkBGRect.bottom = checkBGRect.top + checkboxBGSize.cy; |
michael@0 | 1724 | |
michael@0 | 1725 | DrawThemeBackground(theme, hdc, MENU_POPUPCHECKBACKGROUND, bgState, &checkBGRect, &clipRect); |
michael@0 | 1726 | |
michael@0 | 1727 | MARGINS checkMargins = GetCheckboxMargins(theme, hdc); |
michael@0 | 1728 | RECT checkRect = checkBGRect; |
michael@0 | 1729 | checkRect.left += checkMargins.cxLeftWidth; |
michael@0 | 1730 | checkRect.right -= checkMargins.cxRightWidth; |
michael@0 | 1731 | checkRect.top += checkMargins.cyTopHeight; |
michael@0 | 1732 | checkRect.bottom -= checkMargins.cyBottomHeight; |
michael@0 | 1733 | DrawThemeBackground(theme, hdc, MENU_POPUPCHECK, state, &checkRect, &clipRect); |
michael@0 | 1734 | } |
michael@0 | 1735 | } |
michael@0 | 1736 | else if (aWidgetType == NS_THEME_MENUPOPUP) |
michael@0 | 1737 | { |
michael@0 | 1738 | DrawThemeBackground(theme, hdc, MENU_POPUPBORDERS, /* state */ 0, &widgetRect, &clipRect); |
michael@0 | 1739 | SIZE borderSize; |
michael@0 | 1740 | GetThemePartSize(theme, hdc, MENU_POPUPBORDERS, 0, nullptr, TS_TRUE, &borderSize); |
michael@0 | 1741 | |
michael@0 | 1742 | RECT bgRect = widgetRect; |
michael@0 | 1743 | bgRect.top += borderSize.cy; |
michael@0 | 1744 | bgRect.bottom -= borderSize.cy; |
michael@0 | 1745 | bgRect.left += borderSize.cx; |
michael@0 | 1746 | bgRect.right -= borderSize.cx; |
michael@0 | 1747 | |
michael@0 | 1748 | DrawThemeBackground(theme, hdc, MENU_POPUPBACKGROUND, /* state */ 0, &bgRect, &clipRect); |
michael@0 | 1749 | |
michael@0 | 1750 | SIZE gutterSize(GetGutterSize(theme, hdc)); |
michael@0 | 1751 | |
michael@0 | 1752 | RECT gutterRect; |
michael@0 | 1753 | gutterRect.top = bgRect.top; |
michael@0 | 1754 | gutterRect.bottom = bgRect.bottom; |
michael@0 | 1755 | if (IsFrameRTL(aFrame)) { |
michael@0 | 1756 | gutterRect.right = bgRect.right; |
michael@0 | 1757 | gutterRect.left = gutterRect.right-gutterSize.cx; |
michael@0 | 1758 | } else { |
michael@0 | 1759 | gutterRect.left = bgRect.left; |
michael@0 | 1760 | gutterRect.right = gutterRect.left+gutterSize.cx; |
michael@0 | 1761 | } |
michael@0 | 1762 | |
michael@0 | 1763 | DrawThemeBGRTLAware(theme, hdc, MENU_POPUPGUTTER, /* state */ 0, |
michael@0 | 1764 | &gutterRect, &clipRect, IsFrameRTL(aFrame)); |
michael@0 | 1765 | } |
michael@0 | 1766 | else if (aWidgetType == NS_THEME_MENUSEPARATOR) |
michael@0 | 1767 | { |
michael@0 | 1768 | SIZE gutterSize(GetGutterSize(theme,hdc)); |
michael@0 | 1769 | |
michael@0 | 1770 | RECT sepRect = widgetRect; |
michael@0 | 1771 | if (IsFrameRTL(aFrame)) |
michael@0 | 1772 | sepRect.right -= gutterSize.cx; |
michael@0 | 1773 | else |
michael@0 | 1774 | sepRect.left += gutterSize.cx; |
michael@0 | 1775 | |
michael@0 | 1776 | DrawThemeBackground(theme, hdc, MENU_POPUPSEPARATOR, /* state */ 0, &sepRect, &clipRect); |
michael@0 | 1777 | } |
michael@0 | 1778 | else if (aWidgetType == NS_THEME_MENUARROW) |
michael@0 | 1779 | { |
michael@0 | 1780 | // We're dpi aware and as such on systems that have dpi > 96 set, the |
michael@0 | 1781 | // theme library expects us to do proper positioning and scaling of glyphs. |
michael@0 | 1782 | // For NS_THEME_MENUARROW, layout may hand us a widget rect larger than the |
michael@0 | 1783 | // glyph rect we request in GetMinimumWidgetSize. To prevent distortion we |
michael@0 | 1784 | // have to position and scale what we draw. |
michael@0 | 1785 | |
michael@0 | 1786 | SIZE glyphSize; |
michael@0 | 1787 | GetThemePartSize(theme, hdc, part, state, nullptr, TS_TRUE, &glyphSize); |
michael@0 | 1788 | |
michael@0 | 1789 | int32_t widgetHeight = widgetRect.bottom - widgetRect.top; |
michael@0 | 1790 | |
michael@0 | 1791 | RECT renderRect = widgetRect; |
michael@0 | 1792 | |
michael@0 | 1793 | // We request (glyph width * 2, glyph height) in GetMinimumWidgetSize. In |
michael@0 | 1794 | // Firefox some menu items provide the full height of the item to us, in |
michael@0 | 1795 | // others our widget rect is the exact dims of our arrow glyph. Adjust the |
michael@0 | 1796 | // vertical position by the added space, if any exists. |
michael@0 | 1797 | renderRect.top += ((widgetHeight - glyphSize.cy) / 2); |
michael@0 | 1798 | renderRect.bottom = renderRect.top + glyphSize.cy; |
michael@0 | 1799 | // I'm using the width of the arrow glyph for the arrow-side padding. |
michael@0 | 1800 | // AFAICT there doesn't appear to be a theme constant we can query |
michael@0 | 1801 | // for this value. Generally this looks correct, and has the added |
michael@0 | 1802 | // benefit of being a dpi adjusted value. |
michael@0 | 1803 | if (!IsFrameRTL(aFrame)) { |
michael@0 | 1804 | renderRect.right = widgetRect.right - glyphSize.cx; |
michael@0 | 1805 | renderRect.left = renderRect.right - glyphSize.cx; |
michael@0 | 1806 | } else { |
michael@0 | 1807 | renderRect.left = glyphSize.cx; |
michael@0 | 1808 | renderRect.right = renderRect.left + glyphSize.cx; |
michael@0 | 1809 | } |
michael@0 | 1810 | DrawThemeBGRTLAware(theme, hdc, part, state, &renderRect, &clipRect, |
michael@0 | 1811 | IsFrameRTL(aFrame)); |
michael@0 | 1812 | } |
michael@0 | 1813 | // The following widgets need to be RTL-aware |
michael@0 | 1814 | else if (aWidgetType == NS_THEME_RESIZER || |
michael@0 | 1815 | aWidgetType == NS_THEME_DROPDOWN_BUTTON) |
michael@0 | 1816 | { |
michael@0 | 1817 | DrawThemeBGRTLAware(theme, hdc, part, state, |
michael@0 | 1818 | &widgetRect, &clipRect, IsFrameRTL(aFrame)); |
michael@0 | 1819 | } |
michael@0 | 1820 | else if (aWidgetType == NS_THEME_PROGRESSBAR || |
michael@0 | 1821 | aWidgetType == NS_THEME_PROGRESSBAR_VERTICAL) { |
michael@0 | 1822 | // DrawThemeBackground renders each corner with a solid white pixel. |
michael@0 | 1823 | // Restore these pixels to the underlying color. Tracks are rendered |
michael@0 | 1824 | // using alpha recovery, so this makes the corners transparent. |
michael@0 | 1825 | COLORREF color; |
michael@0 | 1826 | color = GetPixel(hdc, widgetRect.left, widgetRect.top); |
michael@0 | 1827 | DrawThemeBackground(theme, hdc, part, state, &widgetRect, &clipRect); |
michael@0 | 1828 | SetPixel(hdc, widgetRect.left, widgetRect.top, color); |
michael@0 | 1829 | SetPixel(hdc, widgetRect.right-1, widgetRect.top, color); |
michael@0 | 1830 | SetPixel(hdc, widgetRect.right-1, widgetRect.bottom-1, color); |
michael@0 | 1831 | SetPixel(hdc, widgetRect.left, widgetRect.bottom-1, color); |
michael@0 | 1832 | } |
michael@0 | 1833 | else if (aWidgetType == NS_THEME_PROGRESSBAR_CHUNK || |
michael@0 | 1834 | aWidgetType == NS_THEME_PROGRESSBAR_CHUNK_VERTICAL) { |
michael@0 | 1835 | DrawThemedProgressMeter(aFrame, aWidgetType, theme, hdc, part, state, |
michael@0 | 1836 | &widgetRect, &clipRect, p2a); |
michael@0 | 1837 | } |
michael@0 | 1838 | // If part is negative, the element wishes us to not render a themed |
michael@0 | 1839 | // background, instead opting to be drawn specially below. |
michael@0 | 1840 | else if (part >= 0) { |
michael@0 | 1841 | DrawThemeBackground(theme, hdc, part, state, &widgetRect, &clipRect); |
michael@0 | 1842 | } |
michael@0 | 1843 | |
michael@0 | 1844 | // Draw focus rectangles for XP HTML checkboxes and radio buttons |
michael@0 | 1845 | // XXX it'd be nice to draw these outside of the frame |
michael@0 | 1846 | if (((aWidgetType == NS_THEME_CHECKBOX || aWidgetType == NS_THEME_RADIO) && |
michael@0 | 1847 | aFrame->GetContent()->IsHTML()) || |
michael@0 | 1848 | aWidgetType == NS_THEME_RANGE || |
michael@0 | 1849 | aWidgetType == NS_THEME_SCALE_HORIZONTAL || |
michael@0 | 1850 | aWidgetType == NS_THEME_SCALE_VERTICAL) { |
michael@0 | 1851 | EventStates contentState = GetContentState(aFrame, aWidgetType); |
michael@0 | 1852 | |
michael@0 | 1853 | if (contentState.HasState(NS_EVENT_STATE_FOCUS)) { |
michael@0 | 1854 | POINT vpOrg; |
michael@0 | 1855 | HPEN hPen = nullptr; |
michael@0 | 1856 | |
michael@0 | 1857 | uint8_t id = SaveDC(hdc); |
michael@0 | 1858 | |
michael@0 | 1859 | ::SelectClipRgn(hdc, nullptr); |
michael@0 | 1860 | ::GetViewportOrgEx(hdc, &vpOrg); |
michael@0 | 1861 | ::SetBrushOrgEx(hdc, vpOrg.x + widgetRect.left, vpOrg.y + widgetRect.top, nullptr); |
michael@0 | 1862 | |
michael@0 | 1863 | // On vista, choose our own colors and draw an XP style half focus rect |
michael@0 | 1864 | // for focused checkboxes and a full rect when active. |
michael@0 | 1865 | if (IsVistaOrLater() && |
michael@0 | 1866 | aWidgetType == NS_THEME_CHECKBOX) { |
michael@0 | 1867 | LOGBRUSH lb; |
michael@0 | 1868 | lb.lbStyle = BS_SOLID; |
michael@0 | 1869 | lb.lbColor = RGB(255,255,255); |
michael@0 | 1870 | lb.lbHatch = 0; |
michael@0 | 1871 | |
michael@0 | 1872 | hPen = ::ExtCreatePen(PS_COSMETIC|PS_ALTERNATE, 1, &lb, 0, nullptr); |
michael@0 | 1873 | ::SelectObject(hdc, hPen); |
michael@0 | 1874 | |
michael@0 | 1875 | // If pressed, draw the upper left corner of the dotted rect. |
michael@0 | 1876 | if (contentState.HasState(NS_EVENT_STATE_ACTIVE)) { |
michael@0 | 1877 | ::MoveToEx(hdc, widgetRect.left, widgetRect.bottom-1, nullptr); |
michael@0 | 1878 | ::LineTo(hdc, widgetRect.left, widgetRect.top); |
michael@0 | 1879 | ::LineTo(hdc, widgetRect.right-1, widgetRect.top); |
michael@0 | 1880 | } |
michael@0 | 1881 | |
michael@0 | 1882 | // Draw the lower right corner of the dotted rect. |
michael@0 | 1883 | ::MoveToEx(hdc, widgetRect.right-1, widgetRect.top, nullptr); |
michael@0 | 1884 | ::LineTo(hdc, widgetRect.right-1, widgetRect.bottom-1); |
michael@0 | 1885 | ::LineTo(hdc, widgetRect.left, widgetRect.bottom-1); |
michael@0 | 1886 | } else { |
michael@0 | 1887 | ::SetTextColor(hdc, 0); |
michael@0 | 1888 | ::DrawFocusRect(hdc, &widgetRect); |
michael@0 | 1889 | } |
michael@0 | 1890 | ::RestoreDC(hdc, id); |
michael@0 | 1891 | if (hPen) { |
michael@0 | 1892 | ::DeleteObject(hPen); |
michael@0 | 1893 | } |
michael@0 | 1894 | } |
michael@0 | 1895 | } |
michael@0 | 1896 | else if (aWidgetType == NS_THEME_TOOLBAR && state == 0) { |
michael@0 | 1897 | // Draw toolbar separator lines above all toolbars except the first one. |
michael@0 | 1898 | // The lines are part of the Rebar theme, which is loaded for NS_THEME_TOOLBOX. |
michael@0 | 1899 | theme = GetTheme(NS_THEME_TOOLBOX); |
michael@0 | 1900 | if (!theme) |
michael@0 | 1901 | return NS_ERROR_FAILURE; |
michael@0 | 1902 | |
michael@0 | 1903 | widgetRect.bottom = widgetRect.top + TB_SEPARATOR_HEIGHT; |
michael@0 | 1904 | DrawThemeEdge(theme, hdc, RP_BAND, 0, &widgetRect, EDGE_ETCHED, BF_TOP, nullptr); |
michael@0 | 1905 | } |
michael@0 | 1906 | else if (aWidgetType == NS_THEME_SCROLLBAR_THUMB_HORIZONTAL || |
michael@0 | 1907 | aWidgetType == NS_THEME_SCROLLBAR_THUMB_VERTICAL) |
michael@0 | 1908 | { |
michael@0 | 1909 | // Draw the decorative gripper for the scrollbar thumb button, if it fits |
michael@0 | 1910 | |
michael@0 | 1911 | SIZE gripSize; |
michael@0 | 1912 | MARGINS thumbMgns; |
michael@0 | 1913 | int gripPart = (aWidgetType == NS_THEME_SCROLLBAR_THUMB_HORIZONTAL) ? |
michael@0 | 1914 | SP_GRIPPERHOR : SP_GRIPPERVERT; |
michael@0 | 1915 | |
michael@0 | 1916 | if (GetThemePartSize(theme, hdc, gripPart, state, nullptr, TS_TRUE, &gripSize) == S_OK && |
michael@0 | 1917 | GetThemeMargins(theme, hdc, part, state, TMT_CONTENTMARGINS, nullptr, &thumbMgns) == S_OK && |
michael@0 | 1918 | gripSize.cx + thumbMgns.cxLeftWidth + thumbMgns.cxRightWidth <= widgetRect.right - widgetRect.left && |
michael@0 | 1919 | gripSize.cy + thumbMgns.cyTopHeight + thumbMgns.cyBottomHeight <= widgetRect.bottom - widgetRect.top) |
michael@0 | 1920 | { |
michael@0 | 1921 | DrawThemeBackground(theme, hdc, gripPart, state, &widgetRect, &clipRect); |
michael@0 | 1922 | } |
michael@0 | 1923 | } |
michael@0 | 1924 | |
michael@0 | 1925 | nativeDrawing.EndNativeDrawing(); |
michael@0 | 1926 | |
michael@0 | 1927 | if (nativeDrawing.ShouldRenderAgain()) |
michael@0 | 1928 | goto RENDER_AGAIN; |
michael@0 | 1929 | |
michael@0 | 1930 | nativeDrawing.PaintToContext(); |
michael@0 | 1931 | |
michael@0 | 1932 | return NS_OK; |
michael@0 | 1933 | } |
michael@0 | 1934 | |
michael@0 | 1935 | NS_IMETHODIMP |
michael@0 | 1936 | nsNativeThemeWin::GetWidgetBorder(nsDeviceContext* aContext, |
michael@0 | 1937 | nsIFrame* aFrame, |
michael@0 | 1938 | uint8_t aWidgetType, |
michael@0 | 1939 | nsIntMargin* aResult) |
michael@0 | 1940 | { |
michael@0 | 1941 | HANDLE theme = GetTheme(aWidgetType); |
michael@0 | 1942 | if (!theme) |
michael@0 | 1943 | return ClassicGetWidgetBorder(aContext, aFrame, aWidgetType, aResult); |
michael@0 | 1944 | |
michael@0 | 1945 | (*aResult).top = (*aResult).bottom = (*aResult).left = (*aResult).right = 0; |
michael@0 | 1946 | |
michael@0 | 1947 | if (!WidgetIsContainer(aWidgetType) || |
michael@0 | 1948 | aWidgetType == NS_THEME_TOOLBOX || |
michael@0 | 1949 | aWidgetType == NS_THEME_WIN_MEDIA_TOOLBOX || |
michael@0 | 1950 | aWidgetType == NS_THEME_WIN_COMMUNICATIONS_TOOLBOX || |
michael@0 | 1951 | aWidgetType == NS_THEME_WIN_BROWSER_TAB_BAR_TOOLBOX || |
michael@0 | 1952 | aWidgetType == NS_THEME_STATUSBAR || |
michael@0 | 1953 | aWidgetType == NS_THEME_RESIZER || aWidgetType == NS_THEME_TAB_PANEL || |
michael@0 | 1954 | aWidgetType == NS_THEME_SCROLLBAR_TRACK_HORIZONTAL || |
michael@0 | 1955 | aWidgetType == NS_THEME_SCROLLBAR_TRACK_VERTICAL || |
michael@0 | 1956 | aWidgetType == NS_THEME_MENUITEM || aWidgetType == NS_THEME_CHECKMENUITEM || |
michael@0 | 1957 | aWidgetType == NS_THEME_RADIOMENUITEM || aWidgetType == NS_THEME_MENUPOPUP || |
michael@0 | 1958 | aWidgetType == NS_THEME_MENUIMAGE || aWidgetType == NS_THEME_MENUITEMTEXT || |
michael@0 | 1959 | aWidgetType == NS_THEME_TOOLBAR_SEPARATOR || |
michael@0 | 1960 | aWidgetType == NS_THEME_WINDOW_TITLEBAR || |
michael@0 | 1961 | aWidgetType == NS_THEME_WINDOW_TITLEBAR_MAXIMIZED || |
michael@0 | 1962 | aWidgetType == NS_THEME_WIN_GLASS || aWidgetType == NS_THEME_WIN_BORDERLESS_GLASS) |
michael@0 | 1963 | return NS_OK; // Don't worry about it. |
michael@0 | 1964 | |
michael@0 | 1965 | int32_t part, state; |
michael@0 | 1966 | nsresult rv = GetThemePartAndState(aFrame, aWidgetType, part, state); |
michael@0 | 1967 | if (NS_FAILED(rv)) |
michael@0 | 1968 | return rv; |
michael@0 | 1969 | |
michael@0 | 1970 | if (aWidgetType == NS_THEME_TOOLBAR) { |
michael@0 | 1971 | // make space for the separator line above all toolbars but the first |
michael@0 | 1972 | if (state == 0) |
michael@0 | 1973 | aResult->top = TB_SEPARATOR_HEIGHT; |
michael@0 | 1974 | return NS_OK; |
michael@0 | 1975 | } |
michael@0 | 1976 | |
michael@0 | 1977 | // Get our info. |
michael@0 | 1978 | RECT outerRect; // Create a fake outer rect. |
michael@0 | 1979 | outerRect.top = outerRect.left = 100; |
michael@0 | 1980 | outerRect.right = outerRect.bottom = 200; |
michael@0 | 1981 | RECT contentRect(outerRect); |
michael@0 | 1982 | HRESULT res = GetThemeBackgroundContentRect(theme, nullptr, part, state, &outerRect, &contentRect); |
michael@0 | 1983 | |
michael@0 | 1984 | if (FAILED(res)) |
michael@0 | 1985 | return NS_ERROR_FAILURE; |
michael@0 | 1986 | |
michael@0 | 1987 | // Now compute the delta in each direction and place it in our |
michael@0 | 1988 | // nsIntMargin struct. |
michael@0 | 1989 | aResult->top = contentRect.top - outerRect.top; |
michael@0 | 1990 | aResult->bottom = outerRect.bottom - contentRect.bottom; |
michael@0 | 1991 | aResult->left = contentRect.left - outerRect.left; |
michael@0 | 1992 | aResult->right = outerRect.right - contentRect.right; |
michael@0 | 1993 | |
michael@0 | 1994 | // Remove the edges for tabs that are before or after the selected tab, |
michael@0 | 1995 | if (aWidgetType == NS_THEME_TAB) { |
michael@0 | 1996 | if (IsLeftToSelectedTab(aFrame)) |
michael@0 | 1997 | // Remove the right edge, since we won't be drawing it. |
michael@0 | 1998 | aResult->right = 0; |
michael@0 | 1999 | else if (IsRightToSelectedTab(aFrame)) |
michael@0 | 2000 | // Remove the left edge, since we won't be drawing it. |
michael@0 | 2001 | aResult->left = 0; |
michael@0 | 2002 | } |
michael@0 | 2003 | |
michael@0 | 2004 | if (aFrame && (aWidgetType == NS_THEME_NUMBER_INPUT || |
michael@0 | 2005 | aWidgetType == NS_THEME_TEXTFIELD || |
michael@0 | 2006 | aWidgetType == NS_THEME_TEXTFIELD_MULTILINE)) { |
michael@0 | 2007 | nsIContent* content = aFrame->GetContent(); |
michael@0 | 2008 | if (content && content->IsHTML()) { |
michael@0 | 2009 | // We need to pad textfields by 1 pixel, since the caret will draw |
michael@0 | 2010 | // flush against the edge by default if we don't. |
michael@0 | 2011 | aResult->top++; |
michael@0 | 2012 | aResult->left++; |
michael@0 | 2013 | aResult->bottom++; |
michael@0 | 2014 | aResult->right++; |
michael@0 | 2015 | } |
michael@0 | 2016 | } |
michael@0 | 2017 | |
michael@0 | 2018 | return NS_OK; |
michael@0 | 2019 | } |
michael@0 | 2020 | |
michael@0 | 2021 | bool |
michael@0 | 2022 | nsNativeThemeWin::GetWidgetPadding(nsDeviceContext* aContext, |
michael@0 | 2023 | nsIFrame* aFrame, |
michael@0 | 2024 | uint8_t aWidgetType, |
michael@0 | 2025 | nsIntMargin* aResult) |
michael@0 | 2026 | { |
michael@0 | 2027 | switch (aWidgetType) { |
michael@0 | 2028 | // Radios and checkboxes return a fixed size in GetMinimumWidgetSize |
michael@0 | 2029 | // and have a meaningful baseline, so they can't have |
michael@0 | 2030 | // author-specified padding. |
michael@0 | 2031 | case NS_THEME_CHECKBOX: |
michael@0 | 2032 | case NS_THEME_RADIO: |
michael@0 | 2033 | aResult->SizeTo(0, 0, 0, 0); |
michael@0 | 2034 | return true; |
michael@0 | 2035 | } |
michael@0 | 2036 | |
michael@0 | 2037 | HANDLE theme = GetTheme(aWidgetType); |
michael@0 | 2038 | |
michael@0 | 2039 | if (aWidgetType == NS_THEME_WINDOW_BUTTON_BOX || |
michael@0 | 2040 | aWidgetType == NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED) { |
michael@0 | 2041 | aResult->SizeTo(0, 0, 0, 0); |
michael@0 | 2042 | |
michael@0 | 2043 | // aero glass doesn't display custom buttons |
michael@0 | 2044 | if (nsUXThemeData::CheckForCompositor()) |
michael@0 | 2045 | return true; |
michael@0 | 2046 | |
michael@0 | 2047 | // button padding for standard windows |
michael@0 | 2048 | if (aWidgetType == NS_THEME_WINDOW_BUTTON_BOX) { |
michael@0 | 2049 | aResult->top = GetSystemMetrics(SM_CXFRAME); |
michael@0 | 2050 | } |
michael@0 | 2051 | return true; |
michael@0 | 2052 | } |
michael@0 | 2053 | |
michael@0 | 2054 | // Content padding |
michael@0 | 2055 | if (aWidgetType == NS_THEME_WINDOW_TITLEBAR || |
michael@0 | 2056 | aWidgetType == NS_THEME_WINDOW_TITLEBAR_MAXIMIZED) { |
michael@0 | 2057 | aResult->SizeTo(0, 0, 0, 0); |
michael@0 | 2058 | // XXX Maximized windows have an offscreen offset equal to |
michael@0 | 2059 | // the border padding. This should be addressed in nsWindow, |
michael@0 | 2060 | // but currently can't be, see UpdateNonClientMargins. |
michael@0 | 2061 | if (aWidgetType == NS_THEME_WINDOW_TITLEBAR_MAXIMIZED) |
michael@0 | 2062 | aResult->top = GetSystemMetrics(SM_CXFRAME) |
michael@0 | 2063 | + GetSystemMetrics(SM_CXPADDEDBORDER); |
michael@0 | 2064 | return true; |
michael@0 | 2065 | } |
michael@0 | 2066 | |
michael@0 | 2067 | if (!theme) |
michael@0 | 2068 | return ClassicGetWidgetPadding(aContext, aFrame, aWidgetType, aResult); |
michael@0 | 2069 | |
michael@0 | 2070 | if (aWidgetType == NS_THEME_MENUPOPUP) |
michael@0 | 2071 | { |
michael@0 | 2072 | SIZE popupSize; |
michael@0 | 2073 | GetThemePartSize(theme, nullptr, MENU_POPUPBORDERS, /* state */ 0, nullptr, TS_TRUE, &popupSize); |
michael@0 | 2074 | aResult->top = aResult->bottom = popupSize.cy; |
michael@0 | 2075 | aResult->left = aResult->right = popupSize.cx; |
michael@0 | 2076 | return true; |
michael@0 | 2077 | } |
michael@0 | 2078 | |
michael@0 | 2079 | if (IsVistaOrLater()) { |
michael@0 | 2080 | if (aWidgetType == NS_THEME_NUMBER_INPUT || |
michael@0 | 2081 | aWidgetType == NS_THEME_TEXTFIELD || |
michael@0 | 2082 | aWidgetType == NS_THEME_TEXTFIELD_MULTILINE || |
michael@0 | 2083 | aWidgetType == NS_THEME_DROPDOWN) |
michael@0 | 2084 | { |
michael@0 | 2085 | /* If we have author-specified padding for these elements, don't do the fixups below */ |
michael@0 | 2086 | if (aFrame->PresContext()->HasAuthorSpecifiedRules(aFrame, NS_AUTHOR_SPECIFIED_PADDING)) |
michael@0 | 2087 | return false; |
michael@0 | 2088 | } |
michael@0 | 2089 | |
michael@0 | 2090 | /* textfields need extra pixels on all sides, otherwise they |
michael@0 | 2091 | * wrap their content too tightly. The actual border is drawn 1px |
michael@0 | 2092 | * inside the specified rectangle, so Gecko will end up making the |
michael@0 | 2093 | * contents look too small. Instead, we add 2px padding for the |
michael@0 | 2094 | * contents and fix this. (Used to be 1px added, see bug 430212) |
michael@0 | 2095 | */ |
michael@0 | 2096 | if (aWidgetType == NS_THEME_NUMBER_INPUT || |
michael@0 | 2097 | aWidgetType == NS_THEME_TEXTFIELD || |
michael@0 | 2098 | aWidgetType == NS_THEME_TEXTFIELD_MULTILINE) { |
michael@0 | 2099 | aResult->top = aResult->bottom = 2; |
michael@0 | 2100 | aResult->left = aResult->right = 2; |
michael@0 | 2101 | return true; |
michael@0 | 2102 | } else if (IsHTMLContent(aFrame) && aWidgetType == NS_THEME_DROPDOWN) { |
michael@0 | 2103 | /* For content menulist controls, we need an extra pixel so |
michael@0 | 2104 | * that we have room to draw our focus rectangle stuff. |
michael@0 | 2105 | * Otherwise, the focus rect might overlap the control's |
michael@0 | 2106 | * border. |
michael@0 | 2107 | */ |
michael@0 | 2108 | aResult->top = aResult->bottom = 1; |
michael@0 | 2109 | aResult->left = aResult->right = 1; |
michael@0 | 2110 | return true; |
michael@0 | 2111 | } |
michael@0 | 2112 | } |
michael@0 | 2113 | |
michael@0 | 2114 | int32_t right, left, top, bottom; |
michael@0 | 2115 | right = left = top = bottom = 0; |
michael@0 | 2116 | switch (aWidgetType) |
michael@0 | 2117 | { |
michael@0 | 2118 | case NS_THEME_MENUIMAGE: |
michael@0 | 2119 | right = 8; |
michael@0 | 2120 | left = 3; |
michael@0 | 2121 | break; |
michael@0 | 2122 | case NS_THEME_MENUCHECKBOX: |
michael@0 | 2123 | case NS_THEME_MENURADIO: |
michael@0 | 2124 | right = 8; |
michael@0 | 2125 | left = 0; |
michael@0 | 2126 | break; |
michael@0 | 2127 | case NS_THEME_MENUITEMTEXT: |
michael@0 | 2128 | // There seem to be exactly 4 pixels from the edge |
michael@0 | 2129 | // of the gutter to the text: 2px margin (CSS) + 2px padding (here) |
michael@0 | 2130 | { |
michael@0 | 2131 | SIZE size(GetGutterSize(theme, nullptr)); |
michael@0 | 2132 | left = size.cx + 2; |
michael@0 | 2133 | } |
michael@0 | 2134 | break; |
michael@0 | 2135 | case NS_THEME_MENUSEPARATOR: |
michael@0 | 2136 | { |
michael@0 | 2137 | SIZE size(GetGutterSize(theme, nullptr)); |
michael@0 | 2138 | left = size.cx + 5; |
michael@0 | 2139 | top = 10; |
michael@0 | 2140 | bottom = 7; |
michael@0 | 2141 | } |
michael@0 | 2142 | break; |
michael@0 | 2143 | default: |
michael@0 | 2144 | return false; |
michael@0 | 2145 | } |
michael@0 | 2146 | |
michael@0 | 2147 | if (IsFrameRTL(aFrame)) |
michael@0 | 2148 | { |
michael@0 | 2149 | aResult->right = left; |
michael@0 | 2150 | aResult->left = right; |
michael@0 | 2151 | } |
michael@0 | 2152 | else |
michael@0 | 2153 | { |
michael@0 | 2154 | aResult->right = right; |
michael@0 | 2155 | aResult->left = left; |
michael@0 | 2156 | } |
michael@0 | 2157 | |
michael@0 | 2158 | return true; |
michael@0 | 2159 | } |
michael@0 | 2160 | |
michael@0 | 2161 | bool |
michael@0 | 2162 | nsNativeThemeWin::GetWidgetOverflow(nsDeviceContext* aContext, |
michael@0 | 2163 | nsIFrame* aFrame, |
michael@0 | 2164 | uint8_t aOverflowRect, |
michael@0 | 2165 | nsRect* aResult) |
michael@0 | 2166 | { |
michael@0 | 2167 | /* This is disabled for now, because it causes invalidation problems -- |
michael@0 | 2168 | * see bug 420381. The effect of not updating the overflow area is that |
michael@0 | 2169 | * for dropdown buttons in content areas, there is a 1px border on 3 sides |
michael@0 | 2170 | * where, if invalidated, the dropdown control probably won't be repainted. |
michael@0 | 2171 | * This is fairly minor, as by default there is nothing in that area, and |
michael@0 | 2172 | * a border only shows up if the widget is being hovered. |
michael@0 | 2173 | */ |
michael@0 | 2174 | #if 0 |
michael@0 | 2175 | if (IsVistaOrLater()) { |
michael@0 | 2176 | /* We explicitly draw dropdown buttons in HTML content 1px bigger |
michael@0 | 2177 | * up, right, and bottom so that they overlap the dropdown's border |
michael@0 | 2178 | * like they're supposed to. |
michael@0 | 2179 | */ |
michael@0 | 2180 | if (aWidgetType == NS_THEME_DROPDOWN_BUTTON && |
michael@0 | 2181 | IsHTMLContent(aFrame) && |
michael@0 | 2182 | !IsWidgetStyled(aFrame->GetParent()->PresContext(), |
michael@0 | 2183 | aFrame->GetParent(), |
michael@0 | 2184 | NS_THEME_DROPDOWN)) |
michael@0 | 2185 | { |
michael@0 | 2186 | int32_t p2a = aContext->AppUnitsPerDevPixel(); |
michael@0 | 2187 | /* Note: no overflow on the left */ |
michael@0 | 2188 | nsMargin m(p2a, p2a, p2a, 0); |
michael@0 | 2189 | aOverflowRect->Inflate (m); |
michael@0 | 2190 | return true; |
michael@0 | 2191 | } |
michael@0 | 2192 | } |
michael@0 | 2193 | #endif |
michael@0 | 2194 | |
michael@0 | 2195 | return false; |
michael@0 | 2196 | } |
michael@0 | 2197 | |
michael@0 | 2198 | NS_IMETHODIMP |
michael@0 | 2199 | nsNativeThemeWin::GetMinimumWidgetSize(nsRenderingContext* aContext, nsIFrame* aFrame, |
michael@0 | 2200 | uint8_t aWidgetType, |
michael@0 | 2201 | nsIntSize* aResult, bool* aIsOverridable) |
michael@0 | 2202 | { |
michael@0 | 2203 | (*aResult).width = (*aResult).height = 0; |
michael@0 | 2204 | *aIsOverridable = true; |
michael@0 | 2205 | |
michael@0 | 2206 | HANDLE theme = GetTheme(aWidgetType); |
michael@0 | 2207 | if (!theme) |
michael@0 | 2208 | return ClassicGetMinimumWidgetSize(aContext, aFrame, aWidgetType, aResult, aIsOverridable); |
michael@0 | 2209 | |
michael@0 | 2210 | switch (aWidgetType) { |
michael@0 | 2211 | case NS_THEME_GROUPBOX: |
michael@0 | 2212 | case NS_THEME_NUMBER_INPUT: |
michael@0 | 2213 | case NS_THEME_TEXTFIELD: |
michael@0 | 2214 | case NS_THEME_TOOLBOX: |
michael@0 | 2215 | case NS_THEME_WIN_MEDIA_TOOLBOX: |
michael@0 | 2216 | case NS_THEME_WIN_COMMUNICATIONS_TOOLBOX: |
michael@0 | 2217 | case NS_THEME_WIN_BROWSER_TAB_BAR_TOOLBOX: |
michael@0 | 2218 | case NS_THEME_TOOLBAR: |
michael@0 | 2219 | case NS_THEME_STATUSBAR: |
michael@0 | 2220 | case NS_THEME_PROGRESSBAR_CHUNK: |
michael@0 | 2221 | case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL: |
michael@0 | 2222 | case NS_THEME_TAB_PANELS: |
michael@0 | 2223 | case NS_THEME_TAB_PANEL: |
michael@0 | 2224 | case NS_THEME_LISTBOX: |
michael@0 | 2225 | case NS_THEME_TREEVIEW: |
michael@0 | 2226 | case NS_THEME_MENUITEMTEXT: |
michael@0 | 2227 | case NS_THEME_WIN_GLASS: |
michael@0 | 2228 | case NS_THEME_WIN_BORDERLESS_GLASS: |
michael@0 | 2229 | return NS_OK; // Don't worry about it. |
michael@0 | 2230 | } |
michael@0 | 2231 | |
michael@0 | 2232 | if (aWidgetType == NS_THEME_MENUITEM && IsTopLevelMenu(aFrame)) |
michael@0 | 2233 | return NS_OK; // Don't worry about it for top level menus |
michael@0 | 2234 | |
michael@0 | 2235 | // Call GetSystemMetrics to determine size for WinXP scrollbars |
michael@0 | 2236 | // (GetThemeSysSize API returns the optimal size for the theme, but |
michael@0 | 2237 | // Windows appears to always use metrics when drawing standard scrollbars) |
michael@0 | 2238 | THEMESIZE sizeReq = TS_TRUE; // Best-fit size |
michael@0 | 2239 | switch (aWidgetType) { |
michael@0 | 2240 | case NS_THEME_SCROLLBAR_THUMB_VERTICAL: |
michael@0 | 2241 | case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL: |
michael@0 | 2242 | case NS_THEME_SCROLLBAR_BUTTON_UP: |
michael@0 | 2243 | case NS_THEME_SCROLLBAR_BUTTON_DOWN: |
michael@0 | 2244 | case NS_THEME_SCROLLBAR_BUTTON_LEFT: |
michael@0 | 2245 | case NS_THEME_SCROLLBAR_BUTTON_RIGHT: |
michael@0 | 2246 | case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL: |
michael@0 | 2247 | case NS_THEME_SCROLLBAR_TRACK_VERTICAL: |
michael@0 | 2248 | case NS_THEME_DROPDOWN_BUTTON: |
michael@0 | 2249 | return ClassicGetMinimumWidgetSize(aContext, aFrame, aWidgetType, aResult, aIsOverridable); |
michael@0 | 2250 | |
michael@0 | 2251 | case NS_THEME_MENUITEM: |
michael@0 | 2252 | case NS_THEME_CHECKMENUITEM: |
michael@0 | 2253 | case NS_THEME_RADIOMENUITEM: |
michael@0 | 2254 | if(!IsTopLevelMenu(aFrame)) |
michael@0 | 2255 | { |
michael@0 | 2256 | SIZE gutterSize(GetGutterSize(theme, nullptr)); |
michael@0 | 2257 | aResult->width = gutterSize.cx; |
michael@0 | 2258 | aResult->height = gutterSize.cy; |
michael@0 | 2259 | return NS_OK; |
michael@0 | 2260 | } |
michael@0 | 2261 | break; |
michael@0 | 2262 | |
michael@0 | 2263 | case NS_THEME_MENUIMAGE: |
michael@0 | 2264 | case NS_THEME_MENUCHECKBOX: |
michael@0 | 2265 | case NS_THEME_MENURADIO: |
michael@0 | 2266 | { |
michael@0 | 2267 | SIZE boxSize(GetGutterSize(theme, nullptr)); |
michael@0 | 2268 | aResult->width = boxSize.cx+2; |
michael@0 | 2269 | aResult->height = boxSize.cy; |
michael@0 | 2270 | *aIsOverridable = false; |
michael@0 | 2271 | } |
michael@0 | 2272 | |
michael@0 | 2273 | case NS_THEME_MENUITEMTEXT: |
michael@0 | 2274 | return NS_OK; |
michael@0 | 2275 | |
michael@0 | 2276 | case NS_THEME_PROGRESSBAR: |
michael@0 | 2277 | case NS_THEME_PROGRESSBAR_VERTICAL: |
michael@0 | 2278 | // Best-fit size for progress meters is too large for most |
michael@0 | 2279 | // themes. We want these widgets to be able to really shrink |
michael@0 | 2280 | // down, so use the min-size request value (of 0). |
michael@0 | 2281 | sizeReq = TS_MIN; |
michael@0 | 2282 | break; |
michael@0 | 2283 | |
michael@0 | 2284 | case NS_THEME_RESIZER: |
michael@0 | 2285 | *aIsOverridable = false; |
michael@0 | 2286 | break; |
michael@0 | 2287 | |
michael@0 | 2288 | case NS_THEME_RANGE_THUMB: |
michael@0 | 2289 | case NS_THEME_SCALE_THUMB_HORIZONTAL: |
michael@0 | 2290 | case NS_THEME_SCALE_THUMB_VERTICAL: |
michael@0 | 2291 | { |
michael@0 | 2292 | *aIsOverridable = false; |
michael@0 | 2293 | // on Vista, GetThemePartAndState returns odd values for |
michael@0 | 2294 | // scale thumbs, so use a hardcoded size instead. |
michael@0 | 2295 | if (IsVistaOrLater()) { |
michael@0 | 2296 | if (aWidgetType == NS_THEME_SCALE_THUMB_HORIZONTAL || |
michael@0 | 2297 | (aWidgetType == NS_THEME_RANGE_THUMB && IsRangeHorizontal(aFrame))) { |
michael@0 | 2298 | aResult->width = 12; |
michael@0 | 2299 | aResult->height = 20; |
michael@0 | 2300 | } |
michael@0 | 2301 | else { |
michael@0 | 2302 | aResult->width = 20; |
michael@0 | 2303 | aResult->height = 12; |
michael@0 | 2304 | } |
michael@0 | 2305 | return NS_OK; |
michael@0 | 2306 | } |
michael@0 | 2307 | break; |
michael@0 | 2308 | } |
michael@0 | 2309 | |
michael@0 | 2310 | case NS_THEME_SCROLLBAR: |
michael@0 | 2311 | { |
michael@0 | 2312 | if (nsLookAndFeel::GetInt( |
michael@0 | 2313 | nsLookAndFeel::eIntID_UseOverlayScrollbars) != 0) { |
michael@0 | 2314 | aResult->SizeTo(::GetSystemMetrics(SM_CXHSCROLL), |
michael@0 | 2315 | ::GetSystemMetrics(SM_CYVSCROLL)); |
michael@0 | 2316 | return NS_OK; |
michael@0 | 2317 | } |
michael@0 | 2318 | break; |
michael@0 | 2319 | } |
michael@0 | 2320 | |
michael@0 | 2321 | case NS_THEME_TOOLBAR_SEPARATOR: |
michael@0 | 2322 | // that's 2px left margin, 2px right margin and 2px separator |
michael@0 | 2323 | // (the margin is drawn as part of the separator, though) |
michael@0 | 2324 | aResult->width = 6; |
michael@0 | 2325 | return NS_OK; |
michael@0 | 2326 | |
michael@0 | 2327 | case NS_THEME_BUTTON: |
michael@0 | 2328 | // We should let HTML buttons shrink to their min size. |
michael@0 | 2329 | // FIXME bug 403934: We should probably really separate |
michael@0 | 2330 | // GetPreferredWidgetSize from GetMinimumWidgetSize, so callers can |
michael@0 | 2331 | // use the one they want. |
michael@0 | 2332 | if (aFrame->GetContent()->IsHTML()) { |
michael@0 | 2333 | sizeReq = TS_MIN; |
michael@0 | 2334 | } |
michael@0 | 2335 | break; |
michael@0 | 2336 | |
michael@0 | 2337 | case NS_THEME_WINDOW_BUTTON_MAXIMIZE: |
michael@0 | 2338 | case NS_THEME_WINDOW_BUTTON_RESTORE: |
michael@0 | 2339 | // The only way to get accurate titlebar button info is to query a |
michael@0 | 2340 | // window w/buttons when it's visible. nsWindow takes care of this and |
michael@0 | 2341 | // stores that info in nsUXThemeData. |
michael@0 | 2342 | aResult->width = nsUXThemeData::sCommandButtons[CMDBUTTONIDX_RESTORE].cx; |
michael@0 | 2343 | aResult->height = nsUXThemeData::sCommandButtons[CMDBUTTONIDX_RESTORE].cy; |
michael@0 | 2344 | // For XP, subtract 4 from system metrics dimensions. |
michael@0 | 2345 | if (!IsVistaOrLater()) { |
michael@0 | 2346 | aResult->width -= 4; |
michael@0 | 2347 | aResult->height -= 4; |
michael@0 | 2348 | } |
michael@0 | 2349 | AddPaddingRect(aResult, CAPTIONBUTTON_RESTORE); |
michael@0 | 2350 | *aIsOverridable = false; |
michael@0 | 2351 | return NS_OK; |
michael@0 | 2352 | |
michael@0 | 2353 | case NS_THEME_WINDOW_BUTTON_MINIMIZE: |
michael@0 | 2354 | aResult->width = nsUXThemeData::sCommandButtons[CMDBUTTONIDX_MINIMIZE].cx; |
michael@0 | 2355 | aResult->height = nsUXThemeData::sCommandButtons[CMDBUTTONIDX_MINIMIZE].cy; |
michael@0 | 2356 | if (!IsVistaOrLater()) { |
michael@0 | 2357 | aResult->width -= 4; |
michael@0 | 2358 | aResult->height -= 4; |
michael@0 | 2359 | } |
michael@0 | 2360 | AddPaddingRect(aResult, CAPTIONBUTTON_MINIMIZE); |
michael@0 | 2361 | *aIsOverridable = false; |
michael@0 | 2362 | return NS_OK; |
michael@0 | 2363 | |
michael@0 | 2364 | case NS_THEME_WINDOW_BUTTON_CLOSE: |
michael@0 | 2365 | aResult->width = nsUXThemeData::sCommandButtons[CMDBUTTONIDX_CLOSE].cx; |
michael@0 | 2366 | aResult->height = nsUXThemeData::sCommandButtons[CMDBUTTONIDX_CLOSE].cy; |
michael@0 | 2367 | if (!IsVistaOrLater()) { |
michael@0 | 2368 | aResult->width -= 4; |
michael@0 | 2369 | aResult->height -= 4; |
michael@0 | 2370 | } |
michael@0 | 2371 | AddPaddingRect(aResult, CAPTIONBUTTON_CLOSE); |
michael@0 | 2372 | *aIsOverridable = false; |
michael@0 | 2373 | return NS_OK; |
michael@0 | 2374 | |
michael@0 | 2375 | case NS_THEME_WINDOW_TITLEBAR: |
michael@0 | 2376 | case NS_THEME_WINDOW_TITLEBAR_MAXIMIZED: |
michael@0 | 2377 | aResult->height = GetSystemMetrics(SM_CYCAPTION); |
michael@0 | 2378 | aResult->height += GetSystemMetrics(SM_CYFRAME); |
michael@0 | 2379 | aResult->height += GetSystemMetrics(SM_CXPADDEDBORDER); |
michael@0 | 2380 | *aIsOverridable = false; |
michael@0 | 2381 | return NS_OK; |
michael@0 | 2382 | |
michael@0 | 2383 | case NS_THEME_WINDOW_BUTTON_BOX: |
michael@0 | 2384 | case NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED: |
michael@0 | 2385 | if (nsUXThemeData::CheckForCompositor()) { |
michael@0 | 2386 | aResult->width = nsUXThemeData::sCommandButtons[CMDBUTTONIDX_BUTTONBOX].cx; |
michael@0 | 2387 | aResult->height = nsUXThemeData::sCommandButtons[CMDBUTTONIDX_BUTTONBOX].cy |
michael@0 | 2388 | - GetSystemMetrics(SM_CYFRAME) |
michael@0 | 2389 | - GetSystemMetrics(SM_CXPADDEDBORDER); |
michael@0 | 2390 | if (aWidgetType == NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED) { |
michael@0 | 2391 | aResult->width += 1; |
michael@0 | 2392 | aResult->height -= 2; |
michael@0 | 2393 | } |
michael@0 | 2394 | *aIsOverridable = false; |
michael@0 | 2395 | return NS_OK; |
michael@0 | 2396 | } |
michael@0 | 2397 | break; |
michael@0 | 2398 | |
michael@0 | 2399 | case NS_THEME_WINDOW_FRAME_LEFT: |
michael@0 | 2400 | case NS_THEME_WINDOW_FRAME_RIGHT: |
michael@0 | 2401 | case NS_THEME_WINDOW_FRAME_BOTTOM: |
michael@0 | 2402 | aResult->width = GetSystemMetrics(SM_CXFRAME); |
michael@0 | 2403 | aResult->height = GetSystemMetrics(SM_CYFRAME); |
michael@0 | 2404 | *aIsOverridable = false; |
michael@0 | 2405 | return NS_OK; |
michael@0 | 2406 | } |
michael@0 | 2407 | |
michael@0 | 2408 | int32_t part, state; |
michael@0 | 2409 | nsresult rv = GetThemePartAndState(aFrame, aWidgetType, part, state); |
michael@0 | 2410 | if (NS_FAILED(rv)) |
michael@0 | 2411 | return rv; |
michael@0 | 2412 | |
michael@0 | 2413 | HDC hdc = ::GetDC(nullptr); |
michael@0 | 2414 | if (!hdc) |
michael@0 | 2415 | return NS_ERROR_FAILURE; |
michael@0 | 2416 | |
michael@0 | 2417 | SIZE sz; |
michael@0 | 2418 | GetThemePartSize(theme, hdc, part, state, nullptr, sizeReq, &sz); |
michael@0 | 2419 | aResult->width = sz.cx; |
michael@0 | 2420 | aResult->height = sz.cy; |
michael@0 | 2421 | |
michael@0 | 2422 | switch(aWidgetType) { |
michael@0 | 2423 | case NS_THEME_SPINNER_UP_BUTTON: |
michael@0 | 2424 | case NS_THEME_SPINNER_DOWN_BUTTON: |
michael@0 | 2425 | aResult->width++; |
michael@0 | 2426 | aResult->height = aResult->height / 2 + 1; |
michael@0 | 2427 | break; |
michael@0 | 2428 | |
michael@0 | 2429 | case NS_THEME_MENUSEPARATOR: |
michael@0 | 2430 | { |
michael@0 | 2431 | SIZE gutterSize(GetGutterSize(theme, hdc)); |
michael@0 | 2432 | aResult->width += gutterSize.cx; |
michael@0 | 2433 | break; |
michael@0 | 2434 | } |
michael@0 | 2435 | |
michael@0 | 2436 | case NS_THEME_MENUARROW: |
michael@0 | 2437 | { |
michael@0 | 2438 | // Use the width of the arrow glyph as padding. See the drawing |
michael@0 | 2439 | // code for details. |
michael@0 | 2440 | aResult->width *= 2; |
michael@0 | 2441 | break; |
michael@0 | 2442 | } |
michael@0 | 2443 | } |
michael@0 | 2444 | |
michael@0 | 2445 | ::ReleaseDC(nullptr, hdc); |
michael@0 | 2446 | return NS_OK; |
michael@0 | 2447 | } |
michael@0 | 2448 | |
michael@0 | 2449 | NS_IMETHODIMP |
michael@0 | 2450 | nsNativeThemeWin::WidgetStateChanged(nsIFrame* aFrame, uint8_t aWidgetType, |
michael@0 | 2451 | nsIAtom* aAttribute, bool* aShouldRepaint) |
michael@0 | 2452 | { |
michael@0 | 2453 | // Some widget types just never change state. |
michael@0 | 2454 | if (aWidgetType == NS_THEME_TOOLBOX || |
michael@0 | 2455 | aWidgetType == NS_THEME_WIN_MEDIA_TOOLBOX || |
michael@0 | 2456 | aWidgetType == NS_THEME_WIN_COMMUNICATIONS_TOOLBOX || |
michael@0 | 2457 | aWidgetType == NS_THEME_WIN_BROWSER_TAB_BAR_TOOLBOX || |
michael@0 | 2458 | aWidgetType == NS_THEME_TOOLBAR || |
michael@0 | 2459 | aWidgetType == NS_THEME_STATUSBAR || aWidgetType == NS_THEME_STATUSBAR_PANEL || |
michael@0 | 2460 | aWidgetType == NS_THEME_STATUSBAR_RESIZER_PANEL || |
michael@0 | 2461 | aWidgetType == NS_THEME_PROGRESSBAR_CHUNK || |
michael@0 | 2462 | aWidgetType == NS_THEME_PROGRESSBAR_CHUNK_VERTICAL || |
michael@0 | 2463 | aWidgetType == NS_THEME_PROGRESSBAR || |
michael@0 | 2464 | aWidgetType == NS_THEME_PROGRESSBAR_VERTICAL || |
michael@0 | 2465 | aWidgetType == NS_THEME_TOOLTIP || |
michael@0 | 2466 | aWidgetType == NS_THEME_TAB_PANELS || |
michael@0 | 2467 | aWidgetType == NS_THEME_TAB_PANEL || |
michael@0 | 2468 | aWidgetType == NS_THEME_TOOLBAR_SEPARATOR || |
michael@0 | 2469 | aWidgetType == NS_THEME_WIN_GLASS || |
michael@0 | 2470 | aWidgetType == NS_THEME_WIN_BORDERLESS_GLASS) { |
michael@0 | 2471 | *aShouldRepaint = false; |
michael@0 | 2472 | return NS_OK; |
michael@0 | 2473 | } |
michael@0 | 2474 | |
michael@0 | 2475 | if (aWidgetType == NS_THEME_WINDOW_TITLEBAR || |
michael@0 | 2476 | aWidgetType == NS_THEME_WINDOW_TITLEBAR_MAXIMIZED || |
michael@0 | 2477 | aWidgetType == NS_THEME_WINDOW_FRAME_LEFT || |
michael@0 | 2478 | aWidgetType == NS_THEME_WINDOW_FRAME_RIGHT || |
michael@0 | 2479 | aWidgetType == NS_THEME_WINDOW_FRAME_BOTTOM || |
michael@0 | 2480 | aWidgetType == NS_THEME_WINDOW_BUTTON_CLOSE || |
michael@0 | 2481 | aWidgetType == NS_THEME_WINDOW_BUTTON_MINIMIZE || |
michael@0 | 2482 | aWidgetType == NS_THEME_WINDOW_BUTTON_MINIMIZE || |
michael@0 | 2483 | aWidgetType == NS_THEME_WINDOW_BUTTON_RESTORE) { |
michael@0 | 2484 | *aShouldRepaint = true; |
michael@0 | 2485 | return NS_OK; |
michael@0 | 2486 | } |
michael@0 | 2487 | |
michael@0 | 2488 | // On Vista, the scrollbar buttons need to change state when the track has/doesn't have hover |
michael@0 | 2489 | if (!IsVistaOrLater() && |
michael@0 | 2490 | (aWidgetType == NS_THEME_SCROLLBAR_TRACK_VERTICAL || |
michael@0 | 2491 | aWidgetType == NS_THEME_SCROLLBAR_TRACK_HORIZONTAL)) { |
michael@0 | 2492 | *aShouldRepaint = false; |
michael@0 | 2493 | return NS_OK; |
michael@0 | 2494 | } |
michael@0 | 2495 | |
michael@0 | 2496 | // We need to repaint the dropdown arrow in vista HTML combobox controls when |
michael@0 | 2497 | // the control is closed to get rid of the hover effect. |
michael@0 | 2498 | if (IsVistaOrLater() && |
michael@0 | 2499 | (aWidgetType == NS_THEME_DROPDOWN || aWidgetType == NS_THEME_DROPDOWN_BUTTON) && |
michael@0 | 2500 | IsHTMLContent(aFrame)) |
michael@0 | 2501 | { |
michael@0 | 2502 | *aShouldRepaint = true; |
michael@0 | 2503 | return NS_OK; |
michael@0 | 2504 | } |
michael@0 | 2505 | |
michael@0 | 2506 | // XXXdwh Not sure what can really be done here. Can at least guess for |
michael@0 | 2507 | // specific widgets that they're highly unlikely to have certain states. |
michael@0 | 2508 | // For example, a toolbar doesn't care about any states. |
michael@0 | 2509 | if (!aAttribute) { |
michael@0 | 2510 | // Hover/focus/active changed. Always repaint. |
michael@0 | 2511 | *aShouldRepaint = true; |
michael@0 | 2512 | } |
michael@0 | 2513 | else { |
michael@0 | 2514 | // Check the attribute to see if it's relevant. |
michael@0 | 2515 | // disabled, checked, dlgtype, default, etc. |
michael@0 | 2516 | *aShouldRepaint = false; |
michael@0 | 2517 | if (aAttribute == nsGkAtoms::disabled || |
michael@0 | 2518 | aAttribute == nsGkAtoms::checked || |
michael@0 | 2519 | aAttribute == nsGkAtoms::selected || |
michael@0 | 2520 | aAttribute == nsGkAtoms::readonly || |
michael@0 | 2521 | aAttribute == nsGkAtoms::open || |
michael@0 | 2522 | aAttribute == nsGkAtoms::menuactive || |
michael@0 | 2523 | aAttribute == nsGkAtoms::focused) |
michael@0 | 2524 | *aShouldRepaint = true; |
michael@0 | 2525 | } |
michael@0 | 2526 | |
michael@0 | 2527 | return NS_OK; |
michael@0 | 2528 | } |
michael@0 | 2529 | |
michael@0 | 2530 | NS_IMETHODIMP |
michael@0 | 2531 | nsNativeThemeWin::ThemeChanged() |
michael@0 | 2532 | { |
michael@0 | 2533 | nsUXThemeData::Invalidate(); |
michael@0 | 2534 | return NS_OK; |
michael@0 | 2535 | } |
michael@0 | 2536 | |
michael@0 | 2537 | bool |
michael@0 | 2538 | nsNativeThemeWin::ThemeSupportsWidget(nsPresContext* aPresContext, |
michael@0 | 2539 | nsIFrame* aFrame, |
michael@0 | 2540 | uint8_t aWidgetType) |
michael@0 | 2541 | { |
michael@0 | 2542 | // XXXdwh We can go even further and call the API to ask if support exists for |
michael@0 | 2543 | // specific widgets. |
michael@0 | 2544 | |
michael@0 | 2545 | if (aPresContext && !aPresContext->PresShell()->IsThemeSupportEnabled()) |
michael@0 | 2546 | return false; |
michael@0 | 2547 | |
michael@0 | 2548 | HANDLE theme = nullptr; |
michael@0 | 2549 | if (aWidgetType == NS_THEME_CHECKBOX_CONTAINER) |
michael@0 | 2550 | theme = GetTheme(NS_THEME_CHECKBOX); |
michael@0 | 2551 | else if (aWidgetType == NS_THEME_RADIO_CONTAINER) |
michael@0 | 2552 | theme = GetTheme(NS_THEME_RADIO); |
michael@0 | 2553 | else |
michael@0 | 2554 | theme = GetTheme(aWidgetType); |
michael@0 | 2555 | |
michael@0 | 2556 | if ((theme) || (!theme && ClassicThemeSupportsWidget(aPresContext, aFrame, aWidgetType))) |
michael@0 | 2557 | // turn off theming for some HTML widgets styled by the page |
michael@0 | 2558 | return (!IsWidgetStyled(aPresContext, aFrame, aWidgetType)); |
michael@0 | 2559 | |
michael@0 | 2560 | return false; |
michael@0 | 2561 | } |
michael@0 | 2562 | |
michael@0 | 2563 | bool |
michael@0 | 2564 | nsNativeThemeWin::WidgetIsContainer(uint8_t aWidgetType) |
michael@0 | 2565 | { |
michael@0 | 2566 | // XXXdwh At some point flesh all of this out. |
michael@0 | 2567 | if (aWidgetType == NS_THEME_DROPDOWN_BUTTON || |
michael@0 | 2568 | aWidgetType == NS_THEME_RADIO || |
michael@0 | 2569 | aWidgetType == NS_THEME_CHECKBOX) |
michael@0 | 2570 | return false; |
michael@0 | 2571 | return true; |
michael@0 | 2572 | } |
michael@0 | 2573 | |
michael@0 | 2574 | bool |
michael@0 | 2575 | nsNativeThemeWin::ThemeDrawsFocusForWidget(uint8_t aWidgetType) |
michael@0 | 2576 | { |
michael@0 | 2577 | return false; |
michael@0 | 2578 | } |
michael@0 | 2579 | |
michael@0 | 2580 | bool |
michael@0 | 2581 | nsNativeThemeWin::ThemeNeedsComboboxDropmarker() |
michael@0 | 2582 | { |
michael@0 | 2583 | return true; |
michael@0 | 2584 | } |
michael@0 | 2585 | |
michael@0 | 2586 | bool |
michael@0 | 2587 | nsNativeThemeWin::WidgetAppearanceDependsOnWindowFocus(uint8_t aWidgetType) |
michael@0 | 2588 | { |
michael@0 | 2589 | switch (aWidgetType) { |
michael@0 | 2590 | case NS_THEME_WINDOW_TITLEBAR: |
michael@0 | 2591 | case NS_THEME_WINDOW_TITLEBAR_MAXIMIZED: |
michael@0 | 2592 | case NS_THEME_WINDOW_FRAME_LEFT: |
michael@0 | 2593 | case NS_THEME_WINDOW_FRAME_RIGHT: |
michael@0 | 2594 | case NS_THEME_WINDOW_FRAME_BOTTOM: |
michael@0 | 2595 | case NS_THEME_WINDOW_BUTTON_CLOSE: |
michael@0 | 2596 | case NS_THEME_WINDOW_BUTTON_MINIMIZE: |
michael@0 | 2597 | case NS_THEME_WINDOW_BUTTON_MAXIMIZE: |
michael@0 | 2598 | case NS_THEME_WINDOW_BUTTON_RESTORE: |
michael@0 | 2599 | return true; |
michael@0 | 2600 | default: |
michael@0 | 2601 | return false; |
michael@0 | 2602 | } |
michael@0 | 2603 | } |
michael@0 | 2604 | |
michael@0 | 2605 | bool |
michael@0 | 2606 | nsNativeThemeWin::ShouldHideScrollbars() |
michael@0 | 2607 | { |
michael@0 | 2608 | return WinUtils::ShouldHideScrollbars(); |
michael@0 | 2609 | } |
michael@0 | 2610 | |
michael@0 | 2611 | nsITheme::Transparency |
michael@0 | 2612 | nsNativeThemeWin::GetWidgetTransparency(nsIFrame* aFrame, uint8_t aWidgetType) |
michael@0 | 2613 | { |
michael@0 | 2614 | switch (aWidgetType) { |
michael@0 | 2615 | case NS_THEME_SCROLLBAR_SMALL: |
michael@0 | 2616 | case NS_THEME_SCROLLBAR: |
michael@0 | 2617 | case NS_THEME_STATUSBAR: |
michael@0 | 2618 | // Knowing that scrollbars and statusbars are opaque improves |
michael@0 | 2619 | // performance, because we create layers for them. This better be |
michael@0 | 2620 | // true across all Windows themes! If it's not true, we should |
michael@0 | 2621 | // paint an opaque background for them to make it true! |
michael@0 | 2622 | return eOpaque; |
michael@0 | 2623 | case NS_THEME_WIN_GLASS: |
michael@0 | 2624 | case NS_THEME_WIN_BORDERLESS_GLASS: |
michael@0 | 2625 | case NS_THEME_SCALE_HORIZONTAL: |
michael@0 | 2626 | case NS_THEME_SCALE_VERTICAL: |
michael@0 | 2627 | case NS_THEME_PROGRESSBAR: |
michael@0 | 2628 | case NS_THEME_PROGRESSBAR_VERTICAL: |
michael@0 | 2629 | case NS_THEME_PROGRESSBAR_CHUNK: |
michael@0 | 2630 | case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL: |
michael@0 | 2631 | case NS_THEME_RANGE: |
michael@0 | 2632 | return eTransparent; |
michael@0 | 2633 | } |
michael@0 | 2634 | |
michael@0 | 2635 | HANDLE theme = GetTheme(aWidgetType); |
michael@0 | 2636 | // For the classic theme we don't really have a way of knowing |
michael@0 | 2637 | if (!theme) { |
michael@0 | 2638 | // menu backgrounds and tooltips which can't be themed are opaque |
michael@0 | 2639 | if (aWidgetType == NS_THEME_MENUPOPUP || aWidgetType == NS_THEME_TOOLTIP) { |
michael@0 | 2640 | return eOpaque; |
michael@0 | 2641 | } |
michael@0 | 2642 | return eUnknownTransparency; |
michael@0 | 2643 | } |
michael@0 | 2644 | |
michael@0 | 2645 | int32_t part, state; |
michael@0 | 2646 | nsresult rv = GetThemePartAndState(aFrame, aWidgetType, part, state); |
michael@0 | 2647 | // Fail conservatively |
michael@0 | 2648 | NS_ENSURE_SUCCESS(rv, eUnknownTransparency); |
michael@0 | 2649 | |
michael@0 | 2650 | if (part <= 0) { |
michael@0 | 2651 | // Not a real part code, so IsThemeBackgroundPartiallyTransparent may |
michael@0 | 2652 | // not work, so don't call it. |
michael@0 | 2653 | return eUnknownTransparency; |
michael@0 | 2654 | } |
michael@0 | 2655 | |
michael@0 | 2656 | if (IsThemeBackgroundPartiallyTransparent(theme, part, state)) |
michael@0 | 2657 | return eTransparent; |
michael@0 | 2658 | return eOpaque; |
michael@0 | 2659 | } |
michael@0 | 2660 | |
michael@0 | 2661 | /* Windows 9x/NT/2000/Classic XP Theme Support */ |
michael@0 | 2662 | |
michael@0 | 2663 | bool |
michael@0 | 2664 | nsNativeThemeWin::ClassicThemeSupportsWidget(nsPresContext* aPresContext, |
michael@0 | 2665 | nsIFrame* aFrame, |
michael@0 | 2666 | uint8_t aWidgetType) |
michael@0 | 2667 | { |
michael@0 | 2668 | switch (aWidgetType) { |
michael@0 | 2669 | case NS_THEME_RESIZER: |
michael@0 | 2670 | { |
michael@0 | 2671 | // The classic native resizer has an opaque grey background which doesn't |
michael@0 | 2672 | // match the usually white background of the scrollable container, so |
michael@0 | 2673 | // only support the native resizer if not in a scrollframe. |
michael@0 | 2674 | nsIFrame* parentFrame = aFrame->GetParent(); |
michael@0 | 2675 | return (!parentFrame || parentFrame->GetType() != nsGkAtoms::scrollFrame); |
michael@0 | 2676 | } |
michael@0 | 2677 | case NS_THEME_MENUBAR: |
michael@0 | 2678 | case NS_THEME_MENUPOPUP: |
michael@0 | 2679 | // Classic non-flat menus are handled almost entirely through CSS. |
michael@0 | 2680 | if (!nsUXThemeData::sFlatMenus) |
michael@0 | 2681 | return false; |
michael@0 | 2682 | case NS_THEME_BUTTON: |
michael@0 | 2683 | case NS_THEME_NUMBER_INPUT: |
michael@0 | 2684 | case NS_THEME_TEXTFIELD: |
michael@0 | 2685 | case NS_THEME_TEXTFIELD_MULTILINE: |
michael@0 | 2686 | case NS_THEME_CHECKBOX: |
michael@0 | 2687 | case NS_THEME_RADIO: |
michael@0 | 2688 | case NS_THEME_RANGE: |
michael@0 | 2689 | case NS_THEME_RANGE_THUMB: |
michael@0 | 2690 | case NS_THEME_GROUPBOX: |
michael@0 | 2691 | case NS_THEME_SCROLLBAR_BUTTON_UP: |
michael@0 | 2692 | case NS_THEME_SCROLLBAR_BUTTON_DOWN: |
michael@0 | 2693 | case NS_THEME_SCROLLBAR_BUTTON_LEFT: |
michael@0 | 2694 | case NS_THEME_SCROLLBAR_BUTTON_RIGHT: |
michael@0 | 2695 | case NS_THEME_SCROLLBAR_THUMB_VERTICAL: |
michael@0 | 2696 | case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL: |
michael@0 | 2697 | case NS_THEME_SCROLLBAR_TRACK_VERTICAL: |
michael@0 | 2698 | case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL: |
michael@0 | 2699 | case NS_THEME_SCROLLBAR_NON_DISAPPEARING: |
michael@0 | 2700 | case NS_THEME_SCALE_HORIZONTAL: |
michael@0 | 2701 | case NS_THEME_SCALE_VERTICAL: |
michael@0 | 2702 | case NS_THEME_SCALE_THUMB_HORIZONTAL: |
michael@0 | 2703 | case NS_THEME_SCALE_THUMB_VERTICAL: |
michael@0 | 2704 | case NS_THEME_DROPDOWN_BUTTON: |
michael@0 | 2705 | case NS_THEME_SPINNER_UP_BUTTON: |
michael@0 | 2706 | case NS_THEME_SPINNER_DOWN_BUTTON: |
michael@0 | 2707 | case NS_THEME_LISTBOX: |
michael@0 | 2708 | case NS_THEME_TREEVIEW: |
michael@0 | 2709 | case NS_THEME_DROPDOWN_TEXTFIELD: |
michael@0 | 2710 | case NS_THEME_DROPDOWN: |
michael@0 | 2711 | case NS_THEME_TOOLTIP: |
michael@0 | 2712 | case NS_THEME_STATUSBAR: |
michael@0 | 2713 | case NS_THEME_STATUSBAR_PANEL: |
michael@0 | 2714 | case NS_THEME_STATUSBAR_RESIZER_PANEL: |
michael@0 | 2715 | case NS_THEME_PROGRESSBAR: |
michael@0 | 2716 | case NS_THEME_PROGRESSBAR_VERTICAL: |
michael@0 | 2717 | case NS_THEME_PROGRESSBAR_CHUNK: |
michael@0 | 2718 | case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL: |
michael@0 | 2719 | case NS_THEME_TAB: |
michael@0 | 2720 | case NS_THEME_TAB_PANEL: |
michael@0 | 2721 | case NS_THEME_TAB_PANELS: |
michael@0 | 2722 | case NS_THEME_MENUITEM: |
michael@0 | 2723 | case NS_THEME_CHECKMENUITEM: |
michael@0 | 2724 | case NS_THEME_RADIOMENUITEM: |
michael@0 | 2725 | case NS_THEME_MENUCHECKBOX: |
michael@0 | 2726 | case NS_THEME_MENURADIO: |
michael@0 | 2727 | case NS_THEME_MENUARROW: |
michael@0 | 2728 | case NS_THEME_MENUSEPARATOR: |
michael@0 | 2729 | case NS_THEME_MENUITEMTEXT: |
michael@0 | 2730 | case NS_THEME_WINDOW_TITLEBAR: |
michael@0 | 2731 | case NS_THEME_WINDOW_TITLEBAR_MAXIMIZED: |
michael@0 | 2732 | case NS_THEME_WINDOW_FRAME_LEFT: |
michael@0 | 2733 | case NS_THEME_WINDOW_FRAME_RIGHT: |
michael@0 | 2734 | case NS_THEME_WINDOW_FRAME_BOTTOM: |
michael@0 | 2735 | case NS_THEME_WINDOW_BUTTON_CLOSE: |
michael@0 | 2736 | case NS_THEME_WINDOW_BUTTON_MINIMIZE: |
michael@0 | 2737 | case NS_THEME_WINDOW_BUTTON_MAXIMIZE: |
michael@0 | 2738 | case NS_THEME_WINDOW_BUTTON_RESTORE: |
michael@0 | 2739 | case NS_THEME_WINDOW_BUTTON_BOX: |
michael@0 | 2740 | case NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED: |
michael@0 | 2741 | return true; |
michael@0 | 2742 | } |
michael@0 | 2743 | return false; |
michael@0 | 2744 | } |
michael@0 | 2745 | |
michael@0 | 2746 | nsresult |
michael@0 | 2747 | nsNativeThemeWin::ClassicGetWidgetBorder(nsDeviceContext* aContext, |
michael@0 | 2748 | nsIFrame* aFrame, |
michael@0 | 2749 | uint8_t aWidgetType, |
michael@0 | 2750 | nsIntMargin* aResult) |
michael@0 | 2751 | { |
michael@0 | 2752 | switch (aWidgetType) { |
michael@0 | 2753 | case NS_THEME_GROUPBOX: |
michael@0 | 2754 | case NS_THEME_BUTTON: |
michael@0 | 2755 | (*aResult).top = (*aResult).left = (*aResult).bottom = (*aResult).right = 2; |
michael@0 | 2756 | break; |
michael@0 | 2757 | case NS_THEME_STATUSBAR: |
michael@0 | 2758 | (*aResult).bottom = (*aResult).left = (*aResult).right = 0; |
michael@0 | 2759 | (*aResult).top = 2; |
michael@0 | 2760 | break; |
michael@0 | 2761 | case NS_THEME_LISTBOX: |
michael@0 | 2762 | case NS_THEME_TREEVIEW: |
michael@0 | 2763 | case NS_THEME_DROPDOWN: |
michael@0 | 2764 | case NS_THEME_DROPDOWN_TEXTFIELD: |
michael@0 | 2765 | case NS_THEME_TAB: |
michael@0 | 2766 | case NS_THEME_NUMBER_INPUT: |
michael@0 | 2767 | case NS_THEME_TEXTFIELD: |
michael@0 | 2768 | case NS_THEME_TEXTFIELD_MULTILINE: |
michael@0 | 2769 | (*aResult).top = (*aResult).left = (*aResult).bottom = (*aResult).right = 2; |
michael@0 | 2770 | break; |
michael@0 | 2771 | case NS_THEME_STATUSBAR_PANEL: |
michael@0 | 2772 | case NS_THEME_STATUSBAR_RESIZER_PANEL: { |
michael@0 | 2773 | (*aResult).top = 1; |
michael@0 | 2774 | (*aResult).left = 1; |
michael@0 | 2775 | (*aResult).bottom = 1; |
michael@0 | 2776 | (*aResult).right = aFrame->GetNextSibling() ? 3 : 1; |
michael@0 | 2777 | break; |
michael@0 | 2778 | } |
michael@0 | 2779 | case NS_THEME_TOOLTIP: |
michael@0 | 2780 | (*aResult).top = (*aResult).left = (*aResult).bottom = (*aResult).right = 1; |
michael@0 | 2781 | break; |
michael@0 | 2782 | case NS_THEME_PROGRESSBAR: |
michael@0 | 2783 | case NS_THEME_PROGRESSBAR_VERTICAL: |
michael@0 | 2784 | (*aResult).top = (*aResult).left = (*aResult).bottom = (*aResult).right = 1; |
michael@0 | 2785 | break; |
michael@0 | 2786 | case NS_THEME_MENUBAR: |
michael@0 | 2787 | (*aResult).top = (*aResult).left = (*aResult).bottom = (*aResult).right = 0; |
michael@0 | 2788 | break; |
michael@0 | 2789 | case NS_THEME_MENUPOPUP: |
michael@0 | 2790 | (*aResult).top = (*aResult).left = (*aResult).bottom = (*aResult).right = 3; |
michael@0 | 2791 | break; |
michael@0 | 2792 | default: |
michael@0 | 2793 | (*aResult).top = (*aResult).bottom = (*aResult).left = (*aResult).right = 0; |
michael@0 | 2794 | break; |
michael@0 | 2795 | } |
michael@0 | 2796 | return NS_OK; |
michael@0 | 2797 | } |
michael@0 | 2798 | |
michael@0 | 2799 | bool |
michael@0 | 2800 | nsNativeThemeWin::ClassicGetWidgetPadding(nsDeviceContext* aContext, |
michael@0 | 2801 | nsIFrame* aFrame, |
michael@0 | 2802 | uint8_t aWidgetType, |
michael@0 | 2803 | nsIntMargin* aResult) |
michael@0 | 2804 | { |
michael@0 | 2805 | switch (aWidgetType) { |
michael@0 | 2806 | case NS_THEME_MENUITEM: |
michael@0 | 2807 | case NS_THEME_CHECKMENUITEM: |
michael@0 | 2808 | case NS_THEME_RADIOMENUITEM: { |
michael@0 | 2809 | int32_t part, state; |
michael@0 | 2810 | bool focused; |
michael@0 | 2811 | |
michael@0 | 2812 | if (NS_FAILED(ClassicGetThemePartAndState(aFrame, aWidgetType, part, state, focused))) |
michael@0 | 2813 | return false; |
michael@0 | 2814 | |
michael@0 | 2815 | if (part == 1) { // top-level menu |
michael@0 | 2816 | if (nsUXThemeData::sFlatMenus || !(state & DFCS_PUSHED)) { |
michael@0 | 2817 | (*aResult).top = (*aResult).bottom = (*aResult).left = (*aResult).right = 2; |
michael@0 | 2818 | } |
michael@0 | 2819 | else { |
michael@0 | 2820 | // make top-level menus look sunken when pushed in the Classic look |
michael@0 | 2821 | (*aResult).top = (*aResult).left = 3; |
michael@0 | 2822 | (*aResult).bottom = (*aResult).right = 1; |
michael@0 | 2823 | } |
michael@0 | 2824 | } |
michael@0 | 2825 | else { |
michael@0 | 2826 | (*aResult).top = 0; |
michael@0 | 2827 | (*aResult).bottom = (*aResult).left = (*aResult).right = 2; |
michael@0 | 2828 | } |
michael@0 | 2829 | return true; |
michael@0 | 2830 | } |
michael@0 | 2831 | case NS_THEME_PROGRESSBAR: |
michael@0 | 2832 | case NS_THEME_PROGRESSBAR_VERTICAL: |
michael@0 | 2833 | (*aResult).top = (*aResult).left = (*aResult).bottom = (*aResult).right = 1; |
michael@0 | 2834 | return true; |
michael@0 | 2835 | default: |
michael@0 | 2836 | return false; |
michael@0 | 2837 | } |
michael@0 | 2838 | } |
michael@0 | 2839 | |
michael@0 | 2840 | nsresult |
michael@0 | 2841 | nsNativeThemeWin::ClassicGetMinimumWidgetSize(nsRenderingContext* aContext, nsIFrame* aFrame, |
michael@0 | 2842 | uint8_t aWidgetType, |
michael@0 | 2843 | nsIntSize* aResult, bool* aIsOverridable) |
michael@0 | 2844 | { |
michael@0 | 2845 | (*aResult).width = (*aResult).height = 0; |
michael@0 | 2846 | *aIsOverridable = true; |
michael@0 | 2847 | switch (aWidgetType) { |
michael@0 | 2848 | case NS_THEME_RADIO: |
michael@0 | 2849 | case NS_THEME_CHECKBOX: |
michael@0 | 2850 | (*aResult).width = (*aResult).height = 13; |
michael@0 | 2851 | break; |
michael@0 | 2852 | case NS_THEME_MENUCHECKBOX: |
michael@0 | 2853 | case NS_THEME_MENURADIO: |
michael@0 | 2854 | case NS_THEME_MENUARROW: |
michael@0 | 2855 | (*aResult).width = ::GetSystemMetrics(SM_CXMENUCHECK); |
michael@0 | 2856 | (*aResult).height = ::GetSystemMetrics(SM_CYMENUCHECK); |
michael@0 | 2857 | break; |
michael@0 | 2858 | case NS_THEME_SPINNER_UP_BUTTON: |
michael@0 | 2859 | case NS_THEME_SPINNER_DOWN_BUTTON: |
michael@0 | 2860 | (*aResult).width = ::GetSystemMetrics(SM_CXVSCROLL); |
michael@0 | 2861 | (*aResult).height = 8; // No good metrics available for this |
michael@0 | 2862 | *aIsOverridable = false; |
michael@0 | 2863 | break; |
michael@0 | 2864 | case NS_THEME_SCROLLBAR_BUTTON_UP: |
michael@0 | 2865 | case NS_THEME_SCROLLBAR_BUTTON_DOWN: |
michael@0 | 2866 | (*aResult).width = ::GetSystemMetrics(SM_CXVSCROLL); |
michael@0 | 2867 | (*aResult).height = ::GetSystemMetrics(SM_CYVSCROLL); |
michael@0 | 2868 | *aIsOverridable = false; |
michael@0 | 2869 | break; |
michael@0 | 2870 | case NS_THEME_SCROLLBAR_BUTTON_LEFT: |
michael@0 | 2871 | case NS_THEME_SCROLLBAR_BUTTON_RIGHT: |
michael@0 | 2872 | (*aResult).width = ::GetSystemMetrics(SM_CXHSCROLL); |
michael@0 | 2873 | (*aResult).height = ::GetSystemMetrics(SM_CYHSCROLL); |
michael@0 | 2874 | *aIsOverridable = false; |
michael@0 | 2875 | break; |
michael@0 | 2876 | case NS_THEME_SCROLLBAR_TRACK_VERTICAL: |
michael@0 | 2877 | // XXX HACK We should be able to have a minimum height for the scrollbar |
michael@0 | 2878 | // track. However, this causes problems when uncollapsing a scrollbar |
michael@0 | 2879 | // inside a tree. See bug 201379 for details. |
michael@0 | 2880 | |
michael@0 | 2881 | // (*aResult).height = ::GetSystemMetrics(SM_CYVTHUMB) << 1; |
michael@0 | 2882 | break; |
michael@0 | 2883 | case NS_THEME_SCROLLBAR_NON_DISAPPEARING: |
michael@0 | 2884 | { |
michael@0 | 2885 | aResult->SizeTo(::GetSystemMetrics(SM_CXHSCROLL), |
michael@0 | 2886 | ::GetSystemMetrics(SM_CYVSCROLL)); |
michael@0 | 2887 | break; |
michael@0 | 2888 | } |
michael@0 | 2889 | case NS_THEME_RANGE_THUMB: { |
michael@0 | 2890 | if (IsRangeHorizontal(aFrame)) { |
michael@0 | 2891 | (*aResult).width = 12; |
michael@0 | 2892 | (*aResult).height = 20; |
michael@0 | 2893 | } else { |
michael@0 | 2894 | (*aResult).width = 20; |
michael@0 | 2895 | (*aResult).height = 12; |
michael@0 | 2896 | } |
michael@0 | 2897 | *aIsOverridable = false; |
michael@0 | 2898 | break; |
michael@0 | 2899 | } |
michael@0 | 2900 | case NS_THEME_SCALE_THUMB_HORIZONTAL: |
michael@0 | 2901 | (*aResult).width = 12; |
michael@0 | 2902 | (*aResult).height = 20; |
michael@0 | 2903 | *aIsOverridable = false; |
michael@0 | 2904 | break; |
michael@0 | 2905 | case NS_THEME_SCALE_THUMB_VERTICAL: |
michael@0 | 2906 | (*aResult).width = 20; |
michael@0 | 2907 | (*aResult).height = 12; |
michael@0 | 2908 | *aIsOverridable = false; |
michael@0 | 2909 | break; |
michael@0 | 2910 | case NS_THEME_DROPDOWN_BUTTON: |
michael@0 | 2911 | (*aResult).width = ::GetSystemMetrics(SM_CXVSCROLL); |
michael@0 | 2912 | break; |
michael@0 | 2913 | case NS_THEME_DROPDOWN: |
michael@0 | 2914 | case NS_THEME_BUTTON: |
michael@0 | 2915 | case NS_THEME_GROUPBOX: |
michael@0 | 2916 | case NS_THEME_LISTBOX: |
michael@0 | 2917 | case NS_THEME_TREEVIEW: |
michael@0 | 2918 | case NS_THEME_NUMBER_INPUT: |
michael@0 | 2919 | case NS_THEME_TEXTFIELD: |
michael@0 | 2920 | case NS_THEME_TEXTFIELD_MULTILINE: |
michael@0 | 2921 | case NS_THEME_DROPDOWN_TEXTFIELD: |
michael@0 | 2922 | case NS_THEME_STATUSBAR: |
michael@0 | 2923 | case NS_THEME_STATUSBAR_PANEL: |
michael@0 | 2924 | case NS_THEME_STATUSBAR_RESIZER_PANEL: |
michael@0 | 2925 | case NS_THEME_PROGRESSBAR_CHUNK: |
michael@0 | 2926 | case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL: |
michael@0 | 2927 | case NS_THEME_TOOLTIP: |
michael@0 | 2928 | case NS_THEME_PROGRESSBAR: |
michael@0 | 2929 | case NS_THEME_PROGRESSBAR_VERTICAL: |
michael@0 | 2930 | case NS_THEME_TAB: |
michael@0 | 2931 | case NS_THEME_TAB_PANEL: |
michael@0 | 2932 | case NS_THEME_TAB_PANELS: |
michael@0 | 2933 | // no minimum widget size |
michael@0 | 2934 | break; |
michael@0 | 2935 | case NS_THEME_RESIZER: { |
michael@0 | 2936 | NONCLIENTMETRICS nc; |
michael@0 | 2937 | nc.cbSize = sizeof(nc); |
michael@0 | 2938 | if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(nc), &nc, 0)) |
michael@0 | 2939 | (*aResult).width = (*aResult).height = abs(nc.lfStatusFont.lfHeight) + 4; |
michael@0 | 2940 | else |
michael@0 | 2941 | (*aResult).width = (*aResult).height = 15; |
michael@0 | 2942 | *aIsOverridable = false; |
michael@0 | 2943 | break; |
michael@0 | 2944 | case NS_THEME_SCROLLBAR_THUMB_VERTICAL: |
michael@0 | 2945 | (*aResult).width = ::GetSystemMetrics(SM_CXVSCROLL); |
michael@0 | 2946 | (*aResult).height = ::GetSystemMetrics(SM_CYVTHUMB); |
michael@0 | 2947 | // Without theming, divide the thumb size by two in order to look more |
michael@0 | 2948 | // native |
michael@0 | 2949 | if (!GetTheme(aWidgetType)) |
michael@0 | 2950 | (*aResult).height >>= 1; |
michael@0 | 2951 | *aIsOverridable = false; |
michael@0 | 2952 | break; |
michael@0 | 2953 | case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL: |
michael@0 | 2954 | (*aResult).width = ::GetSystemMetrics(SM_CXHTHUMB); |
michael@0 | 2955 | (*aResult).height = ::GetSystemMetrics(SM_CYHSCROLL); |
michael@0 | 2956 | // Without theming, divide the thumb size by two in order to look more |
michael@0 | 2957 | // native |
michael@0 | 2958 | if (!GetTheme(aWidgetType)) |
michael@0 | 2959 | (*aResult).width >>= 1; |
michael@0 | 2960 | *aIsOverridable = false; |
michael@0 | 2961 | break; |
michael@0 | 2962 | case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL: |
michael@0 | 2963 | (*aResult).width = ::GetSystemMetrics(SM_CXHTHUMB) << 1; |
michael@0 | 2964 | break; |
michael@0 | 2965 | } |
michael@0 | 2966 | case NS_THEME_MENUSEPARATOR: |
michael@0 | 2967 | { |
michael@0 | 2968 | aResult->width = 0; |
michael@0 | 2969 | aResult->height = 10; |
michael@0 | 2970 | break; |
michael@0 | 2971 | } |
michael@0 | 2972 | |
michael@0 | 2973 | case NS_THEME_WINDOW_TITLEBAR_MAXIMIZED: |
michael@0 | 2974 | case NS_THEME_WINDOW_TITLEBAR: |
michael@0 | 2975 | aResult->height = GetSystemMetrics(SM_CYCAPTION); |
michael@0 | 2976 | aResult->height += GetSystemMetrics(SM_CYFRAME); |
michael@0 | 2977 | aResult->width = 0; |
michael@0 | 2978 | break; |
michael@0 | 2979 | case NS_THEME_WINDOW_FRAME_LEFT: |
michael@0 | 2980 | case NS_THEME_WINDOW_FRAME_RIGHT: |
michael@0 | 2981 | aResult->width = GetSystemMetrics(SM_CXFRAME); |
michael@0 | 2982 | aResult->height = 0; |
michael@0 | 2983 | break; |
michael@0 | 2984 | |
michael@0 | 2985 | case NS_THEME_WINDOW_FRAME_BOTTOM: |
michael@0 | 2986 | aResult->height = GetSystemMetrics(SM_CYFRAME); |
michael@0 | 2987 | aResult->width = 0; |
michael@0 | 2988 | break; |
michael@0 | 2989 | |
michael@0 | 2990 | case NS_THEME_WINDOW_BUTTON_CLOSE: |
michael@0 | 2991 | case NS_THEME_WINDOW_BUTTON_MINIMIZE: |
michael@0 | 2992 | case NS_THEME_WINDOW_BUTTON_MAXIMIZE: |
michael@0 | 2993 | case NS_THEME_WINDOW_BUTTON_RESTORE: |
michael@0 | 2994 | aResult->width = GetSystemMetrics(SM_CXSIZE); |
michael@0 | 2995 | aResult->height = GetSystemMetrics(SM_CYSIZE); |
michael@0 | 2996 | // XXX I have no idea why these caption metrics are always off, |
michael@0 | 2997 | // but they are. |
michael@0 | 2998 | aResult->width -= 2; |
michael@0 | 2999 | aResult->height -= 4; |
michael@0 | 3000 | if (aWidgetType == NS_THEME_WINDOW_BUTTON_MINIMIZE) { |
michael@0 | 3001 | AddPaddingRect(aResult, CAPTIONBUTTON_MINIMIZE); |
michael@0 | 3002 | } |
michael@0 | 3003 | else if (aWidgetType == NS_THEME_WINDOW_BUTTON_MAXIMIZE || |
michael@0 | 3004 | aWidgetType == NS_THEME_WINDOW_BUTTON_RESTORE) { |
michael@0 | 3005 | AddPaddingRect(aResult, CAPTIONBUTTON_RESTORE); |
michael@0 | 3006 | } |
michael@0 | 3007 | else if (aWidgetType == NS_THEME_WINDOW_BUTTON_CLOSE) { |
michael@0 | 3008 | AddPaddingRect(aResult, CAPTIONBUTTON_CLOSE); |
michael@0 | 3009 | } |
michael@0 | 3010 | break; |
michael@0 | 3011 | |
michael@0 | 3012 | default: |
michael@0 | 3013 | return NS_ERROR_FAILURE; |
michael@0 | 3014 | } |
michael@0 | 3015 | return NS_OK; |
michael@0 | 3016 | } |
michael@0 | 3017 | |
michael@0 | 3018 | |
michael@0 | 3019 | nsresult nsNativeThemeWin::ClassicGetThemePartAndState(nsIFrame* aFrame, uint8_t aWidgetType, |
michael@0 | 3020 | int32_t& aPart, int32_t& aState, bool& aFocused) |
michael@0 | 3021 | { |
michael@0 | 3022 | aFocused = false; |
michael@0 | 3023 | switch (aWidgetType) { |
michael@0 | 3024 | case NS_THEME_BUTTON: { |
michael@0 | 3025 | EventStates contentState; |
michael@0 | 3026 | |
michael@0 | 3027 | aPart = DFC_BUTTON; |
michael@0 | 3028 | aState = DFCS_BUTTONPUSH; |
michael@0 | 3029 | aFocused = false; |
michael@0 | 3030 | |
michael@0 | 3031 | contentState = GetContentState(aFrame, aWidgetType); |
michael@0 | 3032 | if (IsDisabled(aFrame, contentState)) |
michael@0 | 3033 | aState |= DFCS_INACTIVE; |
michael@0 | 3034 | else if (IsOpenButton(aFrame)) |
michael@0 | 3035 | aState |= DFCS_PUSHED; |
michael@0 | 3036 | else if (IsCheckedButton(aFrame)) |
michael@0 | 3037 | aState |= DFCS_CHECKED; |
michael@0 | 3038 | else { |
michael@0 | 3039 | if (contentState.HasAllStates(NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_HOVER)) { |
michael@0 | 3040 | aState |= DFCS_PUSHED; |
michael@0 | 3041 | const nsStyleUserInterface *uiData = aFrame->StyleUserInterface(); |
michael@0 | 3042 | // The down state is flat if the button is focusable |
michael@0 | 3043 | if (uiData->mUserFocus == NS_STYLE_USER_FOCUS_NORMAL) { |
michael@0 | 3044 | if (!aFrame->GetContent()->IsHTML()) |
michael@0 | 3045 | aState |= DFCS_FLAT; |
michael@0 | 3046 | |
michael@0 | 3047 | aFocused = true; |
michael@0 | 3048 | } |
michael@0 | 3049 | } |
michael@0 | 3050 | if (contentState.HasState(NS_EVENT_STATE_FOCUS) || |
michael@0 | 3051 | (aState == DFCS_BUTTONPUSH && IsDefaultButton(aFrame))) { |
michael@0 | 3052 | aFocused = true; |
michael@0 | 3053 | } |
michael@0 | 3054 | |
michael@0 | 3055 | } |
michael@0 | 3056 | |
michael@0 | 3057 | return NS_OK; |
michael@0 | 3058 | } |
michael@0 | 3059 | case NS_THEME_CHECKBOX: |
michael@0 | 3060 | case NS_THEME_RADIO: { |
michael@0 | 3061 | EventStates contentState; |
michael@0 | 3062 | aFocused = false; |
michael@0 | 3063 | |
michael@0 | 3064 | aPart = DFC_BUTTON; |
michael@0 | 3065 | aState = 0; |
michael@0 | 3066 | nsIContent* content = aFrame->GetContent(); |
michael@0 | 3067 | bool isCheckbox = (aWidgetType == NS_THEME_CHECKBOX); |
michael@0 | 3068 | bool isChecked = GetCheckedOrSelected(aFrame, !isCheckbox); |
michael@0 | 3069 | bool isIndeterminate = isCheckbox && GetIndeterminate(aFrame); |
michael@0 | 3070 | |
michael@0 | 3071 | if (isCheckbox) { |
michael@0 | 3072 | // indeterminate state takes precedence over checkedness. |
michael@0 | 3073 | if (isIndeterminate) { |
michael@0 | 3074 | aState = DFCS_BUTTON3STATE | DFCS_CHECKED; |
michael@0 | 3075 | } else { |
michael@0 | 3076 | aState = DFCS_BUTTONCHECK; |
michael@0 | 3077 | } |
michael@0 | 3078 | } else { |
michael@0 | 3079 | aState = DFCS_BUTTONRADIO; |
michael@0 | 3080 | } |
michael@0 | 3081 | if (isChecked) { |
michael@0 | 3082 | aState |= DFCS_CHECKED; |
michael@0 | 3083 | } |
michael@0 | 3084 | |
michael@0 | 3085 | contentState = GetContentState(aFrame, aWidgetType); |
michael@0 | 3086 | if (!content->IsXUL() && |
michael@0 | 3087 | contentState.HasState(NS_EVENT_STATE_FOCUS)) { |
michael@0 | 3088 | aFocused = true; |
michael@0 | 3089 | } |
michael@0 | 3090 | |
michael@0 | 3091 | if (IsDisabled(aFrame, contentState)) { |
michael@0 | 3092 | aState |= DFCS_INACTIVE; |
michael@0 | 3093 | } else if (contentState.HasAllStates(NS_EVENT_STATE_ACTIVE | |
michael@0 | 3094 | NS_EVENT_STATE_HOVER)) { |
michael@0 | 3095 | aState |= DFCS_PUSHED; |
michael@0 | 3096 | } |
michael@0 | 3097 | |
michael@0 | 3098 | return NS_OK; |
michael@0 | 3099 | } |
michael@0 | 3100 | case NS_THEME_MENUITEM: |
michael@0 | 3101 | case NS_THEME_CHECKMENUITEM: |
michael@0 | 3102 | case NS_THEME_RADIOMENUITEM: { |
michael@0 | 3103 | bool isTopLevel = false; |
michael@0 | 3104 | bool isOpen = false; |
michael@0 | 3105 | bool isContainer = false; |
michael@0 | 3106 | nsMenuFrame *menuFrame = do_QueryFrame(aFrame); |
michael@0 | 3107 | EventStates eventState = GetContentState(aFrame, aWidgetType); |
michael@0 | 3108 | |
michael@0 | 3109 | // We indicate top-level-ness using aPart. 0 is a normal menu item, |
michael@0 | 3110 | // 1 is a top-level menu item. The state of the item is composed of |
michael@0 | 3111 | // DFCS_* flags only. |
michael@0 | 3112 | aPart = 0; |
michael@0 | 3113 | aState = 0; |
michael@0 | 3114 | |
michael@0 | 3115 | if (menuFrame) { |
michael@0 | 3116 | // If this is a real menu item, we should check if it is part of the |
michael@0 | 3117 | // main menu bar or not, and if it is a container, as these affect |
michael@0 | 3118 | // rendering. |
michael@0 | 3119 | isTopLevel = menuFrame->IsOnMenuBar(); |
michael@0 | 3120 | isOpen = menuFrame->IsOpen(); |
michael@0 | 3121 | isContainer = menuFrame->IsMenu(); |
michael@0 | 3122 | } |
michael@0 | 3123 | |
michael@0 | 3124 | if (IsDisabled(aFrame, eventState)) |
michael@0 | 3125 | aState |= DFCS_INACTIVE; |
michael@0 | 3126 | |
michael@0 | 3127 | if (isTopLevel) { |
michael@0 | 3128 | aPart = 1; |
michael@0 | 3129 | if (isOpen) |
michael@0 | 3130 | aState |= DFCS_PUSHED; |
michael@0 | 3131 | } |
michael@0 | 3132 | |
michael@0 | 3133 | if (IsMenuActive(aFrame, aWidgetType)) |
michael@0 | 3134 | aState |= DFCS_HOT; |
michael@0 | 3135 | |
michael@0 | 3136 | return NS_OK; |
michael@0 | 3137 | } |
michael@0 | 3138 | case NS_THEME_MENUCHECKBOX: |
michael@0 | 3139 | case NS_THEME_MENURADIO: |
michael@0 | 3140 | case NS_THEME_MENUARROW: { |
michael@0 | 3141 | aState = 0; |
michael@0 | 3142 | EventStates eventState = GetContentState(aFrame, aWidgetType); |
michael@0 | 3143 | |
michael@0 | 3144 | if (IsDisabled(aFrame, eventState)) |
michael@0 | 3145 | aState |= DFCS_INACTIVE; |
michael@0 | 3146 | if (IsMenuActive(aFrame, aWidgetType)) |
michael@0 | 3147 | aState |= DFCS_HOT; |
michael@0 | 3148 | |
michael@0 | 3149 | if (aWidgetType == NS_THEME_MENUCHECKBOX || aWidgetType == NS_THEME_MENURADIO) { |
michael@0 | 3150 | if (IsCheckedButton(aFrame)) |
michael@0 | 3151 | aState |= DFCS_CHECKED; |
michael@0 | 3152 | } else if (IsFrameRTL(aFrame)) { |
michael@0 | 3153 | aState |= DFCS_RTL; |
michael@0 | 3154 | } |
michael@0 | 3155 | return NS_OK; |
michael@0 | 3156 | } |
michael@0 | 3157 | case NS_THEME_LISTBOX: |
michael@0 | 3158 | case NS_THEME_TREEVIEW: |
michael@0 | 3159 | case NS_THEME_NUMBER_INPUT: |
michael@0 | 3160 | case NS_THEME_TEXTFIELD: |
michael@0 | 3161 | case NS_THEME_TEXTFIELD_MULTILINE: |
michael@0 | 3162 | case NS_THEME_DROPDOWN: |
michael@0 | 3163 | case NS_THEME_DROPDOWN_TEXTFIELD: |
michael@0 | 3164 | case NS_THEME_RANGE: |
michael@0 | 3165 | case NS_THEME_RANGE_THUMB: |
michael@0 | 3166 | case NS_THEME_SCROLLBAR_THUMB_VERTICAL: |
michael@0 | 3167 | case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL: |
michael@0 | 3168 | case NS_THEME_SCROLLBAR_TRACK_VERTICAL: |
michael@0 | 3169 | case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL: |
michael@0 | 3170 | case NS_THEME_SCALE_HORIZONTAL: |
michael@0 | 3171 | case NS_THEME_SCALE_VERTICAL: |
michael@0 | 3172 | case NS_THEME_SCALE_THUMB_HORIZONTAL: |
michael@0 | 3173 | case NS_THEME_SCALE_THUMB_VERTICAL: |
michael@0 | 3174 | case NS_THEME_STATUSBAR: |
michael@0 | 3175 | case NS_THEME_STATUSBAR_PANEL: |
michael@0 | 3176 | case NS_THEME_STATUSBAR_RESIZER_PANEL: |
michael@0 | 3177 | case NS_THEME_PROGRESSBAR_CHUNK: |
michael@0 | 3178 | case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL: |
michael@0 | 3179 | case NS_THEME_TOOLTIP: |
michael@0 | 3180 | case NS_THEME_PROGRESSBAR: |
michael@0 | 3181 | case NS_THEME_PROGRESSBAR_VERTICAL: |
michael@0 | 3182 | case NS_THEME_TAB: |
michael@0 | 3183 | case NS_THEME_TAB_PANEL: |
michael@0 | 3184 | case NS_THEME_TAB_PANELS: |
michael@0 | 3185 | case NS_THEME_MENUBAR: |
michael@0 | 3186 | case NS_THEME_MENUPOPUP: |
michael@0 | 3187 | case NS_THEME_GROUPBOX: |
michael@0 | 3188 | // these don't use DrawFrameControl |
michael@0 | 3189 | return NS_OK; |
michael@0 | 3190 | case NS_THEME_DROPDOWN_BUTTON: { |
michael@0 | 3191 | |
michael@0 | 3192 | aPart = DFC_SCROLL; |
michael@0 | 3193 | aState = DFCS_SCROLLCOMBOBOX; |
michael@0 | 3194 | |
michael@0 | 3195 | nsIFrame* parentFrame = aFrame->GetParent(); |
michael@0 | 3196 | bool isHTML = IsHTMLContent(aFrame); |
michael@0 | 3197 | bool isMenulist = !isHTML && parentFrame->GetType() == nsGkAtoms::menuFrame; |
michael@0 | 3198 | bool isOpen = false; |
michael@0 | 3199 | |
michael@0 | 3200 | // HTML select and XUL menulist dropdown buttons get state from the parent. |
michael@0 | 3201 | if (isHTML || isMenulist) |
michael@0 | 3202 | aFrame = parentFrame; |
michael@0 | 3203 | |
michael@0 | 3204 | EventStates eventState = GetContentState(aFrame, aWidgetType); |
michael@0 | 3205 | |
michael@0 | 3206 | if (IsDisabled(aFrame, eventState)) { |
michael@0 | 3207 | aState |= DFCS_INACTIVE; |
michael@0 | 3208 | return NS_OK; |
michael@0 | 3209 | } |
michael@0 | 3210 | |
michael@0 | 3211 | if (isHTML) { |
michael@0 | 3212 | nsIComboboxControlFrame* ccf = do_QueryFrame(aFrame); |
michael@0 | 3213 | isOpen = (ccf && ccf->IsDroppedDown()); |
michael@0 | 3214 | } |
michael@0 | 3215 | else |
michael@0 | 3216 | isOpen = IsOpenButton(aFrame); |
michael@0 | 3217 | |
michael@0 | 3218 | // XXX Button should look active until the mouse is released, but |
michael@0 | 3219 | // without making it look active when the popup is clicked. |
michael@0 | 3220 | if (isOpen && (isHTML || isMenulist)) |
michael@0 | 3221 | return NS_OK; |
michael@0 | 3222 | |
michael@0 | 3223 | // Dropdown button active state doesn't need :hover. |
michael@0 | 3224 | if (eventState.HasState(NS_EVENT_STATE_ACTIVE)) |
michael@0 | 3225 | aState |= DFCS_PUSHED | DFCS_FLAT; |
michael@0 | 3226 | |
michael@0 | 3227 | return NS_OK; |
michael@0 | 3228 | } |
michael@0 | 3229 | case NS_THEME_SCROLLBAR_BUTTON_UP: |
michael@0 | 3230 | case NS_THEME_SCROLLBAR_BUTTON_DOWN: |
michael@0 | 3231 | case NS_THEME_SCROLLBAR_BUTTON_LEFT: |
michael@0 | 3232 | case NS_THEME_SCROLLBAR_BUTTON_RIGHT: { |
michael@0 | 3233 | EventStates contentState = GetContentState(aFrame, aWidgetType); |
michael@0 | 3234 | |
michael@0 | 3235 | aPart = DFC_SCROLL; |
michael@0 | 3236 | switch (aWidgetType) { |
michael@0 | 3237 | case NS_THEME_SCROLLBAR_BUTTON_UP: |
michael@0 | 3238 | aState = DFCS_SCROLLUP; |
michael@0 | 3239 | break; |
michael@0 | 3240 | case NS_THEME_SCROLLBAR_BUTTON_DOWN: |
michael@0 | 3241 | aState = DFCS_SCROLLDOWN; |
michael@0 | 3242 | break; |
michael@0 | 3243 | case NS_THEME_SCROLLBAR_BUTTON_LEFT: |
michael@0 | 3244 | aState = DFCS_SCROLLLEFT; |
michael@0 | 3245 | break; |
michael@0 | 3246 | case NS_THEME_SCROLLBAR_BUTTON_RIGHT: |
michael@0 | 3247 | aState = DFCS_SCROLLRIGHT; |
michael@0 | 3248 | break; |
michael@0 | 3249 | } |
michael@0 | 3250 | |
michael@0 | 3251 | if (IsDisabled(aFrame, contentState)) |
michael@0 | 3252 | aState |= DFCS_INACTIVE; |
michael@0 | 3253 | else { |
michael@0 | 3254 | if (contentState.HasAllStates(NS_EVENT_STATE_HOVER | NS_EVENT_STATE_ACTIVE)) |
michael@0 | 3255 | aState |= DFCS_PUSHED | DFCS_FLAT; |
michael@0 | 3256 | } |
michael@0 | 3257 | |
michael@0 | 3258 | return NS_OK; |
michael@0 | 3259 | } |
michael@0 | 3260 | case NS_THEME_SPINNER_UP_BUTTON: |
michael@0 | 3261 | case NS_THEME_SPINNER_DOWN_BUTTON: { |
michael@0 | 3262 | EventStates contentState = GetContentState(aFrame, aWidgetType); |
michael@0 | 3263 | |
michael@0 | 3264 | aPart = DFC_SCROLL; |
michael@0 | 3265 | switch (aWidgetType) { |
michael@0 | 3266 | case NS_THEME_SPINNER_UP_BUTTON: |
michael@0 | 3267 | aState = DFCS_SCROLLUP; |
michael@0 | 3268 | break; |
michael@0 | 3269 | case NS_THEME_SPINNER_DOWN_BUTTON: |
michael@0 | 3270 | aState = DFCS_SCROLLDOWN; |
michael@0 | 3271 | break; |
michael@0 | 3272 | } |
michael@0 | 3273 | |
michael@0 | 3274 | if (IsDisabled(aFrame, contentState)) |
michael@0 | 3275 | aState |= DFCS_INACTIVE; |
michael@0 | 3276 | else { |
michael@0 | 3277 | if (contentState.HasAllStates(NS_EVENT_STATE_HOVER | NS_EVENT_STATE_ACTIVE)) |
michael@0 | 3278 | aState |= DFCS_PUSHED; |
michael@0 | 3279 | } |
michael@0 | 3280 | |
michael@0 | 3281 | return NS_OK; |
michael@0 | 3282 | } |
michael@0 | 3283 | case NS_THEME_RESIZER: |
michael@0 | 3284 | aPart = DFC_SCROLL; |
michael@0 | 3285 | aState = (IsFrameRTL(aFrame)) ? |
michael@0 | 3286 | DFCS_SCROLLSIZEGRIPRIGHT : DFCS_SCROLLSIZEGRIP; |
michael@0 | 3287 | return NS_OK; |
michael@0 | 3288 | case NS_THEME_MENUSEPARATOR: |
michael@0 | 3289 | aPart = 0; |
michael@0 | 3290 | aState = 0; |
michael@0 | 3291 | return NS_OK; |
michael@0 | 3292 | case NS_THEME_WINDOW_TITLEBAR: |
michael@0 | 3293 | aPart = mozilla::widget::themeconst::WP_CAPTION; |
michael@0 | 3294 | aState = GetTopLevelWindowActiveState(aFrame); |
michael@0 | 3295 | return NS_OK; |
michael@0 | 3296 | case NS_THEME_WINDOW_TITLEBAR_MAXIMIZED: |
michael@0 | 3297 | aPart = mozilla::widget::themeconst::WP_MAXCAPTION; |
michael@0 | 3298 | aState = GetTopLevelWindowActiveState(aFrame); |
michael@0 | 3299 | return NS_OK; |
michael@0 | 3300 | case NS_THEME_WINDOW_FRAME_LEFT: |
michael@0 | 3301 | aPart = mozilla::widget::themeconst::WP_FRAMELEFT; |
michael@0 | 3302 | aState = GetTopLevelWindowActiveState(aFrame); |
michael@0 | 3303 | return NS_OK; |
michael@0 | 3304 | case NS_THEME_WINDOW_FRAME_RIGHT: |
michael@0 | 3305 | aPart = mozilla::widget::themeconst::WP_FRAMERIGHT; |
michael@0 | 3306 | aState = GetTopLevelWindowActiveState(aFrame); |
michael@0 | 3307 | return NS_OK; |
michael@0 | 3308 | case NS_THEME_WINDOW_FRAME_BOTTOM: |
michael@0 | 3309 | aPart = mozilla::widget::themeconst::WP_FRAMEBOTTOM; |
michael@0 | 3310 | aState = GetTopLevelWindowActiveState(aFrame); |
michael@0 | 3311 | return NS_OK; |
michael@0 | 3312 | case NS_THEME_WINDOW_BUTTON_CLOSE: |
michael@0 | 3313 | aPart = DFC_CAPTION; |
michael@0 | 3314 | aState = DFCS_CAPTIONCLOSE | |
michael@0 | 3315 | GetClassicWindowFrameButtonState(GetContentState(aFrame, |
michael@0 | 3316 | aWidgetType)); |
michael@0 | 3317 | return NS_OK; |
michael@0 | 3318 | case NS_THEME_WINDOW_BUTTON_MINIMIZE: |
michael@0 | 3319 | aPart = DFC_CAPTION; |
michael@0 | 3320 | aState = DFCS_CAPTIONMIN | |
michael@0 | 3321 | GetClassicWindowFrameButtonState(GetContentState(aFrame, |
michael@0 | 3322 | aWidgetType)); |
michael@0 | 3323 | return NS_OK; |
michael@0 | 3324 | case NS_THEME_WINDOW_BUTTON_MAXIMIZE: |
michael@0 | 3325 | aPart = DFC_CAPTION; |
michael@0 | 3326 | aState = DFCS_CAPTIONMAX | |
michael@0 | 3327 | GetClassicWindowFrameButtonState(GetContentState(aFrame, |
michael@0 | 3328 | aWidgetType)); |
michael@0 | 3329 | return NS_OK; |
michael@0 | 3330 | case NS_THEME_WINDOW_BUTTON_RESTORE: |
michael@0 | 3331 | aPart = DFC_CAPTION; |
michael@0 | 3332 | aState = DFCS_CAPTIONRESTORE | |
michael@0 | 3333 | GetClassicWindowFrameButtonState(GetContentState(aFrame, |
michael@0 | 3334 | aWidgetType)); |
michael@0 | 3335 | return NS_OK; |
michael@0 | 3336 | } |
michael@0 | 3337 | return NS_ERROR_FAILURE; |
michael@0 | 3338 | } |
michael@0 | 3339 | |
michael@0 | 3340 | // Draw classic Windows tab |
michael@0 | 3341 | // (no system API for this, but DrawEdge can draw all the parts of a tab) |
michael@0 | 3342 | static void DrawTab(HDC hdc, const RECT& R, int32_t aPosition, bool aSelected, |
michael@0 | 3343 | bool aDrawLeft, bool aDrawRight) |
michael@0 | 3344 | { |
michael@0 | 3345 | int32_t leftFlag, topFlag, rightFlag, lightFlag, shadeFlag; |
michael@0 | 3346 | RECT topRect, sideRect, bottomRect, lightRect, shadeRect; |
michael@0 | 3347 | int32_t selectedOffset, lOffset, rOffset; |
michael@0 | 3348 | |
michael@0 | 3349 | selectedOffset = aSelected ? 1 : 0; |
michael@0 | 3350 | lOffset = aDrawLeft ? 2 : 0; |
michael@0 | 3351 | rOffset = aDrawRight ? 2 : 0; |
michael@0 | 3352 | |
michael@0 | 3353 | // Get info for tab orientation/position (Left, Top, Right, Bottom) |
michael@0 | 3354 | switch (aPosition) { |
michael@0 | 3355 | case BF_LEFT: |
michael@0 | 3356 | leftFlag = BF_TOP; topFlag = BF_LEFT; |
michael@0 | 3357 | rightFlag = BF_BOTTOM; |
michael@0 | 3358 | lightFlag = BF_DIAGONAL_ENDTOPRIGHT; |
michael@0 | 3359 | shadeFlag = BF_DIAGONAL_ENDBOTTOMRIGHT; |
michael@0 | 3360 | |
michael@0 | 3361 | ::SetRect(&topRect, R.left, R.top+lOffset, R.right, R.bottom-rOffset); |
michael@0 | 3362 | ::SetRect(&sideRect, R.left+2, R.top, R.right-2+selectedOffset, R.bottom); |
michael@0 | 3363 | ::SetRect(&bottomRect, R.right-2, R.top, R.right, R.bottom); |
michael@0 | 3364 | ::SetRect(&lightRect, R.left, R.top, R.left+3, R.top+3); |
michael@0 | 3365 | ::SetRect(&shadeRect, R.left+1, R.bottom-2, R.left+2, R.bottom-1); |
michael@0 | 3366 | break; |
michael@0 | 3367 | case BF_TOP: |
michael@0 | 3368 | leftFlag = BF_LEFT; topFlag = BF_TOP; |
michael@0 | 3369 | rightFlag = BF_RIGHT; |
michael@0 | 3370 | lightFlag = BF_DIAGONAL_ENDTOPRIGHT; |
michael@0 | 3371 | shadeFlag = BF_DIAGONAL_ENDBOTTOMRIGHT; |
michael@0 | 3372 | |
michael@0 | 3373 | ::SetRect(&topRect, R.left+lOffset, R.top, R.right-rOffset, R.bottom); |
michael@0 | 3374 | ::SetRect(&sideRect, R.left, R.top+2, R.right, R.bottom-1+selectedOffset); |
michael@0 | 3375 | ::SetRect(&bottomRect, R.left, R.bottom-1, R.right, R.bottom); |
michael@0 | 3376 | ::SetRect(&lightRect, R.left, R.top, R.left+3, R.top+3); |
michael@0 | 3377 | ::SetRect(&shadeRect, R.right-2, R.top+1, R.right-1, R.top+2); |
michael@0 | 3378 | break; |
michael@0 | 3379 | case BF_RIGHT: |
michael@0 | 3380 | leftFlag = BF_TOP; topFlag = BF_RIGHT; |
michael@0 | 3381 | rightFlag = BF_BOTTOM; |
michael@0 | 3382 | lightFlag = BF_DIAGONAL_ENDTOPLEFT; |
michael@0 | 3383 | shadeFlag = BF_DIAGONAL_ENDBOTTOMLEFT; |
michael@0 | 3384 | |
michael@0 | 3385 | ::SetRect(&topRect, R.left, R.top+lOffset, R.right, R.bottom-rOffset); |
michael@0 | 3386 | ::SetRect(&sideRect, R.left+2-selectedOffset, R.top, R.right-2, R.bottom); |
michael@0 | 3387 | ::SetRect(&bottomRect, R.left, R.top, R.left+2, R.bottom); |
michael@0 | 3388 | ::SetRect(&lightRect, R.right-3, R.top, R.right-1, R.top+2); |
michael@0 | 3389 | ::SetRect(&shadeRect, R.right-2, R.bottom-3, R.right, R.bottom-1); |
michael@0 | 3390 | break; |
michael@0 | 3391 | case BF_BOTTOM: |
michael@0 | 3392 | leftFlag = BF_LEFT; topFlag = BF_BOTTOM; |
michael@0 | 3393 | rightFlag = BF_RIGHT; |
michael@0 | 3394 | lightFlag = BF_DIAGONAL_ENDTOPLEFT; |
michael@0 | 3395 | shadeFlag = BF_DIAGONAL_ENDBOTTOMLEFT; |
michael@0 | 3396 | |
michael@0 | 3397 | ::SetRect(&topRect, R.left+lOffset, R.top, R.right-rOffset, R.bottom); |
michael@0 | 3398 | ::SetRect(&sideRect, R.left, R.top+2-selectedOffset, R.right, R.bottom-2); |
michael@0 | 3399 | ::SetRect(&bottomRect, R.left, R.top, R.right, R.top+2); |
michael@0 | 3400 | ::SetRect(&lightRect, R.left, R.bottom-3, R.left+2, R.bottom-1); |
michael@0 | 3401 | ::SetRect(&shadeRect, R.right-2, R.bottom-3, R.right, R.bottom-1); |
michael@0 | 3402 | break; |
michael@0 | 3403 | } |
michael@0 | 3404 | |
michael@0 | 3405 | // Background |
michael@0 | 3406 | ::FillRect(hdc, &R, (HBRUSH) (COLOR_3DFACE+1) ); |
michael@0 | 3407 | |
michael@0 | 3408 | // Tab "Top" |
michael@0 | 3409 | ::DrawEdge(hdc, &topRect, EDGE_RAISED, BF_SOFT | topFlag); |
michael@0 | 3410 | |
michael@0 | 3411 | // Tab "Bottom" |
michael@0 | 3412 | if (!aSelected) |
michael@0 | 3413 | ::DrawEdge(hdc, &bottomRect, EDGE_RAISED, BF_SOFT | topFlag); |
michael@0 | 3414 | |
michael@0 | 3415 | // Tab "Sides" |
michael@0 | 3416 | if (!aDrawLeft) |
michael@0 | 3417 | leftFlag = 0; |
michael@0 | 3418 | if (!aDrawRight) |
michael@0 | 3419 | rightFlag = 0; |
michael@0 | 3420 | ::DrawEdge(hdc, &sideRect, EDGE_RAISED, BF_SOFT | leftFlag | rightFlag); |
michael@0 | 3421 | |
michael@0 | 3422 | // Tab Diagonal Corners |
michael@0 | 3423 | if (aDrawLeft) |
michael@0 | 3424 | ::DrawEdge(hdc, &lightRect, EDGE_RAISED, BF_SOFT | lightFlag); |
michael@0 | 3425 | |
michael@0 | 3426 | if (aDrawRight) |
michael@0 | 3427 | ::DrawEdge(hdc, &shadeRect, EDGE_RAISED, BF_SOFT | shadeFlag); |
michael@0 | 3428 | } |
michael@0 | 3429 | |
michael@0 | 3430 | static void DrawMenuImage(HDC hdc, const RECT& rc, int32_t aComponent, uint32_t aColor) |
michael@0 | 3431 | { |
michael@0 | 3432 | // This procedure creates a memory bitmap to contain the check mark, draws |
michael@0 | 3433 | // it into the bitmap (it is a mask image), then composes it onto the menu |
michael@0 | 3434 | // item in appropriate colors. |
michael@0 | 3435 | HDC hMemoryDC = ::CreateCompatibleDC(hdc); |
michael@0 | 3436 | if (hMemoryDC) { |
michael@0 | 3437 | // XXXjgr We should ideally be caching these, but we wont be notified when |
michael@0 | 3438 | // they change currently, so we can't do so easily. Same for the bitmap. |
michael@0 | 3439 | int checkW = ::GetSystemMetrics(SM_CXMENUCHECK); |
michael@0 | 3440 | int checkH = ::GetSystemMetrics(SM_CYMENUCHECK); |
michael@0 | 3441 | |
michael@0 | 3442 | HBITMAP hMonoBitmap = ::CreateBitmap(checkW, checkH, 1, 1, nullptr); |
michael@0 | 3443 | if (hMonoBitmap) { |
michael@0 | 3444 | |
michael@0 | 3445 | HBITMAP hPrevBitmap = (HBITMAP) ::SelectObject(hMemoryDC, hMonoBitmap); |
michael@0 | 3446 | if (hPrevBitmap) { |
michael@0 | 3447 | |
michael@0 | 3448 | // XXXjgr This will go pear-shaped if the image is bigger than the |
michael@0 | 3449 | // provided rect. What should we do? |
michael@0 | 3450 | RECT imgRect = { 0, 0, checkW, checkH }; |
michael@0 | 3451 | POINT imgPos = { |
michael@0 | 3452 | rc.left + (rc.right - rc.left - checkW) / 2, |
michael@0 | 3453 | rc.top + (rc.bottom - rc.top - checkH) / 2 |
michael@0 | 3454 | }; |
michael@0 | 3455 | |
michael@0 | 3456 | // XXXzeniko Windows renders these 1px lower than you'd expect |
michael@0 | 3457 | if (aComponent == DFCS_MENUCHECK || aComponent == DFCS_MENUBULLET) |
michael@0 | 3458 | imgPos.y++; |
michael@0 | 3459 | |
michael@0 | 3460 | ::DrawFrameControl(hMemoryDC, &imgRect, DFC_MENU, aComponent); |
michael@0 | 3461 | COLORREF oldTextCol = ::SetTextColor(hdc, 0x00000000); |
michael@0 | 3462 | COLORREF oldBackCol = ::SetBkColor(hdc, 0x00FFFFFF); |
michael@0 | 3463 | ::BitBlt(hdc, imgPos.x, imgPos.y, checkW, checkH, hMemoryDC, 0, 0, SRCAND); |
michael@0 | 3464 | ::SetTextColor(hdc, ::GetSysColor(aColor)); |
michael@0 | 3465 | ::SetBkColor(hdc, 0x00000000); |
michael@0 | 3466 | ::BitBlt(hdc, imgPos.x, imgPos.y, checkW, checkH, hMemoryDC, 0, 0, SRCPAINT); |
michael@0 | 3467 | ::SetTextColor(hdc, oldTextCol); |
michael@0 | 3468 | ::SetBkColor(hdc, oldBackCol); |
michael@0 | 3469 | ::SelectObject(hMemoryDC, hPrevBitmap); |
michael@0 | 3470 | } |
michael@0 | 3471 | ::DeleteObject(hMonoBitmap); |
michael@0 | 3472 | } |
michael@0 | 3473 | ::DeleteDC(hMemoryDC); |
michael@0 | 3474 | } |
michael@0 | 3475 | } |
michael@0 | 3476 | |
michael@0 | 3477 | void nsNativeThemeWin::DrawCheckedRect(HDC hdc, const RECT& rc, int32_t fore, int32_t back, |
michael@0 | 3478 | HBRUSH defaultBack) |
michael@0 | 3479 | { |
michael@0 | 3480 | static WORD patBits[8] = { |
michael@0 | 3481 | 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 |
michael@0 | 3482 | }; |
michael@0 | 3483 | |
michael@0 | 3484 | HBITMAP patBmp = ::CreateBitmap(8, 8, 1, 1, patBits); |
michael@0 | 3485 | if (patBmp) { |
michael@0 | 3486 | HBRUSH brush = (HBRUSH) ::CreatePatternBrush(patBmp); |
michael@0 | 3487 | if (brush) { |
michael@0 | 3488 | COLORREF oldForeColor = ::SetTextColor(hdc, ::GetSysColor(fore)); |
michael@0 | 3489 | COLORREF oldBackColor = ::SetBkColor(hdc, ::GetSysColor(back)); |
michael@0 | 3490 | POINT vpOrg; |
michael@0 | 3491 | |
michael@0 | 3492 | ::UnrealizeObject(brush); |
michael@0 | 3493 | ::GetViewportOrgEx(hdc, &vpOrg); |
michael@0 | 3494 | ::SetBrushOrgEx(hdc, vpOrg.x + rc.left, vpOrg.y + rc.top, nullptr); |
michael@0 | 3495 | HBRUSH oldBrush = (HBRUSH) ::SelectObject(hdc, brush); |
michael@0 | 3496 | ::FillRect(hdc, &rc, brush); |
michael@0 | 3497 | ::SetTextColor(hdc, oldForeColor); |
michael@0 | 3498 | ::SetBkColor(hdc, oldBackColor); |
michael@0 | 3499 | ::SelectObject(hdc, oldBrush); |
michael@0 | 3500 | ::DeleteObject(brush); |
michael@0 | 3501 | } |
michael@0 | 3502 | else |
michael@0 | 3503 | ::FillRect(hdc, &rc, defaultBack); |
michael@0 | 3504 | |
michael@0 | 3505 | ::DeleteObject(patBmp); |
michael@0 | 3506 | } |
michael@0 | 3507 | } |
michael@0 | 3508 | |
michael@0 | 3509 | nsresult nsNativeThemeWin::ClassicDrawWidgetBackground(nsRenderingContext* aContext, |
michael@0 | 3510 | nsIFrame* aFrame, |
michael@0 | 3511 | uint8_t aWidgetType, |
michael@0 | 3512 | const nsRect& aRect, |
michael@0 | 3513 | const nsRect& aDirtyRect) |
michael@0 | 3514 | { |
michael@0 | 3515 | int32_t part, state; |
michael@0 | 3516 | bool focused; |
michael@0 | 3517 | nsresult rv; |
michael@0 | 3518 | rv = ClassicGetThemePartAndState(aFrame, aWidgetType, part, state, focused); |
michael@0 | 3519 | if (NS_FAILED(rv)) |
michael@0 | 3520 | return rv; |
michael@0 | 3521 | |
michael@0 | 3522 | if (AssumeThemePartAndStateAreTransparent(part, state)) { |
michael@0 | 3523 | return NS_OK; |
michael@0 | 3524 | } |
michael@0 | 3525 | |
michael@0 | 3526 | gfxFloat p2a = gfxFloat(aContext->AppUnitsPerDevPixel()); |
michael@0 | 3527 | RECT widgetRect; |
michael@0 | 3528 | gfxRect tr(aRect.x, aRect.y, aRect.width, aRect.height), |
michael@0 | 3529 | dr(aDirtyRect.x, aDirtyRect.y, aDirtyRect.width, aDirtyRect.height); |
michael@0 | 3530 | |
michael@0 | 3531 | tr.ScaleInverse(p2a); |
michael@0 | 3532 | dr.ScaleInverse(p2a); |
michael@0 | 3533 | |
michael@0 | 3534 | nsRefPtr<gfxContext> ctx = aContext->ThebesContext(); |
michael@0 | 3535 | |
michael@0 | 3536 | gfxWindowsNativeDrawing nativeDrawing(ctx, dr, GetWidgetNativeDrawingFlags(aWidgetType)); |
michael@0 | 3537 | |
michael@0 | 3538 | RENDER_AGAIN: |
michael@0 | 3539 | |
michael@0 | 3540 | HDC hdc = nativeDrawing.BeginNativeDrawing(); |
michael@0 | 3541 | if (!hdc) |
michael@0 | 3542 | return NS_ERROR_FAILURE; |
michael@0 | 3543 | |
michael@0 | 3544 | nativeDrawing.TransformToNativeRect(tr, widgetRect); |
michael@0 | 3545 | |
michael@0 | 3546 | rv = NS_OK; |
michael@0 | 3547 | switch (aWidgetType) { |
michael@0 | 3548 | // Draw button |
michael@0 | 3549 | case NS_THEME_BUTTON: { |
michael@0 | 3550 | if (focused) { |
michael@0 | 3551 | // draw dark button focus border first |
michael@0 | 3552 | HBRUSH brush; |
michael@0 | 3553 | brush = ::GetSysColorBrush(COLOR_3DDKSHADOW); |
michael@0 | 3554 | if (brush) |
michael@0 | 3555 | ::FrameRect(hdc, &widgetRect, brush); |
michael@0 | 3556 | InflateRect(&widgetRect, -1, -1); |
michael@0 | 3557 | } |
michael@0 | 3558 | // fall-through... |
michael@0 | 3559 | } |
michael@0 | 3560 | // Draw controls supported by DrawFrameControl |
michael@0 | 3561 | case NS_THEME_CHECKBOX: |
michael@0 | 3562 | case NS_THEME_RADIO: |
michael@0 | 3563 | case NS_THEME_SCROLLBAR_BUTTON_UP: |
michael@0 | 3564 | case NS_THEME_SCROLLBAR_BUTTON_DOWN: |
michael@0 | 3565 | case NS_THEME_SCROLLBAR_BUTTON_LEFT: |
michael@0 | 3566 | case NS_THEME_SCROLLBAR_BUTTON_RIGHT: |
michael@0 | 3567 | case NS_THEME_SPINNER_UP_BUTTON: |
michael@0 | 3568 | case NS_THEME_SPINNER_DOWN_BUTTON: |
michael@0 | 3569 | case NS_THEME_DROPDOWN_BUTTON: |
michael@0 | 3570 | case NS_THEME_RESIZER: { |
michael@0 | 3571 | int32_t oldTA; |
michael@0 | 3572 | // setup DC to make DrawFrameControl draw correctly |
michael@0 | 3573 | oldTA = ::SetTextAlign(hdc, TA_TOP | TA_LEFT | TA_NOUPDATECP); |
michael@0 | 3574 | ::DrawFrameControl(hdc, &widgetRect, part, state); |
michael@0 | 3575 | ::SetTextAlign(hdc, oldTA); |
michael@0 | 3576 | |
michael@0 | 3577 | // Draw focus rectangles for HTML checkboxes and radio buttons |
michael@0 | 3578 | // XXX it'd be nice to draw these outside of the frame |
michael@0 | 3579 | if (focused && (aWidgetType == NS_THEME_CHECKBOX || aWidgetType == NS_THEME_RADIO)) { |
michael@0 | 3580 | // setup DC to make DrawFocusRect draw correctly |
michael@0 | 3581 | POINT vpOrg; |
michael@0 | 3582 | ::GetViewportOrgEx(hdc, &vpOrg); |
michael@0 | 3583 | ::SetBrushOrgEx(hdc, vpOrg.x + widgetRect.left, vpOrg.y + widgetRect.top, nullptr); |
michael@0 | 3584 | int32_t oldColor; |
michael@0 | 3585 | oldColor = ::SetTextColor(hdc, 0); |
michael@0 | 3586 | // draw focus rectangle |
michael@0 | 3587 | ::DrawFocusRect(hdc, &widgetRect); |
michael@0 | 3588 | ::SetTextColor(hdc, oldColor); |
michael@0 | 3589 | } |
michael@0 | 3590 | break; |
michael@0 | 3591 | } |
michael@0 | 3592 | // Draw controls with 2px 3D inset border |
michael@0 | 3593 | case NS_THEME_NUMBER_INPUT: |
michael@0 | 3594 | case NS_THEME_TEXTFIELD: |
michael@0 | 3595 | case NS_THEME_TEXTFIELD_MULTILINE: |
michael@0 | 3596 | case NS_THEME_LISTBOX: |
michael@0 | 3597 | case NS_THEME_DROPDOWN: |
michael@0 | 3598 | case NS_THEME_DROPDOWN_TEXTFIELD: { |
michael@0 | 3599 | // Draw inset edge |
michael@0 | 3600 | ::DrawEdge(hdc, &widgetRect, EDGE_SUNKEN, BF_RECT | BF_ADJUST); |
michael@0 | 3601 | EventStates eventState = GetContentState(aFrame, aWidgetType); |
michael@0 | 3602 | |
michael@0 | 3603 | // Fill in background |
michael@0 | 3604 | if (IsDisabled(aFrame, eventState) || |
michael@0 | 3605 | (aFrame->GetContent()->IsXUL() && |
michael@0 | 3606 | IsReadOnly(aFrame))) |
michael@0 | 3607 | ::FillRect(hdc, &widgetRect, (HBRUSH) (COLOR_BTNFACE+1)); |
michael@0 | 3608 | else |
michael@0 | 3609 | ::FillRect(hdc, &widgetRect, (HBRUSH) (COLOR_WINDOW+1)); |
michael@0 | 3610 | |
michael@0 | 3611 | break; |
michael@0 | 3612 | } |
michael@0 | 3613 | case NS_THEME_TREEVIEW: { |
michael@0 | 3614 | // Draw inset edge |
michael@0 | 3615 | ::DrawEdge(hdc, &widgetRect, EDGE_SUNKEN, BF_RECT | BF_ADJUST); |
michael@0 | 3616 | |
michael@0 | 3617 | // Fill in window color background |
michael@0 | 3618 | ::FillRect(hdc, &widgetRect, (HBRUSH) (COLOR_WINDOW+1)); |
michael@0 | 3619 | |
michael@0 | 3620 | break; |
michael@0 | 3621 | } |
michael@0 | 3622 | // Draw ToolTip background |
michael@0 | 3623 | case NS_THEME_TOOLTIP: |
michael@0 | 3624 | ::FrameRect(hdc, &widgetRect, ::GetSysColorBrush(COLOR_WINDOWFRAME)); |
michael@0 | 3625 | InflateRect(&widgetRect, -1, -1); |
michael@0 | 3626 | ::FillRect(hdc, &widgetRect, ::GetSysColorBrush(COLOR_INFOBK)); |
michael@0 | 3627 | |
michael@0 | 3628 | break; |
michael@0 | 3629 | case NS_THEME_GROUPBOX: |
michael@0 | 3630 | ::DrawEdge(hdc, &widgetRect, EDGE_ETCHED, BF_RECT | BF_ADJUST); |
michael@0 | 3631 | ::FillRect(hdc, &widgetRect, (HBRUSH) (COLOR_BTNFACE+1)); |
michael@0 | 3632 | break; |
michael@0 | 3633 | // Draw 3D face background controls |
michael@0 | 3634 | case NS_THEME_PROGRESSBAR: |
michael@0 | 3635 | case NS_THEME_PROGRESSBAR_VERTICAL: |
michael@0 | 3636 | // Draw 3D border |
michael@0 | 3637 | ::DrawEdge(hdc, &widgetRect, BDR_SUNKENOUTER, BF_RECT | BF_MIDDLE); |
michael@0 | 3638 | InflateRect(&widgetRect, -1, -1); |
michael@0 | 3639 | // fall through |
michael@0 | 3640 | case NS_THEME_TAB_PANEL: |
michael@0 | 3641 | case NS_THEME_STATUSBAR: |
michael@0 | 3642 | case NS_THEME_STATUSBAR_RESIZER_PANEL: { |
michael@0 | 3643 | ::FillRect(hdc, &widgetRect, (HBRUSH) (COLOR_BTNFACE+1)); |
michael@0 | 3644 | |
michael@0 | 3645 | break; |
michael@0 | 3646 | } |
michael@0 | 3647 | // Draw 3D inset statusbar panel |
michael@0 | 3648 | case NS_THEME_STATUSBAR_PANEL: { |
michael@0 | 3649 | if (aFrame->GetNextSibling()) |
michael@0 | 3650 | widgetRect.right -= 2; // space between sibling status panels |
michael@0 | 3651 | |
michael@0 | 3652 | ::DrawEdge(hdc, &widgetRect, BDR_SUNKENOUTER, BF_RECT | BF_MIDDLE); |
michael@0 | 3653 | |
michael@0 | 3654 | break; |
michael@0 | 3655 | } |
michael@0 | 3656 | // Draw scrollbar thumb |
michael@0 | 3657 | case NS_THEME_SCROLLBAR_THUMB_VERTICAL: |
michael@0 | 3658 | case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL: |
michael@0 | 3659 | ::DrawEdge(hdc, &widgetRect, EDGE_RAISED, BF_RECT | BF_MIDDLE); |
michael@0 | 3660 | |
michael@0 | 3661 | break; |
michael@0 | 3662 | case NS_THEME_RANGE_THUMB: |
michael@0 | 3663 | case NS_THEME_SCALE_THUMB_VERTICAL: |
michael@0 | 3664 | case NS_THEME_SCALE_THUMB_HORIZONTAL: { |
michael@0 | 3665 | EventStates eventState = GetContentState(aFrame, aWidgetType); |
michael@0 | 3666 | |
michael@0 | 3667 | ::DrawEdge(hdc, &widgetRect, EDGE_RAISED, BF_RECT | BF_SOFT | BF_MIDDLE | BF_ADJUST); |
michael@0 | 3668 | if (IsDisabled(aFrame, eventState)) { |
michael@0 | 3669 | DrawCheckedRect(hdc, widgetRect, COLOR_3DFACE, COLOR_3DHILIGHT, |
michael@0 | 3670 | (HBRUSH) COLOR_3DHILIGHT); |
michael@0 | 3671 | } |
michael@0 | 3672 | |
michael@0 | 3673 | break; |
michael@0 | 3674 | } |
michael@0 | 3675 | // Draw scrollbar track background |
michael@0 | 3676 | case NS_THEME_SCROLLBAR_TRACK_VERTICAL: |
michael@0 | 3677 | case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL: { |
michael@0 | 3678 | |
michael@0 | 3679 | // Windows fills in the scrollbar track differently |
michael@0 | 3680 | // depending on whether these are equal |
michael@0 | 3681 | DWORD color3D, colorScrollbar, colorWindow; |
michael@0 | 3682 | |
michael@0 | 3683 | color3D = ::GetSysColor(COLOR_3DFACE); |
michael@0 | 3684 | colorWindow = ::GetSysColor(COLOR_WINDOW); |
michael@0 | 3685 | colorScrollbar = ::GetSysColor(COLOR_SCROLLBAR); |
michael@0 | 3686 | |
michael@0 | 3687 | if ((color3D != colorScrollbar) && (colorWindow != colorScrollbar)) |
michael@0 | 3688 | // Use solid brush |
michael@0 | 3689 | ::FillRect(hdc, &widgetRect, (HBRUSH) (COLOR_SCROLLBAR+1)); |
michael@0 | 3690 | else |
michael@0 | 3691 | { |
michael@0 | 3692 | DrawCheckedRect(hdc, widgetRect, COLOR_3DHILIGHT, COLOR_3DFACE, |
michael@0 | 3693 | (HBRUSH) COLOR_SCROLLBAR+1); |
michael@0 | 3694 | } |
michael@0 | 3695 | // XXX should invert the part of the track being clicked here |
michael@0 | 3696 | // but the track is never :active |
michael@0 | 3697 | |
michael@0 | 3698 | break; |
michael@0 | 3699 | } |
michael@0 | 3700 | // Draw scale track background |
michael@0 | 3701 | case NS_THEME_RANGE: |
michael@0 | 3702 | case NS_THEME_SCALE_VERTICAL: |
michael@0 | 3703 | case NS_THEME_SCALE_HORIZONTAL: { |
michael@0 | 3704 | const int32_t trackWidth = 4; |
michael@0 | 3705 | // When rounding is necessary, we round the position of the track |
michael@0 | 3706 | // away from the chevron of the thumb to make it look better. |
michael@0 | 3707 | if (aWidgetType == NS_THEME_SCALE_HORIZONTAL || |
michael@0 | 3708 | (aWidgetType == NS_THEME_RANGE && IsRangeHorizontal(aFrame))) { |
michael@0 | 3709 | widgetRect.top += (widgetRect.bottom - widgetRect.top - trackWidth) / 2; |
michael@0 | 3710 | widgetRect.bottom = widgetRect.top + trackWidth; |
michael@0 | 3711 | } |
michael@0 | 3712 | else { |
michael@0 | 3713 | if (!IsFrameRTL(aFrame)) { |
michael@0 | 3714 | widgetRect.left += (widgetRect.right - widgetRect.left - trackWidth) / 2; |
michael@0 | 3715 | widgetRect.right = widgetRect.left + trackWidth; |
michael@0 | 3716 | } else { |
michael@0 | 3717 | widgetRect.right -= (widgetRect.right - widgetRect.left - trackWidth) / 2; |
michael@0 | 3718 | widgetRect.left = widgetRect.right - trackWidth; |
michael@0 | 3719 | } |
michael@0 | 3720 | } |
michael@0 | 3721 | |
michael@0 | 3722 | ::DrawEdge(hdc, &widgetRect, EDGE_SUNKEN, BF_RECT | BF_ADJUST); |
michael@0 | 3723 | ::FillRect(hdc, &widgetRect, (HBRUSH) GetStockObject(GRAY_BRUSH)); |
michael@0 | 3724 | |
michael@0 | 3725 | break; |
michael@0 | 3726 | } |
michael@0 | 3727 | case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL: |
michael@0 | 3728 | ::FillRect(hdc, &widgetRect, (HBRUSH) (COLOR_HIGHLIGHT+1)); |
michael@0 | 3729 | break; |
michael@0 | 3730 | |
michael@0 | 3731 | case NS_THEME_PROGRESSBAR_CHUNK: { |
michael@0 | 3732 | nsIFrame* stateFrame = aFrame->GetParent(); |
michael@0 | 3733 | EventStates eventStates = GetContentState(stateFrame, aWidgetType); |
michael@0 | 3734 | |
michael@0 | 3735 | bool indeterminate = IsIndeterminateProgress(stateFrame, eventStates); |
michael@0 | 3736 | bool vertical = IsVerticalProgress(stateFrame) || |
michael@0 | 3737 | aWidgetType == NS_THEME_PROGRESSBAR_CHUNK_VERTICAL; |
michael@0 | 3738 | int32_t overlayPart = GetProgressOverlayStyle(vertical); |
michael@0 | 3739 | |
michael@0 | 3740 | nsIContent* content = aFrame->GetContent(); |
michael@0 | 3741 | if (!indeterminate || !content) { |
michael@0 | 3742 | ::FillRect(hdc, &widgetRect, (HBRUSH) (COLOR_HIGHLIGHT+1)); |
michael@0 | 3743 | break; |
michael@0 | 3744 | } |
michael@0 | 3745 | |
michael@0 | 3746 | RECT overlayRect = |
michael@0 | 3747 | CalculateProgressOverlayRect(aFrame, &widgetRect, vertical, |
michael@0 | 3748 | indeterminate, true); |
michael@0 | 3749 | |
michael@0 | 3750 | ::FillRect(hdc, &overlayRect, (HBRUSH) (COLOR_HIGHLIGHT+1)); |
michael@0 | 3751 | |
michael@0 | 3752 | if (!QueueAnimatedContentForRefresh(aFrame->GetContent(), 30)) { |
michael@0 | 3753 | NS_WARNING("unable to animate progress widget!"); |
michael@0 | 3754 | } |
michael@0 | 3755 | break; |
michael@0 | 3756 | } |
michael@0 | 3757 | |
michael@0 | 3758 | // Draw Tab |
michael@0 | 3759 | case NS_THEME_TAB: { |
michael@0 | 3760 | DrawTab(hdc, widgetRect, |
michael@0 | 3761 | IsBottomTab(aFrame) ? BF_BOTTOM : BF_TOP, |
michael@0 | 3762 | IsSelectedTab(aFrame), |
michael@0 | 3763 | !IsRightToSelectedTab(aFrame), |
michael@0 | 3764 | !IsLeftToSelectedTab(aFrame)); |
michael@0 | 3765 | |
michael@0 | 3766 | break; |
michael@0 | 3767 | } |
michael@0 | 3768 | case NS_THEME_TAB_PANELS: |
michael@0 | 3769 | ::DrawEdge(hdc, &widgetRect, EDGE_RAISED, BF_SOFT | BF_MIDDLE | |
michael@0 | 3770 | BF_LEFT | BF_RIGHT | BF_BOTTOM); |
michael@0 | 3771 | |
michael@0 | 3772 | break; |
michael@0 | 3773 | case NS_THEME_MENUBAR: |
michael@0 | 3774 | break; |
michael@0 | 3775 | case NS_THEME_MENUPOPUP: |
michael@0 | 3776 | NS_ASSERTION(nsUXThemeData::sFlatMenus, "Classic menus are styled entirely through CSS"); |
michael@0 | 3777 | ::FillRect(hdc, &widgetRect, (HBRUSH) (COLOR_MENU+1)); |
michael@0 | 3778 | ::FrameRect(hdc, &widgetRect, ::GetSysColorBrush(COLOR_BTNSHADOW)); |
michael@0 | 3779 | break; |
michael@0 | 3780 | case NS_THEME_MENUITEM: |
michael@0 | 3781 | case NS_THEME_CHECKMENUITEM: |
michael@0 | 3782 | case NS_THEME_RADIOMENUITEM: |
michael@0 | 3783 | // part == 0 for normal items |
michael@0 | 3784 | // part == 1 for top-level menu items |
michael@0 | 3785 | if (nsUXThemeData::sFlatMenus) { |
michael@0 | 3786 | // Not disabled and hot/pushed. |
michael@0 | 3787 | if ((state & (DFCS_HOT | DFCS_PUSHED)) != 0) { |
michael@0 | 3788 | ::FillRect(hdc, &widgetRect, (HBRUSH) (COLOR_MENUHILIGHT+1)); |
michael@0 | 3789 | ::FrameRect(hdc, &widgetRect, ::GetSysColorBrush(COLOR_HIGHLIGHT)); |
michael@0 | 3790 | } |
michael@0 | 3791 | } else { |
michael@0 | 3792 | if (part == 1) { |
michael@0 | 3793 | if ((state & DFCS_INACTIVE) == 0) { |
michael@0 | 3794 | if ((state & DFCS_PUSHED) != 0) { |
michael@0 | 3795 | ::DrawEdge(hdc, &widgetRect, BDR_SUNKENOUTER, BF_RECT); |
michael@0 | 3796 | } else if ((state & DFCS_HOT) != 0) { |
michael@0 | 3797 | ::DrawEdge(hdc, &widgetRect, BDR_RAISEDINNER, BF_RECT); |
michael@0 | 3798 | } |
michael@0 | 3799 | } |
michael@0 | 3800 | } else { |
michael@0 | 3801 | if ((state & (DFCS_HOT | DFCS_PUSHED)) != 0) { |
michael@0 | 3802 | ::FillRect(hdc, &widgetRect, (HBRUSH) (COLOR_HIGHLIGHT+1)); |
michael@0 | 3803 | } |
michael@0 | 3804 | } |
michael@0 | 3805 | } |
michael@0 | 3806 | break; |
michael@0 | 3807 | case NS_THEME_MENUCHECKBOX: |
michael@0 | 3808 | case NS_THEME_MENURADIO: |
michael@0 | 3809 | if (!(state & DFCS_CHECKED)) |
michael@0 | 3810 | break; // nothin' to do |
michael@0 | 3811 | case NS_THEME_MENUARROW: { |
michael@0 | 3812 | uint32_t color = COLOR_MENUTEXT; |
michael@0 | 3813 | if ((state & DFCS_INACTIVE)) |
michael@0 | 3814 | color = COLOR_GRAYTEXT; |
michael@0 | 3815 | else if ((state & DFCS_HOT)) |
michael@0 | 3816 | color = COLOR_HIGHLIGHTTEXT; |
michael@0 | 3817 | |
michael@0 | 3818 | if (aWidgetType == NS_THEME_MENUCHECKBOX) |
michael@0 | 3819 | DrawMenuImage(hdc, widgetRect, DFCS_MENUCHECK, color); |
michael@0 | 3820 | else if (aWidgetType == NS_THEME_MENURADIO) |
michael@0 | 3821 | DrawMenuImage(hdc, widgetRect, DFCS_MENUBULLET, color); |
michael@0 | 3822 | else if (aWidgetType == NS_THEME_MENUARROW) |
michael@0 | 3823 | DrawMenuImage(hdc, widgetRect, |
michael@0 | 3824 | (state & DFCS_RTL) ? DFCS_MENUARROWRIGHT : DFCS_MENUARROW, |
michael@0 | 3825 | color); |
michael@0 | 3826 | break; |
michael@0 | 3827 | } |
michael@0 | 3828 | case NS_THEME_MENUSEPARATOR: { |
michael@0 | 3829 | // separators are offset by a bit (see menu.css) |
michael@0 | 3830 | widgetRect.left++; |
michael@0 | 3831 | widgetRect.right--; |
michael@0 | 3832 | |
michael@0 | 3833 | // This magic number is brought to you by the value in menu.css |
michael@0 | 3834 | widgetRect.top += 4; |
michael@0 | 3835 | // Our rectangles are 1 pixel high (see border size in menu.css) |
michael@0 | 3836 | widgetRect.bottom = widgetRect.top+1; |
michael@0 | 3837 | ::FillRect(hdc, &widgetRect, (HBRUSH)(COLOR_3DSHADOW+1)); |
michael@0 | 3838 | widgetRect.top++; |
michael@0 | 3839 | widgetRect.bottom++; |
michael@0 | 3840 | ::FillRect(hdc, &widgetRect, (HBRUSH)(COLOR_3DHILIGHT+1)); |
michael@0 | 3841 | break; |
michael@0 | 3842 | } |
michael@0 | 3843 | |
michael@0 | 3844 | case NS_THEME_WINDOW_TITLEBAR: |
michael@0 | 3845 | case NS_THEME_WINDOW_TITLEBAR_MAXIMIZED: |
michael@0 | 3846 | { |
michael@0 | 3847 | RECT rect = widgetRect; |
michael@0 | 3848 | int32_t offset = GetSystemMetrics(SM_CXFRAME); |
michael@0 | 3849 | rect.bottom -= 1; |
michael@0 | 3850 | |
michael@0 | 3851 | // first fill the area to the color of the window background |
michael@0 | 3852 | FillRect(hdc, &rect, (HBRUSH)(COLOR_3DFACE+1)); |
michael@0 | 3853 | |
michael@0 | 3854 | // inset the caption area so it doesn't overflow. |
michael@0 | 3855 | rect.top += offset; |
michael@0 | 3856 | // if enabled, draw a gradient titlebar background, otherwise |
michael@0 | 3857 | // fill with a solid color. |
michael@0 | 3858 | BOOL bFlag = TRUE; |
michael@0 | 3859 | SystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, &bFlag, 0); |
michael@0 | 3860 | if (!bFlag) { |
michael@0 | 3861 | if (state == mozilla::widget::themeconst::FS_ACTIVE) |
michael@0 | 3862 | FillRect(hdc, &rect, (HBRUSH)(COLOR_ACTIVECAPTION+1)); |
michael@0 | 3863 | else |
michael@0 | 3864 | FillRect(hdc, &rect, (HBRUSH)(COLOR_INACTIVECAPTION+1)); |
michael@0 | 3865 | } else { |
michael@0 | 3866 | DWORD startColor, endColor; |
michael@0 | 3867 | if (state == mozilla::widget::themeconst::FS_ACTIVE) { |
michael@0 | 3868 | startColor = GetSysColor(COLOR_ACTIVECAPTION); |
michael@0 | 3869 | endColor = GetSysColor(COLOR_GRADIENTACTIVECAPTION); |
michael@0 | 3870 | } else { |
michael@0 | 3871 | startColor = GetSysColor(COLOR_INACTIVECAPTION); |
michael@0 | 3872 | endColor = GetSysColor(COLOR_GRADIENTINACTIVECAPTION); |
michael@0 | 3873 | } |
michael@0 | 3874 | |
michael@0 | 3875 | TRIVERTEX vertex[2]; |
michael@0 | 3876 | vertex[0].x = rect.left; |
michael@0 | 3877 | vertex[0].y = rect.top; |
michael@0 | 3878 | vertex[0].Red = GetRValue(startColor) << 8; |
michael@0 | 3879 | vertex[0].Green = GetGValue(startColor) << 8; |
michael@0 | 3880 | vertex[0].Blue = GetBValue(startColor) << 8; |
michael@0 | 3881 | vertex[0].Alpha = 0; |
michael@0 | 3882 | |
michael@0 | 3883 | vertex[1].x = rect.right; |
michael@0 | 3884 | vertex[1].y = rect.bottom; |
michael@0 | 3885 | vertex[1].Red = GetRValue(endColor) << 8; |
michael@0 | 3886 | vertex[1].Green = GetGValue(endColor) << 8; |
michael@0 | 3887 | vertex[1].Blue = GetBValue(endColor) << 8; |
michael@0 | 3888 | vertex[1].Alpha = 0; |
michael@0 | 3889 | |
michael@0 | 3890 | GRADIENT_RECT gRect; |
michael@0 | 3891 | gRect.UpperLeft = 0; |
michael@0 | 3892 | gRect.LowerRight = 1; |
michael@0 | 3893 | // available on win2k & up |
michael@0 | 3894 | GradientFill(hdc, vertex, 2, &gRect, 1, GRADIENT_FILL_RECT_H); |
michael@0 | 3895 | } |
michael@0 | 3896 | |
michael@0 | 3897 | if (aWidgetType == NS_THEME_WINDOW_TITLEBAR) { |
michael@0 | 3898 | // frame things up with a top raised border. |
michael@0 | 3899 | DrawEdge(hdc, &widgetRect, EDGE_RAISED, BF_TOP); |
michael@0 | 3900 | } |
michael@0 | 3901 | break; |
michael@0 | 3902 | } |
michael@0 | 3903 | |
michael@0 | 3904 | case NS_THEME_WINDOW_FRAME_LEFT: |
michael@0 | 3905 | DrawEdge(hdc, &widgetRect, EDGE_RAISED, BF_LEFT); |
michael@0 | 3906 | break; |
michael@0 | 3907 | |
michael@0 | 3908 | case NS_THEME_WINDOW_FRAME_RIGHT: |
michael@0 | 3909 | DrawEdge(hdc, &widgetRect, EDGE_RAISED, BF_RIGHT); |
michael@0 | 3910 | break; |
michael@0 | 3911 | |
michael@0 | 3912 | case NS_THEME_WINDOW_FRAME_BOTTOM: |
michael@0 | 3913 | DrawEdge(hdc, &widgetRect, EDGE_RAISED, BF_BOTTOM); |
michael@0 | 3914 | break; |
michael@0 | 3915 | |
michael@0 | 3916 | case NS_THEME_WINDOW_BUTTON_CLOSE: |
michael@0 | 3917 | case NS_THEME_WINDOW_BUTTON_MINIMIZE: |
michael@0 | 3918 | case NS_THEME_WINDOW_BUTTON_MAXIMIZE: |
michael@0 | 3919 | case NS_THEME_WINDOW_BUTTON_RESTORE: |
michael@0 | 3920 | { |
michael@0 | 3921 | if (aWidgetType == NS_THEME_WINDOW_BUTTON_MINIMIZE) { |
michael@0 | 3922 | OffsetBackgroundRect(widgetRect, CAPTIONBUTTON_MINIMIZE); |
michael@0 | 3923 | } |
michael@0 | 3924 | else if (aWidgetType == NS_THEME_WINDOW_BUTTON_MAXIMIZE || |
michael@0 | 3925 | aWidgetType == NS_THEME_WINDOW_BUTTON_RESTORE) { |
michael@0 | 3926 | OffsetBackgroundRect(widgetRect, CAPTIONBUTTON_RESTORE); |
michael@0 | 3927 | } |
michael@0 | 3928 | else if (aWidgetType == NS_THEME_WINDOW_BUTTON_CLOSE) { |
michael@0 | 3929 | OffsetBackgroundRect(widgetRect, CAPTIONBUTTON_CLOSE); |
michael@0 | 3930 | } |
michael@0 | 3931 | int32_t oldTA = SetTextAlign(hdc, TA_TOP | TA_LEFT | TA_NOUPDATECP); |
michael@0 | 3932 | DrawFrameControl(hdc, &widgetRect, part, state); |
michael@0 | 3933 | SetTextAlign(hdc, oldTA); |
michael@0 | 3934 | break; |
michael@0 | 3935 | } |
michael@0 | 3936 | |
michael@0 | 3937 | default: |
michael@0 | 3938 | rv = NS_ERROR_FAILURE; |
michael@0 | 3939 | break; |
michael@0 | 3940 | } |
michael@0 | 3941 | |
michael@0 | 3942 | nativeDrawing.EndNativeDrawing(); |
michael@0 | 3943 | |
michael@0 | 3944 | if (NS_FAILED(rv)) |
michael@0 | 3945 | return rv; |
michael@0 | 3946 | |
michael@0 | 3947 | if (nativeDrawing.ShouldRenderAgain()) |
michael@0 | 3948 | goto RENDER_AGAIN; |
michael@0 | 3949 | |
michael@0 | 3950 | nativeDrawing.PaintToContext(); |
michael@0 | 3951 | |
michael@0 | 3952 | return rv; |
michael@0 | 3953 | } |
michael@0 | 3954 | |
michael@0 | 3955 | uint32_t |
michael@0 | 3956 | nsNativeThemeWin::GetWidgetNativeDrawingFlags(uint8_t aWidgetType) |
michael@0 | 3957 | { |
michael@0 | 3958 | switch (aWidgetType) { |
michael@0 | 3959 | case NS_THEME_BUTTON: |
michael@0 | 3960 | case NS_THEME_NUMBER_INPUT: |
michael@0 | 3961 | case NS_THEME_TEXTFIELD: |
michael@0 | 3962 | case NS_THEME_TEXTFIELD_MULTILINE: |
michael@0 | 3963 | |
michael@0 | 3964 | case NS_THEME_DROPDOWN: |
michael@0 | 3965 | case NS_THEME_DROPDOWN_TEXTFIELD: |
michael@0 | 3966 | return |
michael@0 | 3967 | gfxWindowsNativeDrawing::CANNOT_DRAW_TO_COLOR_ALPHA | |
michael@0 | 3968 | gfxWindowsNativeDrawing::CAN_AXIS_ALIGNED_SCALE | |
michael@0 | 3969 | gfxWindowsNativeDrawing::CANNOT_COMPLEX_TRANSFORM; |
michael@0 | 3970 | |
michael@0 | 3971 | // need to check these others |
michael@0 | 3972 | case NS_THEME_RANGE: |
michael@0 | 3973 | case NS_THEME_RANGE_THUMB: |
michael@0 | 3974 | case NS_THEME_SCROLLBAR_BUTTON_UP: |
michael@0 | 3975 | case NS_THEME_SCROLLBAR_BUTTON_DOWN: |
michael@0 | 3976 | case NS_THEME_SCROLLBAR_BUTTON_LEFT: |
michael@0 | 3977 | case NS_THEME_SCROLLBAR_BUTTON_RIGHT: |
michael@0 | 3978 | case NS_THEME_SCROLLBAR_THUMB_VERTICAL: |
michael@0 | 3979 | case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL: |
michael@0 | 3980 | case NS_THEME_SCROLLBAR_TRACK_VERTICAL: |
michael@0 | 3981 | case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL: |
michael@0 | 3982 | case NS_THEME_SCALE_HORIZONTAL: |
michael@0 | 3983 | case NS_THEME_SCALE_VERTICAL: |
michael@0 | 3984 | case NS_THEME_SCALE_THUMB_HORIZONTAL: |
michael@0 | 3985 | case NS_THEME_SCALE_THUMB_VERTICAL: |
michael@0 | 3986 | case NS_THEME_SPINNER_UP_BUTTON: |
michael@0 | 3987 | case NS_THEME_SPINNER_DOWN_BUTTON: |
michael@0 | 3988 | case NS_THEME_LISTBOX: |
michael@0 | 3989 | case NS_THEME_TREEVIEW: |
michael@0 | 3990 | case NS_THEME_TOOLTIP: |
michael@0 | 3991 | case NS_THEME_STATUSBAR: |
michael@0 | 3992 | case NS_THEME_STATUSBAR_PANEL: |
michael@0 | 3993 | case NS_THEME_STATUSBAR_RESIZER_PANEL: |
michael@0 | 3994 | case NS_THEME_RESIZER: |
michael@0 | 3995 | case NS_THEME_PROGRESSBAR: |
michael@0 | 3996 | case NS_THEME_PROGRESSBAR_VERTICAL: |
michael@0 | 3997 | case NS_THEME_PROGRESSBAR_CHUNK: |
michael@0 | 3998 | case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL: |
michael@0 | 3999 | case NS_THEME_TAB: |
michael@0 | 4000 | case NS_THEME_TAB_PANEL: |
michael@0 | 4001 | case NS_THEME_TAB_PANELS: |
michael@0 | 4002 | case NS_THEME_MENUBAR: |
michael@0 | 4003 | case NS_THEME_MENUPOPUP: |
michael@0 | 4004 | case NS_THEME_MENUITEM: |
michael@0 | 4005 | break; |
michael@0 | 4006 | |
michael@0 | 4007 | // the dropdown button /almost/ renders correctly with scaling, |
michael@0 | 4008 | // except that the graphic in the dropdown button (the downward arrow) |
michael@0 | 4009 | // doesn't get scaled up. |
michael@0 | 4010 | case NS_THEME_DROPDOWN_BUTTON: |
michael@0 | 4011 | // these are definitely no; they're all graphics that don't get scaled up |
michael@0 | 4012 | case NS_THEME_CHECKBOX: |
michael@0 | 4013 | case NS_THEME_RADIO: |
michael@0 | 4014 | case NS_THEME_GROUPBOX: |
michael@0 | 4015 | case NS_THEME_CHECKMENUITEM: |
michael@0 | 4016 | case NS_THEME_RADIOMENUITEM: |
michael@0 | 4017 | case NS_THEME_MENUCHECKBOX: |
michael@0 | 4018 | case NS_THEME_MENURADIO: |
michael@0 | 4019 | case NS_THEME_MENUARROW: |
michael@0 | 4020 | return |
michael@0 | 4021 | gfxWindowsNativeDrawing::CANNOT_DRAW_TO_COLOR_ALPHA | |
michael@0 | 4022 | gfxWindowsNativeDrawing::CANNOT_AXIS_ALIGNED_SCALE | |
michael@0 | 4023 | gfxWindowsNativeDrawing::CANNOT_COMPLEX_TRANSFORM; |
michael@0 | 4024 | } |
michael@0 | 4025 | |
michael@0 | 4026 | return |
michael@0 | 4027 | gfxWindowsNativeDrawing::CANNOT_DRAW_TO_COLOR_ALPHA | |
michael@0 | 4028 | gfxWindowsNativeDrawing::CANNOT_AXIS_ALIGNED_SCALE | |
michael@0 | 4029 | gfxWindowsNativeDrawing::CANNOT_COMPLEX_TRANSFORM; |
michael@0 | 4030 | } |
michael@0 | 4031 | |
michael@0 | 4032 | /////////////////////////////////////////// |
michael@0 | 4033 | // Creation Routine |
michael@0 | 4034 | /////////////////////////////////////////// |
michael@0 | 4035 | |
michael@0 | 4036 | // from nsWindow.cpp |
michael@0 | 4037 | extern bool gDisableNativeTheme; |
michael@0 | 4038 | |
michael@0 | 4039 | nsresult NS_NewNativeTheme(nsISupports *aOuter, REFNSIID aIID, void **aResult) |
michael@0 | 4040 | { |
michael@0 | 4041 | if (gDisableNativeTheme) |
michael@0 | 4042 | return NS_ERROR_NO_INTERFACE; |
michael@0 | 4043 | |
michael@0 | 4044 | if (aOuter) |
michael@0 | 4045 | return NS_ERROR_NO_AGGREGATION; |
michael@0 | 4046 | |
michael@0 | 4047 | nsNativeThemeWin* theme = new nsNativeThemeWin(); |
michael@0 | 4048 | if (!theme) |
michael@0 | 4049 | return NS_ERROR_OUT_OF_MEMORY; |
michael@0 | 4050 | return theme->QueryInterface(aIID, aResult); |
michael@0 | 4051 | } |