blob: 075115c1161347dcf9fde1811e5153c872a85579 [file] [log] [blame]
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to you under the Apache License,
Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<document id="component-and-container">
<properties>
<title>Component &amp; Container</title>
</properties>
<body>
<p>
All Pivot components ultimately extend the base <tt>Component</tt> class. This class,
in conjunction with the similarly abstract <tt>Container</tt> class, defines the APIs
that specify where a component will appear on screen, what it will look like, and how a
user will interact with it.
</p>
<h3>Visual and ConstrainedVisual</h3>
<p><img src="component_and_container/visuals.png"/></p>
<p>
As shown in the diagram, <tt>Component</tt> implements the <tt>ConstrainedVisual</tt>
interface. This interface extends the <tt>Visual</tt> interface, which defines methods
common to all visual elements in Pivot. The <tt>org.apache.pivot.wtk.media.Image</tt>
class also implements the <tt>Visual</tt> interface:
</p>
<p>
<tt>public int getWidth()</tt><br/>
<tt>public int getHeight()</tt><br/>
<tt>public int getBaseline()</tt><br/>
<tt>public void paint(Graphics2D graphics)</tt><br/>
</p>
<p>
A visual's size (reported by the <tt>getWidth()</tt> and <tt>getHeight()</tt> methods)
is specified in "device-independent units". Though these generally map
one-to-one to actual pixels on an output device, they are not required to do so. This
allows Pivot applications to be written in a resolution-independent manner, supporting
UI scaling either for accessibility purposes or for very high resolution output devices.
</p>
<p>
The <tt>getBaseline()</tt> method allows a visual to report a baseline offset, which
is used by containers that support it to align components to a common baseline.
The <tt>paint()</tt> method is called as needed to ensure that the visual's current
state is correctly represented on-screen. For example, a component may need to be
repainted when an internal value, such as a button's label, has changed, or when some
part of the component has been exposed due to an overlapping window or other component
having been moved or resized.
</p>
<p>
<tt>ConstrainedVisual</tt> adds methods to support layout, which is discussed in more
detail below:
</p>
<p>
<tt>public void setSize(int width, int height)</tt><br/>
<tt>public int getPreferredWidth(int height)</tt><br/>
<tt>public int getPreferredHeight(int width)</tt><br/>
<tt>public Dimensions getPreferredSize()</tt><br/>
<tt>public int getBaseline(int width, int height)</tt><br/>
</p>
<p>
In addition to <tt>Component</tt>, the <tt>Skin</tt> and <tt>Renderer</tt> interfaces
also extend <tt>ConstrainedVisual</tt>. In Pivot, a component's "skin" is responsible
for the visual representation of the component. As a result, <tt>Component</tt>
delegates the implementation of all <tt>ConstrainedVisual</tt> methods to the skin.
The skin may, in turn, delegate some renderering responsibility to one or more
renderers, which are used to paint some components' content (such as a button label or
a list item); this relationship is represented by the dotted line in the diagram.
Renderers are often implemented as extensions of the <tt>Component</tt> class, allowing
the component's implementation of <tt>ConstrainedVisual</tt> to be re-used (and giving
rise to the notion of renderers as "lightweight components").
</p>
<p>
Components are painted in the order in which they are defined in the parent container's
component sequence. The component sequence thus defines the "z-order" of the components
in the container: components are painted in ascending order, allowing higer components
to overlap lower ones. Z-order is often only noticeable at the window level - individual
components within an application are generally arranged such that the user can see and
readily interact with them. This process, called "layout management", is generally
handled automatically in a Pivot application, and is discussed next.
</p>
<h3>Layout</h3>
<p>
"Layout management" is the process of automatically determining how components should
be arranged on screen, as opposed to requiring the the developer to explicitly set
component size and position. Layout management is performed by all Pivot containers,
and is the responsibility of a container's skin.
</p>
<p>
<tt>ConstrainedVisual</tt>'s preferred size methods, <tt>getPreferredWidth()</tt>,
<tt>getPreferredHeight()</tt>, and <tt>getPreferredSize()</tt>, return information
about the size the visual "wants" to be. This is generally determined based on
attributes such as font size and border thickness, or, in the case of containers, by
recursively asking subcomponents about their own preferred sizes. Containers may use
this information to determine how to arrange their subcomponents during layout.
</p>
<p>
In Pivot, preferred sizes may optionally be constrained by passing a height constraint
value to <tt>getPreferredWidth()</tt> or a width constraint value to
<tt>getPreferredHeight()</tt>. This allows components to "wrap" their contents. For
example, a <tt>Label</tt> component with the "wrapText" style set to <tt>true</tt> will
report a preferred height that is tall enough to render its entire content by applying
line break logic using the given width constraint.
</p>
<p>
<tt>ConstrainedVisual</tt> defines an additional signature for <tt>getBaseline()</tt>
that takes <tt>width</tt> and <tt>height</tt> arguments. This allows a component to
report a constrained baseline given a possible width and height (for example, a
label whose content is vertically aligned to bottom will report a different baseline
than one that is vertically aligned to top when it is given more than its preferred
height).
</p>
<h3>Location and Visibility</h3>
<p>
<tt>Component</tt> defines several additional methods that are used by containers
during layout:
</p>
<p>
<tt>public int getX()</tt><br/>
<tt>public int getY()</tt><br/>
<tt>public Point getLocation()</tt><br/>
<tt>public void setLocation(int x, int y)</tt><br/>
<tt>public final void setLocation(Point location)</tt><br/>
</p>
<p>
These methods are used to manage a component's location, which is defined as an (x, y)
coordinate pair that is relative to the origin of its parent container.
</p>
<p>
<tt>public boolean isVisible()</tt><br/>
<tt>public void setVisible(boolean visible)</tt><br/>
</p>
<p>
These methods manage a component's visibility. A component that is not visible is not
painted. Layout containers will generally also exclude non-visible components from
layout.
</p>
<p>
Container skins use the preferred size and visibility values to determine how to
arrange their subcomponents. They first query the subcomponents for the preferred
values, and then use these values to set the components' actual size and location. As
a result, callers should generally not invoke the methods that set these properties
directly, since the container is likely to override any values set by the caller
during layout.
</p>
<p>
It is important to note that containers are not required to respect a component's
preferred size or visibility. For example, <tt>CardPane</tt> sets the size of its
subcomponent to the maximum preferred size of all its child components, and
<tt>TablePane</tt> sets the size of its components based on the width of its rows and
columns. However, most respect at least one, and many respect both.
</p>
<h3>Disabled Components</h3>
<p>
A component that is "enabled" is currently capable of receiving user input. A component
may be "disabled" to prevent it from receiving input from the user. For example,
buttons are often disabled to prevent a user from initiating an action that would not
be appropriate for the current state of the application. Most components display a
disabled state to indicate to the user that interaction is currently forbidden.
</p>
<p>
Note that, while a user is prevented from interacting with a disabled component,
programmatic interaction is still allowed. For example, it is still valid to set the
selection state of a disabled list view component in code, even though the user cannot
click on an item in the list to change the list's selection state.
</p>
<p>
Also note that disabling a container will prevent all child components of the container
from receiving input as well. Thus, there is no need to propagate the enabled state of
a container down to its children. When a component is either disabled or one of its
ancestors is disabled, it is said to be "blocked".
</p>
<h3>Focus Management</h3>
<p>
A component that is eligible to receive keyboard input is said to have the "input
focus", or simply "focus". Only one component is allowed to have the focus at any given
time. Not all components are focusable, though many are, including text inputs, buttons,
and list views, among others. It is up to a component's skin to decide whether or not it
is capable of receiving focus. In order to receive the focus, a component (and its
ancestry) must be enabled, visible, and focusable.
</p>
<p>
Generally, a focusable component will paint a slightly different state when it has the
focus as a visual cue to the user. For example, a text input may show a blinking
cursor, while a button might draw a dotted line around its label.
</p>
<p>
Clicking on a component with the mouse will usually transfer focus to that component.
However, focus can also be transferred between using the Tab (or Shift-Tab) key. This
is called "focus traversal". Each container provides a "focus traversal policy" that
defines how focus management is performed within the container. By default, most
containers use a default traversal policy that simply traverses child components in the
order in which they appear in the container's component sequence. However, windows use
a traversal policy that ensures that focus is never transferred out of the window
itself; tab panes employ a similar policy. However, callers and skin developers are
free to override these defaults and can install a custom traversal policy on any
container.
</p>
<h3>Cursors</h3>
<p>
A component's skin will generally ensure that an appropriate cursor is displayed when
the mouse is over the component. However, a caller may customize the component's cursor
using the <tt>setCursor()</tt> method of <tt>Component</tt>. Valid cursor values are
defined by the <tt>Cursor</tt> enum.
</p>
<h3>Styles</h3>
<p>
Styles are a means of customizing a component's appearance. They are implemented as
named properties exposed by a skin via the component. For example, a label skin might
define styles such as "font", "color", and "textDecoration", and a list view skin might
define styles including "font", "color", "selectionColor" and
"selectionBackgroundColor". These properties correspond directly to the Java bean
getters and setters defined by the skin class.
</p>
<p>
By design, skins are programmatically hidden from the developer; a caller interacts
with a skin's styles via the component's style collection, an instance of
<tt>org.apache.pivot.wtk.Component.StyleDictionary</tt> returned by
<tt>Component#getStyles()</tt>:
</p>
<p>
<tt>public Object get(String key) - returns the value of a given style</tt><br/>
<tt>public Object put(String key, Object value) - sets a style value</tt><br/>
</p>
<p>
This facilitates a loose, flexible coupling between an application and a skin: an
application need not be tied to a particular skin implementation, and skin developers
are free to add or remove styles without the risk of breaking existing applications.
However, it becomes the responsibility of the caller to be aware of the styles
supported by the current skin. Attempting to set a non-existent style value will
simply generate a warning, but passing an invalid type for a valid style will throw
an exception.
</p>
<p>
Style values can be set in BXML using the "styles" attribute. The value of this
attribute is a JSON-formatted string representing the style values to be applied to
the component after it is constructed. For example, the following attribute applied to
the Label element would produce a bold, 24-point Arial label with red text:
</p>
<p>
<tt>styles="{font:'Arial bold 24', color:'#ff0000'}"</tt><br/>
</p>
<p>
Styles can also be set using a <tt>&lt;styles&gt;</tt> sub-element:
</p>
<p>
<tt>&lt;styles font="Arial bold 24" color="#ff0000"&gt;</tt><br/>
</p>
<p>
Finally, styles can be applied via CSS-like stylesheets. Both typed and untyped
selectors are supported. For example:
</p>
<source type="jscript">
{ Button: {
color: "#aa0000"
},
RadioButton: {
color: "#00aa00"
},
"org.apache.pivot.wtk.PushButton": {
color: "#0000aa"
},
heading: {
font: {
size: "120%",
bold: true
},
color: "#000000"
},
subHeading: {
font: {
size: "110%",
italic: true
},
color: "#666666"
}
}
</source>
<h3>Attributes</h3>
<p>
Attributes are a means of attaching container-specific properties to a component.
Attributes are typed values defined by containers that support or require them. For
example, <tt>TabPane</tt> defines a "label" attribute that allows a caller to specify
the text that is displayed on the tab button for the component; <tt>TablePane</tt>
defines a "rowSpan" attribute that determines how a cell is laid out. Attributes
effectively allow a caller to "tag" a component with values that are relevant only to
its parent container (and the container's skin).
</p>
<p>
Callers can set attribute values programmatically using a static setter method of
the <tt>Container</tt> subclass (e.g. <tt>TabPane#setLabel(Component, String)</tt>).
Alternatively, attributes can be specified in BXML. For example, the sub-elements of
a <tt>TabPane</tt> can provide a <tt>TabPane.label</tt> attribute to specify the value
that should be used as the text label for that component.
</p>
<h3>Events</h3>
<p>
In GUI programming, the term "event" generally refers to a notification sent by a
program in response to some triggering action. The trigger may have been input from
the user, a response from a remote server, or a change in some internal state.
</p>
<p>
Pivot components rely heavily on events, both to respond to change notifications from
data models or other components and to notify external listeners of changes to their
own states. Each concrete component class defines a set of events specific to its own
implementation, and all components inherit a set of common events defined by the base
<tt>Component</tt> and <tt>Container</tt> classes.
</p>
<p>
Events are often placed into groups that share some common
characteristics. For example, <tt>Component</tt> defines a set of mouse button events
that include "mouse down", "mouse up", and "mouse click". Components maintain a list
of listeners who have registered interest in a particular group of events, and each
listener is notified, in turn, as events occur.
</p>
<p>
Event listeners implement a listener interface defined for a particular group. For
example, component mouse listeners implement the ComponentMouseListener interface,
which defines the following methods:
</p>
<p>
<tt>public void mouseMove(Component component, int x, int y)</tt><br/>
<tt>public void mouseOver(Component component)</tt><br/>
<tt>public void mouseOut(Component component)</tt><br/>
</p>
<p>
A caller that implements the <tt>ComponentMouseListener</tt> interface can add itself
as a listener by calling <tt>Component#getComponentMouseListeners().add()</tt>.
Conversely, a listener can remove itself via the
<tt>Component#getComponentMouseButtonListeners().remove()</tt> method. Other event
listeners are registered and unregistered similarly.
</p>
<p>
<tt>Component</tt> defines the following event listener interfaces that are inherited
by all component subclasses:
</p>
<ul>
<li>
<p>
<b>ComponentListener</b> - defines events related to core component properties
including location, size, visibility, etc.
</p>
</li>
<li>
<p>
<b>ComponentStateListener</b> - defines events related to component enabled and
focus state.
</p>
</li>
<li>
<p>
<b>ComponentStyleListener</b> - defines events related to component
styles.
</p>
</li>
<li>
<p>
<b>ComponentDecoratorListener</b> - defines events related to component
decorators.
</p>
</li>
<li>
<p>
<b>ComponentMouseListener</b> - defines events that are fired when the mouse
is positioned over the component.
</p>
</li>
<li>
<p>
<b>ComponentMouseButtonListener</b> - defines mouse button events.
</p>
</li>
<li>
<p>
<b>ComponentMouseWheelListener</b> - defines mouse wheel events.
</p>
</li>
<li>
<p>
<b>ComponentKeyListener</b> - defines events that are fired when the component
has the input focus.
</p>
</li>
<li>
<p>
<b>ComponentTooltipListener</b> - defines events that are related to component
tooltips.
</p>
</li>
<li>
<p>
<b>ComponentDataListener</b> - defines events that are fired when component
user data changes.
</p>
</li>
<li>
<p>
<b>ComponentClassListener</b> - defines events that are fired when class-level
component properties change.
</p>
</li>
</ul>
<p>
The <tt>Container</tt> class defines the following additional events that are inherited
by its subclasses:
</p>
<ul>
<li>
<p>
<b>ContainerListener</b> - defines events related to core container properties
including insertion/removal of components.
</p>
</li>
<li>
<p>
<b>ContainerMouseListener</b> - defines events that are fired when the mouse
is positioned over the container.
</p>
</li>
</ul>
<p>
Note that both <tt>Component</tt> and <tt>Container</tt> define interfaces related to
mouse events. Container mouse events are "tunneling" events, and are fired as an event
is propagated down the container hierarchy, whereas component mouse events are
"bubbling" events, and are fired as the event moves up the container hierarchy. In
other words, the parent of a component will receive a container mouse event before the
component does, but the component will recieve a component mouse event before its
parent does.
</p>
<p>
Tunneling and bubbling events can be "consumed" by a listener. When a tunneling event
is consumed, it will not be propagated further down the component hierarchy.
Conversely, when a bubbling event is consumed, it will not be propagated further up
the hierarchy. This allows a caller to prevent a descendant from receiving a tunneling
event or an ancestor from receiving a bubbling event. Note, however, that it does
not prevent other listeners at the same level in the hierarchy from receiving the event.
Consuming an event only prevents it from progressing further up or down the hierarchy.
</p>
</body>
</document>