2 * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT license.
6 #include "HyperTextView.h"
13 #include <ObjectList.h>
16 // #pragma mark - HyperTextAction
19 HyperTextAction::HyperTextAction()
24 HyperTextAction::~HyperTextAction()
30 HyperTextAction::MouseOver(HyperTextView
* view
, BPoint where
, BMessage
* message
)
32 BCursor
linkCursor(B_CURSOR_ID_FOLLOW_LINK
);
33 view
->SetViewCursor(&linkCursor
);
38 HyperTextAction::Clicked(HyperTextView
* view
, BPoint where
, BMessage
* message
)
43 // #pragma mark - HyperTextView
46 struct HyperTextView::ActionInfo
{
47 ActionInfo(int32 startOffset
, int32 endOffset
, HyperTextAction
* action
)
49 startOffset(startOffset
),
60 static int Compare(const ActionInfo
* a
, const ActionInfo
* b
)
62 return a
->startOffset
- b
->startOffset
;
65 static int CompareEqualIfIntersecting(const ActionInfo
* a
,
68 if (a
->startOffset
< b
->endOffset
&& b
->startOffset
< a
->endOffset
)
70 return a
->startOffset
- b
->startOffset
;
75 HyperTextAction
* action
;
80 class HyperTextView::ActionInfoList
81 : public BObjectList
<HyperTextView::ActionInfo
> {
83 ActionInfoList(int32 itemsPerBlock
= 20, bool owning
= false)
84 : BObjectList
<HyperTextView::ActionInfo
>(itemsPerBlock
, owning
)
90 HyperTextView::HyperTextView(const char* name
, uint32 flags
)
92 BTextView(name
, flags
),
93 fActionInfos(new ActionInfoList(100, true))
98 HyperTextView::HyperTextView(BRect frame
, const char* name
, BRect textRect
,
99 uint32 resizeMask
, uint32 flags
)
101 BTextView(frame
, name
, textRect
, resizeMask
, flags
),
102 fActionInfos(new ActionInfoList(100, true))
107 HyperTextView::~HyperTextView()
114 HyperTextView::MouseDown(BPoint where
)
116 // We eat all mouse button events.
118 BTextView::MouseDown(where
);
123 HyperTextView::MouseUp(BPoint where
)
125 BMessage
* message
= Window()->CurrentMessage();
127 HyperTextAction
* action
= _ActionAt(where
);
129 action
->Clicked(this, where
, message
);
131 BTextView::MouseUp(where
);
136 HyperTextView::MouseMoved(BPoint where
, uint32 transit
,
137 const BMessage
* dragMessage
)
139 BMessage
* message
= Window()->CurrentMessage();
142 HyperTextAction
* action
;
143 if (message
->FindInt32("buttons", (int32
*)&buttons
) == B_OK
144 && buttons
== 0 && (action
= _ActionAt(where
)) != NULL
) {
145 action
->MouseOver(this, where
, message
);
149 BTextView::MouseMoved(where
, transit
, dragMessage
);
154 HyperTextView::AddHyperTextAction(int32 startOffset
, int32 endOffset
,
155 HyperTextAction
* action
)
157 if (action
== NULL
|| startOffset
>= endOffset
) {
162 fActionInfos
->BinaryInsert(new ActionInfo(startOffset
, endOffset
, action
),
163 ActionInfo::Compare
);
165 // TODO: Of course we should check for overlaps...
170 HyperTextView::InsertHyperText(const char* inText
, HyperTextAction
* action
,
171 const text_run_array
* inRuns
)
173 int32 startOffset
= TextLength();
174 Insert(inText
, inRuns
);
175 int32 endOffset
= TextLength();
177 AddHyperTextAction(startOffset
, endOffset
, action
);
182 HyperTextView::InsertHyperText(const char* inText
, int32 inLength
,
183 HyperTextAction
* action
, const text_run_array
* inRuns
)
185 int32 startOffset
= TextLength();
186 Insert(inText
, inLength
, inRuns
);
187 int32 endOffset
= TextLength();
189 AddHyperTextAction(startOffset
, endOffset
, action
);
194 HyperTextView::_ActionAt(const BPoint
& where
) const
196 int32 offset
= OffsetAt(where
);
198 ActionInfo
pointer(offset
, offset
+ 1, NULL
);
200 const ActionInfo
* action
= fActionInfos
->BinarySearch(pointer
,
201 ActionInfo::CompareEqualIfIntersecting
);
202 if (action
!= NULL
) {
203 // verify that the text region was hit
205 GetTextRegion(action
->startOffset
, action
->endOffset
, &textRegion
);
206 if (textRegion
.Contains(where
))
207 return action
->action
;