nss: upgrade to release 3.73
[LibreOffice.git] / vcl / osx / salnativewidgets.cxx
blobff3e5c450edd10a430c6435acc4f6a6f4986f267
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>
21 #include <tools/long.hxx>
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 bounding 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)
236 // there are non key windows which are children of key windows, e.g. autofilter configuration dialog or sidebar dropdown dialogs.
237 // To handle these windows correctly, parent frame's key window state is considered here additionally.
239 const bool bDrawActive = mpFrame == nullptr || [mpFrame->getNSWindow() isKeyWindow]
240 || mpFrame->mpParent == nullptr || [mpFrame->mpParent->getNSWindow() isKeyWindow];
241 if (!(nState & ControlState::ENABLED) || !bDrawActive)
243 return kThemeStateInactive;
245 if (nState & ControlState::PRESSED)
246 return kThemeStatePressed;
247 return kThemeStateActive;
250 UInt32 AquaSalGraphics::getTrackState(ControlState nState)
252 const bool bDrawActive = mpFrame == nullptr || [mpFrame->getNSWindow() isKeyWindow];
253 if (!(nState & ControlState::ENABLED) || !bDrawActive)
254 return kThemeTrackInactive;
255 return kThemeTrackActive;
258 bool AquaSalGraphics::drawNativeControl(ControlType nType,
259 ControlPart nPart,
260 const tools::Rectangle &rControlRegion,
261 ControlState nState,
262 const ImplControlValue &aValue,
263 const OUString &,
264 const Color&)
266 bool bOK = false;
267 if (!CheckContext())
268 return false;
269 maContextHolder.saveState();
270 tools::Rectangle buttonRect = rControlRegion;
271 HIRect rc = ImplGetHIRectFromRectangle(buttonRect);
272 switch (nType)
274 case ControlType::Toolbar:
276 #if HAVE_FEATURE_MACOSX_SANDBOX
277 HIThemeMenuItemDrawInfo aMenuItemDrawInfo;
278 aMenuItemDrawInfo.version = 0;
279 aMenuItemDrawInfo.state = kThemeMenuActive;
280 aMenuItemDrawInfo.itemType = kThemeMenuItemHierBackground;
281 HIThemeDrawMenuItem(&rc, &rc, &aMenuItemDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
282 #else
283 if (rControlRegion.Top() == 0 && nPart == ControlPart::DrawBackgroundHorz)
285 const bool bDrawActive = mpFrame == nullptr || [mpFrame->getNSWindow() isKeyWindow];
286 CGFloat unifiedHeight = rControlRegion.GetHeight();
287 CGRect drawRect = CGRectMake(rControlRegion.Left(), rControlRegion.Top(),
288 rControlRegion.GetWidth(), rControlRegion.GetHeight());
289 CUIDraw([NSWindow coreUIRenderer], drawRect, maContextHolder.get(),
290 reinterpret_cast<CFDictionaryRef>([NSDictionary dictionaryWithObjectsAndKeys:
291 @"kCUIWidgetWindowFrame",
292 @"widget",
293 @"regularwin",
294 @"windowtype",
295 (bDrawActive ? @"normal" : @"inactive"),
296 @"state",
297 [NSNumber numberWithDouble:unifiedHeight],
298 @"kCUIWindowFrameUnifiedTitleBarHeightKey",
299 [NSNumber numberWithBool:NO],
300 @"kCUIWindowFrameDrawTitleSeparatorKey",
301 [NSNumber numberWithBool:YES],
302 @"is.flipped",
303 nil]),
304 nil);
306 else
308 HIThemeMenuItemDrawInfo aMenuItemDrawInfo;
309 aMenuItemDrawInfo.version = 0;
310 aMenuItemDrawInfo.state = kThemeMenuActive;
311 aMenuItemDrawInfo.itemType = kThemeMenuItemHierBackground;
312 HIThemeDrawMenuItem(&rc, &rc, &aMenuItemDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
314 #endif
315 bOK = true;
317 break;
318 case ControlType::WindowBackground:
320 HIThemeBackgroundDrawInfo aThemeBackgroundInfo;
321 aThemeBackgroundInfo.version = 0;
322 aThemeBackgroundInfo.state = getState(nState);
323 aThemeBackgroundInfo.kind = kThemeBrushDialogBackgroundActive;
325 // FIXME: without this magical offset there is a 2 pixel black border on the right and bottom
327 rc.size.width += 2;
328 rc.size.height += 2;
329 HIThemeApplyBackground( &rc, &aThemeBackgroundInfo, maContextHolder.get(), kHIThemeOrientationNormal);
330 CGContextFillRect(maContextHolder.get(), rc);
331 bOK = true;
333 break;
334 case ControlType::Tooltip:
336 HIThemeBackgroundDrawInfo aThemeBackgroundInfo;
337 aThemeBackgroundInfo.version = 0;
338 aThemeBackgroundInfo.state = getState(nState);
339 aThemeBackgroundInfo.kind = kThemeBrushAlertBackgroundActive;
340 rc.size.width += 2;
341 rc.size.height += 2;
342 HIThemeApplyBackground(&rc, &aThemeBackgroundInfo, maContextHolder.get(), kHIThemeOrientationNormal);
343 CGContextFillRect(maContextHolder.get(), rc);
344 bOK = true;
346 break;
347 case ControlType::Menubar:
348 case ControlType::MenuPopup:
349 if (nPart == ControlPart::Entire || nPart == ControlPart::MenuItem || nPart == ControlPart::HasBackgroundTexture)
352 // FIXME: without this magical offset there is a 2 pixel black border on the right
354 rc.size.width += 2;
355 HIThemeMenuDrawInfo aMenuInfo;
356 aMenuInfo.version = 0;
357 aMenuInfo.menuType = kThemeMenuTypePullDown;
358 HIThemeMenuItemDrawInfo aMenuItemDrawInfo;
360 // grey theme when the item is selected is drawn here.
362 aMenuItemDrawInfo.itemType = kThemeMenuItemPlain;
363 if ((nPart == ControlPart::MenuItem) && (nState & ControlState::SELECTED))
365 // blue theme when the item is selected is drawn here.
367 aMenuItemDrawInfo.state = kThemeMenuSelected;
368 else
370 // normal color for non selected item
372 aMenuItemDrawInfo.state = kThemeMenuActive;
374 // repaints the background of the pull down menu
376 HIThemeDrawMenuBackground(&rc, &aMenuInfo,maContextHolder.get(), kHIThemeOrientationNormal);
378 // repaints the item either blue (selected) and/or grey (active only)
380 HIThemeDrawMenuItem(&rc, &rc, &aMenuItemDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal, &rc);
381 bOK = true;
383 else if (nPart == ControlPart::MenuItemCheckMark || nPart == ControlPart::MenuItemRadioMark)
386 // checked, else it is not displayed (see vcl/source/window/menu.cxx)
388 if (nState & ControlState::PRESSED)
390 HIThemeTextInfo aTextInfo;
391 aTextInfo.version = 0;
392 aTextInfo.state = (nState & ControlState::ENABLED) ? kThemeStateInactive: kThemeStateActive;
393 aTextInfo.fontID = kThemeMenuItemMarkFont;
394 aTextInfo.horizontalFlushness = kHIThemeTextHorizontalFlushCenter;
395 aTextInfo.verticalFlushness = kHIThemeTextVerticalFlushTop;
396 aTextInfo.options = kHIThemeTextBoxOptionNone;
397 aTextInfo.truncationPosition = kHIThemeTextTruncationNone;
399 // aTextInfo.truncationMaxLines unused because of kHIThemeTextTruncationNone item highlighted
401 if (nState & ControlState::SELECTED) aTextInfo.state = kThemeStatePressed;
402 UniChar mark=(nPart == ControlPart::MenuItemCheckMark) ? kCheckUnicode: kBulletUnicode;
403 CFStringRef cfString = CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, &mark, 1, kCFAllocatorNull);
404 HIThemeDrawTextBox(cfString, &rc, &aTextInfo, maContextHolder.get(), kHIThemeOrientationNormal);
405 if (cfString)
406 CFRelease(cfString);
407 bOK = true;
410 break;
411 case ControlType::Pushbutton:
414 // FIXME: instead of use a value, VCL can retrieve correct values on the fly (to be implemented)
416 HIThemeButtonDrawInfo aPushInfo;
417 aPushInfo.version = 0;
419 // no animation
421 aPushInfo.animation.time.start = 0;
422 aPushInfo.animation.time.current = 0;
423 PushButtonValue const *pPBVal = aValue.getType() == ControlType::Pushbutton ?
424 static_cast<PushButtonValue const *>(&aValue) : nullptr;
425 int nPaintHeight = static_cast<int>(rc.size.height);
426 if (pPBVal && pPBVal->mbBevelButton)
428 aPushInfo.kind = kThemeRoundedBevelButton;
430 else if (rc.size.height <= PUSH_BUTTON_NORMAL_HEIGHT)
432 aPushInfo.kind = kThemePushButtonMini;
433 nPaintHeight = PUSH_BUTTON_SMALL_HEIGHT;
435 else if ((pPBVal && pPBVal->mbSingleLine) || rc.size.height < PUSH_BUTTON_NORMAL_HEIGHT * 3 / 2)
437 aPushInfo.kind = kThemePushButtonNormal;
438 nPaintHeight = PUSH_BUTTON_NORMAL_HEIGHT;
440 // avoid clipping when focused
442 rc.origin.x += FOCUS_RING_WIDTH / 2;
443 rc.size.width -= FOCUS_RING_WIDTH;
445 else
446 aPushInfo.kind = kThemeBevelButton;
448 // translate the origin for controls with fixed paint height so content ends up somewhere sensible
450 rc.origin.y += (rc.size.height - nPaintHeight) / 2;
451 aPushInfo.state = getState(nState);
452 aPushInfo.value = ImplGetButtonValue(aValue.getTristateVal());
453 aPushInfo.adornment = (nState & ControlState::DEFAULT) ? kThemeAdornmentDefault : kThemeAdornmentNone;
454 if (nState & ControlState::FOCUSED)
455 aPushInfo.adornment |= kThemeAdornmentFocus;
456 HIThemeDrawButton(&rc, &aPushInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
457 bOK = true;
459 break;
460 case ControlType::Radiobutton:
461 case ControlType::Checkbox:
463 HIThemeButtonDrawInfo aInfo;
464 aInfo.version = 0;
465 switch (nType)
467 case ControlType::Radiobutton:
468 if (rc.size.width >= RADIO_BUTTON_SMALL_SIZE)
469 aInfo.kind = kThemeRadioButton;
470 else
471 aInfo.kind = kThemeSmallRadioButton;
472 break;
473 case ControlType::Checkbox:
474 if (rc.size.width >= CHECKBOX_SMALL_SIZE)
475 aInfo.kind = kThemeCheckBox;
476 else
477 aInfo.kind = kThemeSmallCheckBox;
478 break;
479 default:
480 break;
482 aInfo.state = getState(nState);
483 ButtonValue aButtonValue = aValue.getTristateVal();
484 aInfo.value = ImplGetButtonValue(aButtonValue);
485 aInfo.adornment = (nState & ControlState::DEFAULT) ? kThemeAdornmentDefault : kThemeAdornmentNone;
486 if (nState & ControlState::FOCUSED)
487 aInfo.adornment |= kThemeAdornmentFocus;
488 rc.size.width -= 2 * FOCUS_RING_WIDTH;
489 rc.size.height = RADIO_BUTTON_SMALL_SIZE;
490 rc.origin.x += FOCUS_RING_WIDTH;
491 rc.origin.y += FOCUS_RING_WIDTH;
492 HIThemeDrawButton(&rc, &aInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
493 bOK = true;
495 break;
496 case ControlType::ListNode:
498 ButtonValue aButtonValue = aValue.getTristateVal();
499 HIThemeButtonDrawInfo aInfo;
500 aInfo.version = 0;
501 aInfo.kind = kThemeDisclosureTriangle;
502 aInfo.value = kThemeDisclosureRight;
503 aInfo.state = getState(nState);
504 aInfo.adornment = kThemeAdornmentNone;
505 switch (aButtonValue)
507 case ButtonValue::On:
508 aInfo.value = kThemeDisclosureDown;
509 break;
510 case ButtonValue::Off:
511 if (AllSettings::GetLayoutRTL())
512 aInfo.value = kThemeDisclosureLeft;
513 break;
514 case ButtonValue::DontKnow:
515 default:
516 break;
518 HIThemeDrawButton(&rc, &aInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
519 bOK = true;
521 break;
522 case ControlType::Progress:
523 case ControlType::IntroProgress:
525 tools::Long nProgressWidth = aValue.getNumericVal();
526 HIThemeTrackDrawInfo aTrackInfo;
527 aTrackInfo.version = 0;
528 aTrackInfo.kind = (rc.size.height > 10) ? kThemeProgressBarLarge : kThemeProgressBarMedium;
529 aTrackInfo.bounds = rc;
530 aTrackInfo.min = 0;
531 aTrackInfo.max = static_cast<SInt32>(rc.size.width);
532 aTrackInfo.value = nProgressWidth;
533 aTrackInfo.reserved = 0;
534 aTrackInfo.attributes = kThemeTrackHorizontal;
535 if (AllSettings::GetLayoutRTL())
536 aTrackInfo.attributes |= kThemeTrackRightToLeft;
537 aTrackInfo.enableState = getTrackState(nState);
539 // the intro bitmap never gets key anyway; we want to draw that enabled
541 if (nType == ControlType::IntroProgress)
542 aTrackInfo.enableState = kThemeTrackActive;
543 aTrackInfo.filler1 = 0;
544 aTrackInfo.trackInfo.progress.phase = static_cast<long long>(CFAbsoluteTimeGetCurrent() * 10.0);
545 HIThemeDrawTrack(&aTrackInfo, nullptr, maContextHolder.get(), kHIThemeOrientationNormal);
546 bOK = true;
548 break;
549 case ControlType::Slider:
551 const SliderValue *pSliderVal = static_cast<SliderValue const *>(&aValue);
552 HIThemeTrackDrawInfo aTrackDraw;
553 aTrackDraw.kind = kThemeSliderMedium;
554 if (nPart == ControlPart::TrackHorzArea || nPart == ControlPart::TrackVertArea)
556 aTrackDraw.bounds = rc;
557 aTrackDraw.min = pSliderVal->mnMin;
558 aTrackDraw.max = pSliderVal->mnMax;
559 aTrackDraw.value = pSliderVal->mnCur;
560 aTrackDraw.reserved = 0;
561 aTrackDraw.attributes = kThemeTrackShowThumb;
562 if (nPart == ControlPart::TrackHorzArea)
563 aTrackDraw.attributes |= kThemeTrackHorizontal;
564 aTrackDraw.enableState = (nState & ControlState::ENABLED) ? kThemeTrackActive : kThemeTrackInactive;
565 SliderTrackInfo aSlideInfo;
566 aSlideInfo.thumbDir = kThemeThumbUpward;
567 aSlideInfo.pressState = 0;
568 aTrackDraw.trackInfo.slider = aSlideInfo;
569 HIThemeDrawTrack(&aTrackDraw, nullptr, maContextHolder.get(), kHIThemeOrientationNormal);
570 bOK = true;
573 break;
574 case ControlType::Scrollbar:
576 const ScrollbarValue *pScrollbarVal = (aValue.getType() == ControlType::Scrollbar)
577 ? static_cast<const ScrollbarValue *>(&aValue) : nullptr;
578 if (nPart == ControlPart::DrawBackgroundVert || nPart == ControlPart::DrawBackgroundHorz)
580 HIThemeTrackDrawInfo aTrackDraw;
581 aTrackDraw.kind = kThemeMediumScrollBar;
582 aTrackDraw.bounds = rc;
583 aTrackDraw.min = pScrollbarVal->mnMin;
584 aTrackDraw.max = pScrollbarVal->mnMax - pScrollbarVal->mnVisibleSize;
585 aTrackDraw.value = pScrollbarVal->mnCur;
586 aTrackDraw.reserved = 0;
587 aTrackDraw.attributes = kThemeTrackShowThumb;
588 if (nPart == ControlPart::DrawBackgroundHorz)
589 aTrackDraw.attributes |= kThemeTrackHorizontal;
590 aTrackDraw.enableState = getTrackState(nState);
591 ScrollBarTrackInfo aScrollInfo;
592 aScrollInfo.viewsize = pScrollbarVal->mnVisibleSize;
593 aScrollInfo.pressState = 0;
594 if (pScrollbarVal->mnButton1State & ControlState::ENABLED)
595 if (pScrollbarVal->mnButton1State & ControlState::PRESSED)
596 aScrollInfo.pressState = kThemeTopOutsideArrowPressed;
597 if (pScrollbarVal->mnButton2State & ControlState::ENABLED )
598 if (pScrollbarVal->mnButton2State & ControlState::PRESSED )
599 aScrollInfo.pressState = kThemeBottomOutsideArrowPressed;
600 if ( pScrollbarVal->mnThumbState & ControlState::ENABLED)
601 if (pScrollbarVal->mnThumbState & ControlState::PRESSED)
602 aScrollInfo.pressState = kThemeThumbPressed;
603 aTrackDraw.trackInfo.scrollbar = aScrollInfo;
604 HIThemeDrawTrack(&aTrackDraw, nullptr, maContextHolder.get(), kHIThemeOrientationNormal);
605 bOK = true;
608 break;
609 case ControlType::TabPane:
611 HIThemeTabPaneDrawInfo aTabPaneDrawInfo;
612 aTabPaneDrawInfo.version = 1;
613 aTabPaneDrawInfo.state = kThemeStateActive;
614 aTabPaneDrawInfo.direction = kThemeTabNorth;
615 aTabPaneDrawInfo.size = kHIThemeTabSizeNormal;
616 aTabPaneDrawInfo.kind = kHIThemeTabKindNormal;
618 // border is outside the rect rc for Carbon but for VCL it should be inside
620 rc.origin.x += 1;
621 rc.origin.y -= TAB_HEIGHT / 2;
622 rc.size.height += TAB_HEIGHT / 2;
623 rc.size.width -= 2;
624 HIThemeDrawTabPane(&rc, &aTabPaneDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal);
625 bOK = true;
627 break;
628 case ControlType::TabItem:
630 HIThemeTabDrawInfo aTabItemDrawInfo;
631 aTabItemDrawInfo.version = 1;
632 aTabItemDrawInfo.style = kThemeTabNonFront;
633 aTabItemDrawInfo.direction = kThemeTabNorth;
634 aTabItemDrawInfo.size = kHIThemeTabSizeNormal;
635 aTabItemDrawInfo.adornment = kHIThemeTabAdornmentTrailingSeparator;
636 if (nState & ControlState::SELECTED)
637 aTabItemDrawInfo.style = kThemeTabFront;
638 if(nState & ControlState::FOCUSED)
639 aTabItemDrawInfo.adornment |= kHIThemeTabAdornmentFocus;
641 // first, last or middle tab
643 aTabItemDrawInfo.position = kHIThemeTabPositionMiddle;
644 TabitemValue const * pTabValue = static_cast<TabitemValue const *>(&aValue);
645 TabitemFlags nAlignment = pTabValue->mnAlignment;
647 // TabitemFlags::LeftAligned (and TabitemFlags::RightAligned) for the leftmost (or rightmost) tab
648 // when there are several lines of tabs because there is only one first tab and one
649 // last tab and TabitemFlags::FirstInGroup (and TabitemFlags::LastInGroup) because when the
650 // line width is different from window width, there may not be TabitemFlags::RightAligned
652 if (((nAlignment & TabitemFlags::LeftAligned) && (nAlignment & TabitemFlags::RightAligned))
653 || ((nAlignment & TabitemFlags::FirstInGroup) && (nAlignment & TabitemFlags::LastInGroup)))
654 aTabItemDrawInfo.position = kHIThemeTabPositionOnly;
655 else if ((nAlignment & TabitemFlags::LeftAligned) || (nAlignment & TabitemFlags::FirstInGroup))
656 aTabItemDrawInfo.position = kHIThemeTabPositionFirst;
657 else if ((nAlignment & TabitemFlags::RightAligned) || (nAlignment & TabitemFlags::LastInGroup))
658 aTabItemDrawInfo.position = kHIThemeTabPositionLast;
660 // support for RTL (see issue 79748)
662 if (AllSettings::GetLayoutRTL()) {
663 if (aTabItemDrawInfo.position == kHIThemeTabPositionFirst)
664 aTabItemDrawInfo.position = kHIThemeTabPositionLast;
665 else if (aTabItemDrawInfo.position == kHIThemeTabPositionLast)
666 aTabItemDrawInfo.position = kHIThemeTabPositionFirst;
668 rc.size.width += VCL_TAB_TEXT_SEPARATOR;
669 rc.origin.x -= 1;
670 HIThemeDrawTab(&rc, &aTabItemDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
671 bOK=true;
673 break;
674 case ControlType::Editbox:
675 case ControlType::MultilineEditbox:
677 HIThemeFrameDrawInfo aTextDrawInfo;
678 aTextDrawInfo.version = 0;
679 aTextDrawInfo.kind = kHIThemeFrameTextFieldSquare;
680 aTextDrawInfo.state = getState(nState);
681 aTextDrawInfo.isFocused = false;
682 rc.size.width += 2 * EDITBOX_INSET_MARGIN;
683 if (nType == ControlType::Editbox)
684 rc.size.height = EDITBOX_HEIGHT;
685 else
686 rc.size.height += 2 * (EDITBOX_BORDER_WIDTH + EDITBOX_INSET_MARGIN);
687 rc.origin.x -= EDITBOX_INSET_MARGIN;
688 rc.origin.y -= EDITBOX_INSET_MARGIN;
690 // fill a white background, because HIThemeDrawFrame only draws the border
692 CGContextFillRect(maContextHolder.get(), CGRectMake(rc.origin.x, rc.origin.y, rc.size.width, rc.size.height));
693 HIThemeDrawFrame(&rc, &aTextDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal);
694 if (nState & ControlState::FOCUSED)
695 HIThemeDrawFocusRect(&rc, true, maContextHolder.get(), kHIThemeOrientationNormal);
696 bOK = true;
698 break;
699 case ControlType::Combobox:
700 if (nPart == ControlPart::HasBackgroundTexture || nPart == ControlPart::Entire)
702 HIThemeButtonDrawInfo aComboInfo;
703 aComboInfo.version = 0;
704 aComboInfo.kind = kThemeComboBox;
705 aComboInfo.state = getState(nState);
706 aComboInfo.value = kThemeButtonOn;
707 aComboInfo.adornment = kThemeAdornmentNone;
708 if (nState & ControlState::FOCUSED)
709 aComboInfo.adornment |= kThemeAdornmentFocus;
710 rc.size.width -= 2 * FOCUS_RING_WIDTH;
711 rc.size.height = COMBOBOX_HEIGHT;
712 rc.origin.x += FOCUS_RING_WIDTH;
713 rc.origin.y += FOCUS_RING_WIDTH;
714 HIThemeDrawButton(&rc, &aComboInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
715 bOK = true;
717 break;
718 case ControlType::Listbox:
719 switch (nPart)
721 case ControlPart::Entire:
722 case ControlPart::ButtonDown:
723 HIThemeButtonDrawInfo aListInfo;
724 aListInfo.version = 0;
725 aListInfo.kind = kThemePopupButton;
726 aListInfo.state = getState(nState);
727 aListInfo.value = kThemeButtonOn;
728 aListInfo.adornment = kThemeAdornmentDefault;
729 if (nState & ControlState::FOCUSED)
730 aListInfo.adornment |= kThemeAdornmentFocus;
731 rc.size.width -= 2 * FOCUS_RING_WIDTH;
732 rc.size.height = LISTBOX_HEIGHT;
733 rc.origin.x += FOCUS_RING_WIDTH;
734 rc.origin.y += FOCUS_RING_WIDTH;
735 HIThemeDrawButton(&rc, &aListInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
736 bOK = true;
737 break;
738 case ControlPart::ListboxWindow:
739 HIThemeFrameDrawInfo aTextDrawInfo;
740 aTextDrawInfo.version = 0;
741 aTextDrawInfo.kind = kHIThemeFrameTextFieldSquare;
742 aTextDrawInfo.state = getState(nState);
743 aTextDrawInfo.isFocused = false;
744 rc.size.width -= 2 * FOCUS_RING_WIDTH;
745 rc.size.height -= 2 * FOCUS_RING_WIDTH;
746 rc.origin.x += FOCUS_RING_WIDTH;
747 rc.origin.y += FOCUS_RING_WIDTH;
748 HIThemeDrawFrame(&rc, &aTextDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal);
749 if (nState & ControlState::FOCUSED)
750 HIThemeDrawFocusRect(&rc, true, maContextHolder.get(), kHIThemeOrientationNormal);
751 bOK = true;
752 break;
753 default:
754 break;
756 break;
757 case ControlType::Spinbox:
758 if (nPart == ControlPart::Entire)
761 // text field
763 HIThemeFrameDrawInfo aTextDrawInfo;
764 aTextDrawInfo.version = 0;
765 aTextDrawInfo.kind = kHIThemeFrameTextFieldSquare;
766 aTextDrawInfo.state = getState(nState);
767 aTextDrawInfo.isFocused = false;
768 rc.size.width -= SPIN_BUTTON_WIDTH + 4 * FOCUS_RING_WIDTH;
769 rc.size.height = EDITBOX_HEIGHT;
770 rc.origin.x += FOCUS_RING_WIDTH;
771 rc.origin.y += FOCUS_RING_WIDTH;
773 // fill a white background, because HIThemeDrawFrame only draws the border
775 CGContextFillRect(maContextHolder.get(), CGRectMake(rc.origin.x, rc.origin.y, rc.size.width, rc.size.height));
776 HIThemeDrawFrame(&rc, &aTextDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal);
777 if (nState & ControlState::FOCUSED)
778 HIThemeDrawFocusRect(&rc, true, maContextHolder.get(), kHIThemeOrientationNormal);
780 // buttons
782 const SpinbuttonValue *pSpinButtonVal = (aValue.getType() == ControlType::SpinButtons)
783 ? static_cast <const SpinbuttonValue *>(&aValue) : nullptr;
784 ControlState nUpperState = ControlState::ENABLED;
785 ControlState nLowerState = ControlState::ENABLED;
786 if (pSpinButtonVal)
788 nUpperState = pSpinButtonVal->mnUpperState;
789 nLowerState = pSpinButtonVal->mnLowerState;
790 HIThemeButtonDrawInfo aSpinInfo;
791 aSpinInfo.kind = kThemeIncDecButton;
792 aSpinInfo.state = kThemeStateActive;
793 if (nUpperState & ControlState::PRESSED)
794 aSpinInfo.state = kThemeStatePressedUp;
795 else if (nLowerState & ControlState::PRESSED)
796 aSpinInfo.state = kThemeStatePressedDown;
797 else if (nUpperState & ~ControlState::ENABLED || nLowerState & ~ControlState::ENABLED)
798 aSpinInfo.state = kThemeStateInactive;
799 else if (nUpperState & ControlState::ROLLOVER || nLowerState & ControlState::ROLLOVER)
800 aSpinInfo.state = kThemeStateRollover;
801 switch (aValue.getTristateVal())
803 case ButtonValue::On:
804 aSpinInfo.value = kThemeButtonOn;
805 break;
806 case ButtonValue::Off:
807 aSpinInfo.value = kThemeButtonOff;
808 break;
809 case ButtonValue::Mixed:
810 case ButtonValue::DontKnow:
811 default:
812 aSpinInfo.value = kThemeButtonMixed;
813 break;
815 aSpinInfo.adornment = (nUpperState & ControlState::DEFAULT || nLowerState & ControlState::DEFAULT)
816 ? kThemeAdornmentDefault : kThemeAdornmentNone;
817 if (nUpperState & ControlState::FOCUSED || nLowerState & ControlState::FOCUSED)
818 aSpinInfo.adornment |= kThemeAdornmentFocus;
819 rc.origin.x += rc.size.width + 2 * FOCUS_RING_WIDTH;
820 rc.size.width = SPIN_BUTTON_WIDTH;
821 rc.size.height = SPIN_LOWER_BUTTON_HEIGHT + SPIN_LOWER_BUTTON_HEIGHT;
822 HIThemeDrawButton(&rc, &aSpinInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
824 bOK = true;
826 break;
827 case ControlType::Frame:
829 DrawFrameFlags nStyle = static_cast<DrawFrameFlags>(aValue.getNumericVal());
830 if (nPart == ControlPart::Border)
832 if (!(nStyle & DrawFrameFlags::Menu) && !(nStyle & DrawFrameFlags::WindowBorder))
835 // strange effects start to happen when HIThemeDrawFrame meets the border of the window.
836 // These can be avoided by clipping to the boundary of the frame (see issue 84756)
838 if (rc.origin.y + rc.size.height >= mpFrame->maGeometry.nHeight - 3)
840 CGMutablePathRef rPath = CGPathCreateMutable();
841 CGPathAddRect(rPath, nullptr,
842 CGRectMake(0, 0, mpFrame->maGeometry.nWidth - 1, mpFrame->maGeometry.nHeight - 1));
843 CGContextBeginPath(maContextHolder.get());
844 CGContextAddPath(maContextHolder.get(), rPath);
845 CGContextClip(maContextHolder.get());
846 CGPathRelease(rPath);
848 HIThemeFrameDrawInfo aTextDrawInfo;
849 aTextDrawInfo.version = 0;
850 aTextDrawInfo.kind = kHIThemeFrameListBox;
851 aTextDrawInfo.state = kThemeStateActive;
852 aTextDrawInfo.isFocused = false;
853 HIThemeDrawFrame(&rc, &aTextDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal);
854 bOK = true;
858 break;
859 case ControlType::ListNet:
861 // do nothing as there isn't net for listviews on macOS
863 bOK = true;
864 break;
865 default:
866 break;
868 maContextHolder.restoreState();
870 // in most cases invalidating the whole control region instead of just the unclipped part of it is sufficient (and probably
871 // faster). However for the window background we should not unnecessarily enlarge the really changed rectangle since the
872 // difference is usually quite high. Background is always drawn as a whole since we don't know anything about its possible
873 // contents (see issue i90291).
875 if (nType == ControlType::WindowBackground)
877 CGRect aRect = {{0, 0}, {0, 0}};
878 if (mxClipPath)
879 aRect = CGPathGetBoundingBox(mxClipPath);
880 if (aRect.size.width != 0 && aRect.size.height != 0)
881 buttonRect.Intersection(tools::Rectangle(Point(static_cast<tools::Long>(aRect.origin.x),
882 static_cast<tools::Long>(aRect.origin.y)),
883 Size(static_cast<tools::Long>(aRect.size.width),
884 static_cast<tools::Long>(aRect.size.height))));
886 RefreshRect(buttonRect.Left(), buttonRect.Top(), buttonRect.GetWidth(), buttonRect.GetHeight());
887 return bOK;
890 bool AquaSalGraphics::getNativeControlRegion(ControlType nType,
891 ControlPart nPart,
892 const tools::Rectangle &rControlRegion,
893 ControlState,
894 const ImplControlValue &aValue,
895 const OUString &,
896 tools::Rectangle &rNativeBoundingRegion,
897 tools::Rectangle &rNativeContentRegion)
899 bool toReturn = false;
900 tools::Rectangle aCtrlBoundRect(rControlRegion);
901 short x = aCtrlBoundRect.Left();
902 short y = aCtrlBoundRect.Top();
903 short w, h;
904 switch (nType)
906 case ControlType::Pushbutton:
907 case ControlType::Radiobutton:
908 case ControlType::Checkbox:
910 if (nType == ControlType::Pushbutton)
912 w = aCtrlBoundRect.GetWidth();
913 h = aCtrlBoundRect.GetHeight();
915 else
917 w = RADIO_BUTTON_SMALL_SIZE + 2 * FOCUS_RING_WIDTH + RADIO_BUTTON_TEXT_SEPARATOR;
918 h = RADIO_BUTTON_SMALL_SIZE + 2 * FOCUS_RING_WIDTH;
920 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
921 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
922 toReturn = true;
924 break;
925 case ControlType::Progress:
927 tools::Rectangle aRect(aCtrlBoundRect);
928 if (aRect.GetHeight() < LARGE_PROGRESS_INDICATOR_HEIGHT)
929 aRect.SetBottom(aRect.Top() + MEDIUM_PROGRESS_INDICATOR_HEIGHT - 1);
930 else
931 aRect.SetBottom(aRect.Top() + LARGE_PROGRESS_INDICATOR_HEIGHT - 1);
932 rNativeBoundingRegion = aRect;
933 rNativeContentRegion = aRect;
934 toReturn = true;
936 break;
937 case ControlType::IntroProgress:
939 tools::Rectangle aRect(aCtrlBoundRect);
940 aRect.SetBottom(aRect.Top() + MEDIUM_PROGRESS_INDICATOR_HEIGHT - 1);
941 rNativeBoundingRegion = aRect;
942 rNativeContentRegion = aRect;
943 toReturn = true;
945 break;
946 case ControlType::Slider:
947 if (nPart == ControlPart::ThumbHorz)
949 w = SLIDER_WIDTH;
950 h = aCtrlBoundRect.GetHeight();
951 rNativeBoundingRegion = rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
952 toReturn = true;
954 else if (nPart == ControlPart::ThumbVert)
956 w = aCtrlBoundRect.GetWidth();
957 h = SLIDER_HEIGHT;
958 rNativeBoundingRegion = rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
959 toReturn = true;
961 break;
962 case ControlType::Scrollbar:
964 tools::Rectangle aRect;
965 if (AquaGetScrollRect(nPart, aCtrlBoundRect, aRect))
967 toReturn = true;
968 rNativeBoundingRegion = aRect;
969 rNativeContentRegion = aRect;
972 break;
973 case ControlType::TabItem:
975 w = aCtrlBoundRect.GetWidth() + 2 * TAB_TEXT_MARGIN - 2 * VCL_TAB_TEXT_SEPARATOR;
976 h = TAB_HEIGHT + 2;
977 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
978 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
979 toReturn = true;
981 break;
982 case ControlType::Editbox:
984 w = aCtrlBoundRect.GetWidth();
985 h = EDITBOX_HEIGHT + 2 * FOCUS_RING_WIDTH;
986 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
987 w -= 2 * (FOCUS_RING_WIDTH + EDITBOX_BORDER_WIDTH + EDITBOX_INSET_MARGIN);
988 h -= 2 * (FOCUS_RING_WIDTH + EDITBOX_BORDER_WIDTH + EDITBOX_INSET_MARGIN);
989 x += FOCUS_RING_WIDTH + EDITBOX_BORDER_WIDTH + EDITBOX_INSET_MARGIN;
990 y += FOCUS_RING_WIDTH + EDITBOX_BORDER_WIDTH + EDITBOX_INSET_MARGIN;
991 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
992 toReturn = true;
994 break;
995 case ControlType::Combobox:
996 if (nPart == ControlPart::Entire)
998 w = aCtrlBoundRect.GetWidth();
999 h = COMBOBOX_HEIGHT + 2 * FOCUS_RING_WIDTH;
1000 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
1001 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
1002 toReturn = true;
1004 else if (nPart == ControlPart::ButtonDown)
1006 w = COMBOBOX_BUTTON_WIDTH + FOCUS_RING_WIDTH;
1007 h = COMBOBOX_HEIGHT + 2 * FOCUS_RING_WIDTH;
1008 x += aCtrlBoundRect.GetWidth() - w;
1009 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
1010 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
1011 toReturn = true;
1013 else if (nPart == ControlPart::SubEdit)
1015 w = aCtrlBoundRect.GetWidth() - 2 * FOCUS_RING_WIDTH - COMBOBOX_BUTTON_WIDTH - COMBOBOX_BORDER_WIDTH
1016 - 2 * COMBOBOX_TEXT_MARGIN;
1017 h = COMBOBOX_HEIGHT - 2 * COMBOBOX_BORDER_WIDTH;
1018 x += FOCUS_RING_WIDTH + COMBOBOX_BORDER_WIDTH + COMBOBOX_TEXT_MARGIN;
1019 y += FOCUS_RING_WIDTH + COMBOBOX_BORDER_WIDTH;
1020 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
1021 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
1022 toReturn = true;
1024 break;
1025 case ControlType::Listbox:
1026 if (nPart == ControlPart::Entire)
1028 w = aCtrlBoundRect.GetWidth();
1029 h = LISTBOX_HEIGHT + 2 * FOCUS_RING_WIDTH;
1030 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
1031 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
1032 toReturn = true;
1034 else if (nPart == ControlPart::ButtonDown)
1036 w = LISTBOX_BUTTON_WIDTH + FOCUS_RING_WIDTH;
1037 h = LISTBOX_HEIGHT + 2 * FOCUS_RING_WIDTH;
1038 x += aCtrlBoundRect.GetWidth() - w;
1039 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
1040 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
1041 toReturn = true;
1043 else if (nPart == ControlPart::SubEdit)
1045 w = aCtrlBoundRect.GetWidth() - 2 * FOCUS_RING_WIDTH - LISTBOX_BUTTON_WIDTH - LISTBOX_BORDER_WIDTH
1046 - 2 * LISTBOX_TEXT_MARGIN;
1047 h = LISTBOX_HEIGHT - 2 * LISTBOX_BORDER_WIDTH;
1048 x += FOCUS_RING_WIDTH + LISTBOX_BORDER_WIDTH + LISTBOX_TEXT_MARGIN;
1049 y += FOCUS_RING_WIDTH + LISTBOX_BORDER_WIDTH;
1050 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
1051 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
1052 toReturn = true;
1054 break;
1055 case ControlType::Spinbox:
1056 if (nPart == ControlPart::Entire)
1058 w = aCtrlBoundRect.GetWidth();
1059 h = EDITBOX_HEIGHT + 2 * FOCUS_RING_WIDTH;
1060 x += SPINBOX_OFFSET;
1061 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
1062 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
1063 toReturn = true;
1065 else if (nPart == ControlPart::SubEdit)
1067 w = aCtrlBoundRect.GetWidth() - 4 * FOCUS_RING_WIDTH - SPIN_BUTTON_WIDTH - 2 * EDITBOX_BORDER_WIDTH
1068 - 2 * EDITBOX_INSET_MARGIN;
1069 h = EDITBOX_HEIGHT - 2 * (EDITBOX_BORDER_WIDTH + EDITBOX_INSET_MARGIN);
1070 x += FOCUS_RING_WIDTH + EDITBOX_BORDER_WIDTH + EDITBOX_INSET_MARGIN + SPINBOX_OFFSET;
1071 y += FOCUS_RING_WIDTH + EDITBOX_BORDER_WIDTH + EDITBOX_INSET_MARGIN;
1072 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
1073 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
1074 toReturn = true;
1076 else if (nPart == ControlPart::ButtonUp)
1078 w = SPIN_BUTTON_WIDTH + 2 * FOCUS_RING_WIDTH;
1079 h = SPIN_UPPER_BUTTON_HEIGHT + FOCUS_RING_WIDTH;
1080 x += aCtrlBoundRect.GetWidth() - SPIN_BUTTON_WIDTH - 2 * FOCUS_RING_WIDTH + SPINBOX_OFFSET;
1081 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
1082 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
1083 toReturn = true;
1085 else if (nPart == ControlPart::ButtonDown)
1087 w = SPIN_BUTTON_WIDTH + 2 * FOCUS_RING_WIDTH;
1088 h = SPIN_LOWER_BUTTON_HEIGHT + FOCUS_RING_WIDTH;
1089 x += aCtrlBoundRect.GetWidth() - SPIN_BUTTON_WIDTH - 2 * FOCUS_RING_WIDTH + SPINBOX_OFFSET;
1090 y += FOCUS_RING_WIDTH + SPIN_UPPER_BUTTON_HEIGHT;
1091 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
1092 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
1093 toReturn = true;
1095 break;
1096 case ControlType::Frame:
1098 DrawFrameStyle nStyle = static_cast<DrawFrameStyle>(aValue.getNumericVal() & 0x000f);
1099 DrawFrameFlags nFlags = static_cast<DrawFrameFlags>(aValue.getNumericVal() & 0xfff0);
1100 if (nPart == ControlPart::Border
1101 && !(nFlags & (DrawFrameFlags::Menu | DrawFrameFlags::WindowBorder | DrawFrameFlags::BorderWindowBorder)))
1103 tools::Rectangle aRect(aCtrlBoundRect);
1104 if (nStyle == DrawFrameStyle::DoubleIn)
1106 aRect.AdjustLeft(1);
1107 aRect.AdjustTop(1);
1108 // rRect.Right() -= 1;
1109 // rRect.Bottom() -= 1;
1111 else
1113 aRect.AdjustLeft(1);
1114 aRect.AdjustTop(1);
1115 aRect.AdjustRight(-1);
1116 aRect.AdjustBottom(-1);
1118 rNativeContentRegion = aRect;
1119 rNativeBoundingRegion = aRect;
1120 toReturn = true;
1123 break;
1124 case ControlType::Menubar:
1125 case ControlType::MenuPopup:
1126 if (nPart == ControlPart::MenuItemCheckMark || nPart == ControlPart::MenuItemRadioMark)
1128 w=10;
1129 h=10;
1130 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
1131 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
1132 toReturn = true;
1134 break;
1135 default:
1136 break;
1138 return toReturn;
1141 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */