bump product version to 7.2.5.1
[LibreOffice.git] / vcl / osx / salnativewidgets.cxx
blob589feec622080419a7e249371f8c4f5bc7c91593
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 case ButtonValue::Off:
80 case ButtonValue::DontKnow:
81 return kThemeButtonOff;
82 case ButtonValue::Mixed:
83 default:
84 return kThemeButtonMixed;
88 static bool AquaGetScrollRect(/* TODO: int nScreen, */
89 ControlPart nPart, const tools::Rectangle &rControlRect, tools::Rectangle &rResultRect)
91 bool bRetVal = true;
92 rResultRect = rControlRect;
93 switch (nPart)
95 case ControlPart::ButtonUp:
96 rResultRect.SetBottom(rResultRect.Top());
97 break;
98 case ControlPart::ButtonDown:
99 rResultRect.SetTop(rResultRect.Bottom());
100 break;
101 case ControlPart::ButtonLeft:
102 rResultRect.SetRight(rResultRect.Left());
103 break;
104 case ControlPart::ButtonRight:
105 rResultRect.SetLeft(rResultRect.Right());
106 break;
107 case ControlPart::TrackHorzArea:
108 case ControlPart::TrackVertArea:
109 case ControlPart::ThumbHorz:
110 case ControlPart::ThumbVert:
111 case ControlPart::TrackHorzLeft:
112 case ControlPart::TrackHorzRight:
113 case ControlPart::TrackVertUpper:
114 case ControlPart::TrackVertLower:
115 break;
116 default:
117 bRetVal = false;
119 return bRetVal;
122 bool AquaSalGraphics::isNativeControlSupported(ControlType nType, ControlPart nPart)
124 // native controls are now defaults. If you want to disable native controls, set the environment variable SAL_NO_NWF to
125 // something and VCL controls will be used as default again.
127 switch (nType)
129 case ControlType::Pushbutton:
130 case ControlType::Radiobutton:
131 case ControlType::Checkbox:
132 case ControlType::ListNode:
133 if (nPart == ControlPart::Entire)
134 return true;
135 break;
136 case ControlType::Scrollbar:
137 if (nPart == ControlPart::DrawBackgroundHorz || nPart == ControlPart::DrawBackgroundVert
138 || nPart == ControlPart::Entire || nPart == ControlPart::HasThreeButtons)
139 return true;
140 break;
141 case ControlType::Slider:
142 if (nPart == ControlPart::TrackHorzArea || nPart == ControlPart::TrackVertArea)
143 return true;
144 break;
145 case ControlType::Editbox:
146 if (nPart == ControlPart::Entire || nPart == ControlPart::HasBackgroundTexture)
147 return true;
148 break;
149 case ControlType::MultilineEditbox:
150 if (nPart == ControlPart::Entire || nPart == ControlPart::HasBackgroundTexture)
151 return true;
152 break;
153 case ControlType::Spinbox:
154 if (nPart == ControlPart::Entire || nPart == ControlPart::AllButtons || nPart == ControlPart::HasBackgroundTexture)
155 return true;
156 break;
157 case ControlType::SpinButtons:
158 return false;
159 case ControlType::Combobox:
160 if (nPart == ControlPart::Entire || nPart == ControlPart::HasBackgroundTexture)
161 return true;
162 break;
163 case ControlType::Listbox:
164 if (nPart == ControlPart::Entire || nPart == ControlPart::ListboxWindow || nPart == ControlPart::HasBackgroundTexture
165 || nPart == ControlPart::SubEdit)
166 return true;
167 break;
168 case ControlType::TabItem:
169 case ControlType::TabPane:
170 case ControlType::TabBody:
171 if (nPart == ControlPart::Entire || nPart == ControlPart::TabsDrawRtl || nPart == ControlPart::HasBackgroundTexture)
172 return true;
173 break;
174 case ControlType::Toolbar:
175 if (nPart == ControlPart::Entire || nPart == ControlPart::DrawBackgroundHorz
176 || nPart == ControlPart::DrawBackgroundVert)
177 return true;
178 break;
179 case ControlType::WindowBackground:
180 if (nPart == ControlPart::BackgroundWindow || nPart == ControlPart::BackgroundDialog)
181 return true;
182 break;
183 case ControlType::Menubar:
184 if (nPart == ControlPart::Entire)
185 return true;
186 break;
187 case ControlType::Tooltip:
188 if (nPart == ControlPart::Entire)
189 return true;
190 break;
191 case ControlType::MenuPopup:
192 if (nPart == ControlPart::Entire || nPart == ControlPart::MenuItem || nPart == ControlPart::MenuItemCheckMark
193 || nPart == ControlPart::MenuItemRadioMark)
194 return true;
195 break;
196 case ControlType::Progress:
197 case ControlType::IntroProgress:
198 if (nPart == ControlPart::Entire)
199 return true;
200 break;
201 case ControlType::Frame:
202 if (nPart == ControlPart::Border)
203 return true;
204 break;
205 case ControlType::ListNet:
206 if (nPart == ControlPart::Entire)
207 return true;
208 break;
209 default:
210 break;
212 return false;
215 bool AquaSalGraphics::hitTestNativeControl(ControlType nType, ControlPart nPart, const tools::Rectangle &rControlRegion,
216 const Point &rPos, bool& rIsInside)
218 if (nType == ControlType::Scrollbar)
220 tools::Rectangle aRect;
221 bool bValid = AquaGetScrollRect(/* TODO: int nScreen, */
222 nPart, rControlRegion, aRect);
223 rIsInside = bValid && aRect.IsInside(rPos);
224 return bValid;
226 return false;
229 UInt32 AquaSalGraphics::getState(ControlState nState)
232 // there are non key windows which are children of key windows, e.g. autofilter configuration dialog or sidebar dropdown dialogs.
233 // To handle these windows correctly, parent frame's key window state is considered here additionally.
235 const bool bDrawActive = maShared.mpFrame == nullptr || [maShared.mpFrame->getNSWindow() isKeyWindow]
236 || maShared.mpFrame->mpParent == nullptr || [maShared.mpFrame->mpParent->getNSWindow() isKeyWindow];
237 if (!(nState & ControlState::ENABLED) || !bDrawActive)
239 return kThemeStateInactive;
241 if (nState & ControlState::PRESSED)
242 return kThemeStatePressed;
243 return kThemeStateActive;
246 UInt32 AquaSalGraphics::getTrackState(ControlState nState)
248 const bool bDrawActive = maShared.mpFrame == nullptr || [maShared.mpFrame->getNSWindow() isKeyWindow];
249 if (!(nState & ControlState::ENABLED) || !bDrawActive)
250 return kThemeTrackInactive;
251 return kThemeTrackActive;
254 bool AquaSalGraphics::drawNativeControl(ControlType nType,
255 ControlPart nPart,
256 const tools::Rectangle &rControlRegion,
257 ControlState nState,
258 const ImplControlValue &aValue,
259 const OUString &,
260 const Color&)
262 bool bOK = false;
263 if (!maShared.checkContext())
264 return false;
265 maShared.maContextHolder.saveState();
266 tools::Rectangle buttonRect = rControlRegion;
267 HIRect rc = ImplGetHIRectFromRectangle(buttonRect);
268 switch (nType)
270 case ControlType::Toolbar:
272 #if HAVE_FEATURE_MACOSX_SANDBOX
273 HIThemeMenuItemDrawInfo aMenuItemDrawInfo;
274 aMenuItemDrawInfo.version = 0;
275 aMenuItemDrawInfo.state = kThemeMenuActive;
276 aMenuItemDrawInfo.itemType = kThemeMenuItemHierBackground;
277 HIThemeDrawMenuItem(&rc, &rc, &aMenuItemDrawInfo, maShared.maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
278 #else
279 if (rControlRegion.Top() == 0 && nPart == ControlPart::DrawBackgroundHorz)
281 const bool bDrawActive = maShared.mpFrame == nullptr || [maShared.mpFrame->getNSWindow() isKeyWindow];
282 CGFloat unifiedHeight = rControlRegion.GetHeight();
283 CGRect drawRect = CGRectMake(rControlRegion.Left(), rControlRegion.Top(),
284 rControlRegion.GetWidth(), rControlRegion.GetHeight());
285 CUIDraw([NSWindow coreUIRenderer], drawRect, maShared.maContextHolder.get(),
286 reinterpret_cast<CFDictionaryRef>([NSDictionary dictionaryWithObjectsAndKeys:
287 @"kCUIWidgetWindowFrame",
288 @"widget",
289 @"regularwin",
290 @"windowtype",
291 (bDrawActive ? @"normal" : @"inactive"),
292 @"state",
293 [NSNumber numberWithDouble:unifiedHeight],
294 @"kCUIWindowFrameUnifiedTitleBarHeightKey",
295 [NSNumber numberWithBool:NO],
296 @"kCUIWindowFrameDrawTitleSeparatorKey",
297 [NSNumber numberWithBool:YES],
298 @"is.flipped",
299 nil]),
300 nil);
302 else
304 HIThemeMenuItemDrawInfo aMenuItemDrawInfo;
305 aMenuItemDrawInfo.version = 0;
306 aMenuItemDrawInfo.state = kThemeMenuActive;
307 aMenuItemDrawInfo.itemType = kThemeMenuItemHierBackground;
308 HIThemeDrawMenuItem(&rc, &rc, &aMenuItemDrawInfo, maShared.maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
310 #endif
311 bOK = true;
313 break;
314 case ControlType::WindowBackground:
316 HIThemeBackgroundDrawInfo aThemeBackgroundInfo;
317 aThemeBackgroundInfo.version = 0;
318 aThemeBackgroundInfo.state = getState(nState);
319 aThemeBackgroundInfo.kind = kThemeBrushDialogBackgroundActive;
321 // FIXME: without this magical offset there is a 2 pixel black border on the right and bottom
323 rc.size.width += 2;
324 rc.size.height += 2;
325 HIThemeApplyBackground( &rc, &aThemeBackgroundInfo, maShared.maContextHolder.get(), kHIThemeOrientationNormal);
326 CGContextFillRect(maShared.maContextHolder.get(), rc);
327 bOK = true;
329 break;
330 case ControlType::Tooltip:
332 HIThemeBackgroundDrawInfo aThemeBackgroundInfo;
333 aThemeBackgroundInfo.version = 0;
334 aThemeBackgroundInfo.state = getState(nState);
335 aThemeBackgroundInfo.kind = kThemeBrushAlertBackgroundActive;
336 rc.size.width += 2;
337 rc.size.height += 2;
338 HIThemeApplyBackground(&rc, &aThemeBackgroundInfo, maShared.maContextHolder.get(), kHIThemeOrientationNormal);
339 CGContextFillRect(maShared.maContextHolder.get(), rc);
340 bOK = true;
342 break;
343 case ControlType::Menubar:
344 case ControlType::MenuPopup:
345 if (nPart == ControlPart::Entire || nPart == ControlPart::MenuItem || nPart == ControlPart::HasBackgroundTexture)
348 // FIXME: without this magical offset there is a 2 pixel black border on the right
350 rc.size.width += 2;
351 HIThemeMenuDrawInfo aMenuInfo;
352 aMenuInfo.version = 0;
353 aMenuInfo.menuType = kThemeMenuTypePullDown;
354 HIThemeMenuItemDrawInfo aMenuItemDrawInfo;
356 // grey theme when the item is selected is drawn here.
358 aMenuItemDrawInfo.itemType = kThemeMenuItemPlain;
359 if ((nPart == ControlPart::MenuItem) && (nState & ControlState::SELECTED))
361 // blue theme when the item is selected is drawn here.
363 aMenuItemDrawInfo.state = kThemeMenuSelected;
364 else
366 // normal color for non selected item
368 aMenuItemDrawInfo.state = kThemeMenuActive;
370 // repaints the background of the pull down menu
372 HIThemeDrawMenuBackground(&rc, &aMenuInfo, maShared.maContextHolder.get(), kHIThemeOrientationNormal);
374 // repaints the item either blue (selected) and/or grey (active only)
376 HIThemeDrawMenuItem(&rc, &rc, &aMenuItemDrawInfo, maShared.maContextHolder.get(), kHIThemeOrientationNormal, &rc);
377 bOK = true;
379 else if (nPart == ControlPart::MenuItemCheckMark || nPart == ControlPart::MenuItemRadioMark)
382 // checked, else it is not displayed (see vcl/source/window/menu.cxx)
384 if (nState & ControlState::PRESSED)
386 HIThemeTextInfo aTextInfo;
387 aTextInfo.version = 0;
388 aTextInfo.state = (nState & ControlState::ENABLED) ? kThemeStateInactive: kThemeStateActive;
389 aTextInfo.fontID = kThemeMenuItemMarkFont;
390 aTextInfo.horizontalFlushness = kHIThemeTextHorizontalFlushCenter;
391 aTextInfo.verticalFlushness = kHIThemeTextVerticalFlushTop;
392 aTextInfo.options = kHIThemeTextBoxOptionNone;
393 aTextInfo.truncationPosition = kHIThemeTextTruncationNone;
395 // aTextInfo.truncationMaxLines unused because of kHIThemeTextTruncationNone item highlighted
397 if (nState & ControlState::SELECTED) aTextInfo.state = kThemeStatePressed;
398 UniChar mark=(nPart == ControlPart::MenuItemCheckMark) ? kCheckUnicode: kBulletUnicode;
399 CFStringRef cfString = CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, &mark, 1, kCFAllocatorNull);
400 HIThemeDrawTextBox(cfString, &rc, &aTextInfo, maShared.maContextHolder.get(), kHIThemeOrientationNormal);
401 if (cfString)
402 CFRelease(cfString);
403 bOK = true;
406 break;
407 case ControlType::Pushbutton:
410 // FIXME: instead of use a value, VCL can retrieve correct values on the fly (to be implemented)
412 HIThemeButtonDrawInfo aPushInfo;
413 aPushInfo.version = 0;
415 // no animation
417 aPushInfo.animation.time.start = 0;
418 aPushInfo.animation.time.current = 0;
419 PushButtonValue const *pPBVal = aValue.getType() == ControlType::Pushbutton ?
420 static_cast<PushButtonValue const *>(&aValue) : nullptr;
421 int nPaintHeight = static_cast<int>(rc.size.height);
422 if (pPBVal && pPBVal->mbBevelButton)
424 aPushInfo.kind = kThemeRoundedBevelButton;
426 else if (rc.size.height <= PUSH_BUTTON_NORMAL_HEIGHT)
428 aPushInfo.kind = kThemePushButtonMini;
429 nPaintHeight = PUSH_BUTTON_SMALL_HEIGHT;
431 else if ((pPBVal && pPBVal->mbSingleLine) || rc.size.height < PUSH_BUTTON_NORMAL_HEIGHT * 3 / 2)
433 aPushInfo.kind = kThemePushButtonNormal;
434 nPaintHeight = PUSH_BUTTON_NORMAL_HEIGHT;
436 // avoid clipping when focused
438 rc.origin.x += FOCUS_RING_WIDTH / 2;
439 rc.size.width -= FOCUS_RING_WIDTH;
441 else
442 aPushInfo.kind = kThemeBevelButton;
444 // translate the origin for controls with fixed paint height so content ends up somewhere sensible
446 rc.origin.y += (rc.size.height - nPaintHeight) / 2;
447 aPushInfo.state = getState(nState);
448 aPushInfo.value = ImplGetButtonValue(aValue.getTristateVal());
449 aPushInfo.adornment = (nState & ControlState::DEFAULT) ? kThemeAdornmentDefault : kThemeAdornmentNone;
450 if (nState & ControlState::FOCUSED)
451 aPushInfo.adornment |= kThemeAdornmentFocus;
452 HIThemeDrawButton(&rc, &aPushInfo, maShared.maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
453 bOK = true;
455 break;
456 case ControlType::Radiobutton:
457 case ControlType::Checkbox:
459 HIThemeButtonDrawInfo aInfo;
460 aInfo.version = 0;
461 switch (nType)
463 case ControlType::Radiobutton:
464 if (rc.size.width >= RADIO_BUTTON_SMALL_SIZE)
465 aInfo.kind = kThemeRadioButton;
466 else
467 aInfo.kind = kThemeSmallRadioButton;
468 break;
469 case ControlType::Checkbox:
470 if (rc.size.width >= CHECKBOX_SMALL_SIZE)
471 aInfo.kind = kThemeCheckBox;
472 else
473 aInfo.kind = kThemeSmallCheckBox;
474 break;
475 default:
476 break;
478 aInfo.state = getState(nState);
479 ButtonValue aButtonValue = aValue.getTristateVal();
480 aInfo.value = ImplGetButtonValue(aButtonValue);
481 aInfo.adornment = (nState & ControlState::DEFAULT) ? kThemeAdornmentDefault : kThemeAdornmentNone;
482 if (nState & ControlState::FOCUSED)
483 aInfo.adornment |= kThemeAdornmentFocus;
484 rc.size.width -= 2 * FOCUS_RING_WIDTH;
485 rc.size.height = RADIO_BUTTON_SMALL_SIZE;
486 rc.origin.x += FOCUS_RING_WIDTH;
487 rc.origin.y += FOCUS_RING_WIDTH;
488 HIThemeDrawButton(&rc, &aInfo, maShared.maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
489 bOK = true;
491 break;
492 case ControlType::ListNode:
494 ButtonValue aButtonValue = aValue.getTristateVal();
495 HIThemeButtonDrawInfo aInfo;
496 aInfo.version = 0;
497 aInfo.kind = kThemeDisclosureTriangle;
498 aInfo.value = kThemeDisclosureRight;
499 aInfo.state = getState(nState);
500 aInfo.adornment = kThemeAdornmentNone;
501 switch (aButtonValue)
503 case ButtonValue::On:
504 aInfo.value = kThemeDisclosureDown;
505 break;
506 case ButtonValue::Off:
507 if (AllSettings::GetLayoutRTL())
508 aInfo.value = kThemeDisclosureLeft;
509 break;
510 case ButtonValue::DontKnow:
511 default:
512 break;
514 HIThemeDrawButton(&rc, &aInfo, maShared.maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
515 bOK = true;
517 break;
518 case ControlType::Progress:
519 case ControlType::IntroProgress:
521 tools::Long nProgressWidth = aValue.getNumericVal();
522 HIThemeTrackDrawInfo aTrackInfo;
523 aTrackInfo.version = 0;
524 aTrackInfo.kind = (rc.size.height > 10) ? kThemeProgressBarLarge : kThemeProgressBarMedium;
525 aTrackInfo.bounds = rc;
526 aTrackInfo.min = 0;
527 aTrackInfo.max = static_cast<SInt32>(rc.size.width);
528 aTrackInfo.value = nProgressWidth;
529 aTrackInfo.reserved = 0;
530 aTrackInfo.attributes = kThemeTrackHorizontal;
531 if (AllSettings::GetLayoutRTL())
532 aTrackInfo.attributes |= kThemeTrackRightToLeft;
533 aTrackInfo.enableState = getTrackState(nState);
535 // the intro bitmap never gets key anyway; we want to draw that enabled
537 if (nType == ControlType::IntroProgress)
538 aTrackInfo.enableState = kThemeTrackActive;
539 aTrackInfo.filler1 = 0;
540 aTrackInfo.trackInfo.progress.phase = static_cast<long long>(CFAbsoluteTimeGetCurrent() * 10.0);
541 HIThemeDrawTrack(&aTrackInfo, nullptr, maShared.maContextHolder.get(), kHIThemeOrientationNormal);
542 bOK = true;
544 break;
545 case ControlType::Slider:
547 const SliderValue *pSliderVal = static_cast<SliderValue const *>(&aValue);
548 HIThemeTrackDrawInfo aTrackDraw;
549 aTrackDraw.kind = kThemeSliderMedium;
550 if (nPart == ControlPart::TrackHorzArea || nPart == ControlPart::TrackVertArea)
552 aTrackDraw.bounds = rc;
553 aTrackDraw.min = pSliderVal->mnMin;
554 aTrackDraw.max = pSliderVal->mnMax;
555 aTrackDraw.value = pSliderVal->mnCur;
556 aTrackDraw.reserved = 0;
557 aTrackDraw.attributes = kThemeTrackShowThumb;
558 if (nPart == ControlPart::TrackHorzArea)
559 aTrackDraw.attributes |= kThemeTrackHorizontal;
560 aTrackDraw.enableState = (nState & ControlState::ENABLED) ? kThemeTrackActive : kThemeTrackInactive;
561 SliderTrackInfo aSlideInfo;
562 aSlideInfo.thumbDir = kThemeThumbUpward;
563 aSlideInfo.pressState = 0;
564 aTrackDraw.trackInfo.slider = aSlideInfo;
565 HIThemeDrawTrack(&aTrackDraw, nullptr, maShared.maContextHolder.get(), kHIThemeOrientationNormal);
566 bOK = true;
569 break;
570 case ControlType::Scrollbar:
572 const ScrollbarValue *pScrollbarVal = (aValue.getType() == ControlType::Scrollbar)
573 ? static_cast<const ScrollbarValue *>(&aValue) : nullptr;
574 if (nPart == ControlPart::DrawBackgroundVert || nPart == ControlPart::DrawBackgroundHorz)
576 HIThemeTrackDrawInfo aTrackDraw;
577 aTrackDraw.kind = kThemeMediumScrollBar;
578 aTrackDraw.bounds = rc;
579 aTrackDraw.min = pScrollbarVal->mnMin;
580 aTrackDraw.max = pScrollbarVal->mnMax - pScrollbarVal->mnVisibleSize;
581 aTrackDraw.value = pScrollbarVal->mnCur;
582 aTrackDraw.reserved = 0;
583 aTrackDraw.attributes = kThemeTrackShowThumb;
584 if (nPart == ControlPart::DrawBackgroundHorz)
585 aTrackDraw.attributes |= kThemeTrackHorizontal;
586 aTrackDraw.enableState = getTrackState(nState);
587 ScrollBarTrackInfo aScrollInfo;
588 aScrollInfo.viewsize = pScrollbarVal->mnVisibleSize;
589 aScrollInfo.pressState = 0;
590 if (pScrollbarVal->mnButton1State & ControlState::ENABLED)
591 if (pScrollbarVal->mnButton1State & ControlState::PRESSED)
592 aScrollInfo.pressState = kThemeTopOutsideArrowPressed;
593 if (pScrollbarVal->mnButton2State & ControlState::ENABLED )
594 if (pScrollbarVal->mnButton2State & ControlState::PRESSED )
595 aScrollInfo.pressState = kThemeBottomOutsideArrowPressed;
596 if ( pScrollbarVal->mnThumbState & ControlState::ENABLED)
597 if (pScrollbarVal->mnThumbState & ControlState::PRESSED)
598 aScrollInfo.pressState = kThemeThumbPressed;
599 aTrackDraw.trackInfo.scrollbar = aScrollInfo;
600 HIThemeDrawTrack(&aTrackDraw, nullptr, maShared.maContextHolder.get(), kHIThemeOrientationNormal);
601 bOK = true;
604 break;
605 case ControlType::TabPane:
607 HIThemeTabPaneDrawInfo aTabPaneDrawInfo;
608 aTabPaneDrawInfo.version = 1;
609 aTabPaneDrawInfo.state = kThemeStateActive;
610 aTabPaneDrawInfo.direction = kThemeTabNorth;
611 aTabPaneDrawInfo.size = kHIThemeTabSizeNormal;
612 aTabPaneDrawInfo.kind = kHIThemeTabKindNormal;
614 // border is outside the rect rc for Carbon but for VCL it should be inside
616 rc.origin.x += 1;
617 rc.origin.y -= TAB_HEIGHT / 2;
618 rc.size.height += TAB_HEIGHT / 2;
619 rc.size.width -= 2;
620 HIThemeDrawTabPane(&rc, &aTabPaneDrawInfo, maShared.maContextHolder.get(), kHIThemeOrientationNormal);
621 bOK = true;
623 break;
624 case ControlType::TabItem:
626 HIThemeTabDrawInfo aTabItemDrawInfo;
627 aTabItemDrawInfo.version = 1;
628 aTabItemDrawInfo.style = kThemeTabNonFront;
629 aTabItemDrawInfo.direction = kThemeTabNorth;
630 aTabItemDrawInfo.size = kHIThemeTabSizeNormal;
631 aTabItemDrawInfo.adornment = kHIThemeTabAdornmentTrailingSeparator;
632 if (nState & ControlState::SELECTED)
633 aTabItemDrawInfo.style = kThemeTabFront;
634 if(nState & ControlState::FOCUSED)
635 aTabItemDrawInfo.adornment |= kHIThemeTabAdornmentFocus;
637 // first, last or middle tab
639 aTabItemDrawInfo.position = kHIThemeTabPositionMiddle;
640 TabitemValue const * pTabValue = static_cast<TabitemValue const *>(&aValue);
641 TabitemFlags nAlignment = pTabValue->mnAlignment;
643 // TabitemFlags::LeftAligned (and TabitemFlags::RightAligned) for the leftmost (or rightmost) tab
644 // when there are several lines of tabs because there is only one first tab and one
645 // last tab and TabitemFlags::FirstInGroup (and TabitemFlags::LastInGroup) because when the
646 // line width is different from window width, there may not be TabitemFlags::RightAligned
648 if (((nAlignment & TabitemFlags::LeftAligned) && (nAlignment & TabitemFlags::RightAligned))
649 || ((nAlignment & TabitemFlags::FirstInGroup) && (nAlignment & TabitemFlags::LastInGroup)))
650 aTabItemDrawInfo.position = kHIThemeTabPositionOnly;
651 else if ((nAlignment & TabitemFlags::LeftAligned) || (nAlignment & TabitemFlags::FirstInGroup))
652 aTabItemDrawInfo.position = kHIThemeTabPositionFirst;
653 else if ((nAlignment & TabitemFlags::RightAligned) || (nAlignment & TabitemFlags::LastInGroup))
654 aTabItemDrawInfo.position = kHIThemeTabPositionLast;
656 // support for RTL (see issue 79748)
658 if (AllSettings::GetLayoutRTL()) {
659 if (aTabItemDrawInfo.position == kHIThemeTabPositionFirst)
660 aTabItemDrawInfo.position = kHIThemeTabPositionLast;
661 else if (aTabItemDrawInfo.position == kHIThemeTabPositionLast)
662 aTabItemDrawInfo.position = kHIThemeTabPositionFirst;
664 HIThemeDrawTab(&rc, &aTabItemDrawInfo, maShared.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(maShared.maContextHolder.get(), CGRectMake(rc.origin.x, rc.origin.y, rc.size.width, rc.size.height));
687 HIThemeDrawFrame(&rc, &aTextDrawInfo, maShared.maContextHolder.get(), kHIThemeOrientationNormal);
688 if (nState & ControlState::FOCUSED)
689 HIThemeDrawFocusRect(&rc, true, maShared.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, maShared.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, maShared.maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
730 bOK = true;
731 break;
732 case ControlPart::ListboxWindow:
733 HIThemeFrameDrawInfo aTextDrawInfo;
734 aTextDrawInfo.version = 0;
735 aTextDrawInfo.kind = kHIThemeFrameListBox;
736 aTextDrawInfo.state = kThemeStateActive;
737 aTextDrawInfo.isFocused = false;
738 HIThemeDrawFrame(&rc, &aTextDrawInfo, maShared.maContextHolder.get(), kHIThemeOrientationNormal);
739 bOK = true;
740 break;
741 default:
742 break;
744 break;
745 case ControlType::Spinbox:
746 if (nPart == ControlPart::Entire)
749 // text field
751 HIThemeFrameDrawInfo aTextDrawInfo;
752 aTextDrawInfo.version = 0;
753 aTextDrawInfo.kind = kHIThemeFrameTextFieldSquare;
754 aTextDrawInfo.state = getState(nState);
755 aTextDrawInfo.isFocused = false;
756 rc.size.width -= SPIN_BUTTON_WIDTH + 4 * FOCUS_RING_WIDTH;
757 rc.size.height = EDITBOX_HEIGHT;
758 rc.origin.x += FOCUS_RING_WIDTH;
759 rc.origin.y += FOCUS_RING_WIDTH;
761 // fill a white background, because HIThemeDrawFrame only draws the border
763 CGContextFillRect(maShared.maContextHolder.get(), CGRectMake(rc.origin.x, rc.origin.y, rc.size.width, rc.size.height));
764 HIThemeDrawFrame(&rc, &aTextDrawInfo, maShared.maContextHolder.get(), kHIThemeOrientationNormal);
765 if (nState & ControlState::FOCUSED)
766 HIThemeDrawFocusRect(&rc, true, maShared.maContextHolder.get(), kHIThemeOrientationNormal);
768 // buttons
770 const SpinbuttonValue *pSpinButtonVal = (aValue.getType() == ControlType::SpinButtons)
771 ? static_cast <const SpinbuttonValue *>(&aValue) : nullptr;
772 ControlState nUpperState = ControlState::ENABLED;
773 ControlState nLowerState = ControlState::ENABLED;
774 if (pSpinButtonVal)
776 nUpperState = pSpinButtonVal->mnUpperState;
777 nLowerState = pSpinButtonVal->mnLowerState;
778 HIThemeButtonDrawInfo aSpinInfo;
779 aSpinInfo.kind = kThemeIncDecButton;
780 aSpinInfo.state = kThemeStateActive;
781 if (nUpperState & ControlState::PRESSED)
782 aSpinInfo.state = kThemeStatePressedUp;
783 else if (nLowerState & ControlState::PRESSED)
784 aSpinInfo.state = kThemeStatePressedDown;
785 else if (nUpperState & ~ControlState::ENABLED || nLowerState & ~ControlState::ENABLED)
786 aSpinInfo.state = kThemeStateInactive;
787 else if (nUpperState & ControlState::ROLLOVER || nLowerState & ControlState::ROLLOVER)
788 aSpinInfo.state = kThemeStateRollover;
789 switch (aValue.getTristateVal())
791 case ButtonValue::On:
792 aSpinInfo.value = kThemeButtonOn;
793 break;
794 case ButtonValue::Off:
795 aSpinInfo.value = kThemeButtonOff;
796 break;
797 case ButtonValue::Mixed:
798 case ButtonValue::DontKnow:
799 default:
800 aSpinInfo.value = kThemeButtonMixed;
801 break;
803 aSpinInfo.adornment = (nUpperState & ControlState::DEFAULT || nLowerState & ControlState::DEFAULT)
804 ? kThemeAdornmentDefault : kThemeAdornmentNone;
805 if (nUpperState & ControlState::FOCUSED || nLowerState & ControlState::FOCUSED)
806 aSpinInfo.adornment |= kThemeAdornmentFocus;
807 rc.origin.x += rc.size.width + FOCUS_RING_WIDTH + 1;
808 rc.origin.y -= 1;
809 rc.size.width = SPIN_BUTTON_WIDTH;
810 rc.size.height = SPIN_LOWER_BUTTON_HEIGHT + SPIN_LOWER_BUTTON_HEIGHT;
811 HIThemeDrawButton(&rc, &aSpinInfo, maShared.maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
813 bOK = true;
815 break;
816 case ControlType::Frame:
818 DrawFrameFlags nStyle = static_cast<DrawFrameFlags>(aValue.getNumericVal());
819 if (nPart == ControlPart::Border)
821 if (!(nStyle & DrawFrameFlags::Menu) && !(nStyle & DrawFrameFlags::WindowBorder))
824 // strange effects start to happen when HIThemeDrawFrame meets the border of the window.
825 // These can be avoided by clipping to the boundary of the frame (see issue 84756)
827 if (rc.origin.y + rc.size.height >= maShared.mpFrame->maGeometry.nHeight - 3)
829 CGMutablePathRef rPath = CGPathCreateMutable();
830 CGPathAddRect(rPath, nullptr,
831 CGRectMake(0, 0, maShared.mpFrame->maGeometry.nWidth - 1, maShared.mpFrame->maGeometry.nHeight - 1));
832 CGContextBeginPath(maShared.maContextHolder.get());
833 CGContextAddPath(maShared.maContextHolder.get(), rPath);
834 CGContextClip(maShared.maContextHolder.get());
835 CGPathRelease(rPath);
837 HIThemeFrameDrawInfo aTextDrawInfo;
838 aTextDrawInfo.version = 0;
839 aTextDrawInfo.kind = kHIThemeFrameListBox;
840 aTextDrawInfo.state = kThemeStateActive;
841 aTextDrawInfo.isFocused = false;
842 HIThemeDrawFrame(&rc, &aTextDrawInfo, maShared.maContextHolder.get(), kHIThemeOrientationNormal);
843 bOK = true;
847 break;
848 case ControlType::ListNet:
850 // do nothing as there isn't net for listviews on macOS
852 bOK = true;
853 break;
854 default:
855 break;
857 maShared.maContextHolder.restoreState();
859 // in most cases invalidating the whole control region instead of just the unclipped part of it is sufficient (and probably
860 // faster). However for the window background we should not unnecessarily enlarge the really changed rectangle since the
861 // difference is usually quite high. Background is always drawn as a whole since we don't know anything about its possible
862 // contents (see issue i90291).
864 if (nType == ControlType::WindowBackground)
866 CGRect aRect = {{0, 0}, {0, 0}};
867 if (maShared.mxClipPath)
868 aRect = CGPathGetBoundingBox(maShared.mxClipPath);
869 if (aRect.size.width != 0 && aRect.size.height != 0)
870 buttonRect.Intersection(tools::Rectangle(Point(static_cast<tools::Long>(aRect.origin.x),
871 static_cast<tools::Long>(aRect.origin.y)),
872 Size(static_cast<tools::Long>(aRect.size.width),
873 static_cast<tools::Long>(aRect.size.height))));
875 maShared.refreshRect(buttonRect.Left(), buttonRect.Top(), buttonRect.GetWidth(), buttonRect.GetHeight());
876 return bOK;
879 bool AquaSalGraphics::getNativeControlRegion(ControlType nType,
880 ControlPart nPart,
881 const tools::Rectangle &rControlRegion,
882 ControlState,
883 const ImplControlValue &aValue,
884 const OUString &,
885 tools::Rectangle &rNativeBoundingRegion,
886 tools::Rectangle &rNativeContentRegion)
888 bool toReturn = false;
889 tools::Rectangle aCtrlBoundRect(rControlRegion);
890 short x = aCtrlBoundRect.Left();
891 short y = aCtrlBoundRect.Top();
892 short w, h;
893 switch (nType)
895 case ControlType::Pushbutton:
896 case ControlType::Radiobutton:
897 case ControlType::Checkbox:
899 if (nType == ControlType::Pushbutton)
901 w = aCtrlBoundRect.GetWidth();
902 h = aCtrlBoundRect.GetHeight();
904 else
906 w = RADIO_BUTTON_SMALL_SIZE + 2 * FOCUS_RING_WIDTH + RADIO_BUTTON_TEXT_SEPARATOR;
907 h = RADIO_BUTTON_SMALL_SIZE + 2 * FOCUS_RING_WIDTH;
909 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
910 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
911 toReturn = true;
913 break;
914 case ControlType::Progress:
916 tools::Rectangle aRect(aCtrlBoundRect);
917 if (aRect.GetHeight() < LARGE_PROGRESS_INDICATOR_HEIGHT)
918 aRect.SetBottom(aRect.Top() + MEDIUM_PROGRESS_INDICATOR_HEIGHT - 1);
919 else
920 aRect.SetBottom(aRect.Top() + LARGE_PROGRESS_INDICATOR_HEIGHT - 1);
921 rNativeBoundingRegion = aRect;
922 rNativeContentRegion = aRect;
923 toReturn = true;
925 break;
926 case ControlType::IntroProgress:
928 tools::Rectangle aRect(aCtrlBoundRect);
929 aRect.SetBottom(aRect.Top() + MEDIUM_PROGRESS_INDICATOR_HEIGHT - 1);
930 rNativeBoundingRegion = aRect;
931 rNativeContentRegion = aRect;
932 toReturn = true;
934 break;
935 case ControlType::Slider:
936 if (nPart == ControlPart::ThumbHorz)
938 w = SLIDER_WIDTH;
939 h = aCtrlBoundRect.GetHeight();
940 rNativeBoundingRegion = rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
941 toReturn = true;
943 else if (nPart == ControlPart::ThumbVert)
945 w = aCtrlBoundRect.GetWidth();
946 h = SLIDER_HEIGHT;
947 rNativeBoundingRegion = rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
948 toReturn = true;
950 break;
951 case ControlType::Scrollbar:
953 tools::Rectangle aRect;
954 if (AquaGetScrollRect(nPart, aCtrlBoundRect, aRect))
956 toReturn = true;
957 rNativeBoundingRegion = aRect;
958 rNativeContentRegion = aRect;
961 break;
962 case ControlType::TabItem:
964 w = aCtrlBoundRect.GetWidth() + 2 * TAB_TEXT_MARGIN;
965 h = TAB_HEIGHT + 2;
966 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
967 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
968 toReturn = true;
970 break;
971 case ControlType::Editbox:
973 w = aCtrlBoundRect.GetWidth();
974 h = EDITBOX_HEIGHT + 2 * FOCUS_RING_WIDTH;
975 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
976 w -= 2 * (FOCUS_RING_WIDTH + EDITBOX_BORDER_WIDTH + EDITBOX_INSET_MARGIN);
977 h -= 2 * (FOCUS_RING_WIDTH + EDITBOX_BORDER_WIDTH + EDITBOX_INSET_MARGIN);
978 x += FOCUS_RING_WIDTH + EDITBOX_BORDER_WIDTH + EDITBOX_INSET_MARGIN;
979 y += FOCUS_RING_WIDTH + EDITBOX_BORDER_WIDTH + EDITBOX_INSET_MARGIN;
980 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
981 toReturn = true;
983 break;
984 case ControlType::Combobox:
985 if (nPart == ControlPart::Entire)
987 w = aCtrlBoundRect.GetWidth();
988 h = COMBOBOX_HEIGHT + 2 * FOCUS_RING_WIDTH;
989 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
990 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
991 toReturn = true;
993 else if (nPart == ControlPart::ButtonDown)
995 w = COMBOBOX_BUTTON_WIDTH + FOCUS_RING_WIDTH;
996 h = COMBOBOX_HEIGHT + 2 * FOCUS_RING_WIDTH;
997 x += aCtrlBoundRect.GetWidth() - w;
998 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
999 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
1000 toReturn = true;
1002 else if (nPart == ControlPart::SubEdit)
1004 w = aCtrlBoundRect.GetWidth() - 2 * FOCUS_RING_WIDTH - COMBOBOX_BUTTON_WIDTH - COMBOBOX_BORDER_WIDTH
1005 - 2 * COMBOBOX_TEXT_MARGIN;
1006 h = COMBOBOX_HEIGHT - 2 * COMBOBOX_BORDER_WIDTH;
1007 x += FOCUS_RING_WIDTH + COMBOBOX_BORDER_WIDTH + COMBOBOX_TEXT_MARGIN;
1008 y += FOCUS_RING_WIDTH + COMBOBOX_BORDER_WIDTH;
1009 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
1010 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
1011 toReturn = true;
1013 break;
1014 case ControlType::Listbox:
1015 if (nPart == ControlPart::Entire)
1017 w = aCtrlBoundRect.GetWidth();
1018 h = LISTBOX_HEIGHT + 2 * FOCUS_RING_WIDTH;
1019 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
1020 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
1021 toReturn = true;
1023 else if (nPart == ControlPart::ButtonDown)
1025 w = LISTBOX_BUTTON_WIDTH + FOCUS_RING_WIDTH;
1026 h = LISTBOX_HEIGHT + 2 * FOCUS_RING_WIDTH;
1027 x += aCtrlBoundRect.GetWidth() - w;
1028 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
1029 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
1030 toReturn = true;
1032 else if (nPart == ControlPart::SubEdit)
1034 w = aCtrlBoundRect.GetWidth() - 2 * FOCUS_RING_WIDTH - LISTBOX_BUTTON_WIDTH - LISTBOX_BORDER_WIDTH
1035 - 2 * LISTBOX_TEXT_MARGIN;
1036 h = LISTBOX_HEIGHT - 2 * LISTBOX_BORDER_WIDTH;
1037 x += FOCUS_RING_WIDTH + LISTBOX_BORDER_WIDTH + LISTBOX_TEXT_MARGIN;
1038 y += FOCUS_RING_WIDTH + LISTBOX_BORDER_WIDTH;
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::ListboxWindow)
1045 w = aCtrlBoundRect.GetWidth() - 2;
1046 h = aCtrlBoundRect.GetHeight() - 2;
1047 x += 1;
1048 y += 1;
1049 rNativeBoundingRegion = aCtrlBoundRect;
1050 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
1051 toReturn = true;
1053 break;
1054 case ControlType::Spinbox:
1055 if (nPart == ControlPart::Entire)
1057 w = aCtrlBoundRect.GetWidth();
1058 h = EDITBOX_HEIGHT + 2 * FOCUS_RING_WIDTH;
1059 x += SPINBOX_OFFSET;
1060 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
1061 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
1062 toReturn = true;
1064 else if (nPart == ControlPart::SubEdit)
1066 w = aCtrlBoundRect.GetWidth() - 4 * FOCUS_RING_WIDTH - SPIN_BUTTON_WIDTH - 2 * EDITBOX_BORDER_WIDTH
1067 - 2 * EDITBOX_INSET_MARGIN;
1068 h = EDITBOX_HEIGHT - 2 * (EDITBOX_BORDER_WIDTH + EDITBOX_INSET_MARGIN);
1069 x += FOCUS_RING_WIDTH + EDITBOX_BORDER_WIDTH + EDITBOX_INSET_MARGIN + SPINBOX_OFFSET;
1070 y += FOCUS_RING_WIDTH + EDITBOX_BORDER_WIDTH + EDITBOX_INSET_MARGIN;
1071 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
1072 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
1073 toReturn = true;
1075 else if (nPart == ControlPart::ButtonUp)
1077 w = SPIN_BUTTON_WIDTH + 2 * FOCUS_RING_WIDTH;
1078 h = SPIN_UPPER_BUTTON_HEIGHT + FOCUS_RING_WIDTH;
1079 x += aCtrlBoundRect.GetWidth() - SPIN_BUTTON_WIDTH - 2 * FOCUS_RING_WIDTH + SPINBOX_OFFSET;
1080 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
1081 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
1082 toReturn = true;
1084 else if (nPart == ControlPart::ButtonDown)
1086 w = SPIN_BUTTON_WIDTH + 2 * FOCUS_RING_WIDTH;
1087 h = SPIN_LOWER_BUTTON_HEIGHT + FOCUS_RING_WIDTH;
1088 x += aCtrlBoundRect.GetWidth() - SPIN_BUTTON_WIDTH - 2 * FOCUS_RING_WIDTH + SPINBOX_OFFSET;
1089 y += FOCUS_RING_WIDTH + SPIN_UPPER_BUTTON_HEIGHT;
1090 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
1091 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
1092 toReturn = true;
1094 break;
1095 case ControlType::Frame:
1097 DrawFrameStyle nStyle = static_cast<DrawFrameStyle>(aValue.getNumericVal() & 0x000f);
1098 DrawFrameFlags nFlags = static_cast<DrawFrameFlags>(aValue.getNumericVal() & 0xfff0);
1099 if (nPart == ControlPart::Border
1100 && !(nFlags & (DrawFrameFlags::Menu | DrawFrameFlags::WindowBorder | DrawFrameFlags::BorderWindowBorder)))
1102 tools::Rectangle aRect(aCtrlBoundRect);
1103 if (nStyle == DrawFrameStyle::DoubleIn)
1105 aRect.AdjustLeft(1);
1106 aRect.AdjustTop(1);
1107 // rRect.Right() -= 1;
1108 // rRect.Bottom() -= 1;
1110 else
1112 aRect.AdjustLeft(1);
1113 aRect.AdjustTop(1);
1114 aRect.AdjustRight(-1);
1115 aRect.AdjustBottom(-1);
1117 rNativeContentRegion = aRect;
1118 rNativeBoundingRegion = aRect;
1119 toReturn = true;
1122 break;
1123 case ControlType::Menubar:
1124 case ControlType::MenuPopup:
1125 if (nPart == ControlPart::MenuItemCheckMark || nPart == ControlPart::MenuItemRadioMark)
1127 w=10;
1128 h=10;
1129 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
1130 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
1131 toReturn = true;
1133 break;
1134 default:
1135 break;
1137 return toReturn;
1140 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */