Toolbars and Toolboxes
- Feature Owner
- Mike Pinkerton
A toolbar is a strip that contains a set of widgets
called toolbar items. The toolbar can lay out its
components either horizontally or vertically, and it can
optionally wrap to multiple rows/columns. (In fact, a
toolbar is really just an extension of the
box
element. See The
Box System for details.)
The toolbar is specified using the
toolbar
tag. The attribute
align
is used to specify
whether or not the toolbar is a horizontal toolbar or a
vertical toolbar. If this attribute is omitted, the toolbar
will lay out its children horizontally.
The align attribute should be moved into CSS, but for now it must be specified as an attribute on the toolbar.
<toolbar align="vertical"> <html:button>Button One</html:button> <html:button>Button Two</html:button> <html:button>Button Three</html:button> </toolbar>
Toolbars are capable of supporting drag and drop operations by manipulating its DOM subtree. The drag and drop code for toolbars can also provide feedback for insertion before, after, or on other items on the toolbar. In order for this code to work, the contents of the toolbar (e.g., buttons and input fields) must be grouped into a single container within the toolbar, but that container can be an arbitrary child of the toolbar. See below for more details on drag and drop.
A toolbar item is also an extension of a box and it can therefore contain arbitrary HTML and XUL content that is treated as a single toolbar item for the purposes of drag and drop, deletion operations on the toolbar, cut and paste of toolbar items, and context/popup menus on toolbar items.
The toolbar item can lay out its contents horizontally or
vertically (with horizontal being the default) using the
align
attribute.
<toolbar> <toolbaritem> <html:button>Button One</html:button> </toolbaritem> <toolbaritem> <html:button>Button Two</html:button> </toolbaritem> <toolbaritem> <html:img src="icon.gif"/>Input Label: <html:input/> </toolbaritem> </toolbar>
A toolbar's contents can be marked as unmodifiable by
setting the readonly
attribute
on the toolbar. Toolbars with this attribute set will
disallow any drops into their content area, and they will
not allow their contents to be altered in any way.
Although toolbars can be embedded directly in the window,
they are commonly placed inside another object called the
toolbox. The toolbox is represented using the
toolbox
tag. A toolbox contains
one or more toolbars as children, and it surfaces the UI
that allows the toolbars within the toolbox to be reordered
and collapsed.
When a toolbar is placed inside of a toolbox, it acquires a stripe on its left hand side (if the toolbox stacks its components) or on its top side (if the toolbox is horizontal). This stripe is affectionately referred to as the grippy, and it is the object that the user manipulates in order to move the toolbar around or to collapse it.
Collapsed toolbars appear in a thin strip at the bottom of the toolbox (if vertical) or the right of the toolbox (if horizontal). This strip is only shown if at least one of the toolbars in the toolbox is collapsed.
<toolbox> <toolbar id="Command Toolbar"> <html:button>Button One</html:button> </toolbar> <toolbar id="Personal Toolbar> <html:button>Button Two</html:button> </toolbar> <toolbar id="Location Toolbar> <html:img src="icon.gif"/>URL: <html:input/> </toolbar> </toolbox>
When a toolbar is collapsed, an attribute called
collapsed
is set to true on the
toolbar element. When the toolbar is shown again, this
attribute is unset. If this attribute is specified in the
XUL file, it indicates that the initial state of the toolbar
is to be collapsed inside the toolbox, although a new state
may be stored persistently in order for the user's
visibility preferences to be retained. (See Persistence
and Sharing for details.)
The collapsed
attribute is
ignored if the toolbar is not contained in a toolbox.
The toolbar or toolbox can also be hidden using the
standard mechanism (in both HTML and XUL) for hiding content
elements: myToolbar.style.display = none
.
Showing the toolbar requires setting it back to
its original display type (which for toolbars is
block
).
The look of the toolbox grippies can be customized using
the pseudo elements
:toolbox-normal
and
:toolbox-rollover
. The former
is used by default for the grippies, and the latter is used
when the user mouses over the grippies.
:toolbox-rollover { background-color: #ccccff; background-image: url("resource:/res/toolbar/TB_Tab_mo.gif"); background-repeat: no-repeat; color: green; border-bottom: solid darkGray 1px; border-top: solid white 0px; border-left: solid white 0px; border-right: solid darkGray 1px; }
Toolbar Drag & Drop
Tracking During The Drag
The toolbars make use of a DOM event capturer to annotate
the toolbar's content node with information about where the
drag will go in order to draw the correct drop feedback.
Since toolbars can be arbitrarily complicated, however, the
capturer needs a little help figuring out which child frame
contains the drop area. This is done by setting the
dragdroparea
attribute on the
toolbar. If this attribute is not specified, the tracking
code assumes the toolbar frame is the drop area.
Here's an example of a toolbar with nested boxes for some complicated layout. The buttons that can be dragged around live within one of these nested boxes.
<toolbar id="PersonalToolbar" dragdroparea="innermostBox"> <box align="horizontal" flex="1" style="min-width: 1px"> <!-- button area of personal toolbar --> <box align="horizontal" flex="1" style="min-width: 1px; overflow: hidden" datasources="rdf:bookmarks" ref="NC:PersonalToolbarFolder"> <titledbutton> ... </box> </box> </toolbar>
The toolbar also needs a little help from the
ondragover
event handler to
trigger the drop feedback magic. The capturer always
annotates the toolbar with various attributes, but it might
not be valid to drop on the toolbar based on the contents of
the drag. When the event handler determines that a drag is
valid, it needs to touch the
dd-triggerrepaint
attribute on
the toolbar which triggers a repaint with the correct drop
feedback. By not touching this attribute, the toolbar will
not redraw and this prevents the feedback from appearing. If
you don't want drop feedback at all, this is how you'd
accomplish it.
function DragOverPersonalToolbar ( event ) { var validFlavor = false; var dragSession = null; var dragService = Components.classes["component://netscape/widget/dragservice"].getService(Components.interfaces.nsIDragService); if ( dragService ) { dragSession = dragService.getCurrentSession(); if ( dragSession ) { if ( dragSession.isDataFlavorSupported("moz/toolbaritem") ) validFlavor = true; else if ( dragSession.isDataFlavorSupported("text/plain") ) validFlavor = true; //XXX other flavors here... // touch the attribute to trigger the repaint with the drop feedback. if ( validFlavor ) { var toolbar = document.getElementById("PersonalToolbar"); toolbar.setAttribute ( "dd-triggerrepaint", 0 ); dragSession.canDrop = true; event.preventBubble(); } } } } // DragOverPersonalToolbar
Determining Where To Drop
The event capturer sets two attributes on the toolbar
during the drag tracking which are useful when the user
finally releases the mouse over the toolbar. The first is
dd-droplocation
which is an
integer index of the item before which the newly
dropped items should be inserted. This index is zero-based.
The second attribute,
dd-dropon
, tells if the drop
should go on (or into) a container on the toolbar. When this
is true, dd-droplocation
is the
item index of the container.
The toolbar determines if something is a container by
checking the container
attribute of the content node.
Customizing Drop Feedback
The drop feedback marker bar is normally black, but can
be customized on a particular toolbar via CSS. To do this,
use the :-moz-drop-marker
pseudoelement.
For example:
toolbar#PersonalToolbar:-moz-drop-marker { color: white; }