Sign in Join
Wiki copytemporary

Cocoa Internals/Buttons: what changed

Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11## Buttons Map
22
33Despite of being a very basic control, buttons are complicated topic on macOS.
44
5-<table>
6-<thead>
7-<tr>
8-<th><p>LCL Button</p></th>
9-<th><p>macOS Button / Style</p></th>
10-<th><p>Description</p></th>
11-</tr>
12-</thead>
13-<tbody>
14-<tr>
15-<td><p>TButton</p></td>
16-<td><p>Push Button</p>
17-<p>NSRoundedBezelStyle</p></td>
18-<td><p>Per macOS design guidelines, Push buttons should only have labels on them, and no Icons. This is exactly, how LCL TButton behaves.</p>
19-<p>The biggest issue is that macOS Push Buttons are of a fixed height. While LCL buttons can be any height.</p>
20-<p>The approach similar to the Carbon implementation could be used - after a certain height the button changes its bezel. <strong>currently r56760 it's disabled</strong></p></td>
21-</tr>
22-<tr>
23-<td><p>TToggleBox</p></td>
24-<td><p>Push Button</p>
25-<p>NSRoundedBezelStyle with NSButtonTypePushOnPushOff type</p></td>
26-<td><p>In order for ToggleBox to look exactly as TPushButton the same style is used.</p>
27-<p>However, Cocoa button Type is different. (It's required for the button to be drawn differently when "pressed".)</p>
28-<p>Prior to r62250 the bezel style was NSTexturedRoundedBezelStyle, with NSToggleButton for button type.</p>
29-<p>It's possible to use the same settings on revisions after 62250. All you need to do is modify global variables value of CocoaInt unit <strong>CocoaToggleBezel</strong> (which should be desired bezel) and <strong>CocoaToggleType</strong> (which should be the desired Cocoa button type for the toggle button). It's recommended to override them in the "initialization" section, prior to any button handle being created.</p></td>
30-</tr>
31-<tr>
32-<td><p>TBitBtn</p></td>
33-<td><p>Image Button</p>
34-<p>NSRegularSquareBezelStyle</p></td>
35-<td><p>TBitBtn is a button that could hold an image in it's body. The closest (not deprecated) to such tasks is NSRegularSquareBezelStyle in macOS</p>
36-<p>TBitBtn could also be used as a replacement for TButton. I.e. TBitBtn could be a "Default" button on a modal dialog. And there's no corresponding replacement for that in macOS</p></td>
37-</tr>
38-<tr>
39-<td><p>TSpeedButton</p></td>
40-<td></td>
41-<td><p>This is not an actual control button, it's LCL-drawn button.</p>
42-<p>todo: no themes API customdrawn controls used?</p>
43-<p>The font used for caption of the button is <a href="https://developer.apple.com/documentation/appkit/nsfont/1530094-systemfontofsize?language=objc">NSFont.systemFontOfSize</a></p></td>
44-</tr>
45-</tbody>
46-</table>
5+**LCL Button**
476
7+**macOS Button / Style**
8+
9+**Description**
10+
11+TButton
12+
13+Push Button
14+
15+NSRoundedBezelStyle
16+
17+Per macOS design guidelines, Push buttons should only have labels on them, and no Icons. This is exactly, how LCL TButton behaves.
18+
19+The biggest issue is that macOS Push Buttons are of a fixed height. While LCL buttons can be any height.
20+
21+The approach similar to the Carbon implementation could be used - after a certain height the button changes its bezel. **currently r56760 it's disabled**
22+
23+TToggleBox
24+
25+Push Button
26+
27+NSRoundedBezelStyle with NSButtonTypePushOnPushOff type
28+
29+In order for ToggleBox to look exactly as TPushButton the same style is used.
30+
31+However, Cocoa button Type is different. (It's required for the button to be drawn differently when "pressed".)
32+
33+Prior to r62250 the bezel style was NSTexturedRoundedBezelStyle, with NSToggleButton for button type.
34+
35+It's possible to use the same settings on revisions after 62250. All you need to do is modify global variables value of CocoaInt unit **CocoaToggleBezel** (which should be desired bezel) and **CocoaToggleType** (which should be the desired Cocoa button type for the toggle button). It's recommended to override them in the "initialization" section, prior to any button handle being created.
36+
37+TBitBtn
38+
39+Image Button
40+
41+NSRegularSquareBezelStyle
42+
43+TBitBtn is a button that could hold an image in it's body. The closest (not deprecated) to such tasks is NSRegularSquareBezelStyle in macOS
44+
45+TBitBtn could also be used as a replacement for TButton. I.e. TBitBtn could be a "Default" button on a modal dialog. And there's no corresponding replacement for that in macOS
46+
47+TSpeedButton
48+
49+This is not an actual control button, it's LCL-drawn button.
50+
51+todo: no themes API customdrawn controls used?
52+
53+The font used for caption of the button is [NSFont.systemFontOfSize](https://developer.apple.com/documentation/appkit/nsfont/1530094-systemfontofsize?language=objc)
54+
4855### Radio Buttons
4956
5057From [stackoverflow](https://stackoverflow.com/questions/37249986/how-to-group-radio-buttons-from-storyboard-in-cocoa-application)
5158
5259
5360NOTE: Use of NSMatrix is discouraged in apps that run in Mountain Lion 10.8 and later. If you need to create a radio button group in an app that runs in Mountain Lion 10.8 and later, create instances of NSButton that each specify a button type of NSRadioButton and specify the same action and the same superview for each button in the group.
5461
5562If all buttons call the same action method and are in the same superview, Cocoa automatically selects the clicked button and deselects the previous button and -- no code is necessary to do that.
5663
5764## TrackBar
5865
5966[[TTrackBar]] implementation is based on top of **NSSlider** class.
6067
6168**NSSlider** doesn't have a defined property for vertical or horizontal. It draws itself depending on which size (height or width) is larger than the other. Determining the preferred size also uses the current TTrackBar dimension. Thus the frame rect might need to be updated to match the selected orientation.
6269
6370Autosizing allows it to resize one of the dimensions. (For Horizontal oriented trackbar, the height cannot be changed, while width can.)
6471
6572**NSSlider** doesn't support custom tick marks. Those are drawn by the **TCocoaSlider** class (refer to **drawRect:**) method.
6673
6774Cocoa **NSSlider** is always floating-point. It does support min and max values, but those are always of *double* as well. LCL track bar is always INTEGER.
6875
6976Default **NSSlider** keyboard navigation always switches the position by 1/20th (between Min and Max) values.
7077
7178- The value can be adjusted by using **AltIncrementValue**. If it's set, the keyboard navigation would be the specified value.
7279- The value can be restricted to go only by tickMarks (which might give effective of Int only, but only for a limited set of options).
7380- It's odd that method **altIncrementValue** always returns zero, even right after the new value was set. (other "double" returning methods work as expected.)
7481
7582## Textured styles
7683
7784There are number of styles for buttons named "Textured" (i.e. NSTexturedRoundedBezelStyle, NSTexturedSquareBezelStyle). These buttons a designed to be used in "Metal" aka "Textured" style windows, and Window Frames (borders/tool bars) Thus these styles should not be used.
7885
7986To see the all styles of buttons available you can use the following example: <https://github.com/skalogryz/lcltests/tree/master/cocoabuttonsmatrix>
8087
8188### Customize Style
8289
8390In order to change a style of a button, one should change the button bezel (in some cases type also needs to be changed). (i.e. the most common style change is to show the proper "HELP" button. Which has a specific style in Cocoa)
8491
8592```delphi
8693uses
8794 ...
8895 {$ifdef LCLCocoa}
8996 ,CocoaAll
9097 {$endif}
9198
9299var
93100 btn : TButton; // the same approach will work for TToggleBox and TBitBtn
94101
95102 if not btn.HandleAllocated then btn.HandleNeeded;
96103 NSbutton(btn.Handle).setButtonType(NSHelpButtonBezelStyle);
97104 NSbutton(btn.Handle).setBezelStyle(NSMomentaryLightButton);
98105```
99106
100107Such approach is useful when changing button style on case-by-case basis. One should keep in mind, that if buttons handle is recreated, the same steps will need to be completed again.
101108
102109### Styles and Types deprecation
103110
104111A number of bezel styles and button types have been deprecated in the macOS API (eg NSHelpButtonBezelStyle). In fact it's only the name of the constant that is deprecated. The constants have been actually renamed from NSxxxxxBezelStyle to NSBezelStylexxxxx (ie NSHelpButtonBezelStyle to NSBezelStyleHelpButton).
105112
106113## Sizing
107114
108115### Cocoa vs Carbon
109116
110117Styles are for Cocoa and Carbon are a little bit different for buttons. For example "default" height of Push button is different between Cocoa and Carbon. Thus a UI designed for Carbon might not look good for Cocoa.
111118
112119This is a problem of buttons only, other rectangular controls (textbox, listbox) doesn't experience such problem.
113120
114121### Control Sizes
115122
116123Most buttons in macOS design have a fixed height (i.e. Push Button). For such buttons macOS API provides the property "controlSize". Buttons are available in 3 variations: regular, small, mini. Each variant paints in its own manner:
117124
118-<figure>
119-<img src="cocoa_button_sizes.png" title="cocoa_button_sizes.png" />
120-<figcaption>cocoa_button_sizes.png</figcaption>
121-</figure>
125+![](/wiki-images/1/12/Cocoa_button_sizes.png)
122126
123127Since Lazarus r56773, the widgetset auto detects one of the three variants from the button's Height.
124128
125129Prior to that, only the "regular" size was used, causing [visual artifacts](https://bugs.freepascal.org/view.php?id=30577), if the height of a button was smaller than expected by controlSize.
126130
127131Also, the font of a button is forced to match the detected controlSize. (Todo: should do it, only if standard font is selected.)
128132
129133Example of artifact, if button's Height is 21 (it must be 32). Note that top edge is clipped, and some blue area is painted.
130134
131-<figure>
132-<img src="cocoa_button_height_arterfact.png" title="cocoa_button_height_arterfact.png" />
133-<figcaption>cocoa_button_height_arterfact.png</figcaption>
134-</figure>
135+![](/wiki-images/0/09/Cocoa_button_height_arterfact.png)
135136
136137## Smart Style Selection
137138
138139In macOS guidelines, the style that should be used for a button depends on the placement/usage of the button.
139140
140141In the LCL design, there's no such thing as "style". It's presumed that the button would look the same, no matter where on the screen it's or what the button's parent. (It's not uncommon to design the interface in such a way).
141142
142143Thus some LCL buttons might look foreign to macOS native applications, just because the wrong button styles are used. For example, a push button is used in a tool bar.
143144
144145There are a few approaches what could be used:
145146
146147- adding new TxxxButton classes into LCL (quite wasteful, and might not be applicable for other OSes)
147148- adding a style property to TBitBtn button (non Delphi compatible)
148149- changes styles within Cocoa widgetset, automatically, depending on the placement of the button.
149150
150151## Ampersand in Captions
151152
152153LCL is working in Windows compatible mode, where a button can have a hot key assigned by marking a desired letter with an ampersand in front of it.
153154
154155For example
155156
156157
157158&Open
158159
159160turns into
160161
161162
162-<u>O</u>pen
163+Open
163164
164165A user can hit Alt+O to press the button.
165166
166167macOS no longer has the similar concept. (Those were known as **mnemonics**, but APIs for mnemonics are deprecated).
167168
168169LCL assigns button captions with the ampersand in it, and those needs to be removed prior to assigning to the actual button. (see ControlTitleToStr in `CocoaUtils.pas`).
169170
170171LCL also expects the "text" of the control to return the value WITH ampersand, for this reason GetText() for buttons returns FALSE. Indicating that LCL should use the cached "fCaption" value.
171172
172173## See Also
173174
174175- [[Cocoa Internals]]
175176- <https://developer.apple.com/macos/human-interface-guidelines/buttons/checkboxes/> - the official guide to macOS button styles
176177- [<https://developer.apple.com/documentation/appkit/nsbezelstyle?language=objc>](https://developer.apple.com/documentation/appkit/nsbezelstyle) - bezel constants descriptions
177178- <https://mackuba.eu/2014/10/06/a-guide-to-nsbutton-styles/> - a non-official guide to macOS button styles
178179
179180---
180181*From the Free Pascal wiki, page "Cocoa Internals/Buttons", as it stood on 2020-08-26 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*
181182Category: Cocoa
182183Category: Lazarus internals
183184Category: macOS

Back to history