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