xref: /haiku/src/apps/aboutsystem/HyperTextView.cpp (revision 6504b22390c1be7ed1444b433f54e665a4a3bb37)
1b14a49c9SIngo Weinhold /*
2b14a49c9SIngo Weinhold  * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
3b14a49c9SIngo Weinhold  * Distributed under the terms of the MIT license.
4b14a49c9SIngo Weinhold  */
5b14a49c9SIngo Weinhold 
6b14a49c9SIngo Weinhold #include "HyperTextView.h"
7b14a49c9SIngo Weinhold 
88bd89640SStephan Aßmus #include <Cursor.h>
9b14a49c9SIngo Weinhold #include <Message.h>
10b14a49c9SIngo Weinhold #include <Region.h>
11b14a49c9SIngo Weinhold #include <Window.h>
12b14a49c9SIngo Weinhold 
13b14a49c9SIngo Weinhold #include <ObjectList.h>
14b14a49c9SIngo Weinhold 
15b14a49c9SIngo Weinhold 
16b14a49c9SIngo Weinhold // #pragma mark - HyperTextAction
17b14a49c9SIngo Weinhold 
18b14a49c9SIngo Weinhold 
19b14a49c9SIngo Weinhold HyperTextAction::HyperTextAction()
20b14a49c9SIngo Weinhold {
21b14a49c9SIngo Weinhold }
22b14a49c9SIngo Weinhold 
23b14a49c9SIngo Weinhold 
24b14a49c9SIngo Weinhold HyperTextAction::~HyperTextAction()
25b14a49c9SIngo Weinhold {
26b14a49c9SIngo Weinhold }
27b14a49c9SIngo Weinhold 
28b14a49c9SIngo Weinhold 
29b14a49c9SIngo Weinhold void
308bd89640SStephan Aßmus HyperTextAction::MouseOver(HyperTextView* view, BPoint where, BMessage* message)
318bd89640SStephan Aßmus {
328bd89640SStephan Aßmus 	view->SetViewCursor(B_CURSOR_SYSTEM_DEFAULT);
338bd89640SStephan Aßmus }
348bd89640SStephan Aßmus 
358bd89640SStephan Aßmus 
368bd89640SStephan Aßmus void
37b14a49c9SIngo Weinhold HyperTextAction::Clicked(HyperTextView* view, BPoint where, BMessage* message)
38b14a49c9SIngo Weinhold {
39b14a49c9SIngo Weinhold }
40b14a49c9SIngo Weinhold 
41b14a49c9SIngo Weinhold 
42b14a49c9SIngo Weinhold // #pragma mark - HyperTextView
43b14a49c9SIngo Weinhold 
44b14a49c9SIngo Weinhold 
45b14a49c9SIngo Weinhold struct HyperTextView::ActionInfo {
46b14a49c9SIngo Weinhold 	ActionInfo(int32 startOffset, int32 endOffset, HyperTextAction* action)
47b14a49c9SIngo Weinhold 		:
48b14a49c9SIngo Weinhold 		startOffset(startOffset),
49b14a49c9SIngo Weinhold 		endOffset(endOffset),
50b14a49c9SIngo Weinhold 		action(action)
51b14a49c9SIngo Weinhold 	{
52b14a49c9SIngo Weinhold 	}
53b14a49c9SIngo Weinhold 
54b14a49c9SIngo Weinhold 	~ActionInfo()
55b14a49c9SIngo Weinhold 	{
56b14a49c9SIngo Weinhold 		delete action;
57b14a49c9SIngo Weinhold 	}
58b14a49c9SIngo Weinhold 
59b14a49c9SIngo Weinhold 	static int Compare(const ActionInfo* a, const ActionInfo* b)
60b14a49c9SIngo Weinhold 	{
61b14a49c9SIngo Weinhold 		return a->startOffset - b->startOffset;
62b14a49c9SIngo Weinhold 	}
63b14a49c9SIngo Weinhold 
64b14a49c9SIngo Weinhold 	static int CompareEqualIfIntersecting(const ActionInfo* a,
65b14a49c9SIngo Weinhold 		const ActionInfo* b)
66b14a49c9SIngo Weinhold 	{
67b14a49c9SIngo Weinhold 		if (a->startOffset < b->endOffset && b->startOffset < a->endOffset)
68b14a49c9SIngo Weinhold 			return 0;
69b14a49c9SIngo Weinhold 		return a->startOffset - b->startOffset;
70b14a49c9SIngo Weinhold 	}
71b14a49c9SIngo Weinhold 
72b14a49c9SIngo Weinhold 	int32				startOffset;
73b14a49c9SIngo Weinhold 	int32				endOffset;
74b14a49c9SIngo Weinhold 	HyperTextAction*	action;
75b14a49c9SIngo Weinhold };
76b14a49c9SIngo Weinhold 
77b14a49c9SIngo Weinhold 
78b14a49c9SIngo Weinhold 
79b14a49c9SIngo Weinhold class HyperTextView::ActionInfoList
80b14a49c9SIngo Weinhold 	: public BObjectList<HyperTextView::ActionInfo> {
81b14a49c9SIngo Weinhold public:
82b14a49c9SIngo Weinhold 	ActionInfoList(int32 itemsPerBlock = 20, bool owning = false)
83b14a49c9SIngo Weinhold 		: BObjectList<HyperTextView::ActionInfo>(itemsPerBlock, owning)
84b14a49c9SIngo Weinhold 	{
85b14a49c9SIngo Weinhold 	}
86b14a49c9SIngo Weinhold };
87b14a49c9SIngo Weinhold 
88b14a49c9SIngo Weinhold 
89b14a49c9SIngo Weinhold 
90b14a49c9SIngo Weinhold HyperTextView::HyperTextView(BRect frame, const char* name, BRect textRect,
91b14a49c9SIngo Weinhold 	uint32 resizeMask, uint32 flags)
92b14a49c9SIngo Weinhold 	:
93b14a49c9SIngo Weinhold 	BTextView(frame, name, textRect, resizeMask, flags),
94b14a49c9SIngo Weinhold 	fActionInfos(new ActionInfoList(100, true))
95b14a49c9SIngo Weinhold {
96b14a49c9SIngo Weinhold }
97b14a49c9SIngo Weinhold 
98b14a49c9SIngo Weinhold 
99b14a49c9SIngo Weinhold HyperTextView::~HyperTextView()
100b14a49c9SIngo Weinhold {
101b14a49c9SIngo Weinhold 	delete fActionInfos;
102b14a49c9SIngo Weinhold }
103b14a49c9SIngo Weinhold 
104b14a49c9SIngo Weinhold 
105b14a49c9SIngo Weinhold void
106b14a49c9SIngo Weinhold HyperTextView::MouseDown(BPoint where)
107b14a49c9SIngo Weinhold {
108b14a49c9SIngo Weinhold 	// We eat all mouse button events.
109*6504b223SJérôme Duval 
110*6504b223SJérôme Duval 	BTextView::MouseDown(where);
111b14a49c9SIngo Weinhold }
112b14a49c9SIngo Weinhold 
113b14a49c9SIngo Weinhold 
114b14a49c9SIngo Weinhold void
115b14a49c9SIngo Weinhold HyperTextView::MouseUp(BPoint where)
116b14a49c9SIngo Weinhold {
117b14a49c9SIngo Weinhold 	BMessage* message = Window()->CurrentMessage();
118b14a49c9SIngo Weinhold 
1198bd89640SStephan Aßmus 	HyperTextAction* action = _ActionAt(where);
1208bd89640SStephan Aßmus 	if (action != NULL)
1218bd89640SStephan Aßmus 		action->Clicked(this, where, message);
122*6504b223SJérôme Duval 
123*6504b223SJérôme Duval 	BTextView::MouseUp(where);
124b14a49c9SIngo Weinhold }
1258bd89640SStephan Aßmus 
1268bd89640SStephan Aßmus 
1278bd89640SStephan Aßmus void
1288bd89640SStephan Aßmus HyperTextView::MouseMoved(BPoint where, uint32 transit,
1298bd89640SStephan Aßmus 	const BMessage* dragMessage)
1308bd89640SStephan Aßmus {
1318bd89640SStephan Aßmus 	BMessage* message = Window()->CurrentMessage();
1328bd89640SStephan Aßmus 
1338bd89640SStephan Aßmus 	uint32 buttons;
1348bd89640SStephan Aßmus 	HyperTextAction* action;
1358bd89640SStephan Aßmus 	if (message->FindInt32("buttons", (int32*)&buttons) == B_OK
1368bd89640SStephan Aßmus 		&& buttons == 0 && (action = _ActionAt(where)) != NULL) {
1378bd89640SStephan Aßmus 		action->MouseOver(this, where, message);
1388bd89640SStephan Aßmus 		return;
1398bd89640SStephan Aßmus 	}
1408bd89640SStephan Aßmus 
1418bd89640SStephan Aßmus 	BTextView::MouseMoved(where, transit, dragMessage);
142b14a49c9SIngo Weinhold }
143b14a49c9SIngo Weinhold 
144b14a49c9SIngo Weinhold 
145b14a49c9SIngo Weinhold void
146b14a49c9SIngo Weinhold HyperTextView::AddHyperTextAction(int32 startOffset, int32 endOffset,
147b14a49c9SIngo Weinhold 	HyperTextAction* action)
148b14a49c9SIngo Weinhold {
149b14a49c9SIngo Weinhold 	if (action == NULL || startOffset >= endOffset) {
150b14a49c9SIngo Weinhold 		delete action;
151b14a49c9SIngo Weinhold 		return;
152b14a49c9SIngo Weinhold 	}
153b14a49c9SIngo Weinhold 
154b14a49c9SIngo Weinhold 	fActionInfos->BinaryInsert(new ActionInfo(startOffset, endOffset, action),
155b14a49c9SIngo Weinhold 		ActionInfo::Compare);
156b14a49c9SIngo Weinhold 
157b14a49c9SIngo Weinhold 	// TODO: Of course we should check for overlaps...
158b14a49c9SIngo Weinhold }
159b14a49c9SIngo Weinhold 
160b14a49c9SIngo Weinhold 
161b14a49c9SIngo Weinhold void
162b14a49c9SIngo Weinhold HyperTextView::InsertHyperText(const char* inText, HyperTextAction* action,
163b14a49c9SIngo Weinhold 	const text_run_array* inRuns)
164b14a49c9SIngo Weinhold {
165b14a49c9SIngo Weinhold 	int32 startOffset = TextLength();
166b14a49c9SIngo Weinhold 	Insert(inText, inRuns);
167b14a49c9SIngo Weinhold 	int32 endOffset = TextLength();
168b14a49c9SIngo Weinhold 
169b14a49c9SIngo Weinhold 	AddHyperTextAction(startOffset, endOffset, action);
170b14a49c9SIngo Weinhold }
171b14a49c9SIngo Weinhold 
172b14a49c9SIngo Weinhold 
173b14a49c9SIngo Weinhold void
174b14a49c9SIngo Weinhold HyperTextView::InsertHyperText(const char* inText, int32 inLength,
175b14a49c9SIngo Weinhold 	HyperTextAction* action, const text_run_array* inRuns)
176b14a49c9SIngo Weinhold {
177b14a49c9SIngo Weinhold 	int32 startOffset = TextLength();
178b14a49c9SIngo Weinhold 	Insert(inText, inLength, inRuns);
179b14a49c9SIngo Weinhold 	int32 endOffset = TextLength();
180b14a49c9SIngo Weinhold 
181b14a49c9SIngo Weinhold 	AddHyperTextAction(startOffset, endOffset, action);
182b14a49c9SIngo Weinhold }
1838bd89640SStephan Aßmus 
1848bd89640SStephan Aßmus 
1858bd89640SStephan Aßmus HyperTextAction*
1868bd89640SStephan Aßmus HyperTextView::_ActionAt(const BPoint& where) const
1878bd89640SStephan Aßmus {
1888bd89640SStephan Aßmus 	int32 offset = OffsetAt(where);
1898bd89640SStephan Aßmus 
1908bd89640SStephan Aßmus 	ActionInfo pointer(offset, offset + 1, NULL);
1918bd89640SStephan Aßmus 
1928bd89640SStephan Aßmus     const ActionInfo* action = fActionInfos->BinarySearch(pointer,
1938bd89640SStephan Aßmus 			ActionInfo::CompareEqualIfIntersecting);
1948bd89640SStephan Aßmus 	if (action != NULL) {
1958bd89640SStephan Aßmus 		// verify that the text region was hit
1968bd89640SStephan Aßmus 		BRegion textRegion;
1978bd89640SStephan Aßmus 		GetTextRegion(action->startOffset, action->endOffset, &textRegion);
1988bd89640SStephan Aßmus 		if (textRegion.Contains(where))
1998bd89640SStephan Aßmus 			return action->action;
2008bd89640SStephan Aßmus 	}
2018bd89640SStephan Aßmus 
2028bd89640SStephan Aßmus 	return NULL;
2038bd89640SStephan Aßmus }
2048bd89640SStephan Aßmus 
205