summaryrefslogtreecommitdiffstats
path: root/widget/cocoa/nsNativeThemeCocoa.h
blob: a6c9812238aee2010f8bf9641db8b43b929a3fe9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef nsNativeThemeCocoa_h_
#define nsNativeThemeCocoa_h_

#import <Carbon/Carbon.h>
#import <Cocoa/Cocoa.h>

#include "mozilla/Variant.h"

#include "nsITheme.h"
#include "ThemeCocoa.h"
#include "mozilla/dom/RustTypes.h"

@class MOZCellDrawWindow;
@class MOZCellDrawView;
@class MOZSearchFieldCell;
@class NSProgressBarCell;
class nsDeviceContext;
struct SegmentedControlRenderSettings;

namespace mozilla {
namespace gfx {
class DrawTarget;
}  // namespace gfx
}  // namespace mozilla

class nsNativeThemeCocoa : public mozilla::widget::ThemeCocoa {
  using ThemeCocoa = mozilla::widget::ThemeCocoa;

 public:
  enum class MenuIcon : uint8_t {
    eCheckmark,
    eMenuArrow,
    eMenuDownScrollArrow,
    eMenuUpScrollArrow
  };

  enum class CheckboxOrRadioState : uint8_t { eOff, eOn, eIndeterminate };

  enum class ButtonType : uint8_t {
    eRegularPushButton,
    eDefaultPushButton,
    eSquareBezelPushButton,
    eArrowButton,
    eHelpButton,
    eTreeTwistyPointingRight,
    eTreeTwistyPointingDown,
    eDisclosureButtonClosed,
    eDisclosureButtonOpen
  };

  enum class SpinButton : uint8_t { eUp, eDown };

  enum class SegmentType : uint8_t { eToolbarButton, eTab };

  enum class OptimumState : uint8_t { eOptimum, eSubOptimum, eSubSubOptimum };

  struct ControlParams {
    ControlParams()
        : disabled(false), insideActiveWindow(false), pressed(false), focused(false), rtl(false) {}

    bool disabled : 1;
    bool insideActiveWindow : 1;
    bool pressed : 1;
    bool focused : 1;
    bool rtl : 1;
  };

  struct MenuIconParams {
    MenuIcon icon = MenuIcon::eCheckmark;
    bool disabled = false;
    bool insideActiveMenuItem = false;
    bool centerHorizontally = false;
    bool rtl = false;
  };

  struct MenuItemParams {
    bool checked = false;
    bool disabled = false;
    bool selected = false;
    bool rtl = false;
  };

  struct CheckboxOrRadioParams {
    ControlParams controlParams;
    CheckboxOrRadioState state = CheckboxOrRadioState::eOff;
    float verticalAlignFactor = 0.5f;
  };

  struct ButtonParams {
    ControlParams controlParams;
    ButtonType button = ButtonType::eRegularPushButton;
  };

  struct DropdownParams {
    ControlParams controlParams;
    bool pullsDown = false;
    bool editable = false;
  };

  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 TextFieldParams {
    float verticalAlignFactor = 0.5f;
    bool insideToolbar = false;
    bool disabled = false;
    bool focused = false;
    bool rtl = false;
  };

  struct ProgressParams {
    double value = 0.0;
    double max = 0.0;
    float verticalAlignFactor = 0.5f;
    bool insideActiveWindow = false;
    bool indeterminate = false;
    bool horizontal = false;
    bool rtl = false;
  };

  struct MeterParams {
    double value = 0;
    double min = 0;
    double max = 0;
    OptimumState optimumState = OptimumState::eOptimum;
    float verticalAlignFactor = 0.5f;
    bool horizontal = true;
    bool rtl = false;
  };

  struct TreeHeaderCellParams {
    ControlParams controlParams;
    TreeSortDirection sortDirection = eTreeSortDirection_Natural;
    bool lastTreeHeaderCell = false;
  };

  struct ScaleParams {
    int32_t value = 0;
    int32_t min = 0;
    int32_t max = 0;
    bool insideActiveWindow = false;
    bool disabled = false;
    bool focused = false;
    bool horizontal = true;
    bool reverse = false;
  };

  enum Widget : uint8_t {
    eColorFill,       // mozilla::gfx::sRGBColor
    eMenuIcon,        // MenuIconParams
    eMenuItem,        // MenuItemParams
    eMenuSeparator,   // MenuItemParams
    eCheckbox,        // CheckboxOrRadioParams
    eRadio,           // CheckboxOrRadioParams
    eButton,          // ButtonParams
    eDropdown,        // DropdownParams
    eSpinButtons,     // SpinButtonParams
    eSpinButtonUp,    // SpinButtonParams
    eSpinButtonDown,  // SpinButtonParams
    eSegment,         // SegmentParams
    eSeparator,
    eToolbar,    // bool
    eStatusBar,  // bool
    eGroupBox,
    eTextField,           // TextFieldParams
    eSearchField,         // TextFieldParams
    eProgressBar,         // ProgressParams
    eMeter,               // MeterParams
    eTreeHeaderCell,      // TreeHeaderCellParams
    eScale,               // ScaleParams
    eMultilineTextField,  // bool
    eListBox,
    eActiveSourceListSelection,    // bool
    eInactiveSourceListSelection,  // bool
    eTabPanel,
  };

