Mac OS X Porting - Native Controls
Native Controls
Contributors
- Eric Bachard: Ericb
- Pierre de Filippis: Pdefilippis aliscafo@gmail.com
- Pavel Janik
- Christian Lippka: CL
- Ismael Merzaq: Ismael
Introduction
The purpose of this article is to present our current knowledge and progress of the implementation of native controls in the native Mac OS X version of OpenOffice.org. Our goal by implementing native controls is to remove the win32 look as much as possible and replace it by the Aqua look and feel using the Carbon API.
Apple Documentation and References
The Appearance Manager and HITheme
Apple provides an easy way to change a custom user interface to an aqua interface by using the Appearance Manager(AM). This API was first developed for Mac OS 8 and is centered around QuickDraw. The AM is less and less supported by Apple since 10.2 and any implementation needs to be replaced with the HIToolbox version: HITheme. The problem with HITheme is that its implementation started on Mac OS X 10.2 (Jaguar) and has since gone under many revisions and new functions have been progressively added with each new version of OS X. Therefore some functions in the 10.4 version might not be in 10.3 or 10.2. This is one of the reason why the native version of OpenOffice.org will run on Mac OS X 10.4 and higher only.
Using HITheme
Unfortunately there is not much documentation provided by Apple about HITheme. Thus we have to look at the HITheme.h header file directly and read the extensive comments to understand how to use this API. All the constants used to describe the type of controls that we want to implement is still the same as in the AM. This is the reason why the AM reference document is still useful and should always be opened when implementing native controls. The AM and HITheme are very similar in the way they approach the implementation of native controls, most of the time the functions have similar names and the arguments different types so you can always use the AM reference to give you an idea about the procedure to follow.
- Location of HITheme.h: /Developer/SDKs/MacOSX10.4u.sdk/System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/Headers/HITheme.h
Native controls in VCL
salnativewidgets.cxx
This file was copied directly from the Windows implementation of native controls. All the useless functions were removed and we are left with 6 functions:
- isNativeControlSupported: function called to see if a control should be implemented natively or not. A big switch statement that goes through all the controls and part of controls possible. Returns true when a control is supported. Each time a new control is implemented this function should be modified so the new native code is used at compile time.
- hitTestNativeControl: Boolean function. If the return value is TRUE, bIsInside contains information whether aPos was or not inside the native widget specified by the nType/nPart combination. This function will be used to redefine left/top buttons controls areas for e.g. the scrollbar.
- getState: a translation from the VCL constants to the Carbon constants of the state of controls.
- drawNativeControl: the most important function. This is where the code for new native controls is written. Again it is a big switch statment that lists each control with the corresponding implementation. Needs to be modified each time a new control is implemented.
- drawNativeControlText: [TO DO]
- getNativeControlRegion: [TO DO]
salnativewidgets.hxx
Uses AquaSalGraphics class, defined in vcl/aqua/inc/salgdi.h. AquaSalGraphics itself inherits of SalGraphics virtual class (defined in vcl/inc/salgdi.hxx).
This header file describes all the structures, classes and constants used to get the state and properties of the VCL controls. It is necessary to be familiar with this file since its content will be used to translate the state and properties to their Carbon equivalent.
Most of the stuff used in salnativewidgets.hxx are from HITheme.h (or Appearance.h for previous test)
The native controls and the implementation
Here is a list of all the controls that need to be native. Since some of them do not have the same name in VCL and Carbon, they are listed in this format: <VCL name> - <Carbon name> when they are different.
Push Button
- Implemented by: Pdefilippis
- Complemeted : Eric Bachard / Pavel Janik
This is the regular OK, Cancel buttons.
[FIXME] width is still not correct (work in progress)
nType is CONTROL_PUSHBUTTON (value 1) nPart is PART_ENTIRE_CONTROL (value 1)
[FIXME] How implement Heart Beat effect ? ( should be something default)
Radio Button
nType is CTRL_RADIOBUTTON (value is 2) nPart is PART_ENTIRE_CONTROL (value is 1)
- Implemented by: Pdefilippis
- Completed : Eric Bachard / Pavel Janik
This is the regular radio button.
Check Box
This is the regular check box.
- Implementation started by: Pdefilippis
- Work completed : Eric Bachard
Remaining issues : the checkmark is ok, but is only refreshed when the mouse goes out of the control area.
getNativeControlRegion() saved us.
[UPDATE] : with correct refresh, the checkmarks disappears as expected
nType is CTRL_CHECKBOX (value is 2) nPart is PART_ENTIRE_CONTROL (value is 1)
Toolbars and Aqua Theme
- Implemented : Eric Bachard
- Todo : verify if repaint is necessary and it buttons can or not be drawn
Popups Menus
- Implemented : Eric Bachard
Type: CTRL_MENU_POPUP
- Implemented by: Ismael Merzaq
Type: CTRL_MENU_POPUP
Part: PART_MENU_ITEM_CHECK_MARK
Part: PART_MENU_ITEM_RADIO_MARK
ComboBox
Status : begining of the implementation ( HIView now works )
Todo : add text entry, fix some refresh issues
nType is CTRL_COMBOBOX (value is 20) nPart is PART_ENTIRE_CONTROL (value is 1)
Sébastien and me finally found a way to use HIView and draw comboboxes. Please have a look at Mac_OS_X_Implementing_HIView for the documentation and the work in progress
1) Combobox inactive
As you can see, the final control is greyed. [FIXME] : change for status active when not clicked
2) Combobox active
The controls displays ok.
[FIXME] : implement the native popup area
Our previous try was plain wrong, because we where confused with listboxes.
As you can see, we are in facvt using lisboxes (no data entry possible ) :
From OSXHIGuidelines.pdf, page 253: For Carbon, ComboBoxes are available in Interface Builder. To create them programmatically use the HIComboBoxCreate function or DrawThemeButton with the appropriate constant.
Mechanism seems similar to other controls : in vcl/source/control/combobox.cxx, GetNativeControlRegion is used, so we'll proceed like for scrollbar.
ScrollBar
- Implemented by: Pierre de Filippis, Eric Bachard and Pavel Janik
This is the regular scrollbar.
- Improvement : the user can select either Arrows together or séparated arrows ( using System Preferences )
- Todo : vcl and native thumb area are not exactly superposed (offset in % ) between them. To be fixed asap.
Horizontal scrollbar, with left button active :
With arrows separated ( using System Preferences) :
nType is CONTROL_SCROLLBAR (value 60) nPart is PART_ENTIRE_CONTROL (value 1)
Other screenshot, showing vertical scrollbar and top button active :
Native FilePicker
- Implemented : Florian Heckl / Pavel Janik
- Todo : X11 backport ?
- Status : aquafilpicker01 cws, not yet integrated
Current status
[WORK IN PROGRESS] Aqua scrollbar works now as expected (see vcl/aqua/source/gdi/salnatigewidgets.cxx in aquavcl01 cws ), but some issues are remaining:
the main one is replace value for areas, with pointers on correct areas (vcl and aqua controls are not exactly superposed ) when we click on top of slider, it moves up from hlaf of slider size ( sort of "slide" :-) effect ? )
Translation of the Control Area
AquaSalGraphics::IsNativeControlSupported() returns true -> nType is ok , getstate() works , DrawNativeControl() works fine two, and several controls are drawn.
Everything seems to work excepted the button control area, because left/top control button is not located the same way for vcl and for aqua control : same behaviour, but different places.
Vertical scrollbar vcl : top (Button1) / bottom (Button2) aqua: both at bottom
Horizontal scrollbar: vcl : left (Button1) /right ( Button2) aqua: both on right
-> our problem is simple : translate the coordinates of the control area of left/top button under aqua control, else, clicking on the left of the scrollbar ... the button on right is active :-)
(same bug for vertical bar).
Solution proposed by Philipp Lohmann and Jan Holesovsky :
"...The actual hit testing is done in the overloaded SalGraphics::hitTestNativeControl method, so you can implement your own sensitive areas there. The getNativeControlRegion is used for drawing purposes (so the buttons are drawn at the positions you tell there)..."
[done] implement AquaSalGraphics::hitTestNativeControl() for scrollbar, to translate left/top control areas, and manage rIsInside Boolean variable.
How a ScrollBar is drawn
After printing out the part numbers passed to draw a ScrollBar, I found out how it is actually drawn out:
- 1. Part 101 - PART_BUTTON_UP
- 2. Part 102 - PART_BUTTON_DOWN
- 3. Part 211 - PART_THUMB_VERT
- 4. Part 201 - PART_TRACK_VERT_UPPER
- 5. Part 203 - PART_TRACK_VERT_LOWER
The first two parts are self-explanatory. The last 3 are a little more confusing at first especially since some heights and widths can be negative. But here is what they are.
Part 211
This part is the slider. As described by its value, it is vertical. The horizontal equivalent is part 210 - PART_THUMB_HORZ.
Part 201 - Part 203
These are the parts that are between the slider and the arrows. Part 201 is between the slider and the upper arrow. Part 203 is between the slider and the lower arrow. Each one of them can actually have a negative size in the case where the slider touches one or both of the arrows. The equivalents for a horizontal scrollbar are part 200 - PART_TRACK_HORZ_LEFT and part 202 - PART_TRACK_HORZ_RIGHT.
(18 September)
Pierre fixed an important bug, and we now have vertical scrollbar working fine (last remaining problem is top arrow), but horizontal is still having problems.
todo : fix top arrow, and improve horizontal scrollbar.
(10th September) Now the scrollbar is correctly drawn. Missing: always full (needs some work). modify the top control coordinates, manage active/not active.
Patch available here : http://eric.bachard.free.fr/mac/aquavcl/patches/controls/scrollbar/scrollbar10sept.diff
Screenshots :
(03rd September) Does not work as expected, work in progress to fix arrows issue, and obtain correct redrawing (arrows are correctly drawn, but not at good place). See screenshot:
Spinbox
- Started by: Ericb (spin buttons)
- Implemented by: Ismael Merzaq (fixed spin buttons and added text field)
CTRL_SPINBOX : two standalone spin buttons with an edit field
20th October : native spinbox can be drawn.
Todo :
solve the background issue decrease the vcl control size implement up/down parts in hitTestNativeControl() replace hardcoded (currentlky 16) spinbutton width with system returned value
First try (using kThemeIncDecButton ) :
Todo : implement hitTestNativeControl, to draw up and down parts.
Second test (using kThemeArrowButton) :
VCL spinbox button (work in progress to change for native spinbox button)
nType is CTRL_SPINBOX (value is 40) nPart is PART_ENTIRE_CONTROL (value is 1) [FIXME]nPart HAS_BACKGROUND_TEXTURE (value is 4000 ) seems to be defined too
Tab Body
- Implemented by:
CTRL_TAB_BODY : background of a Tab Pane
nType is CTRL_TAB_BODY (value is 56) nPart is PART_ENTIRE_CONTROL (value is 1) [FIXME]nPart HAS_BACKGROUND_TEXTURE (value is 4000 ) seems to be defined too
Edit Box, Multiline Edit Box
- Implemented by: Ismael Merzaq
- Focus rect added by: Philipp Lohmann
CTRL_EDITBOX :
CTRL_MULTILINE_EDITBOX:
The scrollbar is drawn separately.
nType is CTRL_EDITBOX (value is 30) or CTRL_MULTILINE_EDITBOX nPart is PART_ENTIRE_CONTROL (value is 1)
List Box
- Started by: Eric Bachard
- Implemented by: Ismael Merzaq
- Fixed by: Philipp Lohmann
CTRL_LISTBOX : Control that pops up a menu, but does NOT allow data entry
nType is CTRL_LISTBOX (value is 35) nPart is PART_ENTIRE_CONTROL (value is 1)
I (Ismael Merzaq) started to add a more native appearance for the floating frame of the listbox to replace the current one (image on the left) by a more aqua one (image on the right).
Tabs
- Implemented by: Ismael Merzaq
CTRL_TAB_ITEM : a single tab
With HIThemeTabDrawInfo with version=1
with version=0:
Tab Panes
- Implemented by: Ismael Merzaq
CTRL_TAB_PANE : the border around a tab area, but without the tabs themselves.
For the version element of the HIThemeTabPaneDrawInfo structure, see tabs as the values are the same.
Progress bar
- Implemented by: Philipp Lohmann
CTRL_PROGRESS
Intro progress bar
- Implemented by: Ismael Merzaq (added support to native control in the code in desktop)
- Native code by: Philipp Lohmann
CTRL_INTROPROGRESS: Progress bar of the splash screen. Its implementation is in the desktop module
Work in progress
Implement Aqua Theme inside windows and bounds, i.e. modify color panes and windows
Preliminary : in AquaSalGraphics::IsNativeControlSupported(), tabs are present :
case CTRL_TAB_ITEM: case CTRL_TAB_PANE: case CTRL_TAB_BODY: case CTRL_FIXEDBORDER: // ** TO DO + CHECK IF NEEDED ** { if( nPart == PART_ENTIRE_CONTROL || nPart == PART_TABS_DRAW_RTL ) return false; } break;
First try : use
HIThemeTabDrawInfo aTabDrawInfo
HIThemeTabPaneDrawInfo aTabPaneInfo
In AquaSalGraphics::drawNativeControl()
Starting point :
Controls not yet implemented
BOOL AquaSalGraphics::IsNativeControlSupported() returns true when control is one of the listed controls :
CTRL_FIXEDBORDER : a rectangular border, like a Tab Pane, but without the possible gap for a tab Probably not needed : CTRL_TOOLBAR : a toolbar control with buttons and a grip CTRL_MENUBAR : the menubar
Current state of native controls
Links
This work is part of http://wiki.services.openoffice.org/wiki/Mac_OS_X_Porting_-_Work_Areas/Todo%27s