--- a/widget/cocoa/nsNativeThemeCocoa.h
+++ b/widget/cocoa/nsNativeThemeCocoa.h
@@ -74,16 +74,21 @@ public:
eDisclosureButtonOpen
};
enum class SpinButton : uint8_t {
eUp,
eDown
};
+ enum class SegmentType : uint8_t {
+ eToolbarButton,
+ eTab
+ };
+
struct ControlParams {
ControlParams()
: disabled(false)
, insideActiveWindow(false)
, pressed(false)
, focused(false)
, rtl(false)
{}
@@ -135,16 +140,29 @@ public:
};
struct SpinButtonParams {
mozilla::Maybe<SpinButton> pressedButton;
bool disabled = false;
bool insideActiveWindow = false;
};
+ struct SegmentParams {
+ SegmentType segmentType = SegmentType::eToolbarButton;
+ bool insideActiveWindow = false;
+ bool pressed = false;
+ bool selected = false;
+ bool focused = false;
+ bool atLeftEnd = false;
+ bool atRightEnd = false;
+ bool drawsLeftSeparator = false;
+ bool drawsRightSeparator = false;
+ bool rtl = false;
+ };
+
struct TreeHeaderCellParams {
ControlParams controlParams;
TreeSortDirection sortDirection = eTreeSortDirection_Natural;
bool lastTreeHeaderCell = false;
};
nsNativeThemeCocoa();
@@ -201,41 +219,41 @@ public:
static void DrawNativeTitlebar(CGContextRef aContext, CGRect aTitlebarRect,
CGFloat aUnifiedHeight, BOOL aIsMain, BOOL aIsFlipped);
protected:
virtual ~nsNativeThemeCocoa();
nsIntMargin DirectionAwareMargin(const nsIntMargin& aMargin, nsIFrame* aFrame);
nsIFrame* SeparatorResponsibility(nsIFrame* aBefore, nsIFrame* aAfter);
- CGRect SeparatorAdjustedRect(CGRect aRect, nsIFrame* aLeft,
- nsIFrame* aCurrent, nsIFrame* aRight);
bool IsWindowSheet(nsIFrame* aFrame);
ControlParams ComputeControlParams(nsIFrame* aFrame,
mozilla::EventStates aEventState);
MenuBackgroundParams ComputeMenuBackgroundParams(nsIFrame* aFrame,
mozilla::EventStates aEventState);
MenuIconParams ComputeMenuIconParams(nsIFrame* aParams,
mozilla::EventStates aEventState,
MenuIcon aIcon);
MenuItemParams ComputeMenuItemParams(nsIFrame* aFrame,
mozilla::EventStates aEventState,
bool aIsChecked);
+ SegmentParams ComputeSegmentParams(nsIFrame* aFrame,
+ mozilla::EventStates aEventState,
+ SegmentType aSegmentType);
TreeHeaderCellParams ComputeTreeHeaderCellParams(nsIFrame* aFrame,
mozilla::EventStates aEventState);
// HITheme drawing routines
void DrawFrame(CGContextRef context, HIThemeFrameKind inKind,
const HIRect& inBoxRect, bool inReadOnly,
mozilla::EventStates inState);
void DrawMeter(CGContextRef context, const HIRect& inBoxRect,
nsIFrame* aFrame);
void DrawSegment(CGContextRef cgContext, const HIRect& inBoxRect,
- mozilla::EventStates inState, nsIFrame* aFrame,
- const SegmentedControlRenderSettings& aSettings);
+ const SegmentParams& aParams);
void DrawTabPanel(CGContextRef context, const HIRect& inBoxRect, nsIFrame* aFrame);
void DrawScale(CGContextRef context, const HIRect& inBoxRect,
mozilla::EventStates inState, bool inDirection,
bool inIsReverse, int32_t inCurrentValue, int32_t inMinValue,
int32_t inMaxValue, nsIFrame* aFrame);
void DrawCheckboxOrRadio(CGContextRef cgContext, bool inCheckbox,
const HIRect& inBoxRect,
const CheckboxOrRadioParams& aParams);
--- a/widget/cocoa/nsNativeThemeCocoa.mm
+++ b/widget/cocoa/nsNativeThemeCocoa.mm
@@ -2307,30 +2307,30 @@ nsNativeThemeCocoa::SeparatorResponsibil
return nullptr;
if (IsSelectedButton(aAfter))
return aAfter;
if (IsSelectedButton(aBefore) || IsPressedButton(aBefore))
return aBefore;
return aAfter;
}
-CGRect
-nsNativeThemeCocoa::SeparatorAdjustedRect(CGRect aRect, nsIFrame* aLeft,
- nsIFrame* aCurrent, nsIFrame* aRight)
+static CGRect
+SeparatorAdjustedRect(CGRect aRect, nsNativeThemeCocoa::SegmentParams aParams)
{
// A separator between two segments should always be located in the leftmost
// pixel column of the segment to the right of the separator, regardless of
// who ends up drawing it.
// CoreUI draws the separators inside the drawing rect.
- if (aLeft && SeparatorResponsibility(aLeft, aCurrent) == aLeft) {
- // The left button draws the separator, so we need to make room for it.
+ if (!aParams.atLeftEnd && !aParams.drawsLeftSeparator) {
+ // The segment to the left of us draws the separator, so we need to make
+ // room for it.
aRect.origin.x += 1;
aRect.size.width -= 1;
}
- if (SeparatorResponsibility(aCurrent, aRight) == aCurrent) {
+ if (aParams.drawsRightSeparator) {
// We draw the right separator, so we need to extend the draw rect into the
// segment to our right.
aRect.size.width += 1;
}
return aRect;
}
static NSString* ToolbarButtonPosition(BOOL aIsFirst, BOOL aIsLast)
@@ -2343,66 +2343,96 @@ static NSString* ToolbarButtonPosition(B
if (aIsLast)
return @"kCUISegmentPositionLast";
return @"kCUISegmentPositionMiddle";
}
struct SegmentedControlRenderSettings {
const CGFloat* heights;
const NSString* widgetName;
- const BOOL ignoresPressedWhenSelected;
- const BOOL isToolbarControl;
};
static const CGFloat tabHeights[3] = { 17, 20, 23 };
static const SegmentedControlRenderSettings tabRenderSettings = {
- tabHeights, @"tab", YES, NO
+ tabHeights, @"tab"
};
static const CGFloat toolbarButtonHeights[3] = { 15, 18, 22 };
static const SegmentedControlRenderSettings toolbarButtonRenderSettings = {
- toolbarButtonHeights, @"kCUIWidgetButtonSegmentedSCurve", NO, YES
+ toolbarButtonHeights, @"kCUIWidgetButtonSegmentedSCurve"
};
+nsNativeThemeCocoa::SegmentParams
+nsNativeThemeCocoa::ComputeSegmentParams(nsIFrame* aFrame,
+ EventStates aEventState,
+ SegmentType aSegmentType)
+{
+ SegmentParams params;
+ params.segmentType = aSegmentType;
+ params.insideActiveWindow = FrameIsInActiveWindow(aFrame);
+ params.pressed = IsPressedButton(aFrame);
+ params.selected = IsSelectedButton(aFrame);
+ params.focused = aEventState.HasState(NS_EVENT_STATE_FOCUS);
+ bool isRTL = IsFrameRTL(aFrame);
+ nsIFrame* left = GetAdjacentSiblingFrameWithSameAppearance(aFrame, isRTL);
+ nsIFrame* right = GetAdjacentSiblingFrameWithSameAppearance(aFrame, !isRTL);
+ params.atLeftEnd = !left;
+ params.atRightEnd = !right;
+ params.drawsLeftSeparator = SeparatorResponsibility(left, aFrame) == aFrame;
+ params.drawsRightSeparator = SeparatorResponsibility(aFrame, right) == aFrame;
+ params.rtl = isRTL;
+ return params;
+}
+
+static SegmentedControlRenderSettings
+RenderSettingsForSegmentType(nsNativeThemeCocoa::SegmentType aSegmentType)
+{
+ switch (aSegmentType) {
+ case nsNativeThemeCocoa::SegmentType::eToolbarButton:
+ return toolbarButtonRenderSettings;
+ case nsNativeThemeCocoa::SegmentType::eTab:
+ return tabRenderSettings;
+ }
+}
+
void
nsNativeThemeCocoa::DrawSegment(CGContextRef cgContext, const HIRect& inBoxRect,
- EventStates inState, nsIFrame* aFrame,
- const SegmentedControlRenderSettings& aSettings)
+ const SegmentParams& aParams)
{
- BOOL isActive = IsActive(aFrame, aSettings.isToolbarControl);
- BOOL isFocused = inState.HasState(NS_EVENT_STATE_FOCUS);
- BOOL isSelected = IsSelectedButton(aFrame);
- BOOL isPressed = IsPressedButton(aFrame);
- if (isSelected && aSettings.ignoresPressedWhenSelected) {
- isPressed = NO;
- }
-
- BOOL isRTL = IsFrameRTL(aFrame);
- nsIFrame* left = GetAdjacentSiblingFrameWithSameAppearance(aFrame, isRTL);
- nsIFrame* right = GetAdjacentSiblingFrameWithSameAppearance(aFrame, !isRTL);
- CGRect drawRect = SeparatorAdjustedRect(inBoxRect, left, aFrame, right);
- BOOL drawLeftSeparator = SeparatorResponsibility(left, aFrame) == aFrame;
- BOOL drawRightSeparator = SeparatorResponsibility(aFrame, right) == aFrame;
- NSControlSize controlSize = FindControlSize(drawRect.size.height, aSettings.heights, 4.0f);
-
- RenderWithCoreUI(drawRect, cgContext, [NSDictionary dictionaryWithObjectsAndKeys:
- aSettings.widgetName, @"widget",
- (isActive ? @"kCUIPresentationStateActiveKey" : @"kCUIPresentationStateInactive"), @"kCUIPresentationStateKey",
- ToolbarButtonPosition(!left, !right), @"kCUIPositionKey",
- [NSNumber numberWithBool:drawLeftSeparator], @"kCUISegmentLeadingSeparatorKey",
- [NSNumber numberWithBool:drawRightSeparator], @"kCUISegmentTrailingSeparatorKey",
- [NSNumber numberWithBool:isSelected], @"value",
- (isPressed ? @"pressed" : (isActive ? @"normal" : @"inactive")), @"state",
- [NSNumber numberWithBool:isFocused], @"focus",
- CUIControlSizeForCocoaSize(controlSize), @"size",
- [NSNumber numberWithBool:YES], @"is.flipped",
- @"up", @"direction",
- nil]);
+ SegmentedControlRenderSettings renderSettings =
+ RenderSettingsForSegmentType(aParams.segmentType);
+
+ NSControlSize controlSize =
+ FindControlSize(inBoxRect.size.height, renderSettings.heights, 4.0f);
+ CGRect drawRect = SeparatorAdjustedRect(inBoxRect, aParams);
+
+ NSDictionary* dict = @{
+ @"widget": renderSettings.widgetName,
+ @"kCUIPresentationStateKey":
+ (aParams.insideActiveWindow ? @"kCUIPresentationStateActiveKey"
+ : @"kCUIPresentationStateInactive"),
+ @"kCUIPositionKey":
+ ToolbarButtonPosition(aParams.atLeftEnd, aParams.atRightEnd),
+ @"kCUISegmentLeadingSeparatorKey":
+ [NSNumber numberWithBool:aParams.drawsLeftSeparator],
+ @"kCUISegmentTrailingSeparatorKey":
+ [NSNumber numberWithBool:aParams.drawsRightSeparator],
+ @"value": [NSNumber numberWithBool:aParams.selected],
+ @"state": (aParams.pressed ? @"pressed"
+ : (aParams.insideActiveWindow ? @"normal"
+ : @"inactive")),
+ @"focus": [NSNumber numberWithBool:aParams.focused],
+ @"size": CUIControlSizeForCocoaSize(controlSize),
+ @"is.flipped": [NSNumber numberWithBool:YES],
+ @"direction": @"up"
+ };
+
+ RenderWithCoreUI(drawRect, cgContext, dict);
}
nsIFrame*
nsNativeThemeCocoa::GetParentScrollbarFrame(nsIFrame *aFrame)
{
// Walk our parents to find a scrollbar frame
nsIFrame* scrollbarFrame = aFrame;
do {
@@ -2868,18 +2898,22 @@ nsNativeThemeCocoa::DrawWidgetBackground
DrawSpinButton(cgContext, macRect, SpinButton::eUp, params);
} else {
DrawSpinButton(cgContext, macRect, SpinButton::eDown, params);
}
}
}
break;
- case NS_THEME_TOOLBARBUTTON:
- DrawSegment(cgContext, macRect, eventState, aFrame, toolbarButtonRenderSettings);
+ case NS_THEME_TOOLBARBUTTON: {
+ SegmentParams params =
+ ComputeSegmentParams(aFrame, eventState, SegmentType::eToolbarButton);
+ params.insideActiveWindow = [NativeWindowForFrame(aFrame) isMainWindow];
+ DrawSegment(cgContext, macRect, params);
+ }
break;
case NS_THEME_SEPARATOR: {
HIThemeSeparatorDrawInfo sdi = { 0, kThemeStateActive };
HIThemeDrawSeparator(&macRect, &sdi, cgContext, HITHEME_ORIENTATION);
}
break;
@@ -3241,18 +3275,22 @@ nsNativeThemeCocoa::DrawWidgetBackground
@"kCUIVariantGradientSideBarSelection", @"kCUIVariantKey",
(FrameIsInActiveWindow(aFrame) ? @"normal" : @"inactive"), @"state",
@"gradient", @"widget",
nil]);
}
}
break;
- case NS_THEME_TAB:
- DrawSegment(cgContext, macRect, eventState, aFrame, tabRenderSettings);
+ case NS_THEME_TAB: {
+ SegmentParams params =
+ ComputeSegmentParams(aFrame, eventState, SegmentType::eTab);
+ params.pressed = params.pressed && !params.selected;
+ DrawSegment(cgContext, macRect, params);
+ }
break;
case NS_THEME_TABPANELS:
DrawTabPanel(cgContext, macRect, aFrame);
break;
case NS_THEME_RESIZER:
DrawResizer(cgContext, macRect, aFrame);