- Inherits from:
- NSView : NSResponder : NSObject
- Package:
- com.apple.yellow.application
An NSRulerView displays a ruler and markers above or to the side of an NSScrollView's document view. Views within the NSScrollView can become clients of the ruler view, having it display markers for their elements, and receiving messages from the ruler view when the user manipulates the markers.
setHasHorizontalRuler | (NSScrollView) |
setHasVerticalRuler | (NSScrollView) |
Constructor | . |
setClientView | Changes the ruler's client view. |
setMarkers | Sets the markers displayed by the ruler view. |
setAccessoryView | Sets the accessory view. |
trackMarker | Allows the user to add a new marker. |
An NSRulerView resides in an NSScrollView, displaying a labeled ruler and markers for its client, the document view of the NSScrollView or a subview of the document view. The client view can add and remove markers representing its contents, such as graphic elements, margins, and text tabs. The NSRulerView tracks user manipulation of the markers and informs the client view of those actions. NSRulerView handles both horizontal and vertical rulers, which are tiled in the scroll view above and to the side of the content view, respectively. NSRulerViews are sometimes called simply ruler views or even rulers.
A ruler view comprises three regions. First is the ruler area, where the ruler's baseline, hash marks, and labels are drawn. The ruler area is largely static, but it scales its hash marks to document view's coordinate system, and can display the hash marks in arbitrary units. The second region is the marker area, where ruler markers (NSRulerMarker objects) representing elements of the client view are displayed. This is a more dynamic area, changing with the selection and state of the client view. The final region is the accessory view area, which is by default not present but appears when you add an accessory view to the ruler view. An accessory view can contain additional controls for manipulating the ruler's client view, such as alignment buttons or a set of markers that can be dragged onto the ruler.
A ruler view interacts with its client view in several ways. On appropriating the ruler view, the client view usually sets it up according to its needs. The client view can also dynamically update the ruler view's markers as its layout changes. In its turn, the ruler view informs the client view of actions the user takes on the ruler markers, allowing the client view to approve or limit the actions and to update its state based on the results of the actions.
The appearance of a ruler is based on both the document view and the client view. The document view, as the backdrop within the scroll view, serves as the canvas on which any client views are laid. Because of the document view's anchoring role, a ruler always draws its hash marks and labels relative to the document view's coordinate system. A vertical ruler also checks whether the document view is flipped and acts accordingly. However, the ruler view treats subviews of the document view as items laid out within the coordinate system defined by the document view, and so doesn't change its hash marks when a client view other than the document view is moved or scaled. For the client view's convenience it does, however, express marker locations in the client view's coordinate system. A few other operations that ruler views perform are defined in terms of the ruler's own coordinate system. The discussion of a feature or method makes clear which coordinate system applies. For reference, this table summarizes all of the coordinate systems involved in using ruler views, and the operations based on them:
Coordinate System | Used for |
Client view | Marker locations |
Document view | Calculating hash marks based on measurement units and scaling, origin offset for zero marks |
Ruler view | Temporary rulerlines, component layout |
Marker image | Image origin (which locates the image relative to the marker location) |
A new ruler view automatically uses the user's preferred
measurement units for drawing hash marks and labels, as stored in
the user defaults system under the key "MeasurementUnit
".
If your application allows the user to change his preferred measurement
units, you can change them at run time using setMeasurementUnits, which takes
the name of the units to use, such as "Inches" or "Centimeters",
and causes the ruler view to use that unit definition in spacing
its hash marks and labels.
NSRulerView supports the units Inches, Centimeters, Points, and Picas by default. If your application uses other measurement units, your application should define and register them before creating any ruler views. To do, use the class method registerUnit. Your application can register these wherever it's most convenient, such as in the NSApplication delegate method applicationDidFinishLaunching.
Adding a ruler view to a scroll view can be as simple as invoking NSScrollView's setHasHorizontalRuler and setHasVerticalRuler methods. These create instances of the default ruler view class, which you can change using the NSScrollView class method setRulerViewClass. You can also set ruler views directly on a per-instance basis using setHasHorizontalRuler and setHasVerticalRuler. Once you've added rulers to a scroll view, you can hide and reveal them using setRulersVisible.
Beyond creating the rulers, you need take only a few steps to set them up properly for use by the views contained within the scroll view: locating the zero marks of the rulers, and reserving room for accessory views. You normally perform these steps only once, when setting up the NSScrollView with rulers. However, if you allow the user to reset document attributes such as margins, you should change the zero mark locations as well. Also, if you reuse the scroll view by swapping in a new document view you may need to set up the rulers again with different settings.
The first step is to determine where you want the zero marks of the rulers to be located relative to the bounds origin of the document view. The zero marks are coincident with the bounds origin by default, but you can change this with the method setOriginOffset. This method takes an offset specified in the document view's coordinate system. If you need to set the origin offset based on a point in a subview of the document view, such as a text view that's inset on a page, use convertPointFromView to realize it in the document view's coordinate system.
After placing the zero marks, you should set up your rulers so that they don't change in size as the user works within the document view. For example, if two different subviews of the document view use different accessory views, the ruler view enlarges itself as necessary each time you change the accessory view. Such changes are at best unsightly and at worst confusing to the user. To avoid this problem, calculate ahead of time the sizes of the largest accessory view and the largest markers, and set the ruler view's required thickness for these elements using setReservedThicknessForAccessoryView and setReservedThicknessForMarkers. For example, if you have two accessory views for the horizontal ruler, one 16.0 PostScript units high and the other 24.0, invoke setReservedThicknessForAccessoryView with an argument of 24.0.
Once the ruler view is fully set up, the scroll view's document view, or any subview of the document view, can become its client by sending it a setClientView message. This method notifies the prior client that it's losing the ruler view using the rulerViewWillSetClientView method, removes all of the ruler view's markers, and sets the new client view. A client view normally appropriates the ruler when it becomes first responder and keeps it until some other view appropriates it. After appropriating the ruler view, the client needs to set up its layout and markers.
If the client has a custom accessory view, it sets that using setAccessoryView. Clients without accessory views should avoid removing the ruler view's accessory view when appropriating the ruler, as this can cause unsightly screen flicker as the ruler is redrawn. It's better in this case for a client view that has an accessory view to implement rulerViewWillSetClientView, disabling the controls in the accessory view so that they're not active when other clients are using the ruler. Then, when the client view with the accessory view appropriates the ruler, it should set its accessory view again in case another client swapped the accessory view out, and reenable the controls.
Aside from the layout of the ruler view itself, the client can also add markers to indicate the positions of its graphic elements, such as tabs and margins in text or the bounding boxes of drawn shapes or images. Each marker is an NSRulerMarker object, which displays a graphic image on the ruler at its given location, and can be associated with an object that identifies the attribute indicated by the marker. You initialize an NSRulerMarker using its constructor, which takes as arguments the NSRulerView where the marker will be displayed, its location on the ruler in the client view's coordinate system, the image to display, and the point within the image that lies on the ruler's baseline. Once you've created the markers, you can use NSRulerView's addMarker or setMarkers methods to put them on the ruler.
A new NSRulerMarker allows the user to drag it around on its ruler, but not to remove it. You can change these defaults by sending it setMovable and setRemovable messages. For example, you might make markers representing tabs in text removable to allow the user to edit the paragraph settings.
Markers bear one additional attribute, which allows you to distinguish among multiple markers, specifically markers that share the same image. This is the represented object, set with NSRulerMarker's setRepresentedObject method. A represented object can simply be a string identifying a generic attribute, such as "Left Margin" or "Right Margin". It can also be an object stored in the client view or in the selection; for example, the text system records tab stops as NSTextTab objects, which include the tab location and its alignment. When the user manipulates a tab marker, the client can simply retrieve its represented object to get the tab being affected.
A single client view may contain many selectable items, such as graphic shapes or paragraphs of text with different ruler settings. When the selection changes, the client must reset the ruler view's markers based on the new selection. This kind of updating is fairly straightforward and can be performed as described above for situations where the client view itself changes.
Another kind of updating is needed when you wish to support dynamic updating of ruler markers as the user manipulates the elements of the client view. For example, when the user moves a shape, you want the ruler markers to relocate when the user finishes moving it. Any method that changes relevant attributes of the selection should update the ruler markers, whether by replacing them wholesale or by checking each one present and updating its location.
You can even put such updating code within a modal loop that handles dragging items around in the client view, so that the markers track the position of the selected item. This can be a fairly heavyweight operation to perform while also handling movement of the selected item, however. In support of a lighter weight means of showing this information, NSRulerView allows you to draw temporary rulerlines that can be drawn and erased very quickly. One method, moveRulerline, controls the drawing of rulerlines. It takes two locations expressed in the NSRulerView's coordinate system, erasing the rulerline at the old location and redrawing it at the new. To create a new rulerline, specify -1.0 as the old location; to erase one completely, specify -1.0 as the new location. Although you're responsible for keeping track of the locations to erase and redraw, this isn't as cumbersome or inefficient as sifting through or replacing the markers themselves.
While a ruler's client view must perform the work of determining marker locations and placing them on the ruler, the ruler itself handles all the work of tracking user manipulations of the markers, sending messages to the client view that inform it of the changes before they begin, as they occur, and after they finish. The client view can use these messages to update its own state. The following sections describe the individual processes of moving, removing, and adding markers, along with a special method for handling mouse events in the ruler area.
When the user presses the mouse button over a ruler marker,
NSRulerView sends the marker a trackMouseToAddMarker message.
If the marker isn't movable this method does nothing and immediately
returns false
. If it is movable,
then it sends the client a series of messages allowing it to determine
how the user can move the marker around on the ruler.
First of these messages is rulerViewShouldMoveMarker, which
allows the client view to prevent an otherwise movable marker from
being moved. Normally, whether a marker can be moved should be set
on the marker itself, but there are situations, such as where items
can be locked in place, where this is more properly tracked by the
client view instead. If the client view returns true
,
allowing the movement, then it receives a series of rulerViewWillMoveMarker messages
as the user drags the marker around. Each message identifies the
marker being moved and its proposed new location in the client view's
coordinate system. The client view can return an altered location
to restrict the marker's movement, or update its display to reflect
the new location. Finally, when the user releases the mouse button,
the client receives a rulerViewDidMoveMarker,
on which it can update its state and clean up any information it
may have used while tracking the marker's movements.
Removal of markers is handled by a similar set of messages. However, these are always sent during a movement operation, as the user must first be dragging a marker within the ruler to be able to drag it off the ruler. If a marker isn't set to be removable, the user simply can't drag it off. If the marker is removable, then when the user drags the mouse far enough away from the ruler's baseline, it sends the client view a rulerViewShouldRemoveMarker message, allowing the client to approve or veto the removal. No messages are necessary for new locations, of course, but if the user returns the marker to the ruler then it resumes sending rulerViewWillMoveMarker messages as before. If the user releases the mouse with the marker dragged away from the ruler, the marker sends the client view a rulerViewDidRemoveMarker message, so the user can delete the item or attribute represented by the marker.
User addition of a marker must be initiated by the application, of course, since there is no marker yet for the ruler to track. The first step in adding a marker, then, is to create one, using NSRulerMarker's constructor method. Once the new marker is created, you instruct the ruler view to handle dragging it onto itself by sending it a trackMarker message. One means of doing this is to use the mouse event from the client view method rulerViewHandleMouseDown, as described in "Handling Mouse Events in the Ruler Area" below. Another is to create a custom view object-which typically resides in the ruler's accessory view-that displays prototype markers, and that handles a mouse-down event by creating a new marker for the ruler and invoking trackMarker with the new marker and that mouse-down event.
Once you've initiated the addition process, things proceed
in the same manner as for moving a marker. The ruler view sends
the new marker a trackMouseToAddMarker message,
with true
as the second argument
to indicate that the marker isn't merely being moved. The marker
being added then sends the client view a rulerViewShouldAddMarker message,
and if the client approves then it repeatedly sends rulerViewWillAddMarker messages
as the user moves the marker around on the ruler. The user can drag
the marker away to avoid adding it, or release the mouse button
over the ruler, in which case the client receives a rulerViewDidAddMarker message.
As with moving a marker, you should consider enabling and disabling in a more immediate fashion than by the client view method if possible. If the user shouldn't be able to drag a marker from the accessory view, for example, the view containing the prototype marker should disable itself and indicate this in its appearance, rather than allowing the user to drag a marker out only to discover that the ruler won't accept it.
In addition to handling user manipulation of markers, a ruler informs its client view when the user presses the mouse button while the mouse is inside the ruler area (where hash marks are drawn), by sending it a rulerViewHandleMouseDown message. This allows the client view to take some special action, such as adding a new marker to the ruler, as described above. This approach works well when it's quite clear what kind of marker will be created. The client view can also use this message as a cue to change its display in some way; for example to add or remove a guideline that assists the user in laying out and aligning items in the view.
- Constructors
- NSRulerView
- Altering measurement units
- registerUnit
- setMeasurementUnits
- measurementUnits
- Setting the client view
- setClientView
- clientView
- Setting an accessory view
- setAccessoryView
- accessoryView
- Setting the zero mark position
- setOriginOffset
- originOffset
- Adding and removing markers
- setMarkers
- markers
- addMarker
- removeMarker
- trackMarker
- Drawing temporary rulerlines
- moveRulerline
- Drawing
- drawHashMarksAndLabelsInRect
- drawMarkersInRect
- invalidateHashMarks
- Ruler layout
- setScrollView
- scrollView
- setOrientation
- orientation
- setReservedThicknessForAccessoryView
- reservedThicknessForAccessoryView
- setReservedThicknessForMarkers
- reservedThicknessForMarkers
- setRuleThickness
- ruleThickness
- requiredThickness
- baselineLocation
- isFlipped
public NSRulerView()
public NSRulerView(NSRect aRect)
public NSRulerView(
NSScrollView aScrollView,
int orientation)
HorizontalRuler
or VerticalRuler
)
within aScrollView. The
new ruler view displays the user's preferred measurement units,
and has no client, markers, or accessory view. Unlike most subclasses
of NSView, no initial frame rectangle is given for NSRulerView;
its containing NSScrollView adjusts its frame rectangle as needed.public static void registerUnit(
String unitName,
String abbreviation,
float conversionFactor,
NSArray stepUpCycle,
NSArray stepDownCycle)
NSRulerView supports these units by default:
Unit Name | Abbreviation | Points/Unit | Step-up Cycle | Step-down Cycle |
Inches | in | 72.0 | 2.0 | 0.5 |
Centimeters | cm | 28.35 | 2.0 | 0.5, 0.2 |
Points | pt | 1.0 | 10.0 | 0.5 |
Picas | pc | 12.0 | 10.0 | 0.5 |
See Also: setMeasurementUnits
public NSView accessoryView()
See Also: setAccessoryView, reservedThicknessForAccessoryView
public void addMarker(NSRulerMarker aMarker)
See Also: setMarkers, removeMarker, markers, trackMarker
public float baselineLocation()
See Also: ruleThickness
public NSView clientView()
See Also: setClientView
public void drawHashMarksAndLabelsInRect(NSRect aRect)
See Also: invalidateHashMarks, drawMarkersInRect
public void drawMarkersInRect(NSRect aRect)
See Also: reservedThicknessForMarkers, drawHashMarksAndLabelsInRect
public void invalidateHashMarks()
See Also: drawHashMarksAndLabelsInRect
public boolean isFlipped()
true
if
the NSRulerView's coordinate system is flipped, false
otherwise. A
vertical ruler takes into account whether the coordinate system
of the NSScrollView's document view-not the receiver's client
view-is flipped. A horizontal ruler is always flipped.public NSArray markers()
See Also: setMarkers, addMarker, removeMarker, markerLocation (NSRulerMarker)
public String measurementUnits()
See Also: setMeasurementUnits, registerUnit
public void moveRulerline(
float oldLoc,
float newLoc)
This method is useful for drawing highlight lines in the ruler to show the position or extent of an object while it's being dragged in the client view. The sender is responsible for keeping track of the number and positions of temporary lines-the NSRulerView only does the drawing.
public int orientation()
HorizontalRuler
or VerticalRuler
.See Also: setOrientation
public float originOffset()
See Also: setOriginOffset
public void removeMarker(NSRulerMarker aMarker)
See Also: setMarkers, addMarker
public float requiredThickness()
See Also: ruleThickness, reservedThicknessForMarkers, reservedThicknessForAccessoryView
public float reservedThicknessForAccessoryView()
public float reservedThicknessForMarkers()
See Also: thicknessRequiredInRuler (NSRulerMarker)
public float ruleThickness()
See Also: setRuleThickness
public NSScrollView scrollView()
See Also: setScrollView, setHorizontalRulerView (NSScrollView), setVerticalRulerView (NSScrollView)
public void setAccessoryView(NSView aView)
null
and
the receiver has no client view.See Also: accessoryView, reservedThicknessForAccessoryView
public void setClientView(NSView aView)
See Also: clientView
public void setMarkers(NSArray markers)
null
or empty to remove all ruler markers. Throws an InternalInconsistencyException
if markers is not null
and the receiver
has no client view.See Also: addMarker, removeMarker
public void setMeasurementUnits(String unitName)
See Also: measurementUnits
public void setOrientation(int orientation)
HorizontalRuler
or VerticalRuler. You
should never need to invoke this method directly-it's automatically
invoked by the containing NSScrollView.See Also: orientation
public void setOriginOffset(float offset)
See Also: originOffset
public void setReservedThicknessForAccessoryView(float thickness)
An NSRulerView automatically increases the reserved thickness as necessary to that of the accessory view. When the accessory view is thinner than the reserved space, it's centered in that space. If you plan to use several accessory views of different sizes, you should set the reserved thickness beforehand to that of the thickest accessory view, in order to avoid retiling of the NSScrollView.
See Also: reservedThicknessForAccessoryView, setAccessoryView, setReservedThicknessForMarkers
public void setReservedThicknessForMarkers(float thickness)
An NSRulerView automatically increases the reserved thickness as necessary to that of its thickest marker. If you plan to use markers of varying sizes, you should set the reserved thickness beforehand to that of the thickest one in order to avoid retiling of the NSScrollView.
See Also: reservedThicknessForMarkers, setMarkers, setReservedThicknessForAccessoryView, thicknessRequiredInRuler (NSRulerMarker)
public void setRuleThickness(float thickness)
See Also: ruleThickness
public void setScrollView(NSScrollView scrollView)
See Also: scrollView, setHorizontalRulerView (NSScrollView), setVerticalRulerView (NSScrollView)
public boolean trackMarker(
NSRulerMarker aMarker,
NSEvent theEvent)
true
if
the receiver adds aMarker, false
if
it doesn't. This method works by sending trackMouseToAddMarker to aMarker with theEvent and true
as
arguments.An application typically invokes this method in one of two cases. In the simpler case, the client view can implement rulerViewHandleMouseDown to invoke this method when the user presses the mouse button in the NSRulerView's ruler area. This technique is appropriate when it's clear what kind of marker will be added by clicking in the ruler area. The second, more general, case involves the application providing a palette of different kinds of markers that can be dragged onto the ruler, from the ruler's accessory view or from some other place. With this technique the palette tracks the mouse until it enters the ruler view, at which time it hands over control to the ruler view by invoking trackMarker.
See Also: addMarker, setMarkers
public abstract void rulerViewDidAddMarker(
NSRulerView aRulerView,
NSRulerMarker aMarker)
See Also: representedObject (NSRulerMarker), markerLocation (NSRulerMarker)
public abstract void rulerViewDidMoveMarker(
NSRulerView aRulerView,
NSRulerMarker aMarker)
See Also: representedObject (NSRulerMarker), markerLocation (NSRulerMarker)
public abstract void rulerViewDidRemoveMarker(
NSRulerView aRulerView,
NSRulerMarker aMarker)
See Also: representedObject (NSRulerMarker)
public abstract void rulerViewHandleMouseDown(
NSRulerView aRulerView,
NSEvent theEvent)
public abstract boolean rulerViewShouldAddMarker(
NSRulerView aRulerView,
NSRulerMarker aMarker)
true
the ruler view accepts
the new marker and begins tracking its movement; if the client returns false
the
ruler view refuses the new marker.See Also: rulerViewWillAddMarker
public abstract boolean rulerViewShouldMoveMarker(
NSRulerView aRulerView,
NSRulerMarker aMarker)
true
the ruler
view allows the user to move the marker; if the client returns false
the
marker doesn't move.The user's ability to move a marker is typically set on the marker itself, using NSRulerMarker's setMovable method. You should use this client view method only when the marker's movability can vary depending on a variable condition (for example, if graphic items can be locked down to prevent them from being inadvertently moved).
See Also: rulerViewWillMoveMarker
public abstract boolean rulerViewShouldRemoveMarker(
NSRulerView aRulerView,
NSRulerMarker aMarker)
true
the ruler
view allows the user to remove the marker; if the client returns false
the
marker is kept pinned to the ruler's baseline. This message is
sent as many times as needed while the user drags the marker.The user's ability to remove a marker is typically set on the marker itself, using NSRulerMarker's setRemovable method. You should use this client view method only when the marker's removability can vary while the user drags it (for example, if the user must press the Shift key to remove a marker).
public abstract float rulerViewWillAddMarker(
NSRulerView aRulerView,
NSRulerMarker aMarker,
float location)
See Also: rulerViewWillMoveMarker
public abstract float rulerViewWillMoveMarker(
NSRulerView aRulerView,
NSRulerMarker aMarker,
float location)
See Also: rulerViewWillAddMarker
public abstract void rulerViewWillSetClientView(
NSRulerView aRulerView,
NSView newClient)