Dockable palettes have been around a long time, notably in Adobe's range of products, but in various forms have been widely used. Adobe's approach is to use a tabbed design, where a stack of palettes overlap and only the topmost one is fully displayed and is usable. Other apps have taken a different approach in recent times (notwithstanding Adobe's claim to a patent on the tabbed palettes approach), which is actually more useful in practice, though it takes up more screen space. In this design, palettes are stacked one above another, so they are all usable at any time. Palettes can be collapsed to reduce clutter and save space. The user is free to group palettes together in any way they wish and to pull palettes out into their own floating window if they want. This is the type of design presented here.
This code presents a general solution which can be used however you want. No content is supplied or assumed for the palettes - your code will arrange to add controls to these as necessary and link them to a controller. This code provides the view mechanism for displaying and docking the palettes and handling user interaction at this level, for example when dragging and dropping palettes to dock them, collapsing them, etc.
Two main classes are involved (with some other minor ones supporting). Your code will generally interact with the palette class - GCPaletteView. Palettes are grouped into docking stations - GCDockingStationView. For brevity this article refers to these as 'docks' - not to be confused with the Mac OS Dock. Generally your code doesn't need to work directly with docks - you can just set one up as a custom view in Interface Builder and it should "just work™"
When a palette is dragged out of a dock and dropped in empty space, by default this creates a floating window at that location containing the palette. This window will also accept additional palettes dragged from elsewhere, resizing as needed. A palette can be dragged out of a floating window and into any other dock, though by default dragging the topmost palette's title bar moves the window (to drag out such a palette, drag it by the background of its content area). There is nothing very special about these floating docks - they are simply floating utility windows that have a docking station view automatically added. However some appearances and behaviours are automatically modified when the dock knows it is part of such a window.
Dragging out the last palette from a floating window automatically closes and releases the window. Resizeable palettes in a window typically allow the window to be resized normally, i.e. both horizontally and vertically. Palettes in other docks are normally only resizeable vertically, and resize horizontally according to the usual sizing mask set up for the dock view itself. Palettes adopt the width of the dock they are dropped into.
Palettes are animated when they are moved when dragging and dropping to help give the user better feedback about what is happening. The animation does not rely on Core Animation in this version of the code so also works on 10.4.
GCPaletteView implements the palette. In making use of it, you can either subclass it or use it "as is" by supplying a separate content view. Subclassing is generally not required unless you want to substantially customise its appearance. To add content, one easy way is to set up a custom view in Interface Builder including all of the controls that you want to have, then get your controller to add this to a palette using the - setContentView: method.
To create a palette, you can either simply alloc+init one and then add it to an existing dock, or use the convenience method + newPaletteWithFrame:title:contentView: which will create a palette as a standalone floating window which you can then orderFront: to make visible on screen.
Most properties and some behaviours can be changed without subclassing. GCPaletteView has methods for setting the palette's title, whether it has close, collapse and resize controls, its sizing minima and maxima, and its content view.
There are also some compile-time customizations available by changing some of the defined constants. These include the title bar height, gaps and margins between palettes, and so forth.
With subclassing, you are free to alter everything. Code has been factored to make certain common tasks easy to accomplish. For example you can draw a different style of control or an entirely different style of title bar. Some common properties are supplied by class methods. These include the text style attributes used for palette titles, and whether the automatic creation of floating palettes is permitted, for example.
Some behaviours are implemented by the GCDockingStationView class. GCPaletteView works in concert with its dock to implement the overall scheme.
© 2006-2008 Graham Cox