1 /* 2 * Copyright 2006 Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Stephan Aßmus <superstippi@gmx.de> 7 */ 8 9 #include "ExpressionTextView.h" 10 11 #include <new> 12 #include <stdio.h> 13 14 #include <Beep.h> 15 #include <Window.h> 16 17 #include "CalcView.h" 18 19 using std::nothrow; 20 21 static const int32 kMaxPreviousExpressions = 20; 22 23 24 ExpressionTextView::ExpressionTextView(BRect frame, CalcView* calcView) 25 : InputTextView(frame, "expression text view", 26 (frame.OffsetToCopy(B_ORIGIN)).InsetByCopy(2, 2), 27 B_FOLLOW_NONE, B_WILL_DRAW), 28 fCalcView(calcView), 29 fKeypadLabels(""), 30 fPreviousExpressions(20), 31 fHistoryPos(0), 32 fCurrentExpression("") 33 { 34 SetStylable(false); 35 SetDoesUndo(true); 36 SetColorSpace(B_RGB32); 37 SetFontAndColor(be_bold_font, B_FONT_ALL); 38 } 39 40 41 ExpressionTextView::~ExpressionTextView() 42 { 43 int32 count = fPreviousExpressions.CountItems(); 44 for (int32 i = 0; i < count; i++) 45 delete (BString*)fPreviousExpressions.ItemAtFast(i); 46 } 47 48 49 void 50 ExpressionTextView::MakeFocus(bool focused) 51 { 52 if (focused == IsFocus()) { 53 // stop endless loop when CalcView calls us again 54 return; 55 } 56 57 // NOTE: order of lines important! 58 InputTextView::MakeFocus(focused); 59 fCalcView->MakeFocus(focused); 60 } 61 62 63 void 64 ExpressionTextView::KeyDown(const char* bytes, int32 numBytes) 65 { 66 // handle expression history 67 if (bytes[0] == B_UP_ARROW) { 68 PreviousExpression(); 69 return; 70 } 71 if (bytes[0] == B_DOWN_ARROW) { 72 NextExpression(); 73 return; 74 } 75 BString current = Text(); 76 77 // handle in InputTextView, except B_TAB 78 if (bytes[0] != B_TAB) 79 InputTextView::KeyDown(bytes, numBytes); 80 81 // pass on to CalcView if this was a label on a key 82 if (fKeypadLabels.FindFirst(bytes[0]) >= 0) 83 fCalcView->FlashKey(bytes, numBytes); 84 85 // as soon as something is typed, we are at the 86 // end of the expression history 87 if (current != Text()) 88 fHistoryPos = fPreviousExpressions.CountItems(); 89 } 90 91 92 void 93 ExpressionTextView::MouseDown(BPoint where) 94 { 95 uint32 buttons; 96 Window()->CurrentMessage()->FindInt32("buttons", (int32*)&buttons); 97 if (buttons & B_PRIMARY_MOUSE_BUTTON) { 98 InputTextView::MouseDown(where); 99 return; 100 } 101 where = ConvertToParent(where); 102 fCalcView->MouseDown(where); 103 } 104 105 106 // #pragma mark - 107 108 109 void 110 ExpressionTextView::RevertChanges() 111 { 112 Clear(); 113 } 114 115 116 void 117 ExpressionTextView::ApplyChanges() 118 { 119 AddExpressionToHistory(Text()); 120 fCalcView->Evaluate(); 121 } 122 123 124 // #pragma mark - 125 126 127 void 128 ExpressionTextView::AddKeypadLabel(const char* label) 129 { 130 fKeypadLabels << label; 131 } 132 133 134 void 135 ExpressionTextView::SetExpression(const char* expression) 136 { 137 SetText(expression); 138 int32 lastPos = strlen(expression); 139 Select(lastPos, lastPos); 140 } 141 142 143 void 144 ExpressionTextView::BackSpace() 145 { 146 const char bytes[1] = { B_BACKSPACE }; 147 KeyDown(bytes, 1); 148 } 149 150 151 void 152 ExpressionTextView::Clear() 153 { 154 SetText(""); 155 } 156 157 158 // #pragma mark - 159 160 161 void 162 ExpressionTextView::AddExpressionToHistory(const char* expression) 163 { 164 // clean out old expressions that are the same as 165 // the one to be added 166 int32 count = fPreviousExpressions.CountItems(); 167 for (int32 i = 0; i < count; i++) { 168 BString* item = (BString*)fPreviousExpressions.ItemAt(i); 169 if (*item == expression && fPreviousExpressions.RemoveItem(i)) { 170 delete item; 171 i--; 172 count--; 173 } 174 } 175 176 BString* item = new (nothrow) BString(expression); 177 if (!item) 178 return; 179 if (!fPreviousExpressions.AddItem(item)) { 180 delete item; 181 return; 182 } 183 while (fPreviousExpressions.CountItems() > kMaxPreviousExpressions) 184 delete (BString*)fPreviousExpressions.RemoveItem(0L); 185 186 fHistoryPos = fPreviousExpressions.CountItems(); 187 } 188 189 190 void 191 ExpressionTextView::PreviousExpression() 192 { 193 int32 count = fPreviousExpressions.CountItems(); 194 if (fHistoryPos == count) { 195 // save current expression 196 fCurrentExpression = Text(); 197 } 198 199 fHistoryPos--; 200 if (fHistoryPos < 0) { 201 fHistoryPos = 0; 202 return; 203 } 204 205 BString* item = (BString*)fPreviousExpressions.ItemAt(fHistoryPos); 206 if (item) 207 SetExpression(item->String()); 208 } 209 210 211 void 212 ExpressionTextView::NextExpression() 213 { 214 int32 count = fPreviousExpressions.CountItems(); 215 216 fHistoryPos++; 217 if (fHistoryPos == count) { 218 SetExpression(fCurrentExpression.String()); 219 return; 220 } 221 222 if (fHistoryPos > count) { 223 fHistoryPos = count; 224 return; 225 } 226 227 BString* item = (BString*)fPreviousExpressions.ItemAt(fHistoryPos); 228 if (item) 229 SetExpression(item->String()); 230 } 231 232 233 // #pragma mark - 234 235 236 void 237 ExpressionTextView::LoadSettings(const BMessage* archive) 238 { 239 const char* oldExpression; 240 for (int32 i = 0; 241 archive->FindString("previous expression", i, &oldExpression) == B_OK; 242 i++) { 243 AddExpressionToHistory(oldExpression); 244 } 245 } 246 247 248 status_t 249 ExpressionTextView::SaveSettings(BMessage* archive) const 250 { 251 int32 count = fPreviousExpressions.CountItems(); 252 for (int32 i = 0; i < count; i++) { 253 BString* item = (BString*)fPreviousExpressions.ItemAtFast(i); 254 status_t ret = archive->AddString("previous expression", item->String()); 255 if (ret < B_OK) 256 return ret; 257 } 258 return B_OK; 259 } 260 261 262