  struct WidgetInfo {
    static WidgetInfo ColorFill(const mozilla::gfx::sRGBColor& aParams) {
      return WidgetInfo(Widget::eColorFill, aParams);
    }
    static WidgetInfo MenuIcon(const MenuIconParams& aParams) {
      return WidgetInfo(Widget::eMenuIcon, aParams);
    }
    static WidgetInfo MenuItem(const MenuItemParams& aParams) {
      return WidgetInfo(Widget::eMenuItem, aParams);
    }
    static WidgetInfo MenuSeparator(const MenuItemParams& aParams) {
      return WidgetInfo(Widget::eMenuSeparator, aParams);
    }
    static WidgetInfo Checkbox(const CheckboxOrRadioParams& aParams) {
      return WidgetInfo(Widget::eCheckbox, aParams);
    }
    static WidgetInfo Radio(const CheckboxOrRadioParams& aParams) {
      return WidgetInfo(Widget::eRadio, aParams);
    }
    static WidgetInfo Button(const ButtonParams& aParams) {
      return WidgetInfo(Widget::eButton, aParams);
    }
    static WidgetInfo Dropdown(const DropdownParams& aParams) {
      return WidgetInfo(Widget::eDropdown, aParams);
    }
    static WidgetInfo SpinButtons(const SpinButtonParams& aParams) {
      return WidgetInfo(Widget::eSpinButtons, aParams);
    }
    static WidgetInfo SpinButtonUp(const SpinButtonParams& aParams) {
      return WidgetInfo(Widget::eSpinButtonUp, aParams);
    }
    static WidgetInfo SpinButtonDown(const SpinButtonParams& aParams) {
      return WidgetInfo(Widget::eSpinButtonDown, aParams);
    }
    static WidgetInfo Segment(const SegmentParams& aParams) {
      return WidgetInfo(Widget::eSegment, aParams);
    }
    static WidgetInfo Separator() { return WidgetInfo(Widget::eSeparator, false); }
    static WidgetInfo Toolbar(bool aParams) { return WidgetInfo(Widget::eToolbar, aParams); }
    static WidgetInfo StatusBar(bool aParams) { return WidgetInfo(Widget::eStatusBar, aParams); }
    static WidgetInfo GroupBox() { return WidgetInfo(Widget::eGroupBox, false); }
    static WidgetInfo TextField(const TextFieldParams& aParams) {
      return WidgetInfo(Widget::eTextField, aParams);
    }
    static WidgetInfo SearchField(const TextFieldParams& aParams) {
      return WidgetInfo(Widget::eSearchField, aParams);
    }
    static WidgetInfo ProgressBar(const ProgressParams& aParams) {
      return WidgetInfo(Widget::eProgressBar, aParams);
    }
    static WidgetInfo Meter(const MeterParams& aParams) {
      return WidgetInfo(Widget::eMeter, aParams);
    }
    static WidgetInfo TreeHeaderCell(const TreeHeaderCellParams& aParams) {
      return WidgetInfo(Widget::eTreeHeaderCell, aParams);
    }
    static WidgetInfo Scale(const ScaleParams& aParams) {
      return WidgetInfo(Widget::eScale, aParams);
    }
    static WidgetInfo MultilineTextField(bool aParams) {
      return WidgetInfo(Widget::eMultilineTextField, aParams);
    }
    static WidgetInfo ListBox() { return WidgetInfo(Widget::eListBox, false); }
    static WidgetInfo ActiveSourceListSelection(bool aParams) {
      return WidgetInfo(Widget::eActiveSourceListSelection, aParams);
    }
    static WidgetInfo InactiveSourceListSelection(bool aParams) {
      return WidgetInfo(Widget::eInactiveSourceListSelection, aParams);
    }
    static WidgetInfo TabPanel(bool aParams) { return WidgetInfo(Widget::eTabPanel, aParams); }

    template <typename T>
    T Params() const {
      MOZ_RELEASE_ASSERT(mVariant.is<T>());
      return mVariant.as<T>();
    }

    enum Widget Widget() const { return mWidget; }

   private:
    template <typename T>
    WidgetInfo(enum Widget aWidget, const T& aParams) : mVariant(aParams), mWidget(aWidget) {}

