xref: /haiku/src/apps/aboutsystem/HyperTextView.cpp (revision cc6e7cb3477cdb34c23be8ce246203d2b7f002de)
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 <Message.h>
9 #include <Region.h>
10 #include <Window.h>
11 
12 #include <ObjectList.h>
13 
14 
15 // #pragma mark - HyperTextAction
16 
17 
18 HyperTextAction::HyperTextAction()
19 {
20 }
21 
22 
23 HyperTextAction::~HyperTextAction()
24 {
25 }
26 
27 
28 void
29 HyperTextAction::Clicked(HyperTextView* view, BPoint where, BMessage* message)
30 {
31 }
32 
33 
34 // #pragma mark - HyperTextView
35 
36 
37 struct HyperTextView::ActionInfo {
38 	ActionInfo(int32 startOffset, int32 endOffset, HyperTextAction* action)
39 		:
40 		startOffset(startOffset),
41 		endOffset(endOffset),
42 		action(action)
43 	{
44 	}
45 
46 	~ActionInfo()
47 	{
48 		delete action;
49 	}
50 
51 	static int Compare(const ActionInfo* a, const ActionInfo* b)
52 	{
53 		return a->startOffset - b->startOffset;
54 	}
55 
56 	static int CompareEqualIfIntersecting(const ActionInfo* a,
57 		const ActionInfo* b)
58 	{
59 		if (a->startOffset < b->endOffset && b->startOffset < a->endOffset)
60 			return 0;
61 		return a->startOffset - b->startOffset;
62 	}
63 
64 	int32				startOffset;
65 	int32				endOffset;
66 	HyperTextAction*	action;
67 };
68 
69 
70 
71 class HyperTextView::ActionInfoList
72 	: public BObjectList<HyperTextView::ActionInfo> {
73 public:
74 	ActionInfoList(int32 itemsPerBlock = 20, bool owning = false)
75 		: BObjectList<HyperTextView::ActionInfo>(itemsPerBlock, owning)
76 	{
77 	}
78 };
79 
80 
81 
82 HyperTextView::HyperTextView(BRect frame, const char* name, BRect textRect,
83 	uint32 resizeMask, uint32 flags)
84 	:
85 	BTextView(frame, name, textRect, resizeMask, flags),
86 	fActionInfos(new ActionInfoList(100, true))
87 {
88 }
89 
90 
91 HyperTextView::~HyperTextView()
92 {
93 	delete fActionInfos;
94 }
95 
96 
97 void
98 HyperTextView::MouseDown(BPoint where)
99 {
100 	// We eat all mouse button events.
101 }
102 
103 
104 void
105 HyperTextView::MouseUp(BPoint where)
106 {
107 	BMessage* message = Window()->CurrentMessage();
108 
109 	int32 offset = OffsetAt(where);
110 
111 	ActionInfo pointer(offset, offset + 1, NULL);
112 
113     const ActionInfo* action = fActionInfos->BinarySearch(pointer,
114 			ActionInfo::CompareEqualIfIntersecting);
115 	if (action != NULL) {
116 		// verify that the text region was hit
117 		BRegion textRegion;
118 		GetTextRegion(action->startOffset, action->endOffset, &textRegion);
119 		if (textRegion.Contains(where))
120 			action->action->Clicked(this, where, message);
121 	}
122 }
123 
124 
125 void
126 HyperTextView::AddHyperTextAction(int32 startOffset, int32 endOffset,
127 	HyperTextAction* action)
128 {
129 	if (action == NULL || startOffset >= endOffset) {
130 		delete action;
131 		return;
132 	}
133 
134 	fActionInfos->BinaryInsert(new ActionInfo(startOffset, endOffset, action),
135 		ActionInfo::Compare);
136 
137 	// TODO: Of course we should check for overlaps...
138 }
139 
140 
141 void
142 HyperTextView::InsertHyperText(const char* inText, HyperTextAction* action,
143 	const text_run_array* inRuns)
144 {
145 	int32 startOffset = TextLength();
146 	Insert(inText, inRuns);
147 	int32 endOffset = TextLength();
148 
149 	AddHyperTextAction(startOffset, endOffset, action);
150 }
151 
152 
153 void
154 HyperTextView::InsertHyperText(const char* inText, int32 inLength,
155 	HyperTextAction* action, const text_run_array* inRuns)
156 {
157 	int32 startOffset = TextLength();
158 	Insert(inText, inLength, inRuns);
159 	int32 endOffset = TextLength();
160 
161 	AddHyperTextAction(startOffset, endOffset, action);
162 }
163