xref: /haiku/src/apps/aboutsystem/HyperTextView.cpp (revision 4f2fd49bdc6078128b1391191e4edac647044c3d)
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 
90 HyperTextView::HyperTextView(BRect frame, const char* name, BRect textRect,
91 	uint32 resizeMask, uint32 flags)
92 	:
93 	BTextView(frame, name, textRect, resizeMask, flags),
94 	fActionInfos(new ActionInfoList(100, true))
95 {
96 }
97 
98 
99 HyperTextView::~HyperTextView()
100 {
101 	delete fActionInfos;
102 }
103 
104 
105 void
106 HyperTextView::MouseDown(BPoint where)
107 {
108 	// We eat all mouse button events.
109 
110 	BTextView::MouseDown(where);
111 }
112 
113 
114 void
115 HyperTextView::MouseUp(BPoint where)
116 {
117 	BMessage* message = Window()->CurrentMessage();
118 
119 	HyperTextAction* action = _ActionAt(where);
120 	if (action != NULL)
121 		action->Clicked(this, where, message);
122 
123 	BTextView::MouseUp(where);
124 }
125 
126 
127 void
128 HyperTextView::MouseMoved(BPoint where, uint32 transit,
129 	const BMessage* dragMessage)
130 {
131 	BMessage* message = Window()->CurrentMessage();
132 
133 	uint32 buttons;
134 	HyperTextAction* action;
135 	if (message->FindInt32("buttons", (int32*)&buttons) == B_OK
136 		&& buttons == 0 && (action = _ActionAt(where)) != NULL) {
137 		action->MouseOver(this, where, message);
138 		return;
139 	}
140 
141 	BTextView::MouseMoved(where, transit, dragMessage);
142 }
143 
144 
145 void
146 HyperTextView::AddHyperTextAction(int32 startOffset, int32 endOffset,
147 	HyperTextAction* action)
148 {
149 	if (action == NULL || startOffset >= endOffset) {
150 		delete action;
151 		return;
152 	}
153 
154 	fActionInfos->BinaryInsert(new ActionInfo(startOffset, endOffset, action),
155 		ActionInfo::Compare);
156 
157 	// TODO: Of course we should check for overlaps...
158 }
159 
160 
161 void
162 HyperTextView::InsertHyperText(const char* inText, HyperTextAction* action,
163 	const text_run_array* inRuns)
164 {
165 	int32 startOffset = TextLength();
166 	Insert(inText, inRuns);
167 	int32 endOffset = TextLength();
168 
169 	AddHyperTextAction(startOffset, endOffset, action);
170 }
171 
172 
173 void
174 HyperTextView::InsertHyperText(const char* inText, int32 inLength,
175 	HyperTextAction* action, const text_run_array* inRuns)
176 {
177 	int32 startOffset = TextLength();
178 	Insert(inText, inLength, inRuns);
179 	int32 endOffset = TextLength();
180 
181 	AddHyperTextAction(startOffset, endOffset, action);
182 }
183 
184 
185 HyperTextAction*
186 HyperTextView::_ActionAt(const BPoint& where) const
187 {
188 	int32 offset = OffsetAt(where);
189 
190 	ActionInfo pointer(offset, offset + 1, NULL);
191 
192     const ActionInfo* action = fActionInfos->BinarySearch(pointer,
193 			ActionInfo::CompareEqualIfIntersecting);
194 	if (action != NULL) {
195 		// verify that the text region was hit
196 		BRegion textRegion;
197 		GetTextRegion(action->startOffset, action->endOffset, &textRegion);
198 		if (textRegion.Contains(where))
199 			return action->action;
200 	}
201 
202 	return NULL;
203 }
204 
205