xref: /haiku/src/preferences/appearance/FakeScrollBar.cpp (revision dfa8cf8c05bd7173fa5f25170bc297757175daab)
1928ffe6dSJohn Scipione /*
2928ffe6dSJohn Scipione  *  Copyright 2010-2012 Haiku, Inc. All rights reserved.
3928ffe6dSJohn Scipione  *  Distributed under the terms of the MIT license.
4928ffe6dSJohn Scipione  *
5928ffe6dSJohn Scipione  *	Authors:
6928ffe6dSJohn Scipione  *		DarkWyrm <bpmagic@columbus.rr.com>
7928ffe6dSJohn Scipione  *		John Scipione <jscipione@gmail.com>
8928ffe6dSJohn Scipione  */
9928ffe6dSJohn Scipione 
10928ffe6dSJohn Scipione 
11928ffe6dSJohn Scipione #include "FakeScrollBar.h"
12928ffe6dSJohn Scipione 
13928ffe6dSJohn Scipione #include <Box.h>
14928ffe6dSJohn Scipione #include <ControlLook.h>
15928ffe6dSJohn Scipione #include <Message.h>
16928ffe6dSJohn Scipione #include <ScrollBar.h>
17928ffe6dSJohn Scipione #include <Shape.h>
18928ffe6dSJohn Scipione #include <Size.h>
19928ffe6dSJohn Scipione #include <Window.h>
20928ffe6dSJohn Scipione 
21928ffe6dSJohn Scipione 
22928ffe6dSJohn Scipione typedef enum {
23928ffe6dSJohn Scipione 	ARROW_LEFT = 0,
24928ffe6dSJohn Scipione 	ARROW_RIGHT,
25928ffe6dSJohn Scipione 	ARROW_UP,
26928ffe6dSJohn Scipione 	ARROW_DOWN,
27928ffe6dSJohn Scipione 	ARROW_NONE
28928ffe6dSJohn Scipione } arrow_direction;
29928ffe6dSJohn Scipione 
30928ffe6dSJohn Scipione 
31928ffe6dSJohn Scipione FakeScrollBar::FakeScrollBar(bool drawArrows, bool doubleArrows,
32928ffe6dSJohn Scipione 	int32 knobStyle, BMessage* message)
33928ffe6dSJohn Scipione 	:
3412a7abb6SJohn Scipione 	BControl("FakeScrollBar", NULL, message, B_WILL_DRAW | B_NAVIGABLE),
35928ffe6dSJohn Scipione 	fDrawArrows(drawArrows),
36928ffe6dSJohn Scipione 	fDoubleArrows(doubleArrows),
37928ffe6dSJohn Scipione 	fKnobStyle(knobStyle)
38928ffe6dSJohn Scipione {
39928ffe6dSJohn Scipione 	SetExplicitMinSize(BSize(160, 20));
40928ffe6dSJohn Scipione 	SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, 20));
41928ffe6dSJohn Scipione }
42928ffe6dSJohn Scipione 
43928ffe6dSJohn Scipione 
44928ffe6dSJohn Scipione FakeScrollBar::~FakeScrollBar(void)
45928ffe6dSJohn Scipione {
46928ffe6dSJohn Scipione }
47928ffe6dSJohn Scipione 
48928ffe6dSJohn Scipione 
49928ffe6dSJohn Scipione void
50928ffe6dSJohn Scipione FakeScrollBar::Draw(BRect updateRect)
51928ffe6dSJohn Scipione {
52928ffe6dSJohn Scipione 	BRect bounds = Bounds();
53928ffe6dSJohn Scipione 
54928ffe6dSJohn Scipione 	rgb_color normal = ui_color(B_PANEL_BACKGROUND_COLOR);
55928ffe6dSJohn Scipione 
5612a7abb6SJohn Scipione 	if (IsFocus()) {
5712a7abb6SJohn Scipione 		// draw the focus indicator
5812a7abb6SJohn Scipione 		SetHighColor(ui_color(B_NAVIGATION_BASE_COLOR));
5912a7abb6SJohn Scipione 		StrokeRect(bounds);
6012a7abb6SJohn Scipione 		bounds.InsetBy(1.0, 1.0);
6112a7abb6SJohn Scipione 
6212a7abb6SJohn Scipione 		// Draw the selected border (1px)
63928ffe6dSJohn Scipione 		if (Value() == B_CONTROL_ON)
64928ffe6dSJohn Scipione 			SetHighColor(ui_color(B_CONTROL_MARK_COLOR));
65928ffe6dSJohn Scipione 		else
66928ffe6dSJohn Scipione 			SetHighColor(normal);
67928ffe6dSJohn Scipione 
6812a7abb6SJohn Scipione 		StrokeRect(bounds);
6912a7abb6SJohn Scipione 		bounds.InsetBy(1.0, 1.0);
7012a7abb6SJohn Scipione 	} else {
71928ffe6dSJohn Scipione 		// Draw the selected border (2px)
7212a7abb6SJohn Scipione 		if (Value() == B_CONTROL_ON)
7312a7abb6SJohn Scipione 			SetHighColor(ui_color(B_CONTROL_MARK_COLOR));
7412a7abb6SJohn Scipione 		else
7512a7abb6SJohn Scipione 			SetHighColor(normal);
7612a7abb6SJohn Scipione 
77928ffe6dSJohn Scipione 		StrokeRect(bounds);
78928ffe6dSJohn Scipione 		bounds.InsetBy(1.0, 1.0);
79928ffe6dSJohn Scipione 		StrokeRect(bounds);
80928ffe6dSJohn Scipione 		bounds.InsetBy(1.0, 1.0);
8112a7abb6SJohn Scipione 	}
82928ffe6dSJohn Scipione 
83928ffe6dSJohn Scipione 	// draw a gap (1px)
84928ffe6dSJohn Scipione 	SetHighColor(normal);
85928ffe6dSJohn Scipione 	StrokeRect(bounds);
86928ffe6dSJohn Scipione 	bounds.InsetBy(1.0, 1.0);
87928ffe6dSJohn Scipione 
88928ffe6dSJohn Scipione 	// draw a border around control (1px)
89928ffe6dSJohn Scipione 	SetHighColor(tint_color(normal, B_DARKEN_1_TINT));
90928ffe6dSJohn Scipione 	StrokeRect(bounds);
91928ffe6dSJohn Scipione 	bounds.InsetBy(1.0, 1.0);
92928ffe6dSJohn Scipione 
93928ffe6dSJohn Scipione 	BRect thumbBG = bounds;
94928ffe6dSJohn Scipione 	BRect bgRect = bounds;
95928ffe6dSJohn Scipione 
96928ffe6dSJohn Scipione 	if (fDrawArrows) {
97928ffe6dSJohn Scipione 		// draw arrows
98928ffe6dSJohn Scipione 		SetDrawingMode(B_OP_OVER);
99928ffe6dSJohn Scipione 
100928ffe6dSJohn Scipione 		BRect buttonFrame(bounds.left, bounds.top,
101928ffe6dSJohn Scipione 			bounds.left + bounds.Height(), bounds.bottom);
102928ffe6dSJohn Scipione 
103928ffe6dSJohn Scipione 		_DrawArrowButton(ARROW_LEFT, fDoubleArrows, buttonFrame, updateRect);
104928ffe6dSJohn Scipione 
105928ffe6dSJohn Scipione 		if (fDoubleArrows) {
106928ffe6dSJohn Scipione 			buttonFrame.OffsetBy(bounds.Height() + 1, 0.0);
107928ffe6dSJohn Scipione 			_DrawArrowButton(ARROW_RIGHT, fDoubleArrows, buttonFrame,
108928ffe6dSJohn Scipione 				updateRect);
109928ffe6dSJohn Scipione 
110928ffe6dSJohn Scipione 			buttonFrame.OffsetTo(bounds.right - ((bounds.Height() * 2) + 1),
111928ffe6dSJohn Scipione 				bounds.top);
112928ffe6dSJohn Scipione 			_DrawArrowButton(ARROW_LEFT, fDoubleArrows, buttonFrame,
113928ffe6dSJohn Scipione 				updateRect);
114928ffe6dSJohn Scipione 
115928ffe6dSJohn Scipione 			thumbBG.left += bounds.Height() * 2 + 2;
116928ffe6dSJohn Scipione 			thumbBG.right -= bounds.Height() * 2 + 2;
117928ffe6dSJohn Scipione 		} else {
118928ffe6dSJohn Scipione 			thumbBG.left += bounds.Height() + 1;
119928ffe6dSJohn Scipione 			thumbBG.right -= bounds.Height() + 1;
120928ffe6dSJohn Scipione 		}
121928ffe6dSJohn Scipione 
122928ffe6dSJohn Scipione 		buttonFrame.OffsetTo(bounds.right - bounds.Height(), bounds.top);
123928ffe6dSJohn Scipione 		_DrawArrowButton(ARROW_RIGHT, fDoubleArrows, buttonFrame, updateRect);
124928ffe6dSJohn Scipione 
125928ffe6dSJohn Scipione 		SetDrawingMode(B_OP_COPY);
126928ffe6dSJohn Scipione 
127928ffe6dSJohn Scipione 		bgRect = bounds.InsetByCopy(48, 0);
128928ffe6dSJohn Scipione 	} else
129928ffe6dSJohn Scipione 		bgRect = bounds.InsetByCopy(16, 0);
130928ffe6dSJohn Scipione 
131928ffe6dSJohn Scipione 	// fill background besides the thumb
132928ffe6dSJohn Scipione 	BRect leftOfThumb(thumbBG.left, thumbBG.top, bgRect.left - 1,
133928ffe6dSJohn Scipione 		thumbBG.bottom);
134928ffe6dSJohn Scipione 	BRect rightOfThumb(bgRect.right + 1, thumbBG.top, thumbBG.right,
135928ffe6dSJohn Scipione 		thumbBG.bottom);
136928ffe6dSJohn Scipione 
137928ffe6dSJohn Scipione 	be_control_look->DrawScrollBarBackground(this, leftOfThumb,
138928ffe6dSJohn Scipione 		rightOfThumb, updateRect, normal, 0, B_HORIZONTAL);
139928ffe6dSJohn Scipione 
140928ffe6dSJohn Scipione 	// Draw scroll thumb
141928ffe6dSJohn Scipione 
142928ffe6dSJohn Scipione 	// fill the clickable surface of the thumb
143928ffe6dSJohn Scipione 	be_control_look->DrawButtonBackground(this, bgRect, updateRect,
144928ffe6dSJohn Scipione 		normal, 0, BControlLook::B_ALL_BORDERS, B_HORIZONTAL);
145928ffe6dSJohn Scipione 
146*dfa8cf8cSJohn Scipione 	if (fKnobStyle == B_KNOB_STYLE_NONE)
147928ffe6dSJohn Scipione 		return;
148928ffe6dSJohn Scipione 
149928ffe6dSJohn Scipione 	// draw the scrollbar thumb knobs
150*dfa8cf8cSJohn Scipione 	bool square = fKnobStyle == B_KNOB_STYLE_DOTS;
151928ffe6dSJohn Scipione 	int32 hextent = 0;
152928ffe6dSJohn Scipione 	int32 vextent = 0;
153928ffe6dSJohn Scipione 
154928ffe6dSJohn Scipione 	if (square) {
155928ffe6dSJohn Scipione 		hextent = 2;
156928ffe6dSJohn Scipione 		vextent = 2;
157928ffe6dSJohn Scipione 	} else {
158928ffe6dSJohn Scipione 		hextent = 1;
159928ffe6dSJohn Scipione 		vextent = 3;
160928ffe6dSJohn Scipione 	}
161928ffe6dSJohn Scipione 
162928ffe6dSJohn Scipione 	float hmiddle = bgRect.Width() / 2;
163928ffe6dSJohn Scipione 	float vmiddle = bgRect.Height() / 2;
164928ffe6dSJohn Scipione 
165928ffe6dSJohn Scipione 	BRect middleKnob = BRect(bgRect.left + hmiddle - hextent,
166928ffe6dSJohn Scipione 		bgRect.top + vmiddle - vextent,
167928ffe6dSJohn Scipione 		bgRect.left + hmiddle + hextent,
168928ffe6dSJohn Scipione 		bgRect.top + vmiddle + vextent);
169928ffe6dSJohn Scipione 
170928ffe6dSJohn Scipione 	BRect leftKnob = middleKnob.OffsetByCopy(hextent * -4, 0);
171928ffe6dSJohn Scipione 	if (leftKnob.left > bgRect.left + hextent) {
172928ffe6dSJohn Scipione 		be_control_look->DrawButtonBackground(this, leftKnob, updateRect,
173928ffe6dSJohn Scipione 			normal, 0, BControlLook::B_ALL_BORDERS, B_HORIZONTAL);
174928ffe6dSJohn Scipione 	}
175928ffe6dSJohn Scipione 
176928ffe6dSJohn Scipione 	BRect rightKnob = middleKnob.OffsetByCopy(hextent * 4, 0);
177928ffe6dSJohn Scipione 	if (rightKnob.right < bgRect.right - hextent) {
178928ffe6dSJohn Scipione 		be_control_look->DrawButtonBackground(this, rightKnob, updateRect,
179928ffe6dSJohn Scipione 			normal, 0, BControlLook::B_ALL_BORDERS, B_HORIZONTAL);
180928ffe6dSJohn Scipione 	}
181928ffe6dSJohn Scipione 
182928ffe6dSJohn Scipione 	// draw middle knob last because it modifies middleKnob
183928ffe6dSJohn Scipione 	be_control_look->DrawButtonBackground(this, middleKnob, updateRect,
184928ffe6dSJohn Scipione 		normal, 0, BControlLook::B_ALL_BORDERS, B_HORIZONTAL);
185928ffe6dSJohn Scipione }
186928ffe6dSJohn Scipione 
187928ffe6dSJohn Scipione 
188928ffe6dSJohn Scipione void
189928ffe6dSJohn Scipione FakeScrollBar::MouseDown(BPoint point)
190928ffe6dSJohn Scipione {
191928ffe6dSJohn Scipione 	BControl::MouseDown(point);
192928ffe6dSJohn Scipione }
193928ffe6dSJohn Scipione 
194928ffe6dSJohn Scipione 
195928ffe6dSJohn Scipione void
196928ffe6dSJohn Scipione FakeScrollBar::MouseMoved(BPoint point, uint32 transit,
197928ffe6dSJohn Scipione 	const BMessage* message)
198928ffe6dSJohn Scipione {
199928ffe6dSJohn Scipione 	BControl::MouseMoved(point, transit, message);
200928ffe6dSJohn Scipione }
201928ffe6dSJohn Scipione 
202928ffe6dSJohn Scipione 
203928ffe6dSJohn Scipione void
204928ffe6dSJohn Scipione FakeScrollBar::MouseUp(BPoint point)
205928ffe6dSJohn Scipione {
206928ffe6dSJohn Scipione 	SetValue(B_CONTROL_ON);
207928ffe6dSJohn Scipione 	Invoke();
208928ffe6dSJohn Scipione 
209928ffe6dSJohn Scipione 	Invalidate();
210928ffe6dSJohn Scipione 
211928ffe6dSJohn Scipione 	BControl::MouseUp(point);
212928ffe6dSJohn Scipione }
213928ffe6dSJohn Scipione 
214928ffe6dSJohn Scipione 
215928ffe6dSJohn Scipione void
216928ffe6dSJohn Scipione FakeScrollBar::SetValue(int32 value)
217928ffe6dSJohn Scipione {
218928ffe6dSJohn Scipione 	if (value != Value()) {
219928ffe6dSJohn Scipione 		BControl::SetValueNoUpdate(value);
220928ffe6dSJohn Scipione 		Invalidate();
221928ffe6dSJohn Scipione 	}
222928ffe6dSJohn Scipione 
223928ffe6dSJohn Scipione 	if (!value)
224928ffe6dSJohn Scipione 		return;
225928ffe6dSJohn Scipione 
226928ffe6dSJohn Scipione 	BView* parent = Parent();
227928ffe6dSJohn Scipione 	BView* child = NULL;
228928ffe6dSJohn Scipione 
229928ffe6dSJohn Scipione 	if (parent != NULL) {
230928ffe6dSJohn Scipione 		// If the parent is a BBox, the group parent is the parent of the BBox
231928ffe6dSJohn Scipione 		BBox* box = dynamic_cast<BBox*>(parent);
232928ffe6dSJohn Scipione 
233928ffe6dSJohn Scipione 		if (box && box->LabelView() == this)
234928ffe6dSJohn Scipione 			parent = box->Parent();
235928ffe6dSJohn Scipione 
236928ffe6dSJohn Scipione 		if (parent != NULL) {
237928ffe6dSJohn Scipione 			BBox* box = dynamic_cast<BBox*>(parent);
238928ffe6dSJohn Scipione 
239928ffe6dSJohn Scipione 			// If the parent is a BBox, skip the label if there is one
240928ffe6dSJohn Scipione 			if (box && box->LabelView())
241928ffe6dSJohn Scipione 				child = parent->ChildAt(1);
242928ffe6dSJohn Scipione 			else
243928ffe6dSJohn Scipione 				child = parent->ChildAt(0);
244928ffe6dSJohn Scipione 		} else
245928ffe6dSJohn Scipione 			child = Window()->ChildAt(0);
246928ffe6dSJohn Scipione 	} else if (Window())
247928ffe6dSJohn Scipione 		child = Window()->ChildAt(0);
248928ffe6dSJohn Scipione 
249928ffe6dSJohn Scipione 	while (child) {
250928ffe6dSJohn Scipione 		FakeScrollBar* scrollbar = dynamic_cast<FakeScrollBar*>(child);
251928ffe6dSJohn Scipione 
252928ffe6dSJohn Scipione 		if (scrollbar != NULL && (scrollbar != this))
253928ffe6dSJohn Scipione 			scrollbar->SetValue(B_CONTROL_OFF);
254928ffe6dSJohn Scipione 		else {
255928ffe6dSJohn Scipione 			// If the child is a BBox, check if the label is a scrollbarbutton
256928ffe6dSJohn Scipione 			BBox* box = dynamic_cast<BBox*>(child);
257928ffe6dSJohn Scipione 
258928ffe6dSJohn Scipione 			if (box && box->LabelView()) {
259928ffe6dSJohn Scipione 				scrollbar = dynamic_cast<FakeScrollBar*>(box->LabelView());
260928ffe6dSJohn Scipione 
261928ffe6dSJohn Scipione 				if (scrollbar != NULL && (scrollbar != this))
262928ffe6dSJohn Scipione 					scrollbar->SetValue(B_CONTROL_OFF);
263928ffe6dSJohn Scipione 			}
264928ffe6dSJohn Scipione 		}
265928ffe6dSJohn Scipione 
266928ffe6dSJohn Scipione 		child = child->NextSibling();
267928ffe6dSJohn Scipione 	}
268928ffe6dSJohn Scipione 
269928ffe6dSJohn Scipione 	//ASSERT(Value() == B_CONTROL_ON);
270928ffe6dSJohn Scipione }
271928ffe6dSJohn Scipione 
272928ffe6dSJohn Scipione 
273928ffe6dSJohn Scipione //	#pragma mark -
274928ffe6dSJohn Scipione 
275928ffe6dSJohn Scipione 
276928ffe6dSJohn Scipione void
277928ffe6dSJohn Scipione FakeScrollBar::SetDoubleArrows(bool doublearrows)
278928ffe6dSJohn Scipione {
279928ffe6dSJohn Scipione 	fDoubleArrows = doublearrows;
280928ffe6dSJohn Scipione 	Invalidate();
281928ffe6dSJohn Scipione }
282928ffe6dSJohn Scipione 
283928ffe6dSJohn Scipione 
284928ffe6dSJohn Scipione void
285928ffe6dSJohn Scipione FakeScrollBar::SetKnobStyle(uint32 style)
286928ffe6dSJohn Scipione {
287928ffe6dSJohn Scipione 	fKnobStyle = style;
288928ffe6dSJohn Scipione 	Invalidate();
289928ffe6dSJohn Scipione }
290928ffe6dSJohn Scipione 
291928ffe6dSJohn Scipione 
292928ffe6dSJohn Scipione void
293928ffe6dSJohn Scipione FakeScrollBar::SetFromScrollBarInfo(const scroll_bar_info &info)
294928ffe6dSJohn Scipione {
295928ffe6dSJohn Scipione 	fDoubleArrows = info.double_arrows;
296928ffe6dSJohn Scipione 	fKnobStyle = info.knob;
297928ffe6dSJohn Scipione 	Invalidate();
298928ffe6dSJohn Scipione }
299928ffe6dSJohn Scipione 
300928ffe6dSJohn Scipione 
301928ffe6dSJohn Scipione //	#pragma mark -
302928ffe6dSJohn Scipione 
303928ffe6dSJohn Scipione 
304928ffe6dSJohn Scipione void
305928ffe6dSJohn Scipione FakeScrollBar::_DrawArrowButton(int32 direction, bool doubleArrows, BRect r,
306928ffe6dSJohn Scipione 	const BRect& updateRect)
307928ffe6dSJohn Scipione {
308928ffe6dSJohn Scipione 	if (!updateRect.Intersects(r))
309928ffe6dSJohn Scipione 		return;
310928ffe6dSJohn Scipione 
311928ffe6dSJohn Scipione 	rgb_color c = ui_color(B_PANEL_BACKGROUND_COLOR);
312928ffe6dSJohn Scipione 	rgb_color light = tint_color(c, B_LIGHTEN_MAX_TINT);
313928ffe6dSJohn Scipione 	rgb_color dark = tint_color(c, B_DARKEN_1_TINT);
314928ffe6dSJohn Scipione 	rgb_color darker = tint_color(c, B_DARKEN_2_TINT);
315928ffe6dSJohn Scipione 	rgb_color normal = c;
316928ffe6dSJohn Scipione 	rgb_color arrow = tint_color(c,
317928ffe6dSJohn Scipione 		(B_DARKEN_MAX_TINT + B_DARKEN_4_TINT) / 2.0);
318928ffe6dSJohn Scipione 
319928ffe6dSJohn Scipione 	BPoint tri1, tri2, tri3;
320928ffe6dSJohn Scipione 	float hInset = r.Width() / 3;
321928ffe6dSJohn Scipione 	float vInset = r.Height() / 3;
322928ffe6dSJohn Scipione 	r.InsetBy(hInset, vInset);
323928ffe6dSJohn Scipione 
324928ffe6dSJohn Scipione 	switch (direction) {
325928ffe6dSJohn Scipione 		case ARROW_LEFT:
326928ffe6dSJohn Scipione 			tri1.Set(r.right, r.top);
327928ffe6dSJohn Scipione 			tri2.Set(r.right - r.Width() / 1.33, (r.top + r.bottom + 1) / 2);
328928ffe6dSJohn Scipione 			tri3.Set(r.right, r.bottom + 1);
329928ffe6dSJohn Scipione 			break;
330928ffe6dSJohn Scipione 
331928ffe6dSJohn Scipione 		case ARROW_RIGHT:
332928ffe6dSJohn Scipione 			tri1.Set(r.left, r.bottom + 1);
333928ffe6dSJohn Scipione 			tri2.Set(r.left + r.Width() / 1.33, (r.top + r.bottom + 1) / 2);
334928ffe6dSJohn Scipione 			tri3.Set(r.left, r.top);
335928ffe6dSJohn Scipione 			break;
336928ffe6dSJohn Scipione 
337928ffe6dSJohn Scipione 		case ARROW_UP:
338928ffe6dSJohn Scipione 			tri1.Set(r.left, r.bottom);
339928ffe6dSJohn Scipione 			tri2.Set((r.left + r.right + 1) / 2, r.bottom - r.Height() / 1.33);
340928ffe6dSJohn Scipione 			tri3.Set(r.right + 1, r.bottom);
341928ffe6dSJohn Scipione 			break;
342928ffe6dSJohn Scipione 
343928ffe6dSJohn Scipione 		default:
344928ffe6dSJohn Scipione 			tri1.Set(r.left, r.top);
345928ffe6dSJohn Scipione 			tri2.Set((r.left + r.right + 1) / 2, r.top + r.Height() / 1.33);
346928ffe6dSJohn Scipione 			tri3.Set(r.right + 1, r.top);
347928ffe6dSJohn Scipione 			break;
348928ffe6dSJohn Scipione 	}
349928ffe6dSJohn Scipione 
350928ffe6dSJohn Scipione 	r.InsetBy(-(hInset - 1), -(vInset - 1));
351928ffe6dSJohn Scipione 	BRect temp(r.InsetByCopy(-1, -1));
352928ffe6dSJohn Scipione 	be_control_look->DrawButtonBackground(this, temp, updateRect,
353928ffe6dSJohn Scipione 		normal, 0, BControlLook::B_ALL_BORDERS, B_HORIZONTAL);
354928ffe6dSJohn Scipione 
355928ffe6dSJohn Scipione 	BShape arrowShape;
356928ffe6dSJohn Scipione 	arrowShape.MoveTo(tri1);
357928ffe6dSJohn Scipione 	arrowShape.LineTo(tri2);
358928ffe6dSJohn Scipione 	arrowShape.LineTo(tri3);
359928ffe6dSJohn Scipione 
360928ffe6dSJohn Scipione 	SetHighColor(arrow);
361928ffe6dSJohn Scipione 	SetPenSize(ceilf(hInset / 2.0));
362928ffe6dSJohn Scipione 	StrokeShape(&arrowShape);
363928ffe6dSJohn Scipione 	SetPenSize(1.0);
364928ffe6dSJohn Scipione }
365