1b14a49c9SIngo Weinhold /* 2b14a49c9SIngo Weinhold * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. 3b14a49c9SIngo Weinhold * Distributed under the terms of the MIT license. 4b14a49c9SIngo Weinhold */ 5b14a49c9SIngo Weinhold 6b14a49c9SIngo Weinhold #include "HyperTextView.h" 7b14a49c9SIngo Weinhold 88bd89640SStephan Aßmus #include <Cursor.h> 9b14a49c9SIngo Weinhold #include <Message.h> 10b14a49c9SIngo Weinhold #include <Region.h> 11b14a49c9SIngo Weinhold #include <Window.h> 12b14a49c9SIngo Weinhold 13b14a49c9SIngo Weinhold #include <ObjectList.h> 14b14a49c9SIngo Weinhold 15b14a49c9SIngo Weinhold 16b14a49c9SIngo Weinhold // #pragma mark - HyperTextAction 17b14a49c9SIngo Weinhold 18b14a49c9SIngo Weinhold 19b14a49c9SIngo Weinhold HyperTextAction::HyperTextAction() 20b14a49c9SIngo Weinhold { 21b14a49c9SIngo Weinhold } 22b14a49c9SIngo Weinhold 23b14a49c9SIngo Weinhold 24b14a49c9SIngo Weinhold HyperTextAction::~HyperTextAction() 25b14a49c9SIngo Weinhold { 26b14a49c9SIngo Weinhold } 27b14a49c9SIngo Weinhold 28b14a49c9SIngo Weinhold 29b14a49c9SIngo Weinhold void 308bd89640SStephan Aßmus HyperTextAction::MouseOver(HyperTextView* view, BPoint where, BMessage* message) 318bd89640SStephan Aßmus { 328bd89640SStephan Aßmus view->SetViewCursor(B_CURSOR_SYSTEM_DEFAULT); 338bd89640SStephan Aßmus } 348bd89640SStephan Aßmus 358bd89640SStephan Aßmus 368bd89640SStephan Aßmus void 37b14a49c9SIngo Weinhold HyperTextAction::Clicked(HyperTextView* view, BPoint where, BMessage* message) 38b14a49c9SIngo Weinhold { 39b14a49c9SIngo Weinhold } 40b14a49c9SIngo Weinhold 41b14a49c9SIngo Weinhold 42b14a49c9SIngo Weinhold // #pragma mark - HyperTextView 43b14a49c9SIngo Weinhold 44b14a49c9SIngo Weinhold 45b14a49c9SIngo Weinhold struct HyperTextView::ActionInfo { 46b14a49c9SIngo Weinhold ActionInfo(int32 startOffset, int32 endOffset, HyperTextAction* action) 47b14a49c9SIngo Weinhold : 48b14a49c9SIngo Weinhold startOffset(startOffset), 49b14a49c9SIngo Weinhold endOffset(endOffset), 50b14a49c9SIngo Weinhold action(action) 51b14a49c9SIngo Weinhold { 52b14a49c9SIngo Weinhold } 53b14a49c9SIngo Weinhold 54b14a49c9SIngo Weinhold ~ActionInfo() 55b14a49c9SIngo Weinhold { 56b14a49c9SIngo Weinhold delete action; 57b14a49c9SIngo Weinhold } 58b14a49c9SIngo Weinhold 59b14a49c9SIngo Weinhold static int Compare(const ActionInfo* a, const ActionInfo* b) 60b14a49c9SIngo Weinhold { 61b14a49c9SIngo Weinhold return a->startOffset - b->startOffset; 62b14a49c9SIngo Weinhold } 63b14a49c9SIngo Weinhold 64b14a49c9SIngo Weinhold static int CompareEqualIfIntersecting(const ActionInfo* a, 65b14a49c9SIngo Weinhold const ActionInfo* b) 66b14a49c9SIngo Weinhold { 67b14a49c9SIngo Weinhold if (a->startOffset < b->endOffset && b->startOffset < a->endOffset) 68b14a49c9SIngo Weinhold return 0; 69b14a49c9SIngo Weinhold return a->startOffset - b->startOffset; 70b14a49c9SIngo Weinhold } 71b14a49c9SIngo Weinhold 72b14a49c9SIngo Weinhold int32 startOffset; 73b14a49c9SIngo Weinhold int32 endOffset; 74b14a49c9SIngo Weinhold HyperTextAction* action; 75b14a49c9SIngo Weinhold }; 76b14a49c9SIngo Weinhold 77b14a49c9SIngo Weinhold 78b14a49c9SIngo Weinhold 79b14a49c9SIngo Weinhold class HyperTextView::ActionInfoList 80b14a49c9SIngo Weinhold : public BObjectList<HyperTextView::ActionInfo> { 81b14a49c9SIngo Weinhold public: 82b14a49c9SIngo Weinhold ActionInfoList(int32 itemsPerBlock = 20, bool owning = false) 83b14a49c9SIngo Weinhold : BObjectList<HyperTextView::ActionInfo>(itemsPerBlock, owning) 84b14a49c9SIngo Weinhold { 85b14a49c9SIngo Weinhold } 86b14a49c9SIngo Weinhold }; 87b14a49c9SIngo Weinhold 88b14a49c9SIngo Weinhold 89b14a49c9SIngo Weinhold 90b14a49c9SIngo Weinhold HyperTextView::HyperTextView(BRect frame, const char* name, BRect textRect, 91b14a49c9SIngo Weinhold uint32 resizeMask, uint32 flags) 92b14a49c9SIngo Weinhold : 93b14a49c9SIngo Weinhold BTextView(frame, name, textRect, resizeMask, flags), 94b14a49c9SIngo Weinhold fActionInfos(new ActionInfoList(100, true)) 95b14a49c9SIngo Weinhold { 96b14a49c9SIngo Weinhold } 97b14a49c9SIngo Weinhold 98b14a49c9SIngo Weinhold 99b14a49c9SIngo Weinhold HyperTextView::~HyperTextView() 100b14a49c9SIngo Weinhold { 101b14a49c9SIngo Weinhold delete fActionInfos; 102b14a49c9SIngo Weinhold } 103b14a49c9SIngo Weinhold 104b14a49c9SIngo Weinhold 105b14a49c9SIngo Weinhold void 106b14a49c9SIngo Weinhold HyperTextView::MouseDown(BPoint where) 107b14a49c9SIngo Weinhold { 108b14a49c9SIngo Weinhold // We eat all mouse button events. 109*6504b223SJérôme Duval 110*6504b223SJérôme Duval BTextView::MouseDown(where); 111b14a49c9SIngo Weinhold } 112b14a49c9SIngo Weinhold 113b14a49c9SIngo Weinhold 114b14a49c9SIngo Weinhold void 115b14a49c9SIngo Weinhold HyperTextView::MouseUp(BPoint where) 116b14a49c9SIngo Weinhold { 117b14a49c9SIngo Weinhold BMessage* message = Window()->CurrentMessage(); 118b14a49c9SIngo Weinhold 1198bd89640SStephan Aßmus HyperTextAction* action = _ActionAt(where); 1208bd89640SStephan Aßmus if (action != NULL) 1218bd89640SStephan Aßmus action->Clicked(this, where, message); 122*6504b223SJérôme Duval 123*6504b223SJérôme Duval BTextView::MouseUp(where); 124b14a49c9SIngo Weinhold } 1258bd89640SStephan Aßmus 1268bd89640SStephan Aßmus 1278bd89640SStephan Aßmus void 1288bd89640SStephan Aßmus HyperTextView::MouseMoved(BPoint where, uint32 transit, 1298bd89640SStephan Aßmus const BMessage* dragMessage) 1308bd89640SStephan Aßmus { 1318bd89640SStephan Aßmus BMessage* message = Window()->CurrentMessage(); 1328bd89640SStephan Aßmus 1338bd89640SStephan Aßmus uint32 buttons; 1348bd89640SStephan Aßmus HyperTextAction* action; 1358bd89640SStephan Aßmus if (message->FindInt32("buttons", (int32*)&buttons) == B_OK 1368bd89640SStephan Aßmus && buttons == 0 && (action = _ActionAt(where)) != NULL) { 1378bd89640SStephan Aßmus action->MouseOver(this, where, message); 1388bd89640SStephan Aßmus return; 1398bd89640SStephan Aßmus } 1408bd89640SStephan Aßmus 1418bd89640SStephan Aßmus BTextView::MouseMoved(where, transit, dragMessage); 142b14a49c9SIngo Weinhold } 143b14a49c9SIngo Weinhold 144b14a49c9SIngo Weinhold 145b14a49c9SIngo Weinhold void 146b14a49c9SIngo Weinhold HyperTextView::AddHyperTextAction(int32 startOffset, int32 endOffset, 147b14a49c9SIngo Weinhold HyperTextAction* action) 148b14a49c9SIngo Weinhold { 149b14a49c9SIngo Weinhold if (action == NULL || startOffset >= endOffset) { 150b14a49c9SIngo Weinhold delete action; 151b14a49c9SIngo Weinhold return; 152b14a49c9SIngo Weinhold } 153b14a49c9SIngo Weinhold 154b14a49c9SIngo Weinhold fActionInfos->BinaryInsert(new ActionInfo(startOffset, endOffset, action), 155b14a49c9SIngo Weinhold ActionInfo::Compare); 156b14a49c9SIngo Weinhold 157b14a49c9SIngo Weinhold // TODO: Of course we should check for overlaps... 158b14a49c9SIngo Weinhold } 159b14a49c9SIngo Weinhold 160b14a49c9SIngo Weinhold 161b14a49c9SIngo Weinhold void 162b14a49c9SIngo Weinhold HyperTextView::InsertHyperText(const char* inText, HyperTextAction* action, 163b14a49c9SIngo Weinhold const text_run_array* inRuns) 164b14a49c9SIngo Weinhold { 165b14a49c9SIngo Weinhold int32 startOffset = TextLength(); 166b14a49c9SIngo Weinhold Insert(inText, inRuns); 167b14a49c9SIngo Weinhold int32 endOffset = TextLength(); 168b14a49c9SIngo Weinhold 169b14a49c9SIngo Weinhold AddHyperTextAction(startOffset, endOffset, action); 170b14a49c9SIngo Weinhold } 171b14a49c9SIngo Weinhold 172b14a49c9SIngo Weinhold 173b14a49c9SIngo Weinhold void 174b14a49c9SIngo Weinhold HyperTextView::InsertHyperText(const char* inText, int32 inLength, 175b14a49c9SIngo Weinhold HyperTextAction* action, const text_run_array* inRuns) 176b14a49c9SIngo Weinhold { 177b14a49c9SIngo Weinhold int32 startOffset = TextLength(); 178b14a49c9SIngo Weinhold Insert(inText, inLength, inRuns); 179b14a49c9SIngo Weinhold int32 endOffset = TextLength(); 180b14a49c9SIngo Weinhold 181b14a49c9SIngo Weinhold AddHyperTextAction(startOffset, endOffset, action); 182b14a49c9SIngo Weinhold } 1838bd89640SStephan Aßmus 1848bd89640SStephan Aßmus 1858bd89640SStephan Aßmus HyperTextAction* 1868bd89640SStephan Aßmus HyperTextView::_ActionAt(const BPoint& where) const 1878bd89640SStephan Aßmus { 1888bd89640SStephan Aßmus int32 offset = OffsetAt(where); 1898bd89640SStephan Aßmus 1908bd89640SStephan Aßmus ActionInfo pointer(offset, offset + 1, NULL); 1918bd89640SStephan Aßmus 1928bd89640SStephan Aßmus const ActionInfo* action = fActionInfos->BinarySearch(pointer, 1938bd89640SStephan Aßmus ActionInfo::CompareEqualIfIntersecting); 1948bd89640SStephan Aßmus if (action != NULL) { 1958bd89640SStephan Aßmus // verify that the text region was hit 1968bd89640SStephan Aßmus BRegion textRegion; 1978bd89640SStephan Aßmus GetTextRegion(action->startOffset, action->endOffset, &textRegion); 1988bd89640SStephan Aßmus if (textRegion.Contains(where)) 1998bd89640SStephan Aßmus return action->action; 2008bd89640SStephan Aßmus } 2018bd89640SStephan Aßmus 2028bd89640SStephan Aßmus return NULL; 2038bd89640SStephan Aßmus } 2048bd89640SStephan Aßmus 205