Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 244 | chris | 1 | #include "ListWidget.h" |
| 2 | #include "Font.h" |
||
| 3 | #include "WidgetManager.h" |
||
| 4 | #include "ScrollbarWidget.h" |
||
| 5 | #include "ListListener.h" |
||
| 6 | #include "SexyAppBase.h" |
||
| 7 | |||
| 8 | using namespace Sexy; |
||
| 9 | |||
| 10 | static int gInitialListWidgetColors[][3] = {{255, 255, 255}, {255, 255, 255}, {0, 0, 0}, {0, 192, 0}, {0, 0, 128}, {255, 255, 255}}; |
||
| 11 | |||
| 12 | ListWidget::ListWidget(int theId, Font *theFont, ListListener *theListListener) |
||
| 13 | { |
||
| 14 | mJustify = JUSTIFY_LEFT; |
||
| 15 | mHiliteIdx = -1; |
||
| 16 | mSelectIdx = -1; |
||
| 17 | |||
| 18 | if (theFont != NULL) |
||
| 19 | mItemHeight = theFont->GetHeight(); |
||
| 20 | else |
||
| 21 | mItemHeight = -1; |
||
| 22 | |||
| 23 | SetColors(gInitialListWidgetColors, 6); |
||
| 24 | |||
| 25 | mId = theId; |
||
| 26 | mFont = theFont; |
||
| 27 | mListListener = theListListener; |
||
| 28 | mParent = NULL; |
||
| 29 | mChild = NULL; |
||
| 30 | mScrollbar = NULL; |
||
| 31 | mPosition = 0; |
||
| 32 | mPageSize = 0; |
||
| 33 | mSortFromChild = false; |
||
| 34 | mDrawOutline = true; |
||
| 35 | mMaxNumericPlaces = 0; |
||
| 36 | mDrawSelectWhenHilited = false; |
||
| 37 | mDoFingerWhenHilited = true; |
||
| 38 | } |
||
| 39 | |||
| 40 | ListWidget::~ListWidget() |
||
| 41 | { |
||
| 42 | } |
||
| 43 | |||
| 44 | void ListWidget::RemovedFromManager(WidgetManager *theManager) |
||
| 45 | { |
||
| 46 | Widget::RemovedFromManager(theManager); |
||
| 47 | if (mListListener) |
||
| 48 | mListListener->ListClosed(mId); |
||
| 49 | } |
||
| 50 | |||
| 51 | SexyString ListWidget::GetSortKey(int theIdx) |
||
| 52 | { |
||
| 53 | SexyString aString = mLines[theIdx]; |
||
| 54 | |||
| 55 | while (aString.length() < (ulong) mMaxNumericPlaces) |
||
| 56 | aString = _S("0") + aString; |
||
| 57 | |||
| 58 | if (mSortFromChild) |
||
| 59 | return mChild->GetSortKey(theIdx) + aString; |
||
| 60 | else |
||
| 61 | { |
||
| 62 | if (mChild == NULL) |
||
| 63 | return aString; |
||
| 64 | else |
||
| 65 | return aString + mChild->GetSortKey(theIdx); |
||
| 66 | } |
||
| 67 | |||
| 68 | return _S(""); |
||
| 69 | } |
||
| 70 | |||
| 71 | void ListWidget::Sort(bool ascending) |
||
| 72 | { |
||
| 73 | int aCount = mLines.size(); |
||
| 74 | int* aMap = new int[aCount]; |
||
| 75 | SexyString* aKeys = new SexyString[aCount]; |
||
| 76 | |||
| 77 | int i; |
||
| 78 | for (i = 0; i < aCount; i++) |
||
| 79 | { |
||
| 80 | aMap[i] = i; |
||
| 81 | aKeys[i] = GetSortKey(i); |
||
| 82 | } |
||
| 83 | |||
| 84 | for (i = 1; i < aCount; i++) |
||
| 85 | for (int j = 0; j < aCount - i; j++) |
||
| 86 | { |
||
| 87 | int aComp = aKeys[j].compare(aKeys[j+1]); |
||
| 88 | if ((ascending && (aComp > 0)) || (!ascending && (aComp < 0))) |
||
| 89 | { |
||
| 90 | int aSwapInt = aMap[j]; |
||
| 91 | aMap[j] = aMap[j+1]; |
||
| 92 | aMap[j+1] = aSwapInt; |
||
| 93 | |||
| 94 | SexyString aSwapKey = aKeys[j]; |
||
| 95 | aKeys[j] = aKeys[j+1]; |
||
| 96 | aKeys[j+1] = aSwapKey; |
||
| 97 | } |
||
| 98 | } |
||
| 99 | |||
| 100 | ListWidget *aListWidget = this; |
||
| 101 | while (aListWidget->mParent != NULL) |
||
| 102 | aListWidget = aListWidget->mParent; |
||
| 103 | |||
| 104 | while (aListWidget != NULL) |
||
| 105 | { |
||
| 106 | SexyStringVector aNewLines; |
||
| 107 | ColorVector aNewLineColors; |
||
| 108 | |||
| 109 | for (int i = 0; i < aCount; i++) |
||
| 110 | { |
||
| 111 | aNewLines.push_back(aListWidget->mLines[aMap[i]]); |
||
| 112 | aNewLineColors.push_back(aListWidget->mLineColors[aMap[i]]); |
||
| 113 | } |
||
| 114 | |||
| 115 | aListWidget->mLines = aNewLines; |
||
| 116 | aListWidget->mLineColors = aNewLineColors; |
||
| 117 | |||
| 118 | aListWidget->MarkDirty(); |
||
| 119 | |||
| 120 | aListWidget = aListWidget->mChild; |
||
| 121 | } |
||
| 122 | |||
| 123 | delete aMap; |
||
| 124 | delete aKeys; |
||
| 125 | } |
||
| 126 | |||
| 127 | SexyString ListWidget::GetStringAt(int theIdx) |
||
| 128 | { |
||
| 129 | return |
||
| 130 | mLines[theIdx]; |
||
| 131 | } |
||
| 132 | |||
| 133 | void ListWidget::Resize(int theX, int theY, int theWidth, int theHeight) |
||
| 134 | { |
||
| 135 | Widget::Resize(theX, theY, theWidth, theHeight); |
||
| 136 | |||
| 137 | double aPageSize = 1; |
||
| 138 | int anItemHeight = (mItemHeight != -1) ? mItemHeight : mFont->GetHeight(); |
||
| 139 | |||
| 140 | if (mHeight > anItemHeight+8) |
||
| 141 | aPageSize = (mHeight - 8.0) / anItemHeight; |
||
| 142 | |||
| 143 | mPageSize = aPageSize; |
||
| 144 | |||
| 145 | if (mScrollbar != NULL) |
||
| 146 | mScrollbar->SetPageSize(aPageSize); |
||
| 147 | } |
||
| 148 | |||
| 149 | int ListWidget::AddLine(const SexyString& theLine, bool alphabetical) |
||
| 150 | { |
||
| 151 | int anIdx = -1; |
||
| 152 | bool inserted = false; |
||
| 153 | |||
| 154 | if (alphabetical) |
||
| 155 | { |
||
| 156 | for (int i = 0; i < (int) mLines.size(); i++) |
||
| 157 | if (sexystrcmp(theLine.c_str(), mLines[i].c_str()) < 0) |
||
| 158 | { |
||
| 159 | anIdx = i; |
||
| 160 | |||
| 161 | ListWidget *aListWidget = this; |
||
| 162 | |||
| 163 | while (aListWidget->mParent != NULL) |
||
| 164 | aListWidget = aListWidget->mParent; |
||
| 165 | |||
| 166 | while (aListWidget != NULL) |
||
| 167 | { |
||
| 168 | if (aListWidget == this) |
||
| 169 | aListWidget->mLines.insert(aListWidget->mLines.begin() + i, theLine); |
||
| 170 | else |
||
| 171 | aListWidget->mLines.insert(aListWidget->mLines.begin() + i, _S("-")); |
||
| 172 | |||
| 173 | aListWidget->mLineColors.insert(aListWidget->mLineColors.begin() + i, mColors[COLOR_TEXT]); |
||
| 174 | aListWidget->MarkDirty(); |
||
| 175 | |||
| 176 | aListWidget = aListWidget->mChild; |
||
| 177 | } |
||
| 178 | |||
| 179 | inserted = true; |
||
| 180 | break; |
||
| 181 | } |
||
| 182 | } |
||
| 183 | |||
| 184 | if (!inserted) |
||
| 185 | { |
||
| 186 | anIdx = mLines.size(); |
||
| 187 | |||
| 188 | ListWidget *aListWidget = this; |
||
| 189 | |||
| 190 | while (aListWidget->mParent!=NULL) |
||
| 191 | aListWidget = aListWidget->mParent; |
||
| 192 | |||
| 193 | while (aListWidget!=NULL) |
||
| 194 | { |
||
| 195 | if (aListWidget==this) |
||
| 196 | aListWidget->mLines.push_back(theLine); |
||
| 197 | else |
||
| 198 | aListWidget->mLines.push_back(_S("-")); |
||
| 199 | |||
| 200 | aListWidget->mLineColors.push_back(mColors[COLOR_TEXT]); |
||
| 201 | aListWidget->MarkDirty(); |
||
| 202 | |||
| 203 | aListWidget = aListWidget->mChild; |
||
| 204 | } |
||
| 205 | } |
||
| 206 | |||
| 207 | if (mScrollbar!=NULL) |
||
| 208 | mScrollbar->SetMaxValue(mLines.size()); |
||
| 209 | |||
| 210 | return anIdx; |
||
| 211 | } |
||
| 212 | |||
| 213 | |||
| 214 | void ListWidget::SetLine(int theIdx, const SexyString& theString) |
||
| 215 | { |
||
| 216 | mLines[theIdx] = theString; |
||
| 217 | MarkDirty(); |
||
| 218 | } |
||
| 219 | |||
| 220 | int ListWidget::GetLineCount() |
||
| 221 | { |
||
| 222 | return mLines.size(); |
||
| 223 | } |
||
| 224 | |||
| 225 | int ListWidget::GetLineIdx(const SexyString& theLine) |
||
| 226 | { |
||
| 227 | for (ulong i = 0; i < mLines.size(); i++) |
||
| 228 | if (sexystrcmp(mLines[i].c_str(), theLine.c_str()) == 0) |
||
| 229 | return i; |
||
| 230 | |||
| 231 | return -1; |
||
| 232 | } |
||
| 233 | |||
| 234 | void ListWidget::SetColor(const SexyString& theLine, const Color& theColor) |
||
| 235 | { |
||
| 236 | int anIdx = GetLineIdx(theLine); |
||
| 237 | SetLineColor(anIdx, theColor); |
||
| 238 | } |
||
| 239 | |||
| 240 | void ListWidget::SetColor(int theIdx, const Color& theColor) |
||
| 241 | { |
||
| 242 | Widget::SetColor(theIdx, theColor); |
||
| 243 | } |
||
| 244 | |||
| 245 | void ListWidget::SetLineColor(int theIdx, const Color& theColor) |
||
| 246 | { |
||
| 247 | if ((theIdx >= 0) && (theIdx < (int)mLines.size())) |
||
| 248 | { |
||
| 249 | ListWidget *aListWidget = this; |
||
| 250 | |||
| 251 | while (aListWidget->mParent != NULL) |
||
| 252 | aListWidget = aListWidget->mParent; |
||
| 253 | |||
| 254 | while (aListWidget != NULL) |
||
| 255 | { |
||
| 256 | aListWidget->mLineColors[theIdx] = theColor; |
||
| 257 | aListWidget->MarkDirty(); |
||
| 258 | |||
| 259 | aListWidget = aListWidget->mChild; |
||
| 260 | } |
||
| 261 | } |
||
| 262 | } |
||
| 263 | |||
| 264 | void ListWidget::RemoveLine(int theIdx) |
||
| 265 | { |
||
| 266 | if (theIdx != -1) |
||
| 267 | { |
||
| 268 | ListWidget *aListWidget = this; |
||
| 269 | |||
| 270 | while (aListWidget->mParent != NULL) |
||
| 271 | aListWidget = aListWidget->mParent; |
||
| 272 | |||
| 273 | while (aListWidget != NULL) |
||
| 274 | { |
||
| 275 | aListWidget->mLines.erase(aListWidget->mLines.begin() + theIdx); |
||
| 276 | aListWidget->mLineColors.erase(aListWidget->mLineColors.begin() + theIdx); |
||
| 277 | |||
| 278 | aListWidget->MarkDirty(); |
||
| 279 | aListWidget = aListWidget->mChild; |
||
| 280 | } |
||
| 281 | } |
||
| 282 | |||
| 283 | if (mScrollbar != NULL) |
||
| 284 | mScrollbar->SetMaxValue(mLines.size()); |
||
| 285 | } |
||
| 286 | |||
| 287 | void ListWidget::RemoveAll() |
||
| 288 | { |
||
| 289 | ListWidget *aListWidget = this; |
||
| 290 | |||
| 291 | while (aListWidget->mParent != NULL) |
||
| 292 | aListWidget = aListWidget->mParent; |
||
| 293 | |||
| 294 | while (aListWidget != NULL) |
||
| 295 | { |
||
| 296 | aListWidget->mLines.clear(); |
||
| 297 | aListWidget->mLineColors.clear(); |
||
| 298 | aListWidget->mSelectIdx = -1; |
||
| 299 | aListWidget->mHiliteIdx = -1; |
||
| 300 | |||
| 301 | aListWidget->MarkDirty(); |
||
| 302 | aListWidget = aListWidget->mChild; |
||
| 303 | } |
||
| 304 | |||
| 305 | if (mScrollbar != NULL) |
||
| 306 | mScrollbar->SetMaxValue(mLines.size()); |
||
| 307 | } |
||
| 308 | |||
| 309 | int ListWidget::GetOptimalWidth() |
||
| 310 | { |
||
| 311 | int aMaxWidth = 0; |
||
| 312 | |||
| 313 | for (ulong i = 0; i < mLines.size(); i++) |
||
| 314 | aMaxWidth = max(aMaxWidth, mFont->StringWidth(mLines[i])); |
||
| 315 | |||
| 316 | return aMaxWidth + 16; |
||
| 317 | } |
||
| 318 | |||
| 319 | int ListWidget::GetOptimalHeight() |
||
| 320 | { |
||
| 321 | int anItemHeight = (mItemHeight != -1) ? mItemHeight : mFont->GetHeight(); |
||
| 322 | |||
| 323 | return anItemHeight * mLines.size() + 8; |
||
| 324 | } |
||
| 325 | |||
| 326 | void ListWidget::OrderInManagerChanged() |
||
| 327 | { |
||
| 328 | Widget::OrderInManagerChanged(); |
||
| 329 | |||
| 330 | if (mChild != NULL) |
||
| 331 | gSexyAppBase->mWidgetManager->PutInfront(mChild, this); |
||
| 332 | if (mScrollbar != NULL) |
||
| 333 | gSexyAppBase->mWidgetManager->PutInfront(mScrollbar, this); |
||
| 334 | } |
||
| 335 | |||
| 336 | void ListWidget::Draw(Graphics *g) |
||
| 337 | { |
||
| 338 | g->SetColor(mColors[COLOR_BKG]); |
||
| 339 | g->FillRect(0, 0, mWidth, mHeight); |
||
| 340 | |||
| 341 | Graphics aClipG(*g); |
||
| 342 | aClipG.ClipRect(4, 4, mWidth - 8, mHeight - 8); |
||
| 343 | |||
| 344 | Graphics aSelectClipG(*g); |
||
| 345 | aSelectClipG.ClipRect(0, 4, mWidth, mHeight - 8); |
||
| 346 | |||
| 347 | aClipG.SetFont(mFont); |
||
| 348 | |||
| 349 | int aFirstLine = (int) mPosition; |
||
| 350 | int aLastLine = min((int) mLines.size()-1, (int) mPosition + (int) mPageSize + 1); |
||
| 351 | |||
| 352 | int anItemHeight, anItemOffset; |
||
| 353 | if (mItemHeight != -1) |
||
| 354 | { |
||
| 355 | anItemHeight = mItemHeight; |
||
| 356 | anItemOffset = (anItemHeight-mFont->GetHeight())/2; |
||
| 357 | } |
||
| 358 | else |
||
| 359 | { |
||
| 360 | anItemHeight = mFont->GetHeight(); |
||
| 361 | anItemOffset = 0; |
||
| 362 | } |
||
| 363 | |||
| 364 | for (int i = aFirstLine; i <= aLastLine; i++) |
||
| 365 | { |
||
| 366 | int aDrawY = 4 + (int) ((i - mPosition)*anItemHeight); |
||
| 367 | |||
| 368 | if (i == mSelectIdx || (i==mHiliteIdx && mDrawSelectWhenHilited)) |
||
| 369 | { |
||
| 370 | aSelectClipG.SetColor(mColors[COLOR_SELECT]); |
||
| 371 | aSelectClipG.FillRect(0, aDrawY, mWidth, anItemHeight); |
||
| 372 | } |
||
| 373 | |||
| 374 | if (i == mHiliteIdx) |
||
| 375 | aClipG.SetColor(mColors[COLOR_HILITE]); |
||
| 376 | else if ((i == mSelectIdx) && (mColors.size() > COLOR_SELECT_TEXT)) |
||
| 377 | aClipG.SetColor(mColors[COLOR_SELECT_TEXT]); |
||
| 378 | else |
||
| 379 | aClipG.SetColor(mLineColors[i]); |
||
| 380 | |||
| 381 | SexyString aString = mLines[i]; |
||
| 382 | int aFontX; |
||
| 383 | switch (mJustify) |
||
| 384 | { |
||
| 385 | case JUSTIFY_LEFT: |
||
| 386 | aFontX = 4; |
||
| 387 | break; |
||
| 388 | case JUSTIFY_CENTER: |
||
| 389 | aFontX = (mWidth - mFont->StringWidth(aString))/2; |
||
| 390 | break; |
||
| 391 | default: |
||
| 392 | aFontX = mWidth - mFont->StringWidth(aString) - 4; |
||
| 393 | break; |
||
| 394 | } |
||
| 395 | |||
| 396 | aClipG.DrawString(aString, aFontX, aDrawY + mFont->GetAscent() + anItemOffset); |
||
| 397 | } |
||
| 398 | |||
| 399 | if (mDrawOutline) |
||
| 400 | { |
||
| 401 | g->SetColor(mColors[COLOR_OUTLINE]); |
||
| 402 | g->DrawRect(0, 0, mWidth-1, mHeight-1); |
||
| 403 | } |
||
| 404 | } |
||
| 405 | |||
| 406 | void ListWidget::ScrollPosition(int theId, double thePosition) |
||
| 407 | { |
||
| 408 | if (mChild != NULL) |
||
| 409 | mChild->ScrollPosition(theId, thePosition); |
||
| 410 | |||
| 411 | mPosition = thePosition; |
||
| 412 | MarkDirty(); |
||
| 413 | } |
||
| 414 | |||
| 415 | void ListWidget::SetHilite(int theHiliteIdx, bool notifyListener) |
||
| 416 | { |
||
| 417 | int anOldIdx = mHiliteIdx; |
||
| 418 | mHiliteIdx = theHiliteIdx; |
||
| 419 | if (anOldIdx!=mHiliteIdx && notifyListener && mListListener!=NULL) |
||
| 420 | mListListener->ListHiliteChanged(mId,anOldIdx,mHiliteIdx); |
||
| 421 | } |
||
| 422 | |||
| 423 | |||
| 424 | void ListWidget::MouseMove(int x, int y) |
||
| 425 | { |
||
| 426 | int anItemHeight = (mItemHeight != -1) ? mItemHeight : mFont->GetHeight(); |
||
| 427 | |||
| 428 | int aNewHilite = (int) (((y - 4) / (double) anItemHeight) + mPosition); |
||
| 429 | if ((aNewHilite < 0) || (aNewHilite >= (int) mLines.size())) |
||
| 430 | aNewHilite = -1; |
||
| 431 | |||
| 432 | if (aNewHilite != mHiliteIdx) |
||
| 433 | { |
||
| 434 | ListWidget* aListWidget = this; |
||
| 435 | |||
| 436 | while (aListWidget->mParent != NULL) |
||
| 437 | aListWidget = aListWidget->mParent; |
||
| 438 | |||
| 439 | while (aListWidget != NULL) |
||
| 440 | { |
||
| 441 | aListWidget->SetHilite(aNewHilite,true); |
||
| 442 | aListWidget->MarkDirty(); |
||
| 443 | aListWidget = aListWidget->mChild; |
||
| 444 | } |
||
| 445 | |||
| 446 | if (mHiliteIdx == -1 || !mDoFingerWhenHilited) |
||
| 447 | mWidgetManager->mApp->SetCursor(CURSOR_POINTER); |
||
| 448 | else |
||
| 449 | mWidgetManager->mApp->SetCursor(CURSOR_HAND); |
||
| 450 | } |
||
| 451 | } |
||
| 452 | |||
| 453 | void ListWidget::MouseDown(int x, int y, int theBtnNum, int theClickCount) |
||
| 454 | { |
||
| 455 | if ((mHiliteIdx != -1) && (mListListener != NULL)) |
||
| 456 | mListListener->ListClicked(mId, mHiliteIdx, theClickCount); |
||
| 457 | } |
||
| 458 | |||
| 459 | void ListWidget::MouseLeave() |
||
| 460 | { |
||
| 461 | ListWidget *aListWidget = this; |
||
| 462 | |||
| 463 | while (aListWidget->mParent != NULL) |
||
| 464 | aListWidget = aListWidget->mParent; |
||
| 465 | |||
| 466 | while (aListWidget != NULL) |
||
| 467 | { |
||
| 468 | aListWidget->SetHilite(-1,true); |
||
| 469 | aListWidget->MarkDirty(); |
||
| 470 | aListWidget = aListWidget->mChild; |
||
| 471 | } |
||
| 472 | |||
| 473 | mWidgetManager->mApp->SetCursor(CURSOR_POINTER); |
||
| 474 | } |
||
| 475 | |||
| 476 | void ListWidget::SetSelect(int theSelectIdx) |
||
| 477 | { |
||
| 478 | ListWidget *aListWidget = this; |
||
| 479 | |||
| 480 | while (aListWidget->mParent != NULL) |
||
| 481 | aListWidget = aListWidget->mParent; |
||
| 482 | |||
| 483 | while (aListWidget != NULL) |
||
| 484 | { |
||
| 485 | aListWidget->mSelectIdx = theSelectIdx; |
||
| 486 | aListWidget->MarkDirty(); |
||
| 487 | aListWidget = aListWidget->mChild; |
||
| 488 | } |
||
| 489 | } |
||
| 490 | |||
| 491 | |||
| 492 | void ListWidget::MouseWheel(int theDelta) |
||
| 493 | { |
||
| 494 | if (mScrollbar != NULL) |
||
| 495 | { |
||
| 496 | int aScrollAmount = 5; |
||
| 497 | if (theDelta > 0) |
||
| 498 | { |
||
| 499 | mScrollbar->SetValue(mScrollbar->mValue - aScrollAmount); |
||
| 500 | // mScrollbar->mUpdateMode = ScrollbarWidget::UPDATE_MODE_PGUP; |
||
| 501 | // mScrollbar->mUpdateAcc = 0; |
||
| 502 | } |
||
| 503 | else if (theDelta < 0) |
||
| 504 | { |
||
| 505 | mScrollbar->SetValue(mScrollbar->mValue + aScrollAmount); |
||
| 506 | // mScrollbar->mUpdateMode = ScrollbarWidget::UPDATE_MODE_PGDN; |
||
| 507 | // mScrollbar->mUpdateAcc = 0; |
||
| 508 | } |
||
| 509 | } |
||
| 510 | } |