bump product version to 6.4.0.3
[LibreOffice.git] / vcl / osx / salnativewidgets.cxx
blob5248251480c5e97fe080ba7d45df95e0cfd4e005
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_features.h>
22 #include <vcl/salnativewidgets.hxx>
23 #include <vcl/decoview.hxx>
24 #include <vcl/svapp.hxx>
25 #include <vcl/timer.hxx>
26 #include <vcl/settings.hxx>
28 #include <quartz/salgdi.h>
29 #include <osx/salnativewidgets.h>
30 #include <osx/saldata.hxx>
31 #include <osx/salframe.h>
33 #include <premac.h>
34 #include <Carbon/Carbon.h>
35 #include <postmac.h>
37 #include "cuidraw.hxx"
39 // presentation of native widgets consists of two important methods:
41 // AquaSalGraphics::getNativeControlRegion to determine native rectangle in pixels to draw the widget
42 // AquaSalGraphics::drawNativeControl to do the drawing operation itself
44 // getNativeControlRegion has to calculate a content rectangle within it is safe to draw the widget. Furthermore a boundig rectangle
45 // has to be calculated by getNativeControlRegion to consider adornments like a focus rectangle. As drawNativeControl uses Carbon
46 // API calls, all widgets are drawn without text. Drawing of text is done separately by VCL on top of graphical Carbon widget
47 // representation. drawNativeControl is called by VCL using content rectangle determined by getNativeControlRegion.
49 // FIXME: when calculation bounding rectangle larger then content rectangle, text displayed by VCL will become misaligned. To avoid
50 // misalignment bounding rectangle and content rectangle are calculated equally including adornments. Reduction of size for content
51 // is done by drawNativeControl subsequently. Only exception is editbox: As other widgets have distinct ControlPart::SubEdit control
52 // parts, editbox bounding rectangle and content rectangle are both calculated to reflect content area. Extending size for
53 // adornments is done by drawNativeControl subsequently.
55 #if !HAVE_FEATURE_MACOSX_SANDBOX
57 @interface NSWindow(CoreUIRendererPrivate)
58 + (CUIRendererRef)coreUIRenderer;
59 @end
61 #endif
63 static HIRect ImplGetHIRectFromRectangle(tools::Rectangle aRect)
65 HIRect aHIRect;
66 aHIRect.origin.x = static_cast<float>(aRect.Left());
67 aHIRect.origin.y = static_cast<float>(aRect.Top());
68 aHIRect.size.width = static_cast<float>(aRect.GetWidth());
69 aHIRect.size.height = static_cast<float>(aRect.GetHeight());
70 return aHIRect;
73 static ThemeButtonValue ImplGetButtonValue(ButtonValue aButtonValue)
75 switch (aButtonValue)
77 case ButtonValue::On:
78 return kThemeButtonOn;
79 break;
80 case ButtonValue::Off:
81 case ButtonValue::DontKnow:
82 return kThemeButtonOff;
83 break;
84 case ButtonValue::Mixed:
85 default:
86 return kThemeButtonMixed;
87 break;
91 static bool AquaGetScrollRect(/* TODO: int nScreen, */
92 ControlPart nPart, const tools::Rectangle &rControlRect, tools::Rectangle &rResultRect)
94 bool bRetVal = true;
95 rResultRect = rControlRect;
96 switch (nPart)
98 case ControlPart::ButtonUp:
99 rResultRect.SetBottom(rResultRect.Top());
100 break;
101 case ControlPart::ButtonDown:
102 rResultRect.SetTop(rResultRect.Bottom());
103 break;
104 case ControlPart::ButtonLeft:
105 rResultRect.SetRight(rResultRect.Left());
106 break;
107 case ControlPart::ButtonRight:
108 rResultRect.SetLeft(rResultRect.Right());
109 break;
110 case ControlPart::TrackHorzArea:
111 case ControlPart::TrackVertArea:
112 case ControlPart::ThumbHorz:
113 case ControlPart::ThumbVert:
114 case ControlPart::TrackHorzLeft:
115 case ControlPart::TrackHorzRight:
116 case ControlPart::TrackVertUpper:
117 case ControlPart::TrackVertLower:
118 break;
119 default:
120 bRetVal = false;
122 return bRetVal;
125 bool AquaSalGraphics::isNativeControlSupported(ControlType nType, ControlPart nPart)
127 // native controls are now defaults. If you want to disable native controls, set the environment variable SAL_NO_NWF to
128 // something and VCL controls will be used as default again.
130 switch (nType)
132 case ControlType::Pushbutton:
133 case ControlType::Radiobutton:
134 case ControlType::Checkbox:
135 case ControlType::ListNode:
136 if (nPart == ControlPart::Entire)
137 return true;
138 break;
139 case ControlType::Scrollbar:
140 if (nPart == ControlPart::DrawBackgroundHorz || nPart == ControlPart::DrawBackgroundVert
141 || nPart == ControlPart::Entire || nPart == ControlPart::HasThreeButtons)
142 return true;
143 break;
144 case ControlType::Slider:
145 if (nPart == ControlPart::TrackHorzArea || nPart == ControlPart::TrackVertArea)
146 return true;
147 break;
148 case ControlType::Editbox:
149 if (nPart == ControlPart::Entire || nPart == ControlPart::HasBackgroundTexture)
150 return true;
151 break;
152 case ControlType::MultilineEditbox:
153 if (nPart == ControlPart::Entire || nPart == ControlPart::HasBackgroundTexture)
154 return true;
155 break;
156 case ControlType::Spinbox:
157 if (nPart == ControlPart::Entire || nPart == ControlPart::AllButtons || nPart == ControlPart::HasBackgroundTexture)
158 return true;
159 break;
160 case ControlType::SpinButtons:
161 return false;
162 break;
163 case ControlType::Combobox:
164 if (nPart == ControlPart::Entire || nPart == ControlPart::HasBackgroundTexture)
165 return true;
166 break;
167 case ControlType::Listbox:
168 if (nPart == ControlPart::Entire || nPart == ControlPart::ListboxWindow || nPart == ControlPart::HasBackgroundTexture
169 || nPart == ControlPart::SubEdit)
170 return true;
171 break;
172 case ControlType::TabItem:
173 case ControlType::TabPane:
174 case ControlType::TabBody:
175 if (nPart == ControlPart::Entire || nPart == ControlPart::TabsDrawRtl || nPart == ControlPart::HasBackgroundTexture)
176 return true;
177 break;
178 case ControlType::Toolbar:
179 if (nPart == ControlPart::Entire || nPart == ControlPart::DrawBackgroundHorz
180 || nPart == ControlPart::DrawBackgroundVert)
181 return true;
182 break;
183 case ControlType::WindowBackground:
184 if (nPart == ControlPart::BackgroundWindow || nPart == ControlPart::BackgroundDialog)
185 return true;
186 break;
187 case ControlType::Menubar:
188 if (nPart == ControlPart::Entire)
189 return true;
190 break;
191 case ControlType::Tooltip:
192 if (nPart == ControlPart::Entire)
193 return true;
194 break;
195 case ControlType::MenuPopup:
196 if (nPart == ControlPart::Entire || nPart == ControlPart::MenuItem || nPart == ControlPart::MenuItemCheckMark
197 || nPart == ControlPart::MenuItemRadioMark)
198 return true;
199 break;
200 case ControlType::Progress:
201 case ControlType::IntroProgress:
202 if (nPart == ControlPart::Entire)
203 return true;
204 break;
205 case ControlType::Frame:
206 if (nPart == ControlPart::Border)
207 return true;
208 break;
209 case ControlType::ListNet:
210 if (nPart == ControlPart::Entire)
211 return true;
212 break;
213 default:
214 break;
216 return false;
219 bool AquaSalGraphics::hitTestNativeControl(ControlType nType, ControlPart nPart, const tools::Rectangle &rControlRegion,
220 const Point &rPos, bool& rIsInside)
222 if (nType == ControlType::Scrollbar)
224 tools::Rectangle aRect;
225 bool bValid = AquaGetScrollRect(/* TODO: int nScreen, */
226 nPart, rControlRegion, aRect);
227 rIsInside = bValid && aRect.IsInside(rPos);
228 return bValid;
230 return false;
233 UInt32 AquaSalGraphics::getState(ControlState nState)
235 const bool bDrawActive = mpFrame == nullptr || [mpFrame->getNSWindow() isKeyWindow];
236 if (!(nState & ControlState::ENABLED) || !bDrawActive)
238 return kThemeStateInactive;
240 if (nState & ControlState::PRESSED)
241 return kThemeStatePressed;
242 return kThemeStateActive;
245 UInt32 AquaSalGraphics::getTrackState(ControlState nState)
247 const bool bDrawActive = mpFrame == nullptr || [mpFrame->getNSWindow() isKeyWindow];
248 if (!(nState & ControlState::ENABLED) || !bDrawActive)
249 return kThemeTrackInactive;
250 return kThemeTrackActive;
253 bool AquaSalGraphics::drawNativeControl(ControlType nType,
254 ControlPart nPart,
255 const tools::Rectangle &rControlRegion,
256 ControlState nState,
257 const ImplControlValue &aValue,
258 const OUString &)
260 bool bOK = false;
261 if (!CheckContext())
262 return false;
263 maContextHolder.saveState();
264 tools::Rectangle buttonRect = rControlRegion;
265 HIRect rc = ImplGetHIRectFromRectangle(buttonRect);
266 switch (nType)
268 case ControlType::Toolbar:
270 #if HAVE_FEATURE_MACOSX_SANDBOX
271 HIThemeMenuItemDrawInfo aMenuItemDrawInfo;
272 aMenuItemDrawInfo.version = 0;
273 aMenuItemDrawInfo.state = kThemeMenuActive;
274 aMenuItemDrawInfo.itemType = kThemeMenuItemHierBackground;
275 HIThemeDrawMenuItem(&rc, &rc, &aMenuItemDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
276 #else
277 if (rControlRegion.Top() == 0 && nPart == ControlPart::DrawBackgroundHorz)
279 const bool bDrawActive = mpFrame == nullptr || [mpFrame->getNSWindow() isKeyWindow];
280 CGFloat unifiedHeight = rControlRegion.GetHeight();
281 CGRect drawRect = CGRectMake(rControlRegion.Left(), rControlRegion.Top(),
282 rControlRegion.GetWidth(), rControlRegion.GetHeight());
283 CUIDraw([NSWindow coreUIRenderer], drawRect, maContextHolder.get(),
284 reinterpret_cast<CFDictionaryRef>([NSDictionary dictionaryWithObjectsAndKeys:
285 @"kCUIWidgetWindowFrame",
286 @"widget",
287 @"regularwin",
288 @"windowtype",
289 (bDrawActive ? @"normal" : @"inactive"),
290 @"state",
291 [NSNumber numberWithDouble:unifiedHeight],
292 @"kCUIWindowFrameUnifiedTitleBarHeightKey",
293 [NSNumber numberWithBool:NO],
294 @"kCUIWindowFrameDrawTitleSeparatorKey",
295 [NSNumber numberWithBool:YES],
296 @"is.flipped",
297 nil]),
298 nil);
300 else
302 HIThemeMenuItemDrawInfo aMenuItemDrawInfo;
303 aMenuItemDrawInfo.version = 0;
304 aMenuItemDrawInfo.state = kThemeMenuActive;
305 aMenuItemDrawInfo.itemType = kThemeMenuItemHierBackground;
306 HIThemeDrawMenuItem(&rc, &rc, &aMenuItemDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
308 #endif
309 bOK = true;
311 break;
312 case ControlType::WindowBackground:
314 HIThemeBackgroundDrawInfo aThemeBackgroundInfo;
315 aThemeBackgroundInfo.version = 0;
316 aThemeBackgroundInfo.state = getState(nState);
317 aThemeBackgroundInfo.kind = kThemeBrushDialogBackgroundActive;
319 // FIXME: without this magical offset there is a 2 pixel black border on the right and bottom
321 rc.size.width += 2;
322 rc.size.height += 2;
323 HIThemeApplyBackground( &rc, &aThemeBackgroundInfo, maContextHolder.get(), kHIThemeOrientationNormal);
324 CGContextFillRect(maContextHolder.get(), rc);
325 bOK = true;
327 break;
328 case ControlType::Tooltip:
330 HIThemeBackgroundDrawInfo aThemeBackgroundInfo;
331 aThemeBackgroundInfo.version = 0;
332 aThemeBackgroundInfo.state = getState(nState);
333 aThemeBackgroundInfo.kind = kThemeBrushAlertBackgroundActive;
334 rc.size.width += 2;
335 rc.size.height += 2;
336 HIThemeApplyBackground(&rc, &aThemeBackgroundInfo, maContextHolder.get(), kHIThemeOrientationNormal);
337 CGContextFillRect(maContextHolder.get(), rc);
338 bOK = true;
340 break;
341 case ControlType::Menubar:
342 case ControlType::MenuPopup:
343 if (nPart == ControlPart::Entire || nPart == ControlPart::MenuItem || nPart == ControlPart::HasBackgroundTexture)
346 // FIXME: without this magical offset there is a 2 pixel black border on the right
348 rc.size.width += 2;
349 HIThemeMenuDrawInfo aMenuInfo;
350 aMenuInfo.version = 0;
351 aMenuInfo.menuType = kThemeMenuTypePullDown;
352 HIThemeMenuItemDrawInfo aMenuItemDrawInfo;
354 // grey theme when the item is selected is drawn here.
356 aMenuItemDrawInfo.itemType = kThemeMenuItemPlain;
357 if ((nPart == ControlPart::MenuItem) && (nState & ControlState::SELECTED))
359 // blue theme when the item is selected is drawn here.
361 aMenuItemDrawInfo.state = kThemeMenuSelected;
362 else
364 // normal color for non selected item
366 aMenuItemDrawInfo.state = kThemeMenuActive;
368 // repaints the background of the pull down menu
370 HIThemeDrawMenuBackground(&rc, &aMenuInfo,maContextHolder.get(), kHIThemeOrientationNormal);
372 // repaints the item either blue (selected) and/or grey (active only)
374 HIThemeDrawMenuItem(&rc, &rc, &aMenuItemDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal, &rc);
375 bOK = true;
377 else if (nPart == ControlPart::MenuItemCheckMark || nPart == ControlPart::MenuItemRadioMark)
380 // checked, else it is not displayed (see vcl/source/window/menu.cxx)
382 if (nState & ControlState::PRESSED)
384 HIThemeTextInfo aTextInfo;
385 aTextInfo.version = 0;
386 aTextInfo.state = (nState & ControlState::ENABLED) ? kThemeStateInactive: kThemeStateActive;
387 aTextInfo.fontID = kThemeMenuItemMarkFont;
388 aTextInfo.horizontalFlushness = kHIThemeTextHorizontalFlushCenter;
389 aTextInfo.verticalFlushness = kHIThemeTextVerticalFlushTop;
390 aTextInfo.options = kHIThemeTextBoxOptionNone;
391 aTextInfo.truncationPosition = kHIThemeTextTruncationNone;
393 // aTextInfo.truncationMaxLines unused because of kHIThemeTextTruncationNone item highlighted
395 if (nState & ControlState::SELECTED) aTextInfo.state = kThemeStatePressed;
396 UniChar mark=(nPart == ControlPart::MenuItemCheckMark) ? kCheckUnicode: kBulletUnicode;
397 CFStringRef cfString = CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, &mark, 1, kCFAllocatorNull);
398 HIThemeDrawTextBox(cfString, &rc, &aTextInfo, maContextHolder.get(), kHIThemeOrientationNormal);
399 if (cfString)
400 CFRelease(cfString);
401 bOK = true;
404 break;
405 case ControlType::Pushbutton:
408 // FIXME: instead of use a value, VCL can retrieve correct values on the fly (to be implemented)
410 HIThemeButtonDrawInfo aPushInfo;
411 aPushInfo.version = 0;
413 // no animation
415 aPushInfo.animation.time.start = 0;
416 aPushInfo.animation.time.current = 0;
417 PushButtonValue const *pPBVal = aValue.getType() == ControlType::Pushbutton ?
418 static_cast<PushButtonValue const *>(&aValue) : nullptr;
419 int nPaintHeight = static_cast<int>(rc.size.height);
420 if (pPBVal && pPBVal->mbBevelButton)
422 aPushInfo.kind = kThemeRoundedBevelButton;
424 else if (rc.size.height <= PUSH_BUTTON_NORMAL_HEIGHT)
426 aPushInfo.kind = kThemePushButtonMini;
427 nPaintHeight = PUSH_BUTTON_SMALL_HEIGHT;
429 else if ((pPBVal && pPBVal->mbSingleLine) || rc.size.height < PUSH_BUTTON_NORMAL_HEIGHT * 3 / 2)
431 aPushInfo.kind = kThemePushButtonNormal;
432 nPaintHeight = PUSH_BUTTON_NORMAL_HEIGHT;
434 // avoid clipping when focused
436 rc.origin.x += FOCUS_RING_WIDTH / 2;
437 rc.size.width -= FOCUS_RING_WIDTH;
439 else
440 aPushInfo.kind = kThemeBevelButton;
442 // translate the origin for controls with fixed paint height so content ends up somewhere sensible
444 rc.origin.y += (rc.size.height - nPaintHeight) / 2;
445 aPushInfo.state = getState(nState);
446 aPushInfo.value = ImplGetButtonValue(aValue.getTristateVal());
447 aPushInfo.adornment = (nState & ControlState::DEFAULT) ? kThemeAdornmentDefault : kThemeAdornmentNone;
448 if (nState & ControlState::FOCUSED)
449 aPushInfo.adornment |= kThemeAdornmentFocus;
450 HIThemeDrawButton(&rc, &aPushInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
451 bOK = true;
453 break;
454 case ControlType::Radiobutton:
455 case ControlType::Checkbox:
457 HIThemeButtonDrawInfo aInfo;
458 aInfo.version = 0;
459 switch (nType)
461 case ControlType::Radiobutton:
462 if (rc.size.width >= RADIO_BUTTON_SMALL_SIZE)
463 aInfo.kind = kThemeRadioButton;
464 else
465 aInfo.kind = kThemeSmallRadioButton;
466 break;
467 case ControlType::Checkbox:
468 if (rc.size.width >= CHECKBOX_SMALL_SIZE)
469 aInfo.kind = kThemeCheckBox;
470 else
471 aInfo.kind = kThemeSmallCheckBox;
472 break;
473 default:
474 break;
476 aInfo.state = getState(nState);
477 ButtonValue aButtonValue = aValue.getTristateVal();
478 aInfo.value = ImplGetButtonValue(aButtonValue);
479 aInfo.adornment = (nState & ControlState::DEFAULT) ? kThemeAdornmentDefault : kThemeAdornmentNone;
480 if (nState & ControlState::FOCUSED)
481 aInfo.adornment |= kThemeAdornmentFocus;
482 rc.size.width -= 2 * FOCUS_RING_WIDTH;
483 rc.size.height = RADIO_BUTTON_SMALL_SIZE;
484 rc.origin.x += FOCUS_RING_WIDTH;
485 rc.origin.y += FOCUS_RING_WIDTH;
486 HIThemeDrawButton(&rc, &aInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
487 bOK = true;
489 break;
490 case ControlType::ListNode:
492 ButtonValue aButtonValue = aValue.getTristateVal();
493 HIThemeButtonDrawInfo aInfo;
494 aInfo.version = 0;
495 aInfo.kind = kThemeDisclosureTriangle;
496 aInfo.value = kThemeDisclosureRight;
497 aInfo.state = getState(nState);
498 aInfo.adornment = kThemeAdornmentNone;
499 switch (aButtonValue)
501 case ButtonValue::On:
502 aInfo.value = kThemeDisclosureDown;
503 break;
504 case ButtonValue::Off:
505 if (AllSettings::GetLayoutRTL())
506 aInfo.value = kThemeDisclosureLeft;
507 break;
508 case ButtonValue::DontKnow:
509 default:
510 break;
512 HIThemeDrawButton(&rc, &aInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
513 bOK = true;
515 break;
516 case ControlType::Progress:
517 case ControlType::IntroProgress:
519 long nProgressWidth = aValue.getNumericVal();
520 HIThemeTrackDrawInfo aTrackInfo;
521 aTrackInfo.version = 0;
522 aTrackInfo.kind = (rc.size.height > 10) ? kThemeProgressBarLarge : kThemeProgressBarMedium;
523 aTrackInfo.bounds = rc;
524 aTrackInfo.min = 0;
525 aTrackInfo.max = static_cast<SInt32>(rc.size.width);
526 aTrackInfo.value = nProgressWidth;
527 aTrackInfo.reserved = 0;
528 aTrackInfo.attributes = kThemeTrackHorizontal;
529 if (AllSettings::GetLayoutRTL())
530 aTrackInfo.attributes |= kThemeTrackRightToLeft;
531 aTrackInfo.enableState = getTrackState(nState);
533 // the intro bitmap never gets key anyway; we want to draw that enabled
535 if (nType == ControlType::IntroProgress)
536 aTrackInfo.enableState = kThemeTrackActive;
537 aTrackInfo.filler1 = 0;
538 aTrackInfo.trackInfo.progress.phase = static_cast<long long>(CFAbsoluteTimeGetCurrent() * 10.0);
539 HIThemeDrawTrack(&aTrackInfo, nullptr, maContextHolder.get(), kHIThemeOrientationNormal);
540 bOK = true;
542 break;
543 case ControlType::Slider:
545 const SliderValue *pSliderVal = static_cast<SliderValue const *>(&aValue);
546 HIThemeTrackDrawInfo aTrackDraw;
547 aTrackDraw.kind = kThemeSliderMedium;
548 if (nPart == ControlPart::TrackHorzArea || nPart == ControlPart::TrackVertArea)
550 aTrackDraw.bounds = rc;
551 aTrackDraw.min = pSliderVal->mnMin;
552 aTrackDraw.max = pSliderVal->mnMax;
553 aTrackDraw.value = pSliderVal->mnCur;
554 aTrackDraw.reserved = 0;
555 aTrackDraw.attributes = kThemeTrackShowThumb;
556 if (nPart == ControlPart::TrackHorzArea)
557 aTrackDraw.attributes |= kThemeTrackHorizontal;
558 aTrackDraw.enableState = (nState & ControlState::ENABLED) ? kThemeTrackActive : kThemeTrackInactive;
559 SliderTrackInfo aSlideInfo;
560 aSlideInfo.thumbDir = kThemeThumbUpward;
561 aSlideInfo.pressState = 0;
562 aTrackDraw.trackInfo.slider = aSlideInfo;
563 HIThemeDrawTrack(&aTrackDraw, nullptr, maContextHolder.get(), kHIThemeOrientationNormal);
564 bOK = true;
567 break;
568 case ControlType::Scrollbar:
570 const ScrollbarValue *pScrollbarVal = (aValue.getType() == ControlType::Scrollbar)
571 ? static_cast<const ScrollbarValue *>(&aValue) : nullptr;
572 if (nPart == ControlPart::DrawBackgroundVert || nPart == ControlPart::DrawBackgroundHorz)
574 HIThemeTrackDrawInfo aTrackDraw;
575 aTrackDraw.kind = kThemeMediumScrollBar;
576 aTrackDraw.bounds = rc;
577 aTrackDraw.min = pScrollbarVal->mnMin;
578 aTrackDraw.max = pScrollbarVal->mnMax - pScrollbarVal->mnVisibleSize;
579 aTrackDraw.value = pScrollbarVal->mnCur;
580 aTrackDraw.reserved = 0;
581 aTrackDraw.attributes = kThemeTrackShowThumb;
582 if (nPart == ControlPart::DrawBackgroundHorz)
583 aTrackDraw.attributes |= kThemeTrackHorizontal;
584 aTrackDraw.enableState = getTrackState(nState);
585 ScrollBarTrackInfo aScrollInfo;
586 aScrollInfo.viewsize = pScrollbarVal->mnVisibleSize;
587 aScrollInfo.pressState = 0;
588 if (pScrollbarVal->mnButton1State & ControlState::ENABLED)
589 if (pScrollbarVal->mnButton1State & ControlState::PRESSED)
590 aScrollInfo.pressState = kThemeTopOutsideArrowPressed;
591 if (pScrollbarVal->mnButton2State & ControlState::ENABLED )
592 if (pScrollbarVal->mnButton2State & ControlState::PRESSED )
593 aScrollInfo.pressState = kThemeBottomOutsideArrowPressed;
594 if ( pScrollbarVal->mnThumbState & ControlState::ENABLED)
595 if (pScrollbarVal->mnThumbState & ControlState::PRESSED)
596 aScrollInfo.pressState = kThemeThumbPressed;
597 aTrackDraw.trackInfo.scrollbar = aScrollInfo;
598 HIThemeDrawTrack(&aTrackDraw, nullptr, maContextHolder.get(), kHIThemeOrientationNormal);
599 bOK = true;
602 break;
603 case ControlType::TabPane:
605 HIThemeTabPaneDrawInfo aTabPaneDrawInfo;
606 aTabPaneDrawInfo.version = 1;
607 aTabPaneDrawInfo.state = kThemeStateActive;
608 aTabPaneDrawInfo.direction = kThemeTabNorth;
609 aTabPaneDrawInfo.size = kHIThemeTabSizeNormal;
610 aTabPaneDrawInfo.kind = kHIThemeTabKindNormal;
612 // border is outside the rect rc for Carbon but for VCL it should be inside
614 rc.origin.x += 1;
615 rc.origin.y -= TAB_HEIGHT / 2;
616 rc.size.height += TAB_HEIGHT / 2;
617 rc.size.width -= 2;
618 HIThemeDrawTabPane(&rc, &aTabPaneDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal);
619 bOK = true;
621 break;
622 case ControlType::TabItem:
624 HIThemeTabDrawInfo aTabItemDrawInfo;
625 aTabItemDrawInfo.version = 1;
626 aTabItemDrawInfo.style = kThemeTabNonFront;
627 aTabItemDrawInfo.direction = kThemeTabNorth;
628 aTabItemDrawInfo.size = kHIThemeTabSizeNormal;
629 aTabItemDrawInfo.adornment = kHIThemeTabAdornmentTrailingSeparator;
630 if (nState & ControlState::SELECTED)
631 aTabItemDrawInfo.style = kThemeTabFront;
632 if(nState & ControlState::FOCUSED)
633 aTabItemDrawInfo.adornment |= kHIThemeTabAdornmentFocus;
635 // first, last or middle tab
637 aTabItemDrawInfo.position = kHIThemeTabPositionMiddle;
638 TabitemValue const * pTabValue = static_cast<TabitemValue const *>(&aValue);
639 TabitemFlags nAlignment = pTabValue->mnAlignment;
641 // TabitemFlags::LeftAligned (and TabitemFlags::RightAligned) for the leftmost (or rightmost) tab
642 // when there are several lines of tabs because there is only one first tab and one
643 // last tab and TabitemFlags::FirstInGroup (and TabitemFlags::LastInGroup) because when the
644 // line width is different from window width, there may not be TabitemFlags::RightAligned
646 if (((nAlignment & TabitemFlags::LeftAligned) && (nAlignment & TabitemFlags::RightAligned))
647 || ((nAlignment & TabitemFlags::FirstInGroup) && (nAlignment & TabitemFlags::LastInGroup)))
648 aTabItemDrawInfo.position = kHIThemeTabPositionOnly;
649 else if ((nAlignment & TabitemFlags::LeftAligned) || (nAlignment & TabitemFlags::FirstInGroup))
650 aTabItemDrawInfo.position = kHIThemeTabPositionFirst;
651 else if ((nAlignment & TabitemFlags::RightAligned) || (nAlignment & TabitemFlags::LastInGroup))
652 aTabItemDrawInfo.position = kHIThemeTabPositionLast;
654 // support for RTL (see issue 79748)
656 if (AllSettings::GetLayoutRTL()) {
657 if (aTabItemDrawInfo.position == kHIThemeTabPositionFirst)
658 aTabItemDrawInfo.position = kHIThemeTabPositionLast;
659 else if (aTabItemDrawInfo.position == kHIThemeTabPositionLast)
660 aTabItemDrawInfo.position = kHIThemeTabPositionFirst;
662 rc.size.width += VCL_TAB_TEXT_SEPARATOR;
663 rc.origin.x -= 1;
664 HIThemeDrawTab(&rc, &aTabItemDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
665 bOK=true;
667 break;
668 case ControlType::Editbox:
669 case ControlType::MultilineEditbox:
671 HIThemeFrameDrawInfo aTextDrawInfo;
672 aTextDrawInfo.version = 0;
673 aTextDrawInfo.kind = kHIThemeFrameTextFieldSquare;
674 aTextDrawInfo.state = getState(nState);
675 aTextDrawInfo.isFocused = false;
676 rc.size.width += 2 * EDITBOX_INSET_MARGIN;
677 if (nType == ControlType::Editbox)
678 rc.size.height = EDITBOX_HEIGHT;
679 else
680 rc.size.height += 2 * (EDITBOX_BORDER_WIDTH + EDITBOX_INSET_MARGIN);
681 rc.origin.x -= EDITBOX_INSET_MARGIN;
682 rc.origin.y -= EDITBOX_INSET_MARGIN;
684 // fill a white background, because HIThemeDrawFrame only draws the border
686 CGContextFillRect(maContextHolder.get(), CGRectMake(rc.origin.x, rc.origin.y, rc.size.width, rc.size.height));
687 HIThemeDrawFrame(&rc, &aTextDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal);
688 if (nState & ControlState::FOCUSED)
689 HIThemeDrawFocusRect(&rc, true, maContextHolder.get(), kHIThemeOrientationNormal);
690 bOK = true;
692 break;
693 case ControlType::Combobox:
694 if (nPart == ControlPart::HasBackgroundTexture || nPart == ControlPart::Entire)
696 HIThemeButtonDrawInfo aComboInfo;
697 aComboInfo.version = 0;
698 aComboInfo.kind = kThemeComboBox;
699 aComboInfo.state = getState(nState);
700 aComboInfo.value = kThemeButtonOn;
701 aComboInfo.adornment = kThemeAdornmentNone;
702 if (nState & ControlState::FOCUSED)
703 aComboInfo.adornment |= kThemeAdornmentFocus;
704 rc.size.width -= 2 * FOCUS_RING_WIDTH;
705 rc.size.height = COMBOBOX_HEIGHT;
706 rc.origin.x += FOCUS_RING_WIDTH;
707 rc.origin.y += FOCUS_RING_WIDTH;
708 HIThemeDrawButton(&rc, &aComboInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
709 bOK = true;
711 break;
712 case ControlType::Listbox:
713 switch (nPart)
715 case ControlPart::Entire:
716 case ControlPart::ButtonDown:
717 HIThemeButtonDrawInfo aListInfo;
718 aListInfo.version = 0;
719 aListInfo.kind = kThemePopupButton;
720 aListInfo.state = getState(nState);
721 aListInfo.value = kThemeButtonOn;
722 aListInfo.adornment = kThemeAdornmentDefault;
723 if (nState & ControlState::FOCUSED)
724 aListInfo.adornment |= kThemeAdornmentFocus;
725 rc.size.width -= 2 * FOCUS_RING_WIDTH;
726 rc.size.height = LISTBOX_HEIGHT;
727 rc.origin.x += FOCUS_RING_WIDTH;
728 rc.origin.y += FOCUS_RING_WIDTH;
729 HIThemeDrawButton(&rc, &aListInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
730 bOK = true;
731 break;
732 case ControlPart::ListboxWindow:
733 HIThemeFrameDrawInfo aTextDrawInfo;
734 aTextDrawInfo.version = 0;
735 aTextDrawInfo.kind = kHIThemeFrameTextFieldSquare;
736 aTextDrawInfo.state = getState(nState);
737 aTextDrawInfo.isFocused = false;
738 rc.size.width -= 2 * FOCUS_RING_WIDTH;
739 rc.size.height -= 2 * FOCUS_RING_WIDTH;
740 rc.origin.x += FOCUS_RING_WIDTH;
741 rc.origin.y += FOCUS_RING_WIDTH;
742 HIThemeDrawFrame(&rc, &aTextDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal);
743 if (nState & ControlState::FOCUSED)
744 HIThemeDrawFocusRect(&rc, true, maContextHolder.get(), kHIThemeOrientationNormal);
745 bOK = true;
746 break;
747 default:
748 break;
750 break;
751 case ControlType::Spinbox:
752 if (nPart == ControlPart::Entire)
755 // text field
757 HIThemeFrameDrawInfo aTextDrawInfo;
758 aTextDrawInfo.version = 0;
759 aTextDrawInfo.kind = kHIThemeFrameTextFieldSquare;
760 aTextDrawInfo.state = getState(nState);
761 aTextDrawInfo.isFocused = false;
762 rc.size.width -= SPIN_BUTTON_WIDTH + 4 * FOCUS_RING_WIDTH;
763 rc.size.height = EDITBOX_HEIGHT;
764 rc.origin.x += FOCUS_RING_WIDTH;
765 rc.origin.y += FOCUS_RING_WIDTH;
767 // fill a white background, because HIThemeDrawFrame only draws the border
769 CGContextFillRect(maContextHolder.get(), CGRectMake(rc.origin.x, rc.origin.y, rc.size.width, rc.size.height));
770 HIThemeDrawFrame(&rc, &aTextDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal);
771 if (nState & ControlState::FOCUSED)
772 HIThemeDrawFocusRect(&rc, true, maContextHolder.get(), kHIThemeOrientationNormal);
774 // buttons
776 const SpinbuttonValue *pSpinButtonVal = (aValue.getType() == ControlType::SpinButtons)
777 ? static_cast <const SpinbuttonValue *>(&aValue) : nullptr;
778 ControlState nUpperState = ControlState::ENABLED;
779 ControlState nLowerState = ControlState::ENABLED;
780 if (pSpinButtonVal)
782 nUpperState = pSpinButtonVal->mnUpperState;
783 nLowerState = pSpinButtonVal->mnLowerState;
784 HIThemeButtonDrawInfo aSpinInfo;
785 aSpinInfo.kind = kThemeIncDecButton;
786 aSpinInfo.state = kThemeStateActive;
787 if (nUpperState & ControlState::PRESSED)
788 aSpinInfo.state = kThemeStatePressedUp;
789 else if (nLowerState & ControlState::PRESSED)
790 aSpinInfo.state = kThemeStatePressedDown;
791 else if (nUpperState & ~ControlState::ENABLED || nLowerState & ~ControlState::ENABLED)
792 aSpinInfo.state = kThemeStateInactive;
793 else if (nUpperState & ControlState::ROLLOVER || nLowerState & ControlState::ROLLOVER)
794 aSpinInfo.state = kThemeStateRollover;
795 switch (aValue.getTristateVal())
797 case ButtonValue::On:
798 aSpinInfo.value = kThemeButtonOn;
799 break;
800 case ButtonValue::Off:
801 aSpinInfo.value = kThemeButtonOff;
802 break;
803 case ButtonValue::Mixed:
804 case ButtonValue::DontKnow:
805 default:
806 aSpinInfo.value = kThemeButtonMixed;
807 break;
809 aSpinInfo.adornment = (nUpperState & ControlState::DEFAULT || nLowerState & ControlState::DEFAULT)
810 ? kThemeAdornmentDefault : kThemeAdornmentNone;
811 if (nUpperState & ControlState::FOCUSED || nLowerState & ControlState::FOCUSED)
812 aSpinInfo.adornment |= kThemeAdornmentFocus;
813 rc.origin.x += rc.size.width + 2 * FOCUS_RING_WIDTH;
814 rc.size.width = SPIN_BUTTON_WIDTH;
815 rc.size.height = SPIN_LOWER_BUTTON_HEIGHT + SPIN_LOWER_BUTTON_HEIGHT;
816 HIThemeDrawButton(&rc, &aSpinInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
818 bOK = true;
820 break;
821 case ControlType::Frame:
823 DrawFrameFlags nStyle = static_cast<DrawFrameFlags>(aValue.getNumericVal());
824 if (nPart == ControlPart::Border)
826 if (!(nStyle & DrawFrameFlags::Menu) && !(nStyle & DrawFrameFlags::WindowBorder))
829 // strange effects start to happen when HIThemeDrawFrame meets the border of the window.
830 // These can be avoided by clipping to the boundary of the frame (see issue 84756)
832 if (rc.origin.y + rc.size.height >= mpFrame->maGeometry.nHeight - 3)
834 CGMutablePathRef rPath = CGPathCreateMutable();
835 CGPathAddRect(rPath, nullptr,
836 CGRectMake(0, 0, mpFrame->maGeometry.nWidth - 1, mpFrame->maGeometry.nHeight - 1));
837 CGContextBeginPath(maContextHolder.get());
838 CGContextAddPath(maContextHolder.get(), rPath);
839 CGContextClip(maContextHolder.get());
840 CGPathRelease(rPath);
842 HIThemeFrameDrawInfo aTextDrawInfo;
843 aTextDrawInfo.version = 0;
844 aTextDrawInfo.kind = kHIThemeFrameListBox;
845 aTextDrawInfo.state = kThemeStateActive;
846 aTextDrawInfo.isFocused = false;
847 HIThemeDrawFrame(&rc, &aTextDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal);
848 bOK = true;
852 break;
853 case ControlType::ListNet:
855 // do nothing as there isn't net for listviews on macOS
857 bOK = true;
858 break;
859 default:
860 break;
862 maContextHolder.restoreState();
864 // in most cases invalidating the whole control region instead of just the unclipped part of it is sufficient (and probably
865 // faster). However for the window background we should not unnecessarily enlarge the really changed rectangle since the
866 // difference is usually quite high. Background is always drawn as a whole since we don't know anything about its possible
867 // contents (see issue i90291).
869 if (nType == ControlType::WindowBackground)
871 CGRect aRect = {{0, 0}, {0, 0}};
872 if (mxClipPath)
873 aRect = CGPathGetBoundingBox(mxClipPath);
874 if (aRect.size.width != 0 && aRect.size.height != 0)
875 buttonRect.Intersection(tools::Rectangle(Point(static_cast<long int>(aRect.origin.x),
876 static_cast<long int>(aRect.origin.y)),
877 Size(static_cast<long int>(aRect.size.width),
878 static_cast<long int>(aRect.size.height))));
880 RefreshRect(buttonRect.Left(), buttonRect.Top(), buttonRect.GetWidth(), buttonRect.GetHeight());
881 return bOK;
884 bool AquaSalGraphics::getNativeControlRegion(ControlType nType,
885 ControlPart nPart,
886 const tools::Rectangle &rControlRegion,
887 ControlState,
888 const ImplControlValue &aValue,
889 const OUString &,
890 tools::Rectangle &rNativeBoundingRegion,
891 tools::Rectangle &rNativeContentRegion)
893 bool toReturn = false;
894 tools::Rectangle aCtrlBoundRect(rControlRegion);
895 short x = aCtrlBoundRect.Left();
896 short y = aCtrlBoundRect.Top();
897 short w, h;
898 switch (nType)
900 case ControlType::Pushbutton:
901 case ControlType::Radiobutton:
902 case ControlType::Checkbox:
904 if (nType == ControlType::Pushbutton)
906 w = aCtrlBoundRect.GetWidth();
907 h = aCtrlBoundRect.GetHeight();
909 else
911 w = RADIO_BUTTON_SMALL_SIZE + 2 * FOCUS_RING_WIDTH + RADIO_BUTTON_TEXT_SEPARATOR;
912 h = RADIO_BUTTON_SMALL_SIZE + 2 * FOCUS_RING_WIDTH;
914 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
915 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
916 toReturn = true;
918 break;
919 case ControlType::Progress:
921 tools::Rectangle aRect(aCtrlBoundRect);
922 if (aRect.GetHeight() < LARGE_PROGRESS_INDICATOR_HEIGHT)
923 aRect.SetBottom(aRect.Top() + MEDIUM_PROGRESS_INDICATOR_HEIGHT - 1);
924 else
925 aRect.SetBottom(aRect.Top() + LARGE_PROGRESS_INDICATOR_HEIGHT - 1);
926 rNativeBoundingRegion = aRect;
927 rNativeContentRegion = aRect;
928 toReturn = true;
930 break;
931 case ControlType::IntroProgress:
933 tools::Rectangle aRect(aCtrlBoundRect);
934 aRect.SetBottom(aRect.Top() + MEDIUM_PROGRESS_INDICATOR_HEIGHT - 1);
935 rNativeBoundingRegion = aRect;
936 rNativeContentRegion = aRect;
937 toReturn = true;
939 break;
940 case ControlType::Slider:
941 if (nPart == ControlPart::ThumbHorz)
943 w = SLIDER_WIDTH;
944 h = aCtrlBoundRect.GetHeight();
945 rNativeBoundingRegion = rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
946 toReturn = true;
948 else if (nPart == ControlPart::ThumbVert)
950 w = aCtrlBoundRect.GetWidth();
951 h = SLIDER_HEIGHT;
952 rNativeBoundingRegion = rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
953 toReturn = true;
955 break;
956 case ControlType::Scrollbar:
958 tools::Rectangle aRect;
959 if (AquaGetScrollRect(nPart, aCtrlBoundRect, aRect))
961 toReturn = true;
962 rNativeBoundingRegion = aRect;
963 rNativeContentRegion = aRect;
966 break;
967 case ControlType::TabItem:
969 w = aCtrlBoundRect.GetWidth() + 2 * TAB_TEXT_MARGIN - 2 * VCL_TAB_TEXT_SEPARATOR;
970 h = TAB_HEIGHT + 2;
971 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
972 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
973 toReturn = true;
975 break;
976 case ControlType::Editbox:
978 w = aCtrlBoundRect.GetWidth();
979 h = EDITBOX_HEIGHT + 2 * FOCUS_RING_WIDTH;
980 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
981 w -= 2 * (FOCUS_RING_WIDTH + EDITBOX_BORDER_WIDTH + EDITBOX_INSET_MARGIN);
982 h -= 2 * (FOCUS_RING_WIDTH + EDITBOX_BORDER_WIDTH + EDITBOX_INSET_MARGIN);
983 x += FOCUS_RING_WIDTH + EDITBOX_BORDER_WIDTH + EDITBOX_INSET_MARGIN;
984 y += FOCUS_RING_WIDTH + EDITBOX_BORDER_WIDTH + EDITBOX_INSET_MARGIN;
985 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
986 toReturn = true;
988 break;
989 case ControlType::Combobox:
990 if (nPart == ControlPart::Entire)
992 w = aCtrlBoundRect.GetWidth();
993 h = COMBOBOX_HEIGHT + 2 * FOCUS_RING_WIDTH;
994 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
995 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
996 toReturn = true;
998 else if (nPart == ControlPart::ButtonDown)
1000 w = COMBOBOX_BUTTON_WIDTH + FOCUS_RING_WIDTH;
1001 h = COMBOBOX_HEIGHT + 2 * FOCUS_RING_WIDTH;
1002 x += aCtrlBoundRect.GetWidth() - w;
1003 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
1004 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
1005 toReturn = true;
1007 else if (nPart == ControlPart::SubEdit)
1009 w = aCtrlBoundRect.GetWidth() - 2 * FOCUS_RING_WIDTH - COMBOBOX_BUTTON_WIDTH - COMBOBOX_BORDER_WIDTH
1010 - 2 * COMBOBOX_TEXT_MARGIN;
1011 h = COMBOBOX_HEIGHT - 2 * COMBOBOX_BORDER_WIDTH;
1012 x += FOCUS_RING_WIDTH + COMBOBOX_BORDER_WIDTH + COMBOBOX_TEXT_MARGIN;
1013 y += FOCUS_RING_WIDTH + COMBOBOX_BORDER_WIDTH;
1014 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
1015 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
1016 toReturn = true;
1018 break;
1019 case ControlType::Listbox:
1020 if (nPart == ControlPart::Entire)
1022 w = aCtrlBoundRect.GetWidth();
1023 h = LISTBOX_HEIGHT + 2 * FOCUS_RING_WIDTH;
1024 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
1025 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
1026 toReturn = true;
1028 else if (nPart == ControlPart::ButtonDown)
1030 w = LISTBOX_BUTTON_WIDTH + FOCUS_RING_WIDTH;
1031 h = LISTBOX_HEIGHT + 2 * FOCUS_RING_WIDTH;
1032 x += aCtrlBoundRect.GetWidth() - w;
1033 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
1034 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
1035 toReturn = true;
1037 else if (nPart == ControlPart::SubEdit)
1039 w = aCtrlBoundRect.GetWidth() - 2 * FOCUS_RING_WIDTH - LISTBOX_BUTTON_WIDTH - LISTBOX_BORDER_WIDTH
1040 - 2 * LISTBOX_TEXT_MARGIN;
1041 h = LISTBOX_HEIGHT - 2 * LISTBOX_BORDER_WIDTH;
1042 x += FOCUS_RING_WIDTH + LISTBOX_BORDER_WIDTH + LISTBOX_TEXT_MARGIN;
1043 y += FOCUS_RING_WIDTH + LISTBOX_BORDER_WIDTH;
1044 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
1045 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
1046 toReturn = true;
1048 break;
1049 case ControlType::Spinbox:
1050 if (nPart == ControlPart::Entire)
1052 w = aCtrlBoundRect.GetWidth();
1053 h = EDITBOX_HEIGHT + 2 * FOCUS_RING_WIDTH;
1054 x += SPINBOX_OFFSET;
1055 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
1056 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
1057 toReturn = true;
1059 else if (nPart == ControlPart::SubEdit)
1061 w = aCtrlBoundRect.GetWidth() - 4 * FOCUS_RING_WIDTH - SPIN_BUTTON_WIDTH - 2 * EDITBOX_BORDER_WIDTH
1062 - 2 * EDITBOX_INSET_MARGIN;
1063 h = EDITBOX_HEIGHT - 2 * (EDITBOX_BORDER_WIDTH + EDITBOX_INSET_MARGIN);
1064 x += FOCUS_RING_WIDTH + EDITBOX_BORDER_WIDTH + EDITBOX_INSET_MARGIN + SPINBOX_OFFSET;
1065 y += FOCUS_RING_WIDTH + EDITBOX_BORDER_WIDTH + EDITBOX_INSET_MARGIN;
1066 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
1067 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
1068 toReturn = true;
1070 else if (nPart == ControlPart::ButtonUp)
1072 w = SPIN_BUTTON_WIDTH + 2 * FOCUS_RING_WIDTH;
1073 h = SPIN_UPPER_BUTTON_HEIGHT + FOCUS_RING_WIDTH;
1074 x += aCtrlBoundRect.GetWidth() - SPIN_BUTTON_WIDTH - 2 * FOCUS_RING_WIDTH + SPINBOX_OFFSET;
1075 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
1076 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
1077 toReturn = true;
1079 else if (nPart == ControlPart::ButtonDown)
1081 w = SPIN_BUTTON_WIDTH + 2 * FOCUS_RING_WIDTH;
1082 h = SPIN_LOWER_BUTTON_HEIGHT + FOCUS_RING_WIDTH;
1083 x += aCtrlBoundRect.GetWidth() - SPIN_BUTTON_WIDTH - 2 * FOCUS_RING_WIDTH + SPINBOX_OFFSET;
1084 y += FOCUS_RING_WIDTH + SPIN_UPPER_BUTTON_HEIGHT;
1085 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
1086 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
1087 toReturn = true;
1089 break;
1090 case ControlType::Frame:
1092 DrawFrameStyle nStyle = static_cast<DrawFrameStyle>(aValue.getNumericVal() & 0x000f);
1093 DrawFrameFlags nFlags = static_cast<DrawFrameFlags>(aValue.getNumericVal() & 0xfff0);
1094 if (nPart == ControlPart::Border
1095 && !(nFlags & (DrawFrameFlags::Menu | DrawFrameFlags::WindowBorder | DrawFrameFlags::BorderWindowBorder)))
1097 tools::Rectangle aRect(aCtrlBoundRect);
1098 if (nStyle == DrawFrameStyle::DoubleIn)
1100 aRect.AdjustLeft(1);
1101 aRect.AdjustTop(1);
1102 // rRect.Right() -= 1;
1103 // rRect.Bottom() -= 1;
1105 else
1107 aRect.AdjustLeft(1);
1108 aRect.AdjustTop(1);
1109 aRect.AdjustRight(-1);
1110 aRect.AdjustBottom(-1);
1112 rNativeContentRegion = aRect;
1113 rNativeBoundingRegion = aRect;
1114 toReturn = true;
1117 break;
1118 case ControlType::Menubar:
1119 case ControlType::MenuPopup:
1120 if (nPart == ControlPart::MenuItemCheckMark || nPart == ControlPart::MenuItemRadioMark)
1122 w=10;
1123 h=10;
1124 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
1125 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
1126 toReturn = true;
1128 break;
1129 default:
1130 break;
1132 return toReturn;
1135 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */