1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
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>
27 
28 #include <quartz/salgdi.h>
29 #include <osx/salnativewidgets.h>
30 #include <osx/saldata.hxx>
31 #include <osx/salframe.h>
32 
33 #include <premac.h>
34 #include <Carbon/Carbon.h>
35 #include <postmac.h>
36 
37 #include "cuidraw.hxx"
38 
39 // presentation of native widgets consists of two important methods:
40 
41 // AquaSalGraphics::getNativeControlRegion to determine native rectangle in pixels to draw the widget
42 // AquaSalGraphics::drawNativeControl to do the drawing operation itself
43 
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.
48 
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.
54 
55 #if !HAVE_FEATURE_MACOSX_SANDBOX
56 
57 @interface NSWindow(CoreUIRendererPrivate)
58 + (CUIRendererRef)coreUIRenderer;
59 @end
60 
61 #endif
62 
ImplGetHIRectFromRectangle(tools::Rectangle aRect)63 static HIRect ImplGetHIRectFromRectangle(tools::Rectangle aRect)
64 {
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;
71 }
72 
ImplGetButtonValue(ButtonValue aButtonValue)73 static ThemeButtonValue ImplGetButtonValue(ButtonValue aButtonValue)
74 {
75     switch (aButtonValue)
76     {
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;
85     }
86 }
87 
AquaGetScrollRect(ControlPart nPart,const tools::Rectangle & rControlRect,tools::Rectangle & rResultRect)88 static bool AquaGetScrollRect(/* TODO: int nScreen, */
89                               ControlPart nPart, const tools::Rectangle &rControlRect, tools::Rectangle &rResultRect)
90 {
91     bool bRetVal = true;
92     rResultRect = rControlRect;
93     switch (nPart)
94     {
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;
118     }
119     return bRetVal;
120 }
121 
isNativeControlSupported(ControlType nType,ControlPart nPart)122 bool AquaSalGraphics::isNativeControlSupported(ControlType nType, ControlPart nPart)
123 {
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.
126 
127     switch (nType)
128     {
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;
211     }
212     return false;
213 }
214 
hitTestNativeControl(ControlType nType,ControlPart nPart,const tools::Rectangle & rControlRegion,const Point & rPos,bool & rIsInside)215 bool AquaSalGraphics::hitTestNativeControl(ControlType nType, ControlPart nPart, const tools::Rectangle &rControlRegion,
216                                            const Point &rPos, bool& rIsInside)
217 {
218     if (nType == ControlType::Scrollbar)
219     {
220         tools::Rectangle aRect;
221         bool bValid = AquaGetScrollRect(/* TODO: int nScreen, */
222                                         nPart, rControlRegion, aRect);
223         rIsInside = bValid && aRect.IsInside(rPos);
224         return bValid;
225     }
226     return false;
227 }
228 
getState(ControlState nState)229 UInt32 AquaSalGraphics::getState(ControlState nState)
230 {
231 
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.
234 
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)
238     {
239         return kThemeStateInactive;
240     }
241     if (nState & ControlState::PRESSED)
242         return kThemeStatePressed;
243     return kThemeStateActive;
244 }
245 
getTrackState(ControlState nState)246 UInt32 AquaSalGraphics::getTrackState(ControlState nState)
247 {
248     const bool bDrawActive = maShared.mpFrame == nullptr || [maShared.mpFrame->getNSWindow() isKeyWindow];
249     if (!(nState & ControlState::ENABLED) || !bDrawActive)
250         return kThemeTrackInactive;
251     return kThemeTrackActive;
252 }
253 
drawNativeControl(ControlType nType,ControlPart nPart,const tools::Rectangle & rControlRegion,ControlState nState,const ImplControlValue & aValue,const OUString &,const Color &)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&)
261 {
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)
269     {
270         case ControlType::Toolbar:
271             {
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)
280                 {
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);
301                 }
302                 else
303                 {
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);
309                 }
310 #endif
311                 bOK = true;
312             }
313             break;
314         case ControlType::WindowBackground:
315             {
316                 HIThemeBackgroundDrawInfo aThemeBackgroundInfo;
317                 aThemeBackgroundInfo.version = 0;
318                 aThemeBackgroundInfo.state = getState(nState);
319                 aThemeBackgroundInfo.kind = kThemeBrushDialogBackgroundActive;
320 
321                 // FIXME: without this magical offset there is a 2 pixel black border on the right and bottom
322 
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;
328             }
329             break;
330         case ControlType::Tooltip:
331             {
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;
341             }
342             break;
343         case ControlType::Menubar:
344         case ControlType::MenuPopup:
345             if (nPart == ControlPart::Entire || nPart == ControlPart::MenuItem || nPart == ControlPart::HasBackgroundTexture)
346             {
347 
348                 // FIXME: without this magical offset there is a 2 pixel black border on the right
349 
350                 rc.size.width += 2;
351                 HIThemeMenuDrawInfo aMenuInfo;
352                 aMenuInfo.version = 0;
353                 aMenuInfo.menuType = kThemeMenuTypePullDown;
354                 HIThemeMenuItemDrawInfo aMenuItemDrawInfo;
355 
356                 // grey theme when the item is selected is drawn here.
357 
358                 aMenuItemDrawInfo.itemType = kThemeMenuItemPlain;
359                 if ((nPart == ControlPart::MenuItem) && (nState & ControlState::SELECTED))
360 
361                     // blue theme when the item is selected is drawn here.
362 
363                     aMenuItemDrawInfo.state = kThemeMenuSelected;
364                 else
365 
366                     // normal color for non selected item
367 
368                     aMenuItemDrawInfo.state = kThemeMenuActive;
369 
370                 // repaints the background of the pull down menu
371 
372                 HIThemeDrawMenuBackground(&rc, &aMenuInfo, maShared.maContextHolder.get(), kHIThemeOrientationNormal);
373 
374                 // repaints the item either blue (selected) and/or grey (active only)
375 
376                 HIThemeDrawMenuItem(&rc, &rc, &aMenuItemDrawInfo, maShared.maContextHolder.get(), kHIThemeOrientationNormal, &rc);
377                 bOK = true;
378             }
379             else if (nPart == ControlPart::MenuItemCheckMark || nPart == ControlPart::MenuItemRadioMark)
380             {
381 
382                 // checked, else it is not displayed (see vcl/source/window/menu.cxx)
383 
384                 if (nState & ControlState::PRESSED)
385                 {
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;
394 
395                     // aTextInfo.truncationMaxLines unused because of kHIThemeTextTruncationNone item highlighted
396 
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;
404                 }
405             }
406             break;
407         case ControlType::Pushbutton:
408             {
409 
410                 // FIXME: instead of use a value, VCL can retrieve correct values on the fly (to be implemented)
411 
412                 HIThemeButtonDrawInfo aPushInfo;
413                 aPushInfo.version = 0;
414 
415                 // no animation
416 
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)
423                 {
424                     aPushInfo.kind = kThemeRoundedBevelButton;
425                 }
426                 else if (rc.size.height <= PUSH_BUTTON_NORMAL_HEIGHT)
427                 {
428                     aPushInfo.kind = kThemePushButtonMini;
429                     nPaintHeight = PUSH_BUTTON_SMALL_HEIGHT;
430                 }
431                 else if ((pPBVal && pPBVal->mbSingleLine) || rc.size.height < PUSH_BUTTON_NORMAL_HEIGHT * 3 / 2)
432                 {
433                     aPushInfo.kind = kThemePushButtonNormal;
434                     nPaintHeight = PUSH_BUTTON_NORMAL_HEIGHT;
435 
436                     // avoid clipping when focused
437 
438                     rc.origin.x += FOCUS_RING_WIDTH / 2;
439                     rc.size.width -= FOCUS_RING_WIDTH;
440                 }
441                 else
442                     aPushInfo.kind = kThemeBevelButton;
443 
444                 // translate the origin for controls with fixed paint height so content ends up somewhere sensible
445 
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;
454             }
455             break;
456         case ControlType::Radiobutton:
457         case ControlType::Checkbox:
458             {
459                 HIThemeButtonDrawInfo aInfo;
460                 aInfo.version = 0;
461                 switch (nType)
462                 {
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;
477                 }
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;
490             }
491             break;
492         case ControlType::ListNode:
493             {
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)
502                 {
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;
513                 }
514                 HIThemeDrawButton(&rc, &aInfo, maShared.maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
515                 bOK = true;
516             }
517             break;
518         case ControlType::Progress:
519         case ControlType::IntroProgress:
520             {
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);
534 
535                 // the intro bitmap never gets key anyway; we want to draw that enabled
536 
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;
543             }
544             break;
545         case ControlType::Slider:
546             {
547                 const SliderValue *pSliderVal = static_cast<SliderValue const *>(&aValue);
548                 HIThemeTrackDrawInfo aTrackDraw;
549                 aTrackDraw.kind = kThemeSliderMedium;
550                 if (nPart == ControlPart::TrackHorzArea || nPart == ControlPart::TrackVertArea)
551                 {
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;
567                 }
568             }
569             break;
570         case ControlType::Scrollbar:
571             {
572                 const ScrollbarValue *pScrollbarVal = (aValue.getType() == ControlType::Scrollbar)
573                                                     ? static_cast<const ScrollbarValue *>(&aValue) : nullptr;
574                 if (nPart == ControlPart::DrawBackgroundVert || nPart == ControlPart::DrawBackgroundHorz)
575                 {
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;
602                 }
603             }
604             break;
605         case ControlType::TabPane:
606             {
607                 HIThemeTabPaneDrawInfo aTabPaneDrawInfo;
608                 aTabPaneDrawInfo.version = 1;
609                 aTabPaneDrawInfo.state = kThemeStateActive;
610                 aTabPaneDrawInfo.direction = kThemeTabNorth;
611                 aTabPaneDrawInfo.size = kHIThemeTabSizeNormal;
612                 aTabPaneDrawInfo.kind = kHIThemeTabKindNormal;
613 
614                 // border is outside the rect rc for Carbon but for VCL it should be inside
615 
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;
622             }
623             break;
624         case ControlType::TabItem:
625             {
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;
636 
637                 // first, last or middle tab
638 
639                 aTabItemDrawInfo.position = kHIThemeTabPositionMiddle;
640                 TabitemValue const * pTabValue = static_cast<TabitemValue const *>(&aValue);
641                 TabitemFlags nAlignment = pTabValue->mnAlignment;
642 
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
647 
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;
655 
656                 // support for RTL (see issue 79748)
657 
658                 if (AllSettings::GetLayoutRTL()) {
659                     if (aTabItemDrawInfo.position == kHIThemeTabPositionFirst)
660                         aTabItemDrawInfo.position = kHIThemeTabPositionLast;
661                     else if (aTabItemDrawInfo.position == kHIThemeTabPositionLast)
662                         aTabItemDrawInfo.position = kHIThemeTabPositionFirst;
663                 }
664                 HIThemeDrawTab(&rc, &aTabItemDrawInfo, maShared.maContextHolder.get(), kHIThemeOrientationNormal, nullptr);
665                 bOK=true;
666             }
667             break;
668         case ControlType::Editbox:
669         case ControlType::MultilineEditbox:
670             {
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;
683 
684                 // fill a white background, because HIThemeDrawFrame only draws the border
685 
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;
691             }
692             break;
693         case ControlType::Combobox:
694             if (nPart == ControlPart::HasBackgroundTexture || nPart == ControlPart::Entire)
695             {
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;
710             }
711             break;
712         case ControlType::Listbox:
713             switch (nPart)
714             {
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;
743             }
744             break;
745         case ControlType::Spinbox:
746             if (nPart == ControlPart::Entire)
747             {
748 
749                 // text field
750 
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;
760 
761                 // fill a white background, because HIThemeDrawFrame only draws the border
762 
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);
767 
768                 // buttons
769 
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)
775                 {
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())
790                     {
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;
802                     }
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);
812                 }
813                 bOK = true;
814             }
815             break;
816         case ControlType::Frame:
817             {
818                 DrawFrameFlags nStyle = static_cast<DrawFrameFlags>(aValue.getNumericVal());
819                 if (nPart == ControlPart::Border)
820                 {
821                     if (!(nStyle & DrawFrameFlags::Menu) && !(nStyle & DrawFrameFlags::WindowBorder))
822                     {
823 
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)
826 
827                         if (rc.origin.y + rc.size.height >= maShared.mpFrame->maGeometry.nHeight - 3)
828                         {
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);
836                         }
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;
844                     }
845                 }
846             }
847             break;
848         case ControlType::ListNet:
849 
850             // do nothing as there isn't net for listviews on macOS
851 
852             bOK = true;
853             break;
854         default:
855             break;
856     }
857     maShared.maContextHolder.restoreState();
858 
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).
863 
864     if (nType == ControlType::WindowBackground)
865     {
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))));
874     }
875     maShared.refreshRect(buttonRect.Left(), buttonRect.Top(), buttonRect.GetWidth(), buttonRect.GetHeight());
876     return bOK;
877 }
878 
getNativeControlRegion(ControlType nType,ControlPart nPart,const tools::Rectangle & rControlRegion,ControlState,const ImplControlValue & aValue,const OUString &,tools::Rectangle & rNativeBoundingRegion,tools::Rectangle & rNativeContentRegion)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)
887 {
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)
894     {
895         case ControlType::Pushbutton:
896         case ControlType::Radiobutton:
897         case ControlType::Checkbox:
898             {
899                 if (nType == ControlType::Pushbutton)
900                 {
901                     w = aCtrlBoundRect.GetWidth();
902                     h = aCtrlBoundRect.GetHeight();
903                 }
904                 else
905                 {
906                     w = RADIO_BUTTON_SMALL_SIZE + 2 * FOCUS_RING_WIDTH + RADIO_BUTTON_TEXT_SEPARATOR;
907                     h = RADIO_BUTTON_SMALL_SIZE + 2 * FOCUS_RING_WIDTH;
908                 }
909                 rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
910                 rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h));
911                 toReturn = true;
912             }
913             break;
914         case ControlType::Progress:
915             {
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;
924             }
925             break;
926         case ControlType::IntroProgress:
927             {
928                 tools::Rectangle aRect(aCtrlBoundRect);
929                 aRect.SetBottom(aRect.Top() + MEDIUM_PROGRESS_INDICATOR_HEIGHT - 1);
930                 rNativeBoundingRegion = aRect;
931                 rNativeContentRegion = aRect;
932                 toReturn = true;
933             }
934             break;
935         case ControlType::Slider:
936             if (nPart == ControlPart::ThumbHorz)
937             {
938                 w = SLIDER_WIDTH;
939                 h = aCtrlBoundRect.GetHeight();
940                 rNativeBoundingRegion = rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
941                 toReturn = true;
942             }
943             else if (nPart == ControlPart::ThumbVert)
944             {
945                 w = aCtrlBoundRect.GetWidth();
946                 h = SLIDER_HEIGHT;
947                 rNativeBoundingRegion = rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h));
948                 toReturn = true;
949             }
950             break;
951         case ControlType::Scrollbar:
952             {
953                 tools::Rectangle aRect;
954                 if (AquaGetScrollRect(nPart, aCtrlBoundRect, aRect))
955                 {
956                     toReturn = true;
957                     rNativeBoundingRegion = aRect;
958                     rNativeContentRegion = aRect;
959                 }
960             }
961             break;
962         case ControlType::TabItem:
963             {
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;
969             }
970             break;
971         case ControlType::Editbox:
972             {
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;
982             }
983             break;
984         case ControlType::Combobox:
985           if (nPart == ControlPart::Entire)
986             {
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;
992             }
993             else if (nPart == ControlPart::ButtonDown)
994             {
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;
1001             }
1002             else if (nPart == ControlPart::SubEdit)
1003             {
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;
1012             }
1013             break;
1014         case ControlType::Listbox:
1015             if (nPart == ControlPart::Entire)
1016             {
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;
1022             }
1023             else if (nPart == ControlPart::ButtonDown)
1024             {
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;
1031             }
1032             else if (nPart == ControlPart::SubEdit)
1033             {
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;
1042             }
1043             else if (nPart == ControlPart::ListboxWindow)
1044             {
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;
1052             }
1053             break;
1054         case ControlType::Spinbox:
1055             if (nPart == ControlPart::Entire)
1056             {
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;
1063             }
1064             else if (nPart == ControlPart::SubEdit)
1065             {
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;
1074             }
1075             else if (nPart == ControlPart::ButtonUp)
1076             {
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;
1083             }
1084             else if (nPart == ControlPart::ButtonDown)
1085             {
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;
1093             }
1094             break;
1095         case ControlType::Frame:
1096             {
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)))
1101                 {
1102                     tools::Rectangle aRect(aCtrlBoundRect);
1103                     if (nStyle == DrawFrameStyle::DoubleIn)
1104                     {
1105                         aRect.AdjustLeft(1);
1106                         aRect.AdjustTop(1);
1107                         // rRect.Right() -= 1;
1108                         // rRect.Bottom() -= 1;
1109                     }
1110                     else
1111                     {
1112                         aRect.AdjustLeft(1);
1113                         aRect.AdjustTop(1);
1114                         aRect.AdjustRight(-1);
1115                         aRect.AdjustBottom(-1);
1116                     }
1117                     rNativeContentRegion = aRect;
1118                     rNativeBoundingRegion = aRect;
1119                     toReturn = true;
1120                 }
1121             }
1122             break;
1123         case ControlType::Menubar:
1124         case ControlType::MenuPopup:
1125             if (nPart == ControlPart::MenuItemCheckMark || nPart == ControlPart::MenuItemRadioMark)
1126             {
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;
1132             }
1133             break;
1134         default:
1135             break;
1136     }
1137     return toReturn;
1138 }
1139 
1140 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1141