xref: /haiku/src/apps/aboutsystem/HyperTextView.cpp (revision ddac407426cd3b3d0b4589d7a161b300b3539a2a)
1 /*
2  * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT license.
4  */
5 
6 #include "HyperTextView.h"
7 
8 #include <Cursor.h>
9 #include <Message.h>
10 #include <Region.h>
11 #include <Window.h>
12 
13 #include <ObjectList.h>
14 
15 
16 // #pragma mark - HyperTextAction
17 
18 
19 HyperTextAction::HyperTextAction()
20 {
21 }
22 
23 
24 HyperTextAction::~HyperTextAction()
25 {
26 }
27 
28 
29 void
30 HyperTextAction::MouseOver(HyperTextView* view, BPoint where, BMessage* message)
31 {
32 	view->SetViewCursor(B_CURSOR_SYSTEM_DEFAULT);
33 }
34 
35 
36 void
37 HyperTextAction::Clicked(HyperTextView* view, BPoint where, BMessage* message)
38 {
39 }
40 
41 
42 // #pragma mark - HyperTextView
43 
44 
45 struct HyperTextView::ActionInfo {
46 	ActionInfo(int32 startOffset, int32 endOffset, HyperTextAction* action)
47 		:
48 		startOffset(startOffset),
49 		endOffset(endOffset),
50 		action(action)
51 	{
52 	}
53 
54 	~ActionInfo()
55 	{
56 		delete action;
57 	}
58 
59 	static int Compare(const ActionInfo* a, const ActionInfo* b)
60 	{
61 		return a->startOffset - b->startOffset;
62 	}
63 
64 	static int CompareEqualIfIntersecting(const ActionInfo* a,
65 		const ActionInfo* b)
66 	{
67 		if (a->startOffset < b->endOffset && b->startOffset < a->endOffset)
68 			return 0;
69 		return a->startOffset - b->startOffset;
70 	}
71 
72 	int32				startOffset;
73 	int32				endOffset;
74 	HyperTextAction*	action;
75 };
76 
77 
78 
79 class HyperTextView::ActionInfoList
80 	: public BObjectList<HyperTextView::ActionInfo> {
81 public:
82 	ActionInfoList(int32 itemsPerBlock = 20, bool owning = false)
83 		: BObjectList<HyperTextView::ActionInfo>(itemsPerBlock, owning)
84 	{
85 	}
86 };
87 
88 
89 HyperTextView::HyperTextView(const char* name, uint32 flags)
90 	:
91 	BTextView(name, flags),
92 	fActionInfos(new ActionInfoList(100, true))
93 {
94 }
95 
96 
97 HyperTextView::HyperTextView(BRect frame, const char* name, BRect textRect,
98 	uint32 resizeMask, uint32 flags)
99 	:
100 	BTextView(frame, name, textRect, resizeMask, flags),
101 	fActionInfos(new ActionInfoList(100, true))
102 {
103 }
104 
105 
106 HyperTextView::~HyperTextView()
107 {
108 	delete fActionInfos;
109 }
110 
111 
112 void
113 HyperTextView::MouseDown(BPoint where)
114 {
115 	// We eat all mouse button events.
116 
117 	BTextView::MouseDown(where);
118 }
119 
120 
121 void
122 HyperTextView::MouseUp(BPoint where)
123 {
124 	BMessage* message = Window()->CurrentMessage();
125 
126 	HyperTextAction* action = _ActionAt(where);
127 	if (action != NULL)
128 		action->Clicked(this, where, message);
129 
130 	BTextView::MouseUp(where);
131 }
132 
133 
134 void
135 HyperTextView::MouseMoved(BPoint where, uint32 transit,
136 	const BMessage* dragMessage)
137 {
138 	BMessage* message = Window()->CurrentMessage();
139 
140 	uint32 buttons;
141 	HyperTextAction* action;
142 	if (message->FindInt32("buttons", (int32*)&buttons) == B_OK
143 		&& buttons == 0 && (action = _ActionAt(where)) != NULL) {
144 		action->MouseOver(this, where, message);
145 		return;
146 	}
147 
148 	BTextView::MouseMoved(where, transit, dragMessage);
149 }
150 
151 
152 void
153 HyperTextView::AddHyperTextAction(int32 startOffset, int32 endOffset,
154 	HyperTextAction* action)
155 {
156 	if (action == NULL || startOffset >= endOffset) {
157 		delete action;
158 		return;
159 	}
160 
161 	fActionInfos->BinaryInsert(new ActionInfo(startOffset, endOffset, action),
162 		ActionInfo::Compare);
163 
164 	// TODO: Of course we should check for overlaps...
165 }
166 
167 
168 void
169 HyperTextView::InsertHyperText(const char* inText, HyperTextAction* action,
170 	const text_run_array* inRuns)
171 {
172 	int32 startOffset = TextLength();
173 	Insert(inText, inRuns);
174 	int32 endOffset = TextLength();
175 
176 	AddHyperTextAction(startOffset, endOffset, action);
177 }
178 
179 
180 void
181 HyperTextView::InsertHyperText(const char* inText, int32 inLength,
182 	HyperTextAction* action, const text_run_array* inRuns)
183 {
184 	int32 startOffset = TextLength();
185 	Insert(inText, inLength, inRuns);
186 	int32 endOffset = TextLength();
187 
188 	AddHyperTextAction(startOffset, endOffset, action);
189 }
190 
191 
192 HyperTextAction*
193 HyperTextView::_ActionAt(const BPoint& where) const
194 {
195 	int32 offset = OffsetAt(where);
196 
197 	ActionInfo pointer(offset, offset + 1, NULL);
198 
199     const ActionInfo* action = fActionInfos->BinarySearch(pointer,
200 			ActionInfo::CompareEqualIfIntersecting);
201 	if (action != NULL) {
202 		// verify that the text region was hit
203 		BRegion textRegion;
204 		GetTextRegion(action->startOffset, action->endOffset, &textRegion);
205 		if (textRegion.Contains(where))
206 			return action->action;
207 	}
208 
209 	return NULL;
210 }
211 
212