source: Readingame/HyperTextView.cpp@ 3d27dc6

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

Start making the game run

Implemented text rendering, buttons and hyperlinks.

Several opcodes not interpreted yet.

Global buttons are missing.

  • Property mode set to 100644
File size: 5.7 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
203void
204HyperTextView::SetText(const char* text)
205{
206 fLastActionInfo = NULL;
207 fActionInfos->MakeEmpty();
208 BTextView::SetText(text);
209}
210
211
212void
213HyperTextView::AddHyperTextAction(int32 startOffset, int32 endOffset,
214 HyperTextAction* action)
215{
216 if (action == NULL || startOffset >= endOffset) {
217 delete action;
218 return;
219 }
220
221 fActionInfos->BinaryInsert(new ActionInfo(startOffset, endOffset, action),
222 ActionInfo::Compare);
223
224 // TODO: Of course we should check for overlaps...
225}
226
227
228void
229HyperTextView::InsertHyperText(const char* inText, HyperTextAction* action,
230 const text_run_array* inRuns)
231{
232 int32 startOffset = TextLength();
233 Insert(inText, inRuns);
234 int32 endOffset = TextLength();
235
236 AddHyperTextAction(startOffset, endOffset, action);
237}
238
239
240void
241HyperTextView::InsertHyperText(const char* inText, int32 inLength,
242 HyperTextAction* action, const text_run_array* inRuns)
243{
244 int32 startOffset = TextLength();
245 Insert(inText, inLength, inRuns);
246 int32 endOffset = TextLength();
247
248 AddHyperTextAction(startOffset, endOffset, action);
249}
250
251
252const HyperTextView::ActionInfo*
253HyperTextView::_ActionInfoAt(const BPoint& where) const
254{
255 int32 offset = OffsetAt(where);
256
257 ActionInfo pointer(offset, offset + 1, NULL);
258
259 const ActionInfo* action = fActionInfos->BinarySearch(pointer,
260 ActionInfo::CompareEqualIfIntersecting);
261 return action;
262}
263
264
265HyperTextAction*
266HyperTextView::_ActionAt(const BPoint& where) const
267{
268 const ActionInfo* action = _ActionInfoAt(where);
269
270 if (action != NULL) {
271 // verify that the text region was hit
272 BRegion textRegion;
273 GetTextRegion(action->startOffset, action->endOffset, &textRegion);
274 if (textRegion.Contains(where))
275 return action->action;
276 }
277
278 return NULL;
279}
280
Note: See TracBrowser for help on using the repository browser.