source: Readingame/HyperTextView.cpp@ 50676d6

main
Last change on this file since 50676d6 was 3d333fd, checked in by PulkoMandy <pulkomandy@…>, 10 months ago

Continue adding things

  • Fix main window layout (text view sizing)
  • Implement conditional messages (partially)
  • Implements some more opcodes around flags
  • Property mode set to 100644
File size: 5.9 KB
Line 
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 <Application.h>
9#include <Cursor.h>
10#include <Message.h>
11#include <Region.h>
12#include <Window.h>
13
14#include <ObjectList.h>
15
16
17// #pragma mark - HyperTextAction
18
19
20HyperTextAction::HyperTextAction(int32 event)
21 : fMessage(event)
22{
23}
24
25
26HyperTextAction::~HyperTextAction()
27{
28}
29
30
31#include <stdio.h>
32void
33HyperTextAction::MouseOver(HyperTextView* view, BPoint where, int32 startOffset,
34 int32 endOffset, BMessage* message)
35{
36 BCursor linkCursor(B_CURSOR_ID_FOLLOW_LINK);
37 view->SetViewCursor(&linkCursor);
38
39 BFont font;
40 view->GetFont(&font);
41 font.SetFace(B_UNDERSCORE_FACE);
42 view->SetFontAndColor(startOffset, endOffset, &font, B_FONT_FACE);
43}
44
45
46void
47HyperTextAction::MouseAway(HyperTextView* view, BPoint where, int32 startOffset,
48 int32 endOffset, BMessage* message)
49{
50 BCursor linkCursor(B_CURSOR_ID_SYSTEM_DEFAULT);
51 view->SetViewCursor(&linkCursor);
52
53 BFont font;
54 view->GetFont(&font);
55 font.SetFace(B_REGULAR_FACE);
56 view->SetFontAndColor(startOffset, endOffset, &font, B_FONT_FACE);
57}
58
59
60void
61HyperTextAction::Clicked(HyperTextView* view, BPoint where, BMessage* message)
62{
63 be_app->PostMessage(fMessage);
64}
65
66
67// #pragma mark - HyperTextView
68
69
70struct HyperTextView::ActionInfo {
71 ActionInfo(int32 startOffset, int32 endOffset, HyperTextAction* action)
72 :
73 startOffset(startOffset),
74 endOffset(endOffset),
75 action(action)
76 {
77 }
78
79 ~ActionInfo()
80 {
81 delete action;
82 }
83
84 static int Compare(const ActionInfo* a, const ActionInfo* b)
85 {
86 return a->startOffset - b->startOffset;
87 }
88
89 static int CompareEqualIfIntersecting(const ActionInfo* a,
90 const ActionInfo* b)
91 {
92 if (a->startOffset < b->endOffset && b->startOffset < a->endOffset)
93 return 0;
94 return a->startOffset - b->startOffset;
95 }
96
97 int32 startOffset;
98 int32 endOffset;
99 HyperTextAction* action;
100};
101
102
103
104class HyperTextView::ActionInfoList
105 : public BObjectList<HyperTextView::ActionInfo> {
106public:
107 ActionInfoList(int32 itemsPerBlock = 20, bool owning = false)
108 : BObjectList<HyperTextView::ActionInfo>(itemsPerBlock, owning)
109 {
110 }
111};
112
113
114HyperTextView::HyperTextView(const char* name, uint32 flags)
115 :
116 BTextView(name, flags),
117 fActionInfos(new ActionInfoList(100, true)),
118 fLastActionInfo(NULL)
119{
120 SetStylable(true);
121}
122
123
124HyperTextView::HyperTextView(BRect frame, const char* name, BRect textRect,
125 uint32 resizeMask, uint32 flags)
126 :
127 BTextView(frame, name, textRect, resizeMask, flags),
128 fActionInfos(new ActionInfoList(100, true)),
129 fLastActionInfo(NULL)
130{
131 SetStylable(true);
132}
133
134
135HyperTextView::~HyperTextView()
136{
137 delete fActionInfos;
138}
139
140
141void
142HyperTextView::MouseDown(BPoint where)
143{
144 // We eat all mouse button events.
145
146 BTextView::MouseDown(where);
147}
148
149
150void
151HyperTextView::MouseUp(BPoint where)
152{
153 BMessage* message = Window()->CurrentMessage();
154
155 HyperTextAction* action = _ActionAt(where);
156 if (action != NULL)
157 action->Clicked(this, where, message);
158
159 BTextView::MouseUp(where);
160}
161
162
163void
164HyperTextView::MouseMoved(BPoint where, uint32 transit,
165 const BMessage* dragMessage)
166{
167 BMessage* message = Window()->CurrentMessage();
168
169 HyperTextAction* action;
170 const ActionInfo* actionInfo = _ActionInfoAt(where);
171 if (actionInfo != fLastActionInfo) {
172 // We moved to a different "action" zone, de-highlight the previous one
173 if (fLastActionInfo != NULL) {
174 action = fLastActionInfo->action;
175 if (action != NULL) {
176 action->MouseAway(this, where, fLastActionInfo->startOffset,
177 fLastActionInfo->endOffset, message);
178 }
179 }
180
181 // ... and highlight the new one
182 if (actionInfo != NULL) {
183 action = actionInfo->action;
184 if (action != NULL) {
185 action->MouseOver(this, where, actionInfo->startOffset,
186 actionInfo->endOffset, message);
187 }
188 }
189
190 fLastActionInfo = actionInfo;
191 }
192
193 int32 buttons = 0;
194 message->FindInt32("buttons", (int32*)&buttons);
195 if (actionInfo == NULL || buttons != 0) {
196 // This will restore the default mouse pointer, so do it only when not
197 // hovering a link, or when clicking
198 BTextView::MouseMoved(where, transit, dragMessage);
199 }
200}
201
202
203bool
204HyperTextView::HasHeightForWidth()
205{
206 return BView::HasHeightForWidth();
207}
208
209
210void
211HyperTextView::GetHeightForWidth(float width, float* min, float* max, float* preferred)
212{
213 BView::GetHeightForWidth(width, min, max, preferred);
214}
215
216
217void
218HyperTextView::SetText(const char* text)
219{
220 fLastActionInfo = NULL;
221 fActionInfos->MakeEmpty();
222 BTextView::SetText(text);
223}
224
225
226void
227HyperTextView::AddHyperTextAction(int32 startOffset, int32 endOffset,
228 HyperTextAction* action)
229{
230 if (action == NULL || startOffset >= endOffset) {
231 delete action;
232 return;
233 }
234
235 fActionInfos->BinaryInsert(new ActionInfo(startOffset, endOffset, action),
236 ActionInfo::Compare);
237
238 // TODO: Of course we should check for overlaps...
239}
240
241
242void
243HyperTextView::InsertHyperText(const char* inText, HyperTextAction* action,
244 const text_run_array* inRuns)
245{
246 int32 startOffset = TextLength();
247 Insert(inText, inRuns);
248 int32 endOffset = TextLength();
249
250 AddHyperTextAction(startOffset, endOffset, action);
251}
252
253
254void
255HyperTextView::InsertHyperText(const char* inText, int32 inLength,
256 HyperTextAction* action, const text_run_array* inRuns)
257{
258 int32 startOffset = TextLength();
259 Insert(inText, inLength, inRuns);
260 int32 endOffset = TextLength();
261
262 AddHyperTextAction(startOffset, endOffset, action);
263}
264
265
266const HyperTextView::ActionInfo*
267HyperTextView::_ActionInfoAt(const BPoint& where) const
268{
269 int32 offset = OffsetAt(where);
270
271 ActionInfo pointer(offset, offset + 1, NULL);
272
273 const ActionInfo* action = fActionInfos->BinarySearch(pointer,
274 ActionInfo::CompareEqualIfIntersecting);
275 return action;
276}
277
278
279HyperTextAction*
280HyperTextView::_ActionAt(const BPoint& where) const
281{
282 const ActionInfo* action = _ActionInfoAt(where);
283
284 if (action != NULL) {
285 // verify that the text region was hit
286 BRegion textRegion;
287 GetTextRegion(action->startOffset, action->endOffset, &textRegion);
288 if (textRegion.Contains(where))
289 return action->action;
290 }
291
292 return NULL;
293}
294
Note: See TracBrowser for help on using the repository browser.