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::Progress
:
198 case ControlType::IntroProgress
:
199 if (nPart
== ControlPart::Entire
)
202 case ControlType::Frame
:
203 if (nPart
== ControlPart::Border
)
206 case ControlType::ListNet
:
207 if (nPart
== ControlPart::Entire
)
216 bool AquaSalGraphics::hitTestNativeControl(ControlType nType
, ControlPart nPart
, const tools::Rectangle
&rControlRegion
,
217 const Point
&rPos
, bool& rIsInside
)
219 if (nType
== ControlType::Scrollbar
)
221 tools::Rectangle aRect
;
222 bool bValid
= AquaGetScrollRect(/* TODO: int nScreen, */
223 nPart
, rControlRegion
, aRect
);
224 rIsInside
= bValid
&& aRect
.Contains(rPos
);
230 static bool getEnabled(ControlState nState
, AquaSalFrame
* mpFrame
)
233 // there are non key windows which are children of key windows, e.g. autofilter configuration dialog or sidebar dropdown dialogs.
234 // To handle these windows correctly, parent frame's key window state is considered here additionally.
236 const bool bDrawActive
= mpFrame
== nullptr || [mpFrame
->getNSWindow() isKeyWindow
]
237 || mpFrame
->mpParent
== nullptr || [mpFrame
->mpParent
->getNSWindow() isKeyWindow
];
238 if (!(nState
& ControlState::ENABLED
) || !bDrawActive
)
245 bool AquaSalGraphics::drawNativeControl(ControlType nType
,
247 const tools::Rectangle
&rControlRegion
,
249 const ImplControlValue
&aValue
,
253 return mpBackend
->drawNativeControl(nType
, nPart
, rControlRegion
, nState
, aValue
);
256 static void paintCell(NSCell
* pBtn
, const NSRect
& bounds
, bool bShowsFirstResponder
, CGContextRef context
, NSView
* pView
)
258 //translate and scale because up side down otherwise
259 CGContextSaveGState(context
);
260 CGContextTranslateCTM(context
, bounds
.origin
.x
, bounds
.origin
.y
+ bounds
.size
.height
);
261 CGContextScaleCTM(context
, 1, -1);
263 NSGraphicsContext
* savedContext
= [NSGraphicsContext currentContext
];
264 [NSGraphicsContext setCurrentContext
:[NSGraphicsContext graphicsContextWithCGContext
:context flipped
:NO
]];
266 NSRect rect
= { NSZeroPoint
, bounds
.size
};
268 if ([pBtn isKindOfClass
: [NSSliderCell
class]])
270 // NSSliderCell doesn't seem to work with drawWithFrame(?), so draw the elements directly
271 [static_cast<NSSliderCell
*>(pBtn
)
272 drawBarInside
: [static_cast<NSSliderCell
*>(pBtn
) barRectFlipped
: NO
] flipped
: NO
];
273 rect
= [static_cast<NSSliderCell
*>(pBtn
) knobRectFlipped
: NO
];
274 [static_cast<NSSliderCell
*>(pBtn
) drawKnob
: rect
];
277 [pBtn drawWithFrame
: rect inView
: pView
];
279 // setShowsFirstResponder apparently causes a hang when set on NSComboBoxCell
280 const bool bIsComboBox
= [pBtn isMemberOfClass
: [NSComboBoxCell
class]];
282 [pBtn setShowsFirstResponder
: bShowsFirstResponder
];
284 if (bShowsFirstResponder
)
286 NSSetFocusRingStyle(NSFocusRingOnly
);
288 CGContextBeginTransparencyLayerWithRect(context
, rect
, nullptr);
289 if ([pBtn isMemberOfClass
: [NSTextFieldCell
class]])
291 // I wonder why NSTextFieldCell doesn't work for me in the default else branch.
292 // NSComboBoxCell works, and that derives from NSTextFieldCell, on the other
293 // hand setShowsFirstResponder causes a hangs when set on NSComboBoxCell
294 NSRect out
= [pBtn focusRingMaskBoundsForFrame
: rect inView
: pView
];
295 CGContextFillRect(context
, out
);
297 else if ([pBtn isKindOfClass
: [NSSliderCell
class]])
299 // Not getting anything useful for a NSSliderCell, so use the knob
300 [static_cast<NSSliderCell
*>(pBtn
) drawKnob
: rect
];
303 [pBtn drawFocusRingMaskWithFrame
:rect inView
: pView
];
305 CGContextEndTransparencyLayer(context
);
308 [NSGraphicsContext setCurrentContext
:savedContext
];
309 CGContextRestoreGState(context
);
312 static void paintFocusRect(double radius
, const NSRect
& rect
, CGContextRef context
)
314 NSRect bounds
= rect
;
316 CGPathRef path
= CGPathCreateWithRoundedRect(bounds
, radius
, radius
, nullptr);
317 CGContextSetStrokeColorWithColor(context
, [NSColor keyboardFocusIndicatorColor
].CGColor
);
318 CGContextSetLineWidth(context
, FOCUS_RING_WIDTH
);
319 CGContextBeginPath(context
);
320 CGContextAddPath(context
, path
);
321 CGContextStrokePath(context
);
325 @interface FixedWidthTabViewItem
: NSTabViewItem
{
328 - (NSSize
)sizeOfLabel
: (BOOL
)computeMin
;
329 - (void)setTabWidth
: (int)nWidth
;
332 @implementation FixedWidthTabViewItem
333 - (NSSize
)sizeOfLabel
: (BOOL
)computeMin
335 NSSize size
= [super sizeOfLabel
: computeMin
];
336 size
.width
= m_nWidth
;
339 - (void)setTabWidth
: (int)nWidth
345 bool AquaGraphicsBackend::drawNativeControl(ControlType nType
,
347 const tools::Rectangle
&rControlRegion
,
349 const ImplControlValue
&aValue
)
351 if (!mrShared
.checkContext())
353 mrShared
.maContextHolder
.saveState();
354 bool bOK
= performDrawNativeControl(nType
, nPart
, rControlRegion
, nState
, aValue
,
355 mrShared
.maContextHolder
.get(), mrShared
.mpFrame
);
356 mrShared
.maContextHolder
.restoreState();
358 tools::Rectangle buttonRect
= rControlRegion
;
360 // in most cases invalidating the whole control region instead of just the unclipped part of it is sufficient (and probably
361 // faster). However for the window background we should not unnecessarily enlarge the really changed rectangle since the
362 // difference is usually quite high. Background is always drawn as a whole since we don't know anything about its possible
363 // contents (see issue i90291).
365 if (nType
== ControlType::WindowBackground
)
367 CGRect aRect
= {{0, 0}, {0, 0}};
368 if (mrShared
.mxClipPath
)
369 aRect
= CGPathGetBoundingBox(mrShared
.mxClipPath
);
370 if (aRect
.size
.width
!= 0 && aRect
.size
.height
!= 0)
371 buttonRect
.Intersection(tools::Rectangle(Point(static_cast<tools::Long
>(aRect
.origin
.x
),
372 static_cast<tools::Long
>(aRect
.origin
.y
)),
373 Size(static_cast<tools::Long
>(aRect
.size
.width
),
374 static_cast<tools::Long
>(aRect
.size
.height
))));
376 mrShared
.refreshRect(buttonRect
.Left(), buttonRect
.Top(), buttonRect
.GetWidth(), buttonRect
.GetHeight());
380 static void drawBox(CGContextRef context
, const NSRect
& rc
, NSColor
* pColor
)
382 CGContextSaveGState(context
);
383 CGContextTranslateCTM(context
, rc
.origin
.x
, rc
.origin
.y
+ rc
.size
.height
);
384 CGContextScaleCTM(context
, 1, -1);
386 NSGraphicsContext
* graphicsContext
= [NSGraphicsContext graphicsContextWithCGContext
:context flipped
:NO
];
388 NSRect rect
= { NSZeroPoint
, NSMakeSize(rc
.size
.width
, rc
.size
.height
) };
389 NSBox
* pBox
= [[NSBox alloc
] initWithFrame
: rect
];
391 [pBox setBoxType
: NSBoxCustom
];
392 [pBox setFillColor
: pColor
];
393 SAL_WNODEPRECATED_DECLARATIONS_PUSH
// setBorderType first deprecated in macOS 10.15
394 [pBox setBorderType
: NSNoBorder
];
395 SAL_WNODEPRECATED_DECLARATIONS_POP
397 [pBox displayRectIgnoringOpacity
: rect inContext
: graphicsContext
];
401 CGContextRestoreGState(context
);
404 // if I don't crystallize this bg then the InvertCursor using kCGBlendModeDifference doesn't
405 // work correctly and the cursor doesn't appear correctly
406 static void drawEditableBackground(CGContextRef context
, const NSRect
& rc
)
408 CGContextSaveGState(context
);
409 CGContextSetFillColorWithColor(context
, [NSColor controlBackgroundColor
].CGColor
);
410 CGContextFillRect(context
, rc
);
411 CGContextRestoreGState(context
);
414 // As seen in macOS 12.3.1. All a bit odd really.
415 const int RoundedMargin
[4] = { 6, 4, 0, 3 };
417 bool AquaGraphicsBackendBase::performDrawNativeControl(ControlType nType
,
419 const tools::Rectangle
&rControlRegion
,
421 const ImplControlValue
&aValue
,
422 CGContextRef context
,
423 AquaSalFrame
* mpFrame
)
426 AquaSalInstance
* pInst
= GetSalData()->mpInstance
;
427 HIRect rc
= ImplGetHIRectFromRectangle(rControlRegion
);
430 case ControlType::Toolbar
:
432 drawBox(context
, rc
, NSColor
.windowBackgroundColor
);
436 case ControlType::WindowBackground
:
438 drawBox(context
, rc
, NSColor
.windowBackgroundColor
);
442 case ControlType::Tooltip
:
446 drawBox(context
, rc
, NSColor
.controlBackgroundColor
);
450 case ControlType::Menubar
:
451 case ControlType::MenuPopup
:
452 if (nPart
== ControlPart::Entire
|| nPart
== ControlPart::MenuItem
|| nPart
== ControlPart::HasBackgroundTexture
)
454 // FIXME: without this magical offset there is a 2 pixel black border on the right
457 HIThemeMenuDrawInfo aMenuInfo
;
458 aMenuInfo
.version
= 0;
459 aMenuInfo
.menuType
= kThemeMenuTypePullDown
;
460 HIThemeMenuItemDrawInfo aMenuItemDrawInfo
;
462 // grey theme when the item is selected is drawn here.
464 aMenuItemDrawInfo
.itemType
= kThemeMenuItemPlain
;
465 if ((nPart
== ControlPart::MenuItem
) && (nState
& ControlState::SELECTED
))
467 // blue theme when the item is selected is drawn here.
469 aMenuItemDrawInfo
.state
= kThemeMenuSelected
;
472 // normal color for non selected item
474 aMenuItemDrawInfo
.state
= kThemeMenuActive
;
476 // repaints the background of the pull down menu
478 HIThemeDrawMenuBackground(&rc
, &aMenuInfo
, context
, kHIThemeOrientationNormal
);
480 // repaints the item either blue (selected) and/or grey (active only)
482 HIThemeDrawMenuItem(&rc
, &rc
, &aMenuItemDrawInfo
, context
, kHIThemeOrientationNormal
, &rc
);
485 else if (nPart
== ControlPart::MenuItemCheckMark
|| nPart
== ControlPart::MenuItemRadioMark
)
487 // checked, else it is not displayed (see vcl/source/window/menu.cxx)
489 if (nState
& ControlState::PRESSED
)
491 HIThemeTextInfo aTextInfo
;
492 aTextInfo
.version
= 0;
493 aTextInfo
.state
= (nState
& ControlState::ENABLED
) ? kThemeStateInactive
: kThemeStateActive
;
494 aTextInfo
.fontID
= kThemeMenuItemMarkFont
;
495 aTextInfo
.horizontalFlushness
= kHIThemeTextHorizontalFlushCenter
;
496 aTextInfo
.verticalFlushness
= kHIThemeTextVerticalFlushTop
;
497 aTextInfo
.options
= kHIThemeTextBoxOptionNone
;
498 aTextInfo
.truncationPosition
= kHIThemeTextTruncationNone
;
500 // aTextInfo.truncationMaxLines unused because of kHIThemeTextTruncationNone item highlighted
502 if (nState
& ControlState::SELECTED
) aTextInfo
.state
= kThemeStatePressed
;
503 UniChar mark
=(nPart
== ControlPart::MenuItemCheckMark
) ? kCheckUnicode
: kBulletUnicode
;
504 CFStringRef cfString
= CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault
, &mark
, 1, kCFAllocatorNull
);
505 HIThemeDrawTextBox(cfString
, &rc
, &aTextInfo
, context
, kHIThemeOrientationNormal
);
512 case ControlType::Pushbutton
:
514 NSControlSize eSizeKind
= NSControlSizeRegular
;
515 NSBezelStyle eBezelStyle
= NSBezelStyleRounded
;
517 PushButtonValue
const *pPBVal
= aValue
.getType() == ControlType::Pushbutton
?
518 static_cast<PushButtonValue
const *>(&aValue
) : nullptr;
520 SInt32 nPaintHeight
= rc
.size
.height
;
521 if (rc
.size
.height
<= PUSH_BUTTON_NORMAL_HEIGHT
)
523 eSizeKind
= NSControlSizeMini
;
524 GetThemeMetric(kThemeMetricSmallPushButtonHeight
, &nPaintHeight
);
526 else if ((pPBVal
&& pPBVal
->mbSingleLine
) || rc
.size
.height
< PUSH_BUTTON_NORMAL_HEIGHT
* 3 / 2)
528 GetThemeMetric(kThemeMetricPushButtonHeight
, &nPaintHeight
);
532 // A simple square bezel style that can scale to any size
533 eBezelStyle
= NSBezelStyleSmallSquare
;
536 // translate the origin for controls with fixed paint height so content ends up somewhere sensible
537 rc
.origin
.y
+= (rc
.size
.height
- nPaintHeight
+ 1) / 2;
538 rc
.size
.height
= nPaintHeight
;
540 NSButtonCell
* pBtn
= pInst
->mpButtonCell
;
541 pBtn
.allowsMixedState
= YES
;
543 [pBtn setTitle
: @
""];
544 [pBtn setButtonType
: NSButtonTypeMomentaryPushIn
];
545 [pBtn setBezelStyle
: eBezelStyle
];
546 [pBtn setState
: ImplGetButtonValue(aValue
.getTristateVal())];
547 [pBtn setEnabled
: getEnabled(nState
, mpFrame
)];
548 [pBtn setFocusRingType
: NSFocusRingTypeExterior
];
549 [pBtn setHighlighted
: (nState
& ControlState::PRESSED
) ? YES
: NO
];
550 [pBtn setControlSize
: eSizeKind
];
551 if (nState
& ControlState::DEFAULT
)
552 [pBtn setKeyEquivalent
: @
"\r"];
554 [pBtn setKeyEquivalent
: @
""];
556 if (eBezelStyle
== NSBezelStyleRounded
)
558 int nMargin
= RoundedMargin
[eSizeKind
];
559 rc
.origin
.x
-= nMargin
;
560 rc
.size
.width
+= nMargin
* 2;
562 rc
.origin
.x
+= FOCUS_RING_WIDTH
/ 2;
563 rc
.size
.width
-= FOCUS_RING_WIDTH
;
566 const bool bFocused(nState
& ControlState::FOCUSED
);
567 paintCell(pBtn
, rc
, bFocused
, context
, nullptr);
572 case ControlType::Radiobutton
:
573 case ControlType::Checkbox
:
575 rc
.size
.width
-= 2 * FOCUS_RING_WIDTH
;
576 rc
.size
.height
= RADIO_BUTTON_SMALL_SIZE
;
577 rc
.origin
.x
+= FOCUS_RING_WIDTH
;
578 rc
.origin
.y
+= FOCUS_RING_WIDTH
;
580 NSButtonCell
* pBtn
= nType
== ControlType::Checkbox
? pInst
->mpCheckCell
: pInst
->mpRadioCell
;
581 pBtn
.allowsMixedState
= YES
;
583 [pBtn setTitle
: @
""];
584 [pBtn setButtonType
: nType
== ControlType::Checkbox
? NSButtonTypeSwitch
: NSButtonTypeRadio
];
585 [pBtn setState
: ImplGetButtonValue(aValue
.getTristateVal())];
586 [pBtn setEnabled
: getEnabled(nState
, mpFrame
)];
587 [pBtn setFocusRingType
: NSFocusRingTypeExterior
];
588 [pBtn setHighlighted
: (nState
& ControlState::PRESSED
) ? YES
: NO
];
590 const bool bFocused(nState
& ControlState::FOCUSED
);
591 paintCell(pBtn
, rc
, bFocused
, context
, nullptr);
596 case ControlType::ListNode
:
598 NSButtonCell
* pBtn
= pInst
->mpListNodeCell
;
599 pBtn
.allowsMixedState
= YES
;
601 [pBtn setTitle
: @
""];
602 [pBtn setButtonType
: NSButtonTypeOnOff
];
603 [pBtn setBezelStyle
: NSBezelStyleDisclosure
];
604 [pBtn setState
: ImplGetButtonValue(aValue
.getTristateVal())];
605 [pBtn setEnabled
: getEnabled(nState
, mpFrame
)];
606 [pBtn setFocusRingType
: NSFocusRingTypeExterior
];
608 const bool bFocused(nState
& ControlState::FOCUSED
);
609 paintCell(pBtn
, rc
, bFocused
, context
, nullptr);
614 case ControlType::Progress
:
615 case ControlType::IntroProgress
:
617 NSRect rect
= { NSZeroPoint
, NSMakeSize(rc
.size
.width
, rc
.size
.height
) };
618 NSProgressIndicator
* pBox
= [[NSProgressIndicator alloc
] initWithFrame
: rect
];
619 [pBox setControlSize
: (rc
.size
.height
> MEDIUM_PROGRESS_INDICATOR_HEIGHT
) ?
620 NSControlSizeRegular
: NSControlSizeSmall
];
621 [pBox setMinValue
: 0];
622 [pBox setMaxValue
: rc
.size
.width
];
623 [pBox setDoubleValue
: aValue
.getNumericVal()];
624 pBox
.usesThreadedAnimation
= NO
;
625 [pBox setIndeterminate
: NO
];
627 CGContextSaveGState(context
);
628 CGContextTranslateCTM(context
, rc
.origin
.x
, rc
.origin
.y
);
630 NSGraphicsContext
* savedContext
= [NSGraphicsContext currentContext
];
631 NSGraphicsContext
* graphicsContext
= [NSGraphicsContext graphicsContextWithCGContext
:context flipped
:NO
];
632 [NSGraphicsContext setCurrentContext
: graphicsContext
];
634 [pBox drawRect
: rect
];
636 [NSGraphicsContext setCurrentContext
: savedContext
];
638 CGContextRestoreGState(context
);
645 case ControlType::Slider
:
647 const SliderValue
*pSliderVal
= static_cast<SliderValue
const *>(&aValue
);
648 if (nPart
== ControlPart::TrackHorzArea
|| nPart
== ControlPart::TrackVertArea
)
650 NSRect rect
= { NSZeroPoint
, NSMakeSize(rc
.size
.width
, rc
.size
.height
) };
651 NSSlider
* pBox
= [[NSSlider alloc
] initWithFrame
: rect
];
653 [pBox setEnabled
: getEnabled(nState
, mpFrame
)];
654 [pBox setVertical
: nPart
== ControlPart::TrackVertArea
];
655 [pBox setMinValue
: pSliderVal
->mnMin
];
656 [pBox setMaxValue
: pSliderVal
->mnMax
];
657 [pBox setIntegerValue
: pSliderVal
->mnCur
];
658 [pBox setSliderType
: NSSliderTypeLinear
];
659 [pBox setFocusRingType
: NSFocusRingTypeExterior
];
661 const bool bFocused(nState
& ControlState::FOCUSED
);
662 paintCell(pBox
.cell
, rc
, bFocused
, context
, mpFrame
->getNSView());
670 case ControlType::Scrollbar
:
672 const ScrollbarValue
*pScrollbarVal
= (aValue
.getType() == ControlType::Scrollbar
)
673 ? static_cast<const ScrollbarValue
*>(&aValue
) : nullptr;
674 if (nPart
== ControlPart::DrawBackgroundVert
|| nPart
== ControlPart::DrawBackgroundHorz
)
676 drawBox(context
, rc
, NSColor
.controlBackgroundColor
);
678 NSRect rect
= { NSZeroPoint
, NSMakeSize(rc
.size
.width
, rc
.size
.height
) };
679 NSScroller
* pBar
= [[NSScroller alloc
] initWithFrame
: rect
];
681 double range
= pScrollbarVal
->mnMax
- pScrollbarVal
->mnVisibleSize
- pScrollbarVal
->mnMin
;
682 double value
= range
? (pScrollbarVal
->mnCur
- pScrollbarVal
->mnMin
) / range
: 0;
684 double length
= pScrollbarVal
->mnMax
- pScrollbarVal
->mnMin
;
685 double proportion
= pScrollbarVal
->mnVisibleSize
/ length
;
687 [pBar setEnabled
: getEnabled(nState
, mpFrame
)];
688 [pBar setScrollerStyle
: NSScrollerStyleLegacy
];
689 [pBar setFloatValue
: value
];
690 [pBar setKnobProportion
: proportion
];
691 bool bPressed
= (pScrollbarVal
->mnThumbState
& ControlState::ENABLED
) &&
692 (pScrollbarVal
->mnThumbState
& ControlState::PRESSED
);
694 CGContextSaveGState(context
);
695 CGContextTranslateCTM(context
, rc
.origin
.x
, rc
.origin
.y
);
697 NSGraphicsContext
* graphicsContext
= [NSGraphicsContext graphicsContextWithCGContext
:context flipped
:NO
];
699 NSGraphicsContext
* savedContext
= [NSGraphicsContext currentContext
];
700 [NSGraphicsContext setCurrentContext
: graphicsContext
];
702 // For not-pressed first draw without the knob and then
703 // draw just the knob but with 50% opaque which looks sort of
706 [pBar drawKnobSlotInRect
: rect highlight
: NO
];
708 NSBitmapImageRep
* pImageRep
= [pBar bitmapImageRepForCachingDisplayInRect
: rect
];
710 NSGraphicsContext
* imageContext
= [NSGraphicsContext graphicsContextWithBitmapImageRep
:pImageRep
];
711 [NSGraphicsContext setCurrentContext
: imageContext
];
715 [NSGraphicsContext setCurrentContext
: graphicsContext
];
717 NSImage
* pImage
= [[NSImage alloc
] initWithSize
: rect
.size
];
718 [pImage addRepresentation
: pImageRep
]; // takes ownership of pImageRep
720 [pImage drawInRect
: rect fromRect
: rect
721 operation
: NSCompositingOperationSourceOver
722 fraction
: bPressed
? 1.0 : 0.5];
726 [NSGraphicsContext setCurrentContext
:savedContext
];
728 CGContextRestoreGState(context
);
736 case ControlType::TabPane
:
738 NSTabView
* pBox
= [[NSTabView alloc
] initWithFrame
: rc
];
741 GetThemeMetric(kThemeMetricTabFrameOverlap
, &nOverlap
);
743 // this calculation is probably more than a little dubious
744 rc
.origin
.x
-= pBox
.contentRect
.origin
.x
- FOCUS_RING_WIDTH
;
745 rc
.size
.width
+= rc
.size
.width
- pBox
.contentRect
.size
.width
- 2 * FOCUS_RING_WIDTH
;
746 double nTopBorder
= pBox
.contentRect
.origin
.y
;
747 double nBottomBorder
= rc
.size
.height
- pBox
.contentRect
.size
.height
- nTopBorder
;
748 double nExtraTop
= (nTopBorder
- nBottomBorder
) / 2;
749 rc
.origin
.y
-= (nTopBorder
- nExtraTop
+ nOverlap
);
750 rc
.size
.height
+= (nTopBorder
- nExtraTop
+ nBottomBorder
);
752 CGContextSaveGState(context
);
753 CGContextTranslateCTM(context
, rc
.origin
.x
, rc
.origin
.y
);
758 [pBox setBoundsOrigin
: rc
.origin
];
759 [pBox setBoundsSize
: rc
.size
];
761 // jam this in to force the tab contents area to be left undrawn, the ControlType::TabItem
762 // will be drawn in this space.
763 const TabPaneValue
& rValue
= static_cast<const TabPaneValue
&>(aValue
);
765 GetThemeMetric(kThemeMetricLargeTabCapsWidth
, &nEndCapWidth
);
766 FixedWidthTabViewItem
* pItem
= [[[FixedWidthTabViewItem alloc
] initWithIdentifier
: @
"tab"] autorelease
];
767 [pItem setTabWidth
: rValue
.m_aTabHeaderRect
.GetWidth() - 2 * nEndCapWidth
];
768 [pBox addTabViewItem
: pItem
];
770 NSGraphicsContext
* graphicsContext
= [NSGraphicsContext graphicsContextWithCGContext
:context flipped
:NO
];
772 NSGraphicsContext
* savedContext
= [NSGraphicsContext currentContext
];
773 [NSGraphicsContext setCurrentContext
: graphicsContext
];
777 [NSGraphicsContext setCurrentContext
: savedContext
];
781 CGContextRestoreGState(context
);
786 case ControlType::TabItem
:
788 // first, last or middle tab
790 TabitemValue
const * pTabValue
= static_cast<TabitemValue
const *>(&aValue
);
791 TabitemFlags nAlignment
= pTabValue
->mnAlignment
;
793 // TabitemFlags::LeftAligned (and TabitemFlags::RightAligned) for the leftmost (or rightmost) tab
794 // when there are several lines of tabs because there is only one first tab and one
795 // last tab and TabitemFlags::FirstInGroup (and TabitemFlags::LastInGroup) because when the
796 // line width is different from window width, there may not be TabitemFlags::RightAligned
799 if (((nAlignment
& TabitemFlags::LeftAligned
) && (nAlignment
& TabitemFlags::RightAligned
))
800 || ((nAlignment
& TabitemFlags::FirstInGroup
) && (nAlignment
& TabitemFlags::LastInGroup
)))
805 else if ((nAlignment
& TabitemFlags::LeftAligned
) || (nAlignment
& TabitemFlags::FirstInGroup
))
806 nPaintIndex
= !AllSettings::GetLayoutRTL() ? 0 : 2;
807 else if ((nAlignment
& TabitemFlags::RightAligned
) || (nAlignment
& TabitemFlags::LastInGroup
))
808 nPaintIndex
= !AllSettings::GetLayoutRTL() ? 2 : 0;
810 int nCells
= !bSolo
? 3 : 1;
811 NSRect ctrlrect
= { NSZeroPoint
, NSMakeSize(rc
.size
.width
* nCells
+ FOCUS_RING_WIDTH
, rc
.size
.height
) };
812 NSSegmentedControl
* pCtrl
= [[NSSegmentedControl alloc
] initWithFrame
: ctrlrect
];
813 [pCtrl setSegmentCount
: nCells
];
815 [pCtrl setWidth
: rc
.size
.width
+ FOCUS_RING_WIDTH forSegment
: 0];
818 [pCtrl setWidth
: rc
.size
.width
+ FOCUS_RING_WIDTH
/2 forSegment
: 0];
819 [pCtrl setWidth
: rc
.size
.width forSegment
: 1];
820 [pCtrl setWidth
: rc
.size
.width
+ FOCUS_RING_WIDTH
/2 forSegment
: 2];
822 [pCtrl setSelected
: (nState
& ControlState::SELECTED
) ? YES
: NO forSegment
: nPaintIndex
];
823 [pCtrl setFocusRingType
: NSFocusRingTypeExterior
];
825 NSGraphicsContext
* savedContext
= [NSGraphicsContext currentContext
];
826 [NSGraphicsContext setCurrentContext
:[NSGraphicsContext graphicsContextWithCGContext
:context flipped
:NO
]];
828 NSRect rect
= { NSZeroPoint
, NSMakeSize(rc
.size
.width
, rc
.size
.height
) };
829 NSRect tabrect
= { NSMakePoint(rc
.size
.width
* nPaintIndex
+ FOCUS_RING_WIDTH
/ 2, 0),
830 NSMakeSize(rc
.size
.width
, rc
.size
.height
) };
831 NSBitmapImageRep
* pImageRep
= [pCtrl bitmapImageRepForCachingDisplayInRect
: tabrect
];
832 [pCtrl cacheDisplayInRect
: tabrect toBitmapImageRep
: pImageRep
];
834 NSImage
* pImage
= [[NSImage alloc
] initWithSize
: rect
.size
];
835 [pImage addRepresentation
: pImageRep
]; // takes ownership of pImageRep
837 [pImage drawInRect
: rc fromRect
: rect
838 operation
: NSCompositingOperationSourceOver
843 [NSGraphicsContext setCurrentContext
:savedContext
];
847 if (nState
& ControlState::FOCUSED
)
851 if (nPaintIndex
== 0)
853 rc
.origin
.x
+= FOCUS_RING_WIDTH
/ 2;
854 rc
.size
.width
-= FOCUS_RING_WIDTH
/ 2;
856 else if (nPaintIndex
== 2)
858 rc
.size
.width
-= FOCUS_RING_WIDTH
/ 2;
859 rc
.size
.width
-= FOCUS_RING_WIDTH
/ 2;
863 paintFocusRect(4.0, rc
, context
);
868 case ControlType::Editbox
:
869 case ControlType::MultilineEditbox
:
871 rc
.size
.width
+= 2 * EDITBOX_INSET_MARGIN
;
872 if (nType
== ControlType::Editbox
)
873 rc
.size
.height
= EDITBOX_HEIGHT
;
875 rc
.size
.height
+= 2 * (EDITBOX_BORDER_WIDTH
+ EDITBOX_INSET_MARGIN
);
876 rc
.origin
.x
-= EDITBOX_INSET_MARGIN
;
877 rc
.origin
.y
-= EDITBOX_INSET_MARGIN
;
879 NSTextFieldCell
* pBtn
= pInst
->mpTextFieldCell
;
881 [pBtn setEnabled
: getEnabled(nState
, mpFrame
)];
882 [pBtn setBezeled
: YES
];
883 [pBtn setEditable
: YES
];
884 [pBtn setFocusRingType
: NSFocusRingTypeExterior
];
886 drawEditableBackground(context
, rc
);
887 const bool bFocused(nState
& ControlState::FOCUSED
);
888 paintCell(pBtn
, rc
, bFocused
, context
, mpFrame
->getNSView());
893 case ControlType::Combobox
:
894 if (nPart
== ControlPart::HasBackgroundTexture
|| nPart
== ControlPart::Entire
)
896 rc
.origin
.y
+= (rc
.size
.height
- COMBOBOX_HEIGHT
+ 1) / 2;
897 rc
.size
.height
= COMBOBOX_HEIGHT
;
899 NSComboBoxCell
* pBtn
= pInst
->mpComboBoxCell
;
901 [pBtn setEnabled
: getEnabled(nState
, mpFrame
)];
902 [pBtn setEditable
: YES
];
903 [pBtn setState
: ImplGetButtonValue(aValue
.getTristateVal())];
904 [pBtn setFocusRingType
: NSFocusRingTypeExterior
];
911 drawEditableBackground(context
, rc
);
912 const bool bFocused(nState
& ControlState::FOCUSED
);
913 paintCell(pBtn
, rc
, bFocused
, context
, mpFrame
->getNSView());
918 case ControlType::Listbox
:
922 case ControlPart::Entire
:
923 case ControlPart::ButtonDown
:
925 rc
.origin
.y
+= (rc
.size
.height
- LISTBOX_HEIGHT
+ 1) / 2;
926 rc
.size
.height
= LISTBOX_HEIGHT
;
928 NSPopUpButtonCell
* pBtn
= pInst
->mpPopUpButtonCell
;
930 [pBtn setTitle
: @
""];
931 [pBtn setEnabled
: getEnabled(nState
, mpFrame
)];
932 [pBtn setFocusRingType
: NSFocusRingTypeExterior
];
933 [pBtn setHighlighted
: (nState
& ControlState::PRESSED
) ? YES
: NO
];
934 if (nState
& ControlState::DEFAULT
)
935 [pBtn setKeyEquivalent
: @
"\r"];
937 [pBtn setKeyEquivalent
: @
""];
943 const bool bFocused(nState
& ControlState::FOCUSED
);
944 paintCell(pBtn
, rc
, bFocused
, context
, nullptr);
949 case ControlPart::ListboxWindow
:
951 NSRect rect
= { NSZeroPoint
, NSMakeSize(rc
.size
.width
, rc
.size
.height
) };
952 NSScrollView
* pBox
= [[NSScrollView alloc
] initWithFrame
: rect
];
953 [pBox setBorderType
: NSLineBorder
];
955 CGContextSaveGState(context
);
956 CGContextTranslateCTM(context
, rc
.origin
.x
, rc
.origin
.y
);
958 NSGraphicsContext
* savedContext
= [NSGraphicsContext currentContext
];
959 NSGraphicsContext
* graphicsContext
= [NSGraphicsContext graphicsContextWithCGContext
:context flipped
:NO
];
960 [NSGraphicsContext setCurrentContext
: graphicsContext
];
962 [pBox drawRect
: rect
];
964 [NSGraphicsContext setCurrentContext
: savedContext
];
966 CGContextRestoreGState(context
);
977 case ControlType::Spinbox
:
978 if (nPart
== ControlPart::Entire
)
982 rc
.size
.width
-= SPIN_BUTTON_WIDTH
+ 4 * FOCUS_RING_WIDTH
;
983 rc
.size
.height
= EDITBOX_HEIGHT
;
984 rc
.origin
.x
+= FOCUS_RING_WIDTH
;
985 rc
.origin
.y
+= FOCUS_RING_WIDTH
;
987 NSTextFieldCell
* pEdit
= pInst
->mpTextFieldCell
;
989 [pEdit setEnabled
: YES
];
990 [pEdit setBezeled
: YES
];
991 [pEdit setEditable
: YES
];
992 [pEdit setFocusRingType
: NSFocusRingTypeExterior
];
994 drawEditableBackground(context
, rc
);
995 const bool bFocused(nState
& ControlState::FOCUSED
);
996 paintCell(pEdit
, rc
, bFocused
, context
, mpFrame
->getNSView());
1000 const SpinbuttonValue
*pSpinButtonVal
= (aValue
.getType() == ControlType::SpinButtons
)
1001 ? static_cast <const SpinbuttonValue
*>(&aValue
) : nullptr;
1004 ControlState nUpperState
= pSpinButtonVal
->mnUpperState
;
1005 ControlState nLowerState
= pSpinButtonVal
->mnLowerState
;
1007 rc
.origin
.x
+= rc
.size
.width
+ FOCUS_RING_WIDTH
+ 1;
1009 rc
.size
.width
= SPIN_BUTTON_WIDTH
;
1010 rc
.size
.height
= SPIN_LOWER_BUTTON_HEIGHT
+ SPIN_LOWER_BUTTON_HEIGHT
;
1012 NSStepperCell
* pBtn
= pInst
->mpStepperCell
;
1014 [pBtn setTitle
: @
""];
1015 [pBtn setState
: ImplGetButtonValue(aValue
.getTristateVal())];
1016 [pBtn setEnabled
: (nUpperState
& ControlState::ENABLED
|| nLowerState
& ControlState::ENABLED
) ?
1018 [pBtn setFocusRingType
: NSFocusRingTypeExterior
];
1019 [pBtn setHighlighted
: (nState
& ControlState::PRESSED
) ? YES
: NO
];
1021 const bool bSpinFocused(nUpperState
& ControlState::FOCUSED
|| nLowerState
& ControlState::FOCUSED
);
1022 paintCell(pBtn
, rc
, bSpinFocused
, context
, nullptr);
1027 case ControlType::Frame
:
1029 DrawFrameFlags nStyle
= static_cast<DrawFrameFlags
>(aValue
.getNumericVal());
1030 if (nPart
== ControlPart::Border
)
1032 if (!(nStyle
& DrawFrameFlags::Menu
) && !(nStyle
& DrawFrameFlags::WindowBorder
))
1035 // strange effects start to happen when HIThemeDrawFrame meets the border of the window.
1036 // These can be avoided by clipping to the boundary of the frame (see issue 84756)
1038 if (rc
.origin
.y
+ rc
.size
.height
>= mpFrame
->maGeometry
.height() - 3)
1040 CGMutablePathRef rPath
= CGPathCreateMutable();
1041 CGPathAddRect(rPath
, nullptr,
1042 CGRectMake(0, 0, mpFrame
->maGeometry
.width() - 1, mpFrame
->maGeometry
.height() - 1));
1043 CGContextBeginPath(context
);
1044 CGContextAddPath(context
, rPath
);
1045 CGContextClip(context
);
1046 CGPathRelease(rPath
);
1048 HIThemeFrameDrawInfo aTextDrawInfo
;
1049 aTextDrawInfo
.version
= 0;
1050 aTextDrawInfo
.kind
= kHIThemeFrameListBox
;
1051 aTextDrawInfo
.state
= kThemeStateActive
;
1052 aTextDrawInfo
.isFocused
= false;
1053 HIThemeDrawFrame(&rc
, &aTextDrawInfo
, context
, kHIThemeOrientationNormal
);
1059 case ControlType::ListNet
:
1061 // do nothing as there isn't net for listviews on macOS
1072 bool AquaSalGraphics::getNativeControlRegion(ControlType nType
,
1074 const tools::Rectangle
&rControlRegion
,
1076 const ImplControlValue
&aValue
,
1078 tools::Rectangle
&rNativeBoundingRegion
,
1079 tools::Rectangle
&rNativeContentRegion
)
1081 bool toReturn
= false;
1082 tools::Rectangle
aCtrlBoundRect(rControlRegion
);
1083 short x
= aCtrlBoundRect
.Left();
1084 short y
= aCtrlBoundRect
.Top();
1088 case ControlType::Pushbutton
:
1089 case ControlType::Radiobutton
:
1090 case ControlType::Checkbox
:
1092 if (nType
== ControlType::Pushbutton
)
1094 w
= aCtrlBoundRect
.GetWidth();
1095 h
= aCtrlBoundRect
.GetHeight();
1099 w
= RADIO_BUTTON_SMALL_SIZE
+ 2 * FOCUS_RING_WIDTH
+ RADIO_BUTTON_TEXT_SEPARATOR
;
1100 h
= RADIO_BUTTON_SMALL_SIZE
+ 2 * FOCUS_RING_WIDTH
;
1102 rNativeContentRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1103 rNativeBoundingRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1107 case ControlType::Progress
:
1109 tools::Rectangle
aRect(aCtrlBoundRect
);
1110 if (aRect
.GetHeight() < LARGE_PROGRESS_INDICATOR_HEIGHT
)
1111 aRect
.SetBottom(aRect
.Top() + MEDIUM_PROGRESS_INDICATOR_HEIGHT
- 1);
1113 aRect
.SetBottom(aRect
.Top() + LARGE_PROGRESS_INDICATOR_HEIGHT
- 1);
1114 rNativeBoundingRegion
= aRect
;
1115 rNativeContentRegion
= aRect
;
1119 case ControlType::IntroProgress
:
1121 tools::Rectangle
aRect(aCtrlBoundRect
);
1122 aRect
.SetBottom(aRect
.Top() + MEDIUM_PROGRESS_INDICATOR_HEIGHT
- 1);
1123 rNativeBoundingRegion
= aRect
;
1124 rNativeContentRegion
= aRect
;
1128 case ControlType::Slider
:
1129 if (nPart
== ControlPart::ThumbHorz
)
1132 h
= aCtrlBoundRect
.GetHeight();
1133 rNativeBoundingRegion
= rNativeContentRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1136 else if (nPart
== ControlPart::ThumbVert
)
1138 w
= aCtrlBoundRect
.GetWidth();
1140 rNativeBoundingRegion
= rNativeContentRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1144 case ControlType::Scrollbar
:
1146 tools::Rectangle aRect
;
1147 if (AquaGetScrollRect(nPart
, aCtrlBoundRect
, aRect
))
1150 rNativeBoundingRegion
= aRect
;
1151 rNativeContentRegion
= aRect
;
1155 case ControlType::TabItem
:
1157 w
= aCtrlBoundRect
.GetWidth() + 2 * TAB_TEXT_MARGIN
;
1159 rNativeContentRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1160 rNativeBoundingRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1164 case ControlType::Editbox
:
1166 const tools::Long nBorderThickness
= FOCUS_RING_WIDTH
+ EDITBOX_BORDER_WIDTH
+ EDITBOX_INSET_MARGIN
;
1167 // tdf#144241 don't return a negative width, expand the region to the min osx width
1168 w
= std::max(nBorderThickness
* 2, aCtrlBoundRect
.GetWidth());
1169 h
= EDITBOX_HEIGHT
+ 2 * FOCUS_RING_WIDTH
;
1170 rNativeBoundingRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1171 w
-= 2 * nBorderThickness
;
1172 h
-= 2 * nBorderThickness
;
1173 x
+= nBorderThickness
;
1174 y
+= nBorderThickness
;
1175 rNativeContentRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1179 case ControlType::Combobox
:
1180 if (nPart
== ControlPart::Entire
)
1182 w
= aCtrlBoundRect
.GetWidth();
1183 h
= COMBOBOX_HEIGHT
+ 2 * FOCUS_RING_WIDTH
;
1184 rNativeBoundingRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1185 rNativeContentRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1188 else if (nPart
== ControlPart::ButtonDown
)
1190 w
= COMBOBOX_BUTTON_WIDTH
+ FOCUS_RING_WIDTH
;
1191 h
= COMBOBOX_HEIGHT
+ 2 * FOCUS_RING_WIDTH
;
1192 x
+= aCtrlBoundRect
.GetWidth() - w
;
1193 rNativeBoundingRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1194 rNativeContentRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1197 else if (nPart
== ControlPart::SubEdit
)
1199 w
= aCtrlBoundRect
.GetWidth() - 2 * FOCUS_RING_WIDTH
- COMBOBOX_BUTTON_WIDTH
- COMBOBOX_BORDER_WIDTH
1200 - 2 * COMBOBOX_TEXT_MARGIN
;
1201 h
= COMBOBOX_HEIGHT
- 2 * COMBOBOX_BORDER_WIDTH
;
1202 x
+= FOCUS_RING_WIDTH
+ COMBOBOX_BORDER_WIDTH
+ COMBOBOX_TEXT_MARGIN
;
1203 y
+= FOCUS_RING_WIDTH
+ COMBOBOX_BORDER_WIDTH
;
1204 rNativeBoundingRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1205 rNativeContentRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1209 case ControlType::Listbox
:
1210 if (nPart
== ControlPart::Entire
)
1212 w
= aCtrlBoundRect
.GetWidth();
1213 h
= LISTBOX_HEIGHT
+ 2 * FOCUS_RING_WIDTH
;
1214 rNativeBoundingRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1215 rNativeContentRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1218 else if (nPart
== ControlPart::ButtonDown
)
1220 w
= LISTBOX_BUTTON_WIDTH
+ FOCUS_RING_WIDTH
;
1221 h
= LISTBOX_HEIGHT
+ 2 * FOCUS_RING_WIDTH
;
1222 x
+= aCtrlBoundRect
.GetWidth() - w
;
1223 rNativeBoundingRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1224 rNativeContentRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1227 else if (nPart
== ControlPart::SubEdit
)
1229 w
= aCtrlBoundRect
.GetWidth() - 2 * FOCUS_RING_WIDTH
- LISTBOX_BUTTON_WIDTH
- LISTBOX_BORDER_WIDTH
1230 - 2 * LISTBOX_TEXT_MARGIN
;
1231 h
= LISTBOX_HEIGHT
- 2 * LISTBOX_BORDER_WIDTH
;
1232 x
+= FOCUS_RING_WIDTH
+ LISTBOX_BORDER_WIDTH
+ LISTBOX_TEXT_MARGIN
;
1233 y
+= FOCUS_RING_WIDTH
+ LISTBOX_BORDER_WIDTH
;
1234 rNativeBoundingRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1235 rNativeContentRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1238 else if (nPart
== ControlPart::ListboxWindow
)
1240 w
= aCtrlBoundRect
.GetWidth() - 2;
1241 h
= aCtrlBoundRect
.GetHeight() - 2;
1244 rNativeBoundingRegion
= aCtrlBoundRect
;
1245 rNativeContentRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1249 case ControlType::Spinbox
:
1250 if (nPart
== ControlPart::Entire
)
1252 w
= aCtrlBoundRect
.GetWidth();
1253 h
= EDITBOX_HEIGHT
+ 2 * FOCUS_RING_WIDTH
;
1254 x
+= SPINBOX_OFFSET
;
1255 rNativeBoundingRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1256 rNativeContentRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1259 else if (nPart
== ControlPart::SubEdit
)
1261 w
= aCtrlBoundRect
.GetWidth() - 4 * FOCUS_RING_WIDTH
- SPIN_BUTTON_WIDTH
- 2 * EDITBOX_BORDER_WIDTH
1262 - 2 * EDITBOX_INSET_MARGIN
;
1263 h
= EDITBOX_HEIGHT
- 2 * (EDITBOX_BORDER_WIDTH
+ EDITBOX_INSET_MARGIN
);
1264 x
+= FOCUS_RING_WIDTH
+ EDITBOX_BORDER_WIDTH
+ EDITBOX_INSET_MARGIN
+ SPINBOX_OFFSET
;
1265 y
+= FOCUS_RING_WIDTH
+ EDITBOX_BORDER_WIDTH
+ EDITBOX_INSET_MARGIN
;
1266 rNativeBoundingRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1267 rNativeContentRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1270 else if (nPart
== ControlPart::ButtonUp
)
1272 w
= SPIN_BUTTON_WIDTH
+ 2 * FOCUS_RING_WIDTH
;
1273 h
= SPIN_UPPER_BUTTON_HEIGHT
+ FOCUS_RING_WIDTH
;
1274 x
+= aCtrlBoundRect
.GetWidth() - SPIN_BUTTON_WIDTH
- 2 * FOCUS_RING_WIDTH
+ SPINBOX_OFFSET
;
1275 rNativeBoundingRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1276 rNativeContentRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1279 else if (nPart
== ControlPart::ButtonDown
)
1281 w
= SPIN_BUTTON_WIDTH
+ 2 * FOCUS_RING_WIDTH
;
1282 h
= SPIN_LOWER_BUTTON_HEIGHT
+ FOCUS_RING_WIDTH
;
1283 x
+= aCtrlBoundRect
.GetWidth() - SPIN_BUTTON_WIDTH
- 2 * FOCUS_RING_WIDTH
+ SPINBOX_OFFSET
;
1284 y
+= FOCUS_RING_WIDTH
+ SPIN_UPPER_BUTTON_HEIGHT
;
1285 rNativeBoundingRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1286 rNativeContentRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1290 case ControlType::Frame
:
1292 DrawFrameStyle nStyle
= static_cast<DrawFrameStyle
>(aValue
.getNumericVal() & 0x000f);
1293 DrawFrameFlags nFlags
= static_cast<DrawFrameFlags
>(aValue
.getNumericVal() & 0xfff0);
1294 if (nPart
== ControlPart::Border
1295 && !(nFlags
& (DrawFrameFlags::Menu
| DrawFrameFlags::WindowBorder
| DrawFrameFlags::BorderWindowBorder
)))
1297 tools::Rectangle
aRect(aCtrlBoundRect
);
1298 if (nStyle
== DrawFrameStyle::DoubleIn
)
1300 aRect
.AdjustLeft(1);
1302 // rRect.Right() -= 1;
1303 // rRect.Bottom() -= 1;
1307 aRect
.AdjustLeft(1);
1309 aRect
.AdjustRight(-1);
1310 aRect
.AdjustBottom(-1);
1312 rNativeContentRegion
= aRect
;
1313 rNativeBoundingRegion
= aRect
;
1318 case ControlType::Menubar
:
1319 case ControlType::MenuPopup
:
1320 if (nPart
== ControlPart::MenuItemCheckMark
|| nPart
== ControlPart::MenuItemRadioMark
)
1324 rNativeContentRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1325 rNativeBoundingRegion
= tools::Rectangle(Point(x
, y
), Size(w
, h
));
1335 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */