1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/threadex.hxx>
26 #include <vcl/timer.hxx>
27 #include <vcl/settings.hxx>
29 #include <quartz/salgdi.h>
30 #include <osx/salnativewidgets.h>
31 #include <osx/saldata.hxx>
32 #include <osx/salframe.h>
35 #include <Carbon/Carbon.h>
38 #include "cuidraw.hxx"
40 // presentation of native widgets consists of two important methods:
42 // AquaSalGraphics::getNativeControlRegion to determine native rectangle in pixels to draw the widget
43 // AquaSalGraphics::drawNativeControl to do the drawing operation itself
45 // getNativeControlRegion has to calculate a content rectangle within it is safe to draw the widget. Furthermore a bounding rectangle
46 // has to be calculated by getNativeControlRegion to consider adornments like a focus rectangle. As drawNativeControl uses Carbon
47 // API calls, all widgets are drawn without text. Drawing of text is done separately by VCL on top of graphical Carbon widget
48 // representation. drawNativeControl is called by VCL using content rectangle determined by getNativeControlRegion.
50 // FIXME: when calculation bounding rectangle larger then content rectangle, text displayed by VCL will become misaligned. To avoid
51 // misalignment bounding rectangle and content rectangle are calculated equally including adornments. Reduction of size for content
52 // is done by drawNativeControl subsequently. Only exception is editbox: As other widgets have distinct ControlPart::SubEdit control
53 // parts, editbox bounding rectangle and content rectangle are both calculated to reflect content area. Extending size for
54 // adornments is done by drawNativeControl subsequently.
56 #if !HAVE_FEATURE_MACOSX_SANDBOX
58 @interface
NSWindow(CoreUIRendererPrivate
)
59 + (CUIRendererRef
)coreUIRenderer
;
64 static HIRect
ImplGetHIRectFromRectangle(tools::Rectangle aRect
)
67 aHIRect
.origin
.x
= static_cast<float>(aRect
.Left());
68 aHIRect
.origin
.y
= static_cast<float>(aRect
.Top());
69 aHIRect
.size
.width
= static_cast<float>(aRect
.GetWidth());
70 aHIRect
.size
.height
= static_cast<float>(aRect
.GetHeight());
74 static NSControlStateValue
ImplGetButtonValue(ButtonValue aButtonValue
)
79 return NSControlStateValueOn
;
80 case ButtonValue::Off
:
81 case ButtonValue::DontKnow
:
82 return NSControlStateValueOff
;
83 case ButtonValue::Mixed
:
85 return NSControlStateValueMixed
;
89 static bool AquaGetScrollRect(/* TODO: int nScreen, */
90 ControlPart nPart
, const tools::Rectangle
&rControlRect
, tools::Rectangle
&rResultRect
)
93 rResultRect
= rControlRect
;
96 case ControlPart::ButtonUp
:
97 rResultRect
.SetBottom(rResultRect
.Top());
99 case ControlPart::ButtonDown
:
100 rResultRect
.SetTop(rResultRect
.Bottom());
102 case ControlPart::ButtonLeft
:
103 rResultRect
.SetRight(rResultRect
.Left());
105 case ControlPart::ButtonRight
:
106 rResultRect
.SetLeft(rResultRect
.Right());
108 case ControlPart::TrackHorzArea
:
109 case ControlPart::TrackVertArea
:
110 case ControlPart::ThumbHorz
:
111 case ControlPart::ThumbVert
:
112 case ControlPart::TrackHorzLeft
:
113 case ControlPart::TrackHorzRight
:
114 case ControlPart::TrackVertUpper
:
115 case ControlPart::TrackVertLower
:
123 bool AquaSalGraphics::isNativeControlSupported(ControlType nType
, ControlPart nPart
)
125 // native controls are now defaults. If you want to disable native controls, set the environment variable SAL_NO_NWF to
126 // something and VCL controls will be used as default again.
130 case ControlType::Pushbutton
:
131 case ControlType::Radiobutton
:
132 case ControlType::Checkbox
:
133 case ControlType::ListNode
:
134 if (nPart
== ControlPart::Entire
)
137 case ControlType::Scrollbar
:
138 if (nPart
== ControlPart::DrawBackgroundHorz
|| nPart
== ControlPart::DrawBackgroundVert
139 || nPart
== ControlPart::Entire
|| nPart
== ControlPart::HasThreeButtons
)
142 case ControlType::Slider
:
143 if (nPart
== ControlPart::TrackHorzArea
|| nPart
== ControlPart::TrackVertArea
)
146 case ControlType::Editbox
:
147 if (nPart
== ControlPart::Entire
|| nPart
== ControlPart::HasBackgroundTexture
)
150 case ControlType::MultilineEditbox
:
151 if (nPart
== ControlPart::Entire
|| nPart
== ControlPart::HasBackgroundTexture
)
154 case ControlType::Spinbox
:
155 if (nPart
== ControlPart::Entire
|| nPart
== ControlPart::AllButtons
|| nPart
== ControlPart::HasBackgroundTexture
)
158 case ControlType::SpinButtons
:
160 case ControlType::Combobox
:
161 if (nPart
== ControlPart::Entire
|| nPart
== ControlPart::HasBackgroundTexture
)
164 case ControlType::Listbox
:
165 if (nPart
== ControlPart::Entire
|| nPart
== ControlPart::ListboxWindow
|| nPart
== ControlPart::HasBackgroundTexture
166 || nPart
== ControlPart::SubEdit
)
169 case ControlType::TabItem
:
170 case ControlType::TabPane
:
171 case ControlType::TabBody
:
172 if (nPart
== ControlPart::Entire
|| nPart
== ControlPart::TabsDrawRtl
|| nPart
== ControlPart::HasBackgroundTexture
)
175 case ControlType::Toolbar
:
176 if (nPart
== ControlPart::Entire
|| nPart
== ControlPart::DrawBackgroundHorz
177 || nPart
== ControlPart::DrawBackgroundVert
)
180 case ControlType::WindowBackground
:
181 if (nPart
== ControlPart::BackgroundWindow
|| nPart
== ControlPart::BackgroundDialog
)
184 case ControlType::Menubar
:
185 if (nPart
== ControlPart::Entire
)
188 case ControlType::Tooltip
:
189 if (nPart
== ControlPart::Entire
)
192 case ControlType::MenuPopup
:
193 if (nPart
== ControlPart::Entire
|| nPart
== ControlPart::MenuItem
|| nPart
== ControlPart::MenuItemCheckMark
194 || nPart
== ControlPart::MenuItemRadioMark
)
197 case ControlType::LevelBar
:
198 case ControlType::Progress
:
199 case ControlType::IntroProgress
:
200 if (nPart
== ControlPart::Entire
)
203 case ControlType::Frame
:
204 if (nPart
== ControlPart::Border
)
207 case ControlType::ListNet
:
208 if (nPart
== ControlPart::Entire
)
217 bool AquaSalGraphics::hitTestNativeControl(ControlType nType
, ControlPart nPart
, const tools::Rectangle
&rControlRegion
,
218 const Point
&rPos
, bool& rIsInside
)
220 if (nType
== ControlType::Scrollbar
)
222 tools::Rectangle aRect
;
223 bool bValid
= AquaGetScrollRect(/* TODO: int nScreen, */
224 nPart
, rControlRegion
, aRect
);
225 rIsInside
= bValid
&& aRect
.Contains(rPos
);
231 static bool getEnabled(ControlState nState
, AquaSalFrame
* mpFrame
)
234 // there are non key windows which are children of key windows, e.g. autofilter configuration dialog or sidebar dropdown dialogs.
235 // To handle these windows correctly, parent frame's key window state is considered here additionally.
237 const bool bDrawActive
= mpFrame
== nullptr || [mpFrame
->getNSWindow() isKeyWindow
]
238 || mpFrame
->mpParent
== nullptr || [mpFrame
->mpParent
->getNSWindow() isKeyWindow
];
239 if (!(nState
& ControlState::ENABLED
) || !bDrawActive
)
246 bool AquaSalGraphics::drawNativeControl(ControlType nType
,
248 const tools::Rectangle
&rControlRegion
,
250 const ImplControlValue
&aValue
,
254 return mpBackend
->drawNativeControl(nType
, nPart
, rControlRegion
, nState
, aValue
);
257 static void paintCell(NSCell
* pBtn
, const NSRect
& bounds
, bool bShowsFirstResponder
, CGContextRef context
, NSView
* pView
)
259 //translate and scale because up side down otherwise
260 CGContextSaveGState(context
);
261 CGContextTranslateCTM(context
, bounds
.origin
.x
, bounds
.origin
.y
+ bounds
.size
.height
);
262 CGContextScaleCTM(context
, 1, -1);
264 NSGraphicsContext
* savedContext
= [NSGraphicsContext currentContext
];
265 [NSGraphicsContext setCurrentContext
:[NSGraphicsContext graphicsContextWithCGContext
:context flipped
:NO
]];
267 NSRect rect
= { NSZeroPoint
, bounds
.size
};
269 if ([pBtn isKindOfClass
: [NSSliderCell
class]])
271 // NSSliderCell doesn't seem to work with drawWithFrame(?), so draw the elements directly
272 [static_cast<NSSliderCell
*>(pBtn
)
273 drawBarInside
: [static_cast<NSSliderCell
*>(pBtn
) barRectFlipped
: NO
] flipped
: NO
];
274 rect
= [static_cast<NSSliderCell
*>(pBtn
) knobRectFlipped
: NO
];
275 [static_cast<NSSliderCell
*>(pBtn
) drawKnob
: rect
];
278 [pBtn drawWithFrame
: rect inView
: pView
];
280 // setShowsFirstResponder apparently causes a hang when set on NSComboBoxCell
281 const bool bIsComboBox
= [pBtn isMemberOfClass
: [NSComboBoxCell
class]];
283 [pBtn setShowsFirstResponder
: bShowsFirstResponder
];
285 if (bShowsFirstResponder
)
287 NSSetFocusRingStyle(NSFocusRingOnly
);
289 CGContextBeginTransparencyLayerWithRect(context
, rect
, nullptr);
290 if ([pBtn isMemberOfClass
: [NSTextFieldCell
class]])
292 // I wonder why NSTextFieldCell doesn't work for me in the default else branch.
293 // NSComboBoxCell works, and that derives from NSTextFieldCell, on the other
294 // hand setShowsFirstResponder causes a hangs when set on NSComboBoxCell
295 NSRect out
= [pBtn focusRingMaskBoundsForFrame
: rect inView
: pView
];
296 CGContextFillRect(context
, out
);
298 else if ([pBtn isKindOfClass
: [NSSliderCell
class]])
300 // Not getting anything useful for a NSSliderCell, so use the knob
301 [static_cast<NSSliderCell
*>(pBtn
) drawKnob
: rect
];
304 [pBtn drawFocusRingMaskWithFrame
:rect inView
: pView
];
306 CGContextEndTransparencyLayer(context
);
309 [NSGraphicsContext setCurrentContext
:savedContext
];
310 CGContextRestoreGState(context
);
313 static void paintFocusRect(double radius
, const NSRect
& rect
, CGContextRef context
)
315 NSRect bounds
= rect
;
317 CGPathRef path
= CGPathCreateWithRoundedRect(bounds
, radius
, radius
, nullptr);
318 CGContextSetStrokeColorWithColor(context
, [NSColor keyboardFocusIndicatorColor
].CGColor
);
319 CGContextSetLineWidth(context
, FOCUS_RING_WIDTH
);
320 CGContextBeginPath(context
);
321 CGContextAddPath(context
, path
);
322 CGContextStrokePath(context
);
326 @interface FixedWidthTabViewItem
: NSTabViewItem
{
329 - (NSSize
)sizeOfLabel
: (BOOL
)computeMin
;
330 - (void)setTabWidth
: (int)nWidth
;
333 @implementation FixedWidthTabViewItem
334 - (NSSize
)sizeOfLabel
: (BOOL
)computeMin
336 NSSize size
= [super sizeOfLabel
: computeMin
];
337 size
.width
= m_nWidth
;
340 - (void)setTabWidth
: (int)nWidth
346 bool AquaGraphicsBackend::drawNativeControl(ControlType nType
,
348 const tools::Rectangle
&rControlRegion
,
350 const ImplControlValue
&aValue
)
352 if (!mrShared
.checkContext())
354 mrShared
.maContextHolder
.saveState();
355 bool bOK
= performDrawNativeControl(nType
, nPart
, rControlRegion
, nState
, aValue
,
356 mrShared
.maContextHolder
.get(), mrShared
.mpFrame
);
357 mrShared
.maContextHolder
.restoreState();
359 tools::Rectangle buttonRect
= rControlRegion
;
361 // in most cases invalidating the whole control region instead of just the unclipped part of it is sufficient (and probably
362 // faster). However for the window background we should not unnecessarily enlarge the really changed rectangle since the
363 // difference is usually quite high. Background is always drawn as a whole since we don't know anything about its possible
364 // contents (see issue i90291).
366 if (nType
== ControlType::WindowBackground
)
368 CGRect aRect
= {{0, 0}, {0, 0}};
369 if (mrShared
.mxClipPath
)
370 aRect
= CGPathGetBoundingBox(mrShared
.mxClipPath
);
371 if (aRect
.size
.width
!= 0 && aRect
.size
.height
!= 0)
372 buttonRect
.Intersection(tools::Rectangle(Point(static_cast<tools::Long
>(aRect
.origin
.x
),
373 static_cast<tools::Long
>(aRect
.origin
.y
)),
374 Size(static_cast<tools::Long
>(aRect
.size
.width
),
375 static_cast<tools::Long
>(aRect
.size
.height
))));
377 mrShared
.refreshRect(buttonRect
.Left(), buttonRect
.Top(), buttonRect
.GetWidth(), buttonRect
.GetHeight());
381 static void drawBox(CGContextRef context
, const NSRect
& rc
, NSColor
* pColor
)
383 CGContextSaveGState(context
);
384 CGContextTranslateCTM(context
, rc
.origin
.x
, rc
.origin
.y
+ rc
.size
.height
);
385 CGContextScaleCTM(context
, 1, -1);
387 NSGraphicsContext
* graphicsContext
= [NSGraphicsContext graphicsContextWithCGContext
:context flipped
:NO
];
389 NSRect rect
= { NSZeroPoint
, NSMakeSize(rc
.size
.width
, rc
.size
.height
) };
390 NSBox
* pBox
= [[NSBox alloc
] initWithFrame
: rect
];
392 [pBox setBoxType
: NSBoxCustom
];
393 [pBox setFillColor
: pColor
];
394 SAL_WNODEPRECATED_DECLARATIONS_PUSH
// setBorderType first deprecated in macOS 10.15
395 [pBox setBorderType
: NSNoBorder
];
396 SAL_WNODEPRECATED_DECLARATIONS_POP
398 [pBox displayRectIgnoringOpacity
: rect inContext
: graphicsContext
];
402 CGContextRestoreGState(context
);
405 // if I don't crystallize this bg then the InvertCursor using kCGBlendModeDifference doesn't
406 // work correctly and the cursor doesn't appear correctly
407 static void drawEditableBackground(CGContextRef context
, const NSRect
& rc
)
409 CGContextSaveGState(context
);
410 CGContextSetFillColorWithColor(context
, [NSColor controlBackgroundColor
].CGColor
);
411 CGContextFillRect(context
, rc
);
412 CGContextRestoreGState(context
);
415 // As seen in macOS 12.3.1. All a bit odd really.
416 const int RoundedMargin
[4] = { 6, 4, 0, 3 };
418 bool AquaGraphicsBackendBase::performDrawNativeControl(ControlType nType
,
420 const tools::Rectangle
&rControlRegion
,
422 const ImplControlValue
&aValue
,
423 CGContextRef context
,
424 AquaSalFrame
* mpFrame
)
427 AquaSalInstance
* pInst
= GetSalData()->mpInstance
;
428 HIRect rc
= ImplGetHIRectFromRectangle(rControlRegion
);
431 case ControlType::Toolbar
:
433 drawBox(context
, rc
, NSColor
.windowBackgroundColor
);
437 case ControlType::WindowBackground
:
439 drawBox(context
, rc
, NSColor
.windowBackgroundColor
);
443 case ControlType::Tooltip
:
447 drawBox(context
, rc
, NSColor
.controlBackgroundColor
);
451 case ControlType::Menubar
:
452 case ControlType::MenuPopup
:
453 if (nPart
== ControlPart::Entire
|| nPart
== ControlPart::MenuItem
|| nPart
== ControlPart::HasBackgroundTexture
)
455 // FIXME: without this magical offset there is a 2 pixel black border on the right
458 HIThemeMenuDrawInfo aMenuInfo
;
459 aMenuInfo
.version
= 0;
460 aMenuInfo
.menuType
= kThemeMenuTypePullDown
;
461 HIThemeMenuItemDrawInfo aMenuItemDrawInfo
;
463 // grey theme when the item is selected is drawn here.
465 aMenuItemDrawInfo
.itemType
= kThemeMenuItemPlain
;
466 if ((nPart
== ControlPart::MenuItem
) && (nState
& ControlState::SELECTED
))
468 // blue theme when the item is selected is drawn here.
470 aMenuItemDrawInfo
.state
= kThemeMenuSelected
;
473 // normal color for non selected item
475 aMenuItemDrawInfo
.state
= kThemeMenuActive
;
477 // repaints the background of the pull down menu
479 HIThemeDrawMenuBackground(&rc
, &aMenuInfo
, context
, kHIThemeOrientationNormal
);
481 // repaints the item either blue (selected) and/or grey (active only)
483 HIThemeDrawMenuItem(&rc
, &rc
, &aMenuItemDrawInfo
, context
, kHIThemeOrientationNormal
, &rc
);
486 else if (nPart
== ControlPart::MenuItemCheckMark
|| nPart
== ControlPart::MenuItemRadioMark
)
488 // checked, else it is not displayed (see vcl/source/window/menu.cxx)
490 if (nState
& ControlState::PRESSED
)
492 HIThemeTextInfo aTextInfo
;
493 aTextInfo
.version
= 0;
494 aTextInfo
.state
= (nState
& ControlState::ENABLED
) ? kThemeStateInactive
: kThemeStateActive
;
495 aTextInfo
.fontID
= kThemeMenuItemMarkFont
;
496 aTextInfo
.horizontalFlushness
= kHIThemeTextHorizontalFlushCenter
;
497 aTextInfo
.verticalFlushness
= kHIThemeTextVerticalFlushTop
;
498 aTextInfo
.options
= kHIThemeTextBoxOptionNone
;
499 aTextInfo
.truncationPosition
= kHIThemeTextTruncationNone
;
501 // aTextInfo.truncationMaxLines unused because of kHIThemeTextTruncationNone item highlighted
503 if (nState
& ControlState::SELECTED
) aTextInfo
.state
= kThemeStatePressed
;
504 UniChar mark
=(nPart
== ControlPart::MenuItemCheckMark
) ? kCheckUnicode
: kBulletUnicode
;
505 CFStringRef cfString
= CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault
, &mark
, 1, kCFAllocatorNull
);
506 HIThemeDrawTextBox(cfString
, &rc
, &aTextInfo
, context
, kHIThemeOrientationNormal
);
513 case ControlType::Pushbutton
:
515 NSControlSize eSizeKind
= NSControlSizeRegular
;
516 NSBezelStyle eBezelStyle
= NSBezelStyleRounded
;
518 PushButtonValue
const *pPBVal
= aValue
.getType() == ControlType::Pushbutton
?
519 static_cast<PushButtonValue
const *>(&aValue
) : nullptr;
521 SInt32 nPaintHeight
= rc
.size
.height
;
522 if (rc
.size
.height
<= PUSH_BUTTON_NORMAL_HEIGHT
)
524 eSizeKind
= NSControlSizeMini
;
525 GetThemeMetric(kThemeMetricSmallPushButtonHeight
, &nPaintHeight
);
527 else if ((pPBVal
&& pPBVal
->mbSingleLine
) || rc
.size
.height
< PUSH_BUTTON_NORMAL_HEIGHT
* 3 / 2)
529 GetThemeMetric(kThemeMetricPushButtonHeight
, &nPaintHeight
);
533 // A simple square bezel style that can scale to any size
534 eBezelStyle
= NSBezelStyleSmallSquare
;
537 // translate the origin for controls with fixed paint height so content ends up somewhere sensible
538 rc
.origin
.y
+= (rc
.size
.height
- nPaintHeight
+ 1) / 2;
539 rc
.size
.height
= nPaintHeight
;
541 NSButtonCell
* pBtn
= pInst
->mpButtonCell
;
542 pBtn
.allowsMixedState
= YES
;
544 [pBtn setTitle
: @
""];
545 [pBtn setButtonType
: NSButtonTypeMomentaryPushIn
];
546 [pBtn setBezelStyle
: eBezelStyle
];
547 [pBtn setState
: ImplGetButtonValue(aValue
.getTristateVal())];
548 [pBtn setEnabled
: getEnabled(nState
, mpFrame
)];
549 [pBtn setFocusRingType
: NSFocusRingTypeExterior
];
550 [pBtn setHighlighted
: (nState
& ControlState::PRESSED
) ? YES
: NO
];
551 [pBtn setControlSize
: eSizeKind
];
552 if (nState
& ControlState::DEFAULT
)
553 [pBtn setKeyEquivalent
: @
"\r"];
555 [pBtn setKeyEquivalent
: @
""];
557 if (eBezelStyle
== NSBezelStyleRounded
)
559 int nMargin
= RoundedMargin
[eSizeKind
];
560 rc
.origin
.x
-= nMargin
;
561 rc
.size
.width
+= nMargin
* 2;
563 rc
.origin
.x
+= FOCUS_RING_WIDTH
/ 2;
564 rc
.size
.width
-= FOCUS_RING_WIDTH
;
567 const bool bFocused(nState
& ControlState::FOCUSED
);
568 paintCell(pBtn
, rc
, bFocused
, context
, nullptr);
573 case ControlType::Radiobutton
:
574 case ControlType::Checkbox
:
576 rc
.size
.width
-= 2 * FOCUS_RING_WIDTH
;
577 rc
.size
.height
= RADIO_BUTTON_SMALL_SIZE
;
578 rc
.origin
.x
+= FOCUS_RING_WIDTH
;
579 rc
.origin
.y
+= FOCUS_RING_WIDTH
;
581 NSButtonCell
* pBtn
= nType
== ControlType::Checkbox
? pInst
->mpCheckCell
: pInst
->mpRadioCell
;
582 pBtn
.allowsMixedState
= YES
;
584 [pBtn setTitle
: @
""];
585 [pBtn setButtonType
: nType
== ControlType::Checkbox
? NSButtonTypeSwitch
: NSButtonTypeRadio
];
586 [pBtn setState
: ImplGetButtonValue(aValue
.getTristateVal())];
587 [pBtn setEnabled
: getEnabled(nState
, mpFrame
)];
588 [pBtn setFocusRingType
: NSFocusRingTypeExterior
];
589 [pBtn setHighlighted
: (nState
& ControlState::PRESSED
) ? YES
: NO
];
591 const bool bFocused(nState
& ControlState::FOCUSED
);
592 paintCell(pBtn
, rc
, bFocused
, context
, nullptr);
597 case ControlType::ListNode
:
599 NSButtonCell
* pBtn
= pInst
->mpListNodeCell
;
600 pBtn
.allowsMixedState
= YES
;
602 [pBtn setTitle
: @
""];
603 [pBtn setButtonType
: NSButtonTypeOnOff
];
604 [pBtn setBezelStyle
: NSBezelStyleDisclosure
];
605 [pBtn setState
: ImplGetButtonValue(aValue
.getTristateVal())];
606 [pBtn setEnabled
: getEnabled(nState
, mpFrame
)];
607 [pBtn setFocusRingType
: NSFocusRingTypeExterior
];
609 const bool bFocused(nState
& ControlState::FOCUSED
);
610 paintCell(pBtn
, rc
, bFocused
, context
, nullptr);
615 case ControlType::LevelBar
:
617 NSRect rect
= { NSZeroPoint
, NSMakeSize(rc
.size
.width
, rc
.size
.height
) };
618 NSLevelIndicator
* pBox
= [[NSLevelIndicator alloc
] initWithFrame
:rect
];
619 [pBox setLevelIndicatorStyle
: NSLevelIndicatorStyleContinuousCapacity
];
620 [pBox setMinValue
: 0];
621 [pBox setMaxValue
: rc
.size
.width
];
622 [pBox setCriticalValue
: rc
.size
.width
* 35.0 / 100.0];
623 [pBox setWarningValue
: rc
.size
.width
* 70.0 / 100.0];
624 [pBox setDoubleValue
: aValue
.getNumericVal()];
626 CGContextSaveGState(context
);
627 CGContextTranslateCTM(context
, rc
.origin
.x
, rc
.origin
.y
);
629 NSGraphicsContext
* savedContext
= [NSGraphicsContext currentContext
];
630 NSGraphicsContext
* graphicsContext
= [NSGraphicsContext graphicsContextWithCGContext
:context flipped
:NO
];
631 [NSGraphicsContext setCurrentContext
: graphicsContext
];
633 [pBox drawRect
: rect
];
635 [NSGraphicsContext setCurrentContext
: savedContext
];
637 CGContextRestoreGState(context
);
644 case ControlType::Progress
:
645 case ControlType::IntroProgress
:
647 NSRect rect
= { NSZeroPoint
, NSMakeSize(rc
.size
.width
, rc
.size
.height
) };
648 NSProgressIndicator
* pBox
= [[NSProgressIndicator alloc
] initWithFrame
: rect
];
649 [pBox setControlSize
: (rc
.size
.height
> MEDIUM_PROGRESS_INDICATOR_HEIGHT
) ?
650 NSControlSizeRegular
: NSControlSizeSmall
];
651 [pBox setMinValue
: 0];
652 [pBox setMaxValue
: rc
.size
.width
];
653 [pBox setDoubleValue
: aValue
.getNumericVal()];
654 pBox
.usesThreadedAnimation
= NO
;
655 [pBox setIndeterminate
: NO
];
657 CGContextSaveGState(context
);
658 CGContextTranslateCTM(context
, rc
.origin
.x
, rc
.origin
.y
);
660 NSGraphicsContext
* savedContext
= [NSGraphicsContext currentContext
];
661 NSGraphicsContext
* graphicsContext
= [NSGraphicsContext graphicsContextWithCGContext
:context flipped
:NO
];
662 [NSGraphicsContext setCurrentContext
: graphicsContext
];
664 [pBox drawRect
: rect
];
666 [NSGraphicsContext setCurrentContext
: savedContext
];
668 CGContextRestoreGState(context
);
675 case ControlType::Slider
:
677 const SliderValue
*pSliderVal
= static_cast<SliderValue
const *>(&aValue
);
678 if (nPart
== ControlPart::TrackHorzArea
|| nPart
== ControlPart::TrackVertArea
)
680 NSRect rect
= { NSZeroPoint
, NSMakeSize(rc
.size
.width
, rc
.size
.height
) };
681 NSSlider
* pBox
= [[NSSlider alloc
] initWithFrame
: rect
];
683 [pBox setEnabled
: getEnabled(nState
, mpFrame
)];
684 [pBox setVertical
: nPart
== ControlPart::TrackVertArea
];
685 [pBox setMinValue
: pSliderVal
->mnMin
];
686 [pBox setMaxValue
: pSliderVal
->mnMax
];
687 [pBox setIntegerValue
: pSliderVal
->mnCur
];
688 [pBox setSliderType
: NSSliderTypeLinear
];
689 [pBox setFocusRingType
: NSFocusRingTypeExterior
];
691 const bool bFocused(nState
& ControlState::FOCUSED
);
692 paintCell(pBox
.cell
, rc
, bFocused
, context
, mpFrame
->getNSView());
700 case ControlType::Scrollbar
:
702 const ScrollbarValue
*pScrollbarVal
= (aValue
.getType() == ControlType::Scrollbar
)
703 ? static_cast<const ScrollbarValue
*>(&aValue
) : nullptr;
704 if (nPart
== ControlPart::DrawBackgroundVert
|| nPart
== ControlPart::DrawBackgroundHorz
)
706 drawBox(context
, rc
, NSColor
.controlBackgroundColor
);
708 NSRect rect
= { NSZeroPoint
, NSMakeSize(rc
.size
.width
, rc
.size
.height
) };
709 NSScroller
* pBar
= [[NSScroller alloc
] initWithFrame
: rect
];
711 double range
= pScrollbarVal
->mnMax
- pScrollbarVal
->mnVisibleSize
- pScrollbarVal
->mnMin
;
712 double value
= range
? (pScrollbarVal
->mnCur
- pScrollbarVal
->mnMin
) / range
: 0;
714 double length
= pScrollbarVal
->mnMax
- pScrollbarVal
->mnMin
;
715 double proportion
= pScrollbarVal
->mnVisibleSize
/ length
;
717 [pBar setEnabled
: getEnabled(nState
, mpFrame
)];
718 [pBar setScrollerStyle
: NSScrollerStyleLegacy
];
719 [pBar setFloatValue
: value
];
720 [pBar setKnobProportion
: proportion
];
721 bool bPressed
= (pScrollbarVal
->mnThumbState
& ControlState::ENABLED
) &&
722 (pScrollbarVal
->mnThumbState
& ControlState::PRESSED
);
724 CGContextSaveGState(context
);
725 CGContextTranslateCTM(context
, rc
.origin
.x
, rc
.origin
.y
);
727 NSGraphicsContext
* graphicsContext
= [NSGraphicsContext graphicsContextWithCGContext
:context flipped
:NO
];
729 NSGraphicsContext
* savedContext
= [NSGraphicsContext currentContext
];
730 [NSGraphicsContext setCurrentContext
: graphicsContext
];
732 // For not-pressed first draw without the knob and then
733 // draw just the knob but with 50% opaque which looks sort of
736 [pBar drawKnobSlotInRect
: rect highlight
: NO
];
738 NSBitmapImageRep
* pImageRep
= [pBar bitmapImageRepForCachingDisplayInRect
: rect
];
740 NSGraphicsContext
* imageContext
= [NSGraphicsContext graphicsContextWithBitmapImageRep
:pImageRep
];
741 [NSGraphicsContext setCurrentContext
: imageContext
];
745 [NSGraphicsContext setCurrentContext
: graphicsContext
];
747 NSImage
* pImage
= [[NSImage alloc
] initWithSize
: rect
.size
];
748 [pImage addRepresentation
: pImageRep
]; // takes ownership of pImageRep
750 [pImage drawInRect
: rect fromRect
: rect
751 operation
: NSCompositingOperationSourceOver
752 fraction
: bPressed
? 1.0 : 0.5];
756 [NSGraphicsContext setCurrentContext
:savedContext
];
758 CGContextRestoreGState(context
);
766 case ControlType::TabPane
:
768 NSTabView
* pBox
= [[NSTabView alloc
] initWithFrame
: rc
];
771 GetThemeMetric(kThemeMetricTabFrameOverlap
, &nOverlap
);
773 // this calculation is probably more than a little dubious
774 rc
.origin
.x
-= pBox
.contentRect
.origin
.x
- FOCUS_RING_WIDTH
;
775 rc
.size
.width
+= rc
.size
.width
- pBox
.contentRect
.size
.width
- 2 * FOCUS_RING_WIDTH
;
776 double nTopBorder
= pBox
.contentRect
.origin
.y
;
777 double nBottomBorder
= rc
.size
.height
- pBox
.contentRect
.size
.height
- nTopBorder
;
778 double nExtraTop
= (nTopBorder
- nBottomBorder
) / 2;
779 rc
.origin
.y
-= (nTopBorder
- nExtraTop
+ nOverlap
);
780 rc
.size
.height
+= (nTopBorder
- nExtraTop
+ nBottomBorder
);
782 CGContextSaveGState(context
);
783 CGContextTranslateCTM(context
, rc
.origin
.x
, rc
.origin
.y
);
788 [pBox setBoundsOrigin
: rc
.origin
];
789 [pBox setBoundsSize
: rc
.size
];
791 // jam this in to force the tab contents area to be left undrawn, the ControlType::TabItem
792 // will be drawn in this space.
793 const TabPaneValue
& rValue
= static_cast<const TabPaneValue
&>(aValue
);
795 GetThemeMetric(kThemeMetricLargeTabCapsWidth
, &nEndCapWidth
);
796 FixedWidthTabViewItem
* pItem
= [[[FixedWidthTabViewItem alloc
] initWithIdentifier
: @
"tab"] autorelease
];
797 [pItem setTabWidth
: rValue
.m_aTabHeaderRect
.GetWidth() - 2 * nEndCapWidth
];
798 [pBox addTabViewItem
: pItem
];
800 NSGraphicsContext
* graphicsContext
= [NSGraphicsContext graphicsContextWithCGContext
:context flipped
:NO
];
802 NSGraphicsContext
* savedContext
= [NSGraphicsContext currentContext
];
803 [NSGraphicsContext setCurrentContext
: graphicsContext
];
807 [NSGraphicsContext setCurrentContext
: savedContext
];
811 CGContextRestoreGState(context
);
816 case ControlType::TabItem
:
818 // first, last or middle tab
820 TabitemValue
const * pTabValue
= static_cast<TabitemValue
const *>(&aValue
);
821 TabitemFlags nAlignment
= pTabValue
->mnAlignment
;
823 // TabitemFlags::LeftAligned (and TabitemFlags::RightAligned) for the leftmost (or rightmost) tab
824 // when there are several lines of tabs because there is only one first tab and one
825 // last tab and TabitemFlags::FirstInGroup (and TabitemFlags::LastInGroup) because when the
826 // line width is different from window width, there may not be TabitemFlags::RightAligned
829 if (((nAlignment
& TabitemFlags::LeftAligned
) && (nAlignment
& TabitemFlags::RightAligned
))
830 || ((nAlignment
& TabitemFlags::FirstInGroup
) && (nAlignment
& TabitemFlags::LastInGroup
)))
835 else if ((nAlignment
& TabitemFlags::LeftAligned
) || (nAlignment
& TabitemFlags::FirstInGroup
))
836 nPaintIndex
= !AllSettings::GetLayoutRTL() ? 0 : 2;
837 else if ((nAlignment
& TabitemFlags::RightAligned
) || (nAlignment
& TabitemFlags::LastInGroup
))
838 nPaintIndex
= !AllSettings::GetLayoutRTL() ? 2 : 0;
840 int nCells
= !bSolo
? 3 : 1;
841 NSRect ctrlrect
= { NSZeroPoint
, NSMakeSize(rc
.size
.width
* nCells
+ FOCUS_RING_WIDTH
, rc
.size
.height
) };
842 NSSegmentedControl
* pCtrl
= [[NSSegmentedControl alloc
] initWithFrame
: ctrlrect
];
843 [pCtrl setSegmentCount
: nCells
];
845 [pCtrl setWidth
: rc
.size
.width
+ FOCUS_RING_WIDTH forSegment
: 0];
848 [pCtrl setWidth
: rc
.size
.width
+ FOCUS_RING_WIDTH
/2 forSegment
: 0];
849 [pCtrl setWidth
: rc
.size
.width forSegment
: 1];
850 [pCtrl setWidth
: rc
.size
.width
+ FOCUS_RING_WIDTH
/2 forSegment
: 2];
852 [pCtrl setSelected
: (nState
& ControlState::SELECTED
) ? YES
: NO forSegment
: nPaintIndex
];
853 [pCtrl setFocusRingType
: NSFocusRingTypeExterior
];
855 NSGraphicsContext
* savedContext
= [NSGraphicsContext currentContext
];
856 [NSGraphicsContext setCurrentContext
:[NSGraphicsContext graphicsContextWithCGContext
:context flipped
:NO
]];
858 NSRect rect
= { NSZeroPoint
, NSMakeSize(rc
.size
.width
, rc
.size
.height
) };
859 NSRect tabrect
= { NSMakePoint(rc
.size
.width
* nPaintIndex
+ FOCUS_RING_WIDTH
/ 2, 0),
860 NSMakeSize(rc
.size
.width
, rc
.size
.height
) };
861 NSBitmapImageRep
* pImageRep
= [pCtrl bitmapImageRepForCachingDisplayInRect
: tabrect
];
862 [pCtrl cacheDisplayInRect
: tabrect toBitmapImageRep
: pImageRep
];
864 NSImage
* pImage
= [[NSImage alloc
] initWithSize
: rect
.size
];
865 [pImage addRepresentation
: pImageRep
]; // takes ownership of pImageRep
867 [pImage drawInRect
: rc fromRect
: rect
868 operation
: NSCompositingOperationSourceOver
873 [NSGraphicsContext setCurrentContext
:savedContext
];
877 if (nState
& ControlState::FOCUSED
)
881 if (nPaintIndex
== 0)
883 rc
.origin
.x
+= FOCUS_RING_WIDTH
/ 2;
884 rc
.size
.width
-= FOCUS_RING_WIDTH
/ 2;
886 else if (nPaintIndex
== 2)
888 rc
.size
.width
-= FOCUS_RING_WIDTH
/ 2;
889 rc
.size
.width
-= FOCUS_RING_WIDTH
/ 2;
893 paintFocusRect(4.0, rc
, context
);
898 case ControlType::Editbox
:
899 case ControlType::MultilineEditbox
:
901 rc
.size
.width
+= 2 * EDITBOX_INSET_MARGIN
;
902 if (nType
== ControlType::Editbox
)
903 rc
.size
.height
= EDITBOX_HEIGHT
;
905 rc
.size
.height
+= 2 * (EDITBOX_BORDER_WIDTH
+ EDITBOX_INSET_MARGIN
);
906 rc
.origin
.x
-= EDITBOX_INSET_MARGIN
;
907 rc
.origin
.y
-= EDITBOX_INSET_MARGIN
;
909 NSTextFieldCell
* pBtn
= pInst
->mpTextFieldCell
;
911 [pBtn setEnabled
: getEnabled(nState
, mpFrame
)];
912 [pBtn setBezeled
: YES
];
913 [pBtn setEditable
: YES
];
914 [pBtn setFocusRingType
: NSFocusRingTypeExterior
];
916 drawEditableBackground(context
, rc
);
917 const bool bFocused(nState
& ControlState::FOCUSED
);
918 paintCell(pBtn
, rc
, bFocused
, context
, mpFrame
->getNSView());
923 case ControlType::Combobox
:
924 if (nPart
== ControlPart::HasBackgroundTexture
|| nPart
== ControlPart::Entire
)
926 rc
.origin
.y
+= (rc
.size
.height
- COMBOBOX_HEIGHT
+ 1) / 2;
927 rc
.size
.height
= COMBOBOX_HEIGHT
;
929 NSComboBoxCell
* pBtn
= pInst
->mpComboBoxCell
;
931 [pBtn setEnabled
: getEnabled(nState
, mpFrame
)];
932 [pBtn setEditable
: YES
];
933 [pBtn setState
: ImplGetButtonValue(aValue
.getTristateVal())];
934 [pBtn setFocusRingType
: NSFocusRingTypeExterior
];
941 drawEditableBackground(context
, rc
);
942 const bool bFocused(nState
& ControlState::FOCUSED
);
943 paintCell(pBtn
, rc
, bFocused
, context
, mpFrame
->getNSView());
948 case ControlType::Listbox
:
952 case ControlPart::Entire
:
953 case ControlPart::ButtonDown
:
955 rc
.origin
.y
+= (rc
.size
.height
- LISTBOX_HEIGHT
+ 1) / 2;
956 rc
.size
.height
= LISTBOX_HEIGHT
;
958 NSPopUpButtonCell
* pBtn
= pInst
->mpPopUpButtonCell
;
960 [pBtn setTitle
: @
""];
961 [pBtn setEnabled
: getEnabled(nState
, mpFrame
)];
962 [pBtn setFocusRingType
: NSFocusRingTypeExterior
];
963 [pBtn setHighlighted
: (nState
& ControlState::PRESSED
) ? YES
: NO
];
964 if (nState
& ControlState::DEFAULT
)
965 [pBtn setKeyEquivalent
: @
"\r"];
967 [pBtn setKeyEquivalent
: @
""];
973 const bool bFocused(nState
& ControlState::FOCUSED
);
974 paintCell(pBtn
, rc
, bFocused
, context
, nullptr);
979 case ControlPart::ListboxWindow
:
981 NSRect rect
= { NSZeroPoint
, NSMakeSize(rc
.size
.width
, rc
.size
.height
) };
982 NSScrollView
* pBox
= [[NSScrollView alloc
] initWithFrame
: rect
];
983 [pBox setBorderType
: NSLineBorder
];
985 CGContextSaveGState(context
);
986 CGContextTranslateCTM(context
, rc
.origin
.x
, rc
.origin
.y
);
988 NSGraphicsContext
* savedContext
= [NSGraphicsContext currentContext
];
989 NSGraphicsContext
* graphicsContext
= [NSGraphicsContext graphicsContextWithCGContext
:context flipped
:NO
];
990 [NSGraphicsContext setCurrentContext
: graphicsContext
];
992 [pBox drawRect
: rect
];
994 [NSGraphicsContext setCurrentContext
: savedContext
];
996 CGContextRestoreGState(context
);
1007 case ControlType::Spinbox
:
1008 if (nPart
== ControlPart::Entire
)
1012 rc
.size
.width
-= SPIN_BUTTON_WIDTH
+ 4 * FOCUS_RING_WIDTH
;
1013 rc
.size
.height
= EDITBOX_HEIGHT
;
1014 rc
.origin
.x
+= FOCUS_RING_WIDTH
;
1015 rc
.origin
.y
+= FOCUS_RING_WIDTH
;
1017 NSTextFieldCell
* pEdit
= pInst
->mpTextFieldCell
;
1019 [pEdit setEnabled
: YES
];
1020 [pEdit setBezeled
: YES
];
1021 [pEdit setEditable
: YES
];
1022 [pEdit setFocusRingType
: NSFocusRingTypeExterior
];
1024 drawEditableBackground(context
, rc
);
1025 const bool bFocused(nState
& ControlState::FOCUSED
);
1026 paintCell(pEdit
, rc
, bFocused
, context
, mpFrame
->getNSView());
1030 const SpinbuttonValue
*pSpinButtonVal
= (aValue
.getType() == ControlType::SpinButtons
)
1031 ? static_cast <const SpinbuttonValue
*>(&aValue
) : nullptr;
1034 ControlState nUpperState
= pSpinButtonVal
->mnUpperState
;
1035 ControlState nLowerState
= pSpinButtonVal
->mnLowerState
;
1037 rc
.origin
.x
+= rc
.size
.width
+ FOCUS_RING_WIDTH
+ 1;
1039 rc
.size
.width
= SPIN_BUTTON_WIDTH
;
1040 rc
.size
.height
= SPIN_LOWER_BUTTON_HEIGHT
+ SPIN_LOWER_BUTTON_HEIGHT
;
1042 NSStepperCell
* pBtn
= pInst
->mpStepperCell
;
1044 [pBtn setTitle
: @
""];
1045 [pBtn setState
: ImplGetButtonValue(aValue
.getTristateVal())];
1046 [pBtn setEnabled
: (nUpperState
& ControlState::ENABLED
|| nLowerState
& ControlState::ENABLED
) ?
1048 [pBtn setFocusRingType
: NSFocusRingTypeExterior
];
1049 [pBtn setHighlighted
: (nState
& ControlState::PRESSED
) ? YES
: NO
];
1051 const bool bSpinFocused(nUpperState
& ControlState::FOCUSED
|| nLowerState
& ControlState::FOCUSED
);
1052 paintCell(pBtn
, rc
, bSpinFocused
, context
, nullptr);
1057 case ControlType::Frame
:
1059 DrawFrameFlags nStyle
= static_cast<DrawFrameFlags
>(aValue
.getNumericVal());
1060 if (nPart
== ControlPart::Border
)
1062 if (!(nStyle
& DrawFrameFlags::Menu
) && !(nStyle
& DrawFrameFlags::WindowBorder
))
1065 // strange effects start to happen when HIThemeDrawFrame meets the border of the window.
1066 // These can be avoided by clipping to the boundary of the frame (see issue 84756)
1068 if (rc
.origin
.y
+ rc
.size
.height
>= mpFrame
->maGeometry
.height() - 3)
1070 CGMutablePathRef rPath
= CGPathCreateMutable();
1071 CGPathAddRect(rPath
, nullptr,
1072 CGRectMake(0, 0, mpFrame
->maGeometry
.width() - 1, mpFrame
->maGeometry
.height() - 1));
1073 CGContextBeginPath(context
);
1074 CGContextAddPath(context
, rPath
);
1075 CGContextClip(context
);
1076 CGPathRelease(rPath
);
1078 HIThemeFrameDrawInfo aTextDrawInfo
;
1079 aTextDrawInfo
.version
= 0;
1080 aTextDrawInfo
.kind
= kHIThemeFrameListBox
;
1081 aTextDrawInfo
.state
= kThemeStateActive
;
1082 aTextDrawInfo
.isFocused
= false;
1083 HIThemeDrawFrame(&rc
, &aTextDrawInfo
, context
, kHIThemeOrientationNormal
);
1089 case ControlType::ListNet
:
1091 // do nothing as there isn't net for listviews on macOS
1102 bool AquaSalGraphics::getNativeControlRegion(ControlType nType
,
1104 const tools::Rectangle
&rControlRegion
,
1106 const ImplControlValue
&aValue
,
1108 tools::Rectangle
&rNativeBoundingRegion
,
1109 tools::Rectangle
&rNativeContentRegion
)
1111 bool toReturn
= false;
1112 tools::Rectangle
aCtrlBoundRect(rControlRegion
);
1113 short x
= aCtrlBoundRect
.Left();
1114 short y
= aCtrlBoundRect
.Top();
1118 case ControlType::Pushbutton
:
1119 case ControlType::Radiobutton
:
1120 case ControlType::Checkbox
:
1122 if (nType
== ControlType::Pushbutton
)
1124 w
= aCtrlBoundRect
.GetWidth();
1125 h
= aCtrlBoundRect
.GetHeight();
1129 w
= RADIO_BUTTON_SMALL_SIZE
+ 2 * FOCUS_RING_WIDTH
+ RADIO_BUTTON_TEXT_SEPARATOR
;
1130 h
= RADIO_BUTTON_SMALL_SIZE
+ 2 * FOCUS_RING_WIDTH
;
1132 rNativeContentRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1133 rNativeBoundingRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1137 case ControlType::LevelBar
:
1138 case ControlType::Progress
:
1140 tools::Rectangle
aRect(aCtrlBoundRect
);
1141 if (aRect
.GetHeight() < LARGE_PROGRESS_INDICATOR_HEIGHT
)
1142 aRect
.SetBottom(aRect
.Top() + MEDIUM_PROGRESS_INDICATOR_HEIGHT
- 1);
1144 aRect
.SetBottom(aRect
.Top() + LARGE_PROGRESS_INDICATOR_HEIGHT
- 1);
1145 rNativeBoundingRegion
= aRect
;
1146 rNativeContentRegion
= aRect
;
1150 case ControlType::IntroProgress
:
1152 tools::Rectangle
aRect(aCtrlBoundRect
);
1153 aRect
.SetBottom(aRect
.Top() + MEDIUM_PROGRESS_INDICATOR_HEIGHT
- 1);
1154 rNativeBoundingRegion
= aRect
;
1155 rNativeContentRegion
= aRect
;
1159 case ControlType::Slider
:
1160 if (nPart
== ControlPart::ThumbHorz
)
1163 h
= aCtrlBoundRect
.GetHeight();
1164 rNativeBoundingRegion
= rNativeContentRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1167 else if (nPart
== ControlPart::ThumbVert
)
1169 w
= aCtrlBoundRect
.GetWidth();
1171 rNativeBoundingRegion
= rNativeContentRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1175 case ControlType::Scrollbar
:
1177 tools::Rectangle aRect
;
1178 if (AquaGetScrollRect(nPart
, aCtrlBoundRect
, aRect
))
1181 rNativeBoundingRegion
= aRect
;
1182 rNativeContentRegion
= aRect
;
1186 case ControlType::TabItem
:
1188 w
= aCtrlBoundRect
.GetWidth() + 2 * TAB_TEXT_MARGIN
;
1190 rNativeContentRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1191 rNativeBoundingRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1195 case ControlType::Editbox
:
1197 const tools::Long nBorderThickness
= FOCUS_RING_WIDTH
+ EDITBOX_BORDER_WIDTH
+ EDITBOX_INSET_MARGIN
;
1198 // tdf#144241 don't return a negative width, expand the region to the min osx width
1199 w
= std::max(nBorderThickness
* 2, aCtrlBoundRect
.GetWidth());
1200 h
= EDITBOX_HEIGHT
+ 2 * FOCUS_RING_WIDTH
;
1201 rNativeBoundingRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1202 w
-= 2 * nBorderThickness
;
1203 h
-= 2 * nBorderThickness
;
1204 x
+= nBorderThickness
;
1205 y
+= nBorderThickness
;
1206 rNativeContentRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1210 case ControlType::Combobox
:
1211 if (nPart
== ControlPart::Entire
)
1213 w
= aCtrlBoundRect
.GetWidth();
1214 h
= COMBOBOX_HEIGHT
+ 2 * FOCUS_RING_WIDTH
;
1215 rNativeBoundingRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1216 rNativeContentRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1219 else if (nPart
== ControlPart::ButtonDown
)
1221 w
= COMBOBOX_BUTTON_WIDTH
+ FOCUS_RING_WIDTH
;
1222 h
= COMBOBOX_HEIGHT
+ 2 * FOCUS_RING_WIDTH
;
1223 x
+= aCtrlBoundRect
.GetWidth() - w
;
1224 rNativeBoundingRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1225 rNativeContentRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1228 else if (nPart
== ControlPart::SubEdit
)
1230 w
= aCtrlBoundRect
.GetWidth() - 2 * FOCUS_RING_WIDTH
- COMBOBOX_BUTTON_WIDTH
- COMBOBOX_BORDER_WIDTH
1231 - 2 * COMBOBOX_TEXT_MARGIN
;
1232 h
= COMBOBOX_HEIGHT
- 2 * COMBOBOX_BORDER_WIDTH
;
1233 x
+= FOCUS_RING_WIDTH
+ COMBOBOX_BORDER_WIDTH
+ COMBOBOX_TEXT_MARGIN
;
1234 y
+= FOCUS_RING_WIDTH
+ COMBOBOX_BORDER_WIDTH
;
1235 rNativeBoundingRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1236 rNativeContentRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1240 case ControlType::Listbox
:
1241 if (nPart
== ControlPart::Entire
)
1243 w
= aCtrlBoundRect
.GetWidth();
1244 h
= LISTBOX_HEIGHT
+ 2 * FOCUS_RING_WIDTH
;
1245 rNativeBoundingRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1246 rNativeContentRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1249 else if (nPart
== ControlPart::ButtonDown
)
1251 w
= LISTBOX_BUTTON_WIDTH
+ FOCUS_RING_WIDTH
;
1252 h
= LISTBOX_HEIGHT
+ 2 * FOCUS_RING_WIDTH
;
1253 x
+= aCtrlBoundRect
.GetWidth() - w
;
1254 rNativeBoundingRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1255 rNativeContentRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1258 else if (nPart
== ControlPart::SubEdit
)
1260 w
= aCtrlBoundRect
.GetWidth() - 2 * FOCUS_RING_WIDTH
- LISTBOX_BUTTON_WIDTH
- LISTBOX_BORDER_WIDTH
1261 - 2 * LISTBOX_TEXT_MARGIN
;
1262 h
= LISTBOX_HEIGHT
- 2 * LISTBOX_BORDER_WIDTH
;
1263 x
+= FOCUS_RING_WIDTH
+ LISTBOX_BORDER_WIDTH
+ LISTBOX_TEXT_MARGIN
;
1264 y
+= FOCUS_RING_WIDTH
+ LISTBOX_BORDER_WIDTH
;
1265 rNativeBoundingRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1266 rNativeContentRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1269 else if (nPart
== ControlPart::ListboxWindow
)
1271 w
= aCtrlBoundRect
.GetWidth() - 2;
1272 h
= aCtrlBoundRect
.GetHeight() - 2;
1275 rNativeBoundingRegion
= aCtrlBoundRect
;
1276 rNativeContentRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1280 case ControlType::Spinbox
:
1281 if (nPart
== ControlPart::Entire
)
1283 w
= aCtrlBoundRect
.GetWidth();
1284 h
= EDITBOX_HEIGHT
+ 2 * FOCUS_RING_WIDTH
;
1285 x
+= SPINBOX_OFFSET
;
1286 rNativeBoundingRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1287 rNativeContentRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1290 else if (nPart
== ControlPart::SubEdit
)
1292 w
= aCtrlBoundRect
.GetWidth() - 4 * FOCUS_RING_WIDTH
- SPIN_BUTTON_WIDTH
- 2 * EDITBOX_BORDER_WIDTH
1293 - 2 * EDITBOX_INSET_MARGIN
;
1294 h
= EDITBOX_HEIGHT
- 2 * (EDITBOX_BORDER_WIDTH
+ EDITBOX_INSET_MARGIN
);
1295 x
+= FOCUS_RING_WIDTH
+ EDITBOX_BORDER_WIDTH
+ EDITBOX_INSET_MARGIN
+ SPINBOX_OFFSET
;
1296 y
+= FOCUS_RING_WIDTH
+ EDITBOX_BORDER_WIDTH
+ EDITBOX_INSET_MARGIN
;
1297 rNativeBoundingRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1298 rNativeContentRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1301 else if (nPart
== ControlPart::ButtonUp
)
1303 w
= SPIN_BUTTON_WIDTH
+ 2 * FOCUS_RING_WIDTH
;
1304 h
= SPIN_UPPER_BUTTON_HEIGHT
+ FOCUS_RING_WIDTH
;
1305 x
+= aCtrlBoundRect
.GetWidth() - SPIN_BUTTON_WIDTH
- 2 * FOCUS_RING_WIDTH
+ SPINBOX_OFFSET
;
1306 rNativeBoundingRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1307 rNativeContentRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1310 else if (nPart
== ControlPart::ButtonDown
)
1312 w
= SPIN_BUTTON_WIDTH
+ 2 * FOCUS_RING_WIDTH
;
1313 h
= SPIN_LOWER_BUTTON_HEIGHT
+ FOCUS_RING_WIDTH
;
1314 x
+= aCtrlBoundRect
.GetWidth() - SPIN_BUTTON_WIDTH
- 2 * FOCUS_RING_WIDTH
+ SPINBOX_OFFSET
;
1315 y
+= FOCUS_RING_WIDTH
+ SPIN_UPPER_BUTTON_HEIGHT
;
1316 rNativeBoundingRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1317 rNativeContentRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1321 case ControlType::Frame
:
1323 DrawFrameStyle nStyle
= static_cast<DrawFrameStyle
>(aValue
.getNumericVal() & 0x000f);
1324 DrawFrameFlags nFlags
= static_cast<DrawFrameFlags
>(aValue
.getNumericVal() & 0xfff0);
1325 if (nPart
== ControlPart::Border
1326 && !(nFlags
& (DrawFrameFlags::Menu
| DrawFrameFlags::WindowBorder
| DrawFrameFlags::BorderWindowBorder
)))
1328 tools::Rectangle
aRect(aCtrlBoundRect
);
1329 if (nStyle
== DrawFrameStyle::DoubleIn
)
1331 aRect
.AdjustLeft(1);
1333 // rRect.Right() -= 1;
1334 // rRect.Bottom() -= 1;
1338 aRect
.AdjustLeft(1);
1340 aRect
.AdjustRight(-1);
1341 aRect
.AdjustBottom(-1);
1343 rNativeContentRegion
= aRect
;
1344 rNativeBoundingRegion
= aRect
;
1349 case ControlType::Menubar
:
1350 case ControlType::MenuPopup
:
1351 if (nPart
== ControlPart::MenuItemCheckMark
|| nPart
== ControlPart::MenuItemRadioMark
)
1355 rNativeContentRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1356 rNativeBoundingRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1366 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */