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