    mozilla::Variant<mozilla::gfx::sRGBColor, MenuIconParams, MenuItemParams, CheckboxOrRadioParams,
                     ButtonParams, DropdownParams, SpinButtonParams, SegmentParams, TextFieldParams,
                     ProgressParams, MeterParams, TreeHeaderCellParams, ScaleParams, bool>
        mVariant;

    enum Widget mWidget;
  };

  explicit nsNativeThemeCocoa();

  NS_DECL_ISUPPORTS_INHERITED

  // The nsITheme interface.
  NS_IMETHOD DrawWidgetBackground(gfxContext* aContext, nsIFrame* aFrame,
                                  StyleAppearance aAppearance, const nsRect& aRect,
                                  const nsRect& aDirtyRect, DrawOverflow) override;
  bool CreateWebRenderCommandsForWidget(mozilla::wr::DisplayListBuilder& aBuilder,
                                        mozilla::wr::IpcResourceUpdateQueue& aResources,
                                        const mozilla::layers::StackingContextHelper& aSc,
                                        mozilla::layers::RenderRootStateManager* aManager,
                                        nsIFrame* aFrame, StyleAppearance aAppearance,
                                        const nsRect& aRect) override;
  [[nodiscard]] LayoutDeviceIntMargin GetWidgetBorder(nsDeviceContext* aContext, nsIFrame* aFrame,
                                                      StyleAppearance aAppearance) override;

  bool GetWidgetPadding(nsDeviceContext* aContext, nsIFrame* aFrame, StyleAppearance aAppearance,
                        LayoutDeviceIntMargin* aResult) override;

  virtual bool GetWidgetOverflow(nsDeviceContext* aContext, nsIFrame* aFrame,
                                 StyleAppearance aAppearance, nsRect* aOverflowRect) override;

  LayoutDeviceIntSize GetMinimumWidgetSize(nsPresContext*, nsIFrame*, StyleAppearance) override;
  NS_IMETHOD WidgetStateChanged(nsIFrame* aFrame, StyleAppearance aAppearance, nsAtom* aAttribute,
                                bool* aShouldRepaint, const nsAttrValue* aOldValue) override;
  NS_IMETHOD ThemeChanged() override;
  bool ThemeSupportsWidget(nsPresContext* aPresContext, nsIFrame* aFrame,
                           StyleAppearance aAppearance) override;
  bool WidgetIsContainer(StyleAppearance aAppearance) override;
  bool ThemeDrawsFocusForWidget(nsIFrame*, StyleAppearance) override;
  bool ThemeNeedsComboboxDropmarker() override;
  virtual bool WidgetAppearanceDependsOnWindowFocus(StyleAppearance aAppearance) override;
  virtual ThemeGeometryType ThemeGeometryTypeForWidget(nsIFrame* aFrame,
                                                       StyleAppearance aAppearance) override;
  virtual Transparency GetWidgetTransparency(nsIFrame* aFrame,
                                             StyleAppearance aAppearance) override;
  mozilla::Maybe<WidgetInfo> ComputeWidgetInfo(nsIFrame* aFrame, StyleAppearance aAppearance,
                                               const nsRect& aRect);
  void DrawProgress(CGContextRef context, const HIRect& inBoxRect, const ProgressParams& aParams);

 protected:
  virtual ~nsNativeThemeCocoa();

  LayoutDeviceIntMargin DirectionAwareMargin(const LayoutDeviceIntMargin& aMargin,
                                             nsIFrame* aFrame);
  nsIFrame* SeparatorResponsibility(nsIFrame* aBefore, nsIFrame* aAfter);
  ControlParams ComputeControlParams(nsIFrame* aFrame, mozilla::dom::ElementState aEventState);
  MenuIconParams ComputeMenuIconParams(nsIFrame* aParams, mozilla::dom::ElementState aEventState,
                                       MenuIcon aIcon);
  MenuItemParams ComputeMenuItemParams(nsIFrame* aFrame, mozilla::dom::ElementState aEventState,
                                       bool aIsChecked);
  SegmentParams ComputeSegmentParams(nsIFrame* aFrame, mozilla::dom::ElementState aEventState,
                                     SegmentType aSegmentType);
  TextFieldParams ComputeTextFieldParams(nsIFrame* aFrame, mozilla::dom::ElementState aEventState);
  ProgressParams ComputeProgressParams(nsIFrame* aFrame, mozilla::dom::ElementState aEventState,
                                       bool aIsHorizontal);
  MeterParams ComputeMeterParams(nsIFrame* aFrame);
  TreeHeaderCellParams ComputeTreeHeaderCellParams(nsIFrame* aFrame,
                                                   mozilla::dom::ElementState aEventState);
  mozilla::Maybe<ScaleParams> ComputeHTMLScaleParams(nsIFrame* aFrame,
                                                     mozilla::dom::ElementState aEventState);

  // HITheme drawing routines
  void DrawMeter(CGContextRef context, const HIRect& inBoxRect, const MeterParams& aParams);
  void DrawSegment(CGContextRef cgContext, const HIRect& inBoxRect, const SegmentParams& aParams);
  void DrawSegmentBackground(CGContextRef cgContext, const HIRect& inBoxRect,
                             const SegmentParams& aParams);
  void DrawTabPanel(CGContextRef context, const HIRect& inBoxRect, bool aIsInsideActiveWindow);
  void DrawScale(CGContextRef context, const HIRect& inBoxRect, const ScaleParams& aParams);
  void DrawCheckboxOrRadio(CGContextRef cgContext, bool inCheckbox, const HIRect& inBoxRect,
                           const CheckboxOrRadioParams& aParams);
  void DrawSearchField(CGContextRef cgContext, const HIRect& inBoxRect,
                       const TextFieldParams& aParams);
  void DrawTextField(CGContextRef cgContext, const HIRect& inBoxRect,
                     const TextFieldParams& aParams);
  void DrawPushButton(CGContextRef cgContext, const HIRect& inBoxRect, ButtonType aButtonType,
                      ControlParams aControlParams);
  void DrawSquareBezelPushButton(CGContextRef cgContext, const HIRect& inBoxRect,
                                 ControlParams aControlParams);
  void DrawHelpButton(CGContextRef cgContext, const HIRect& inBoxRect,
                      ControlParams aControlParams);
  void DrawDisclosureButton(CGContextRef cgContext, const HIRect& inBoxRect,
                            ControlParams aControlParams, NSControlStateValue aState);
  NSString* GetMenuIconName(const MenuIconParams& aParams);
  NSSize GetMenuIconSize(MenuIcon aIcon);
  void DrawMenuIcon(CGContextRef cgContext, const CGRect& aRect, const MenuIconParams& aParams);
  void DrawMenuItem(CGContextRef cgContext, const CGRect& inBoxRect, const MenuItemParams& aParams);
  void DrawMenuSeparator(CGContextRef cgContext, const CGRect& inBoxRect,
                         const MenuItemParams& aParams);
  void DrawHIThemeButton(CGContextRef cgContext, const HIRect& aRect, ThemeButtonKind aKind,
                         ThemeButtonValue aValue, ThemeDrawState aState,
                         ThemeButtonAdornment aAdornment, const ControlParams& aParams);
  void DrawButton(CGContextRef context, const HIRect& inBoxRect, const ButtonParams& aParams);
  void DrawTreeHeaderCell(CGContextRef context, const HIRect& inBoxRect,
                          const TreeHeaderCellParams& aParams);
  void DrawDropdown(CGContextRef context, const HIRect& inBoxRect, const DropdownParams& aParams);
  HIThemeButtonDrawInfo SpinButtonDrawInfo(ThemeButtonKind aKind, const SpinButtonParams& aParams);
  void DrawSpinButtons(CGContextRef context, const HIRect& inBoxRect,
                       const SpinButtonParams& aParams);
  void DrawSpinButton(CGContextRef context, const HIRect& inBoxRect, SpinButton aDrawnButton,
                      const SpinButtonParams& aParams);
  void DrawToolbar(CGContextRef cgContext, const CGRect& inBoxRect, bool aIsMain);
  void DrawStatusBar(CGContextRef cgContext, const HIRect& inBoxRect, bool aIsMain);
  void DrawMultilineTextField(CGContextRef cgContext, const CGRect& inBoxRect, bool aIsFocused);
  void DrawSourceListSelection(CGContextRef aContext, const CGRect& aRect, bool aWindowIsActive,
                               bool aSelectionIsActive);

  void RenderWidget(const WidgetInfo& aWidgetInfo, mozilla::ColorScheme,
                    mozilla::gfx::DrawTarget& aDrawTarget, const mozilla::gfx::Rect& aWidgetRect,
                    const mozilla::gfx::Rect& aDirtyRect, float aScale);

 private:
  NSButtonCell* mDisclosureButtonCell;
  NSButtonCell* mHelpButtonCell;
  NSButtonCell* mPushButtonCell;
  NSButtonCell* mRadioButtonCell;
  NSButtonCell* mCheckboxCell;
  NSTextFieldCell* mTextFieldCell;
  MOZSearchFieldCell* mSearchFieldCell;
  NSPopUpButtonCell* mDropdownCell;
  NSComboBoxCell* mComboBoxCell;
  NSProgressBarCell* mProgressBarCell;
  NSLevelIndicatorCell* mMeterBarCell;
  NSTableHeaderCell* mTreeHeaderCell;
  MOZCellDrawWindow* mCellDrawWindow = nil;
  MOZCellDrawView* mCellDrawView;
};

#endif  // nsNativeThemeCocoa_h_