Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 244 | chris | 1 | #include "Widget.h" |
| 2 | #include "WidgetManager.h" |
||
| 3 | #include "Graphics.h" |
||
| 4 | #include "Font.h" |
||
| 5 | #include "Image.h" |
||
| 6 | #include "SexyAppBase.h" |
||
| 7 | #include "debug.h" |
||
| 8 | |||
| 9 | using namespace Sexy; |
||
| 10 | |||
| 11 | bool Widget::mWriteColoredString = true; |
||
| 12 | |||
| 13 | Widget::Widget() |
||
| 14 | { |
||
| 15 | mWidgetManager = NULL; |
||
| 16 | mVisible = true; |
||
| 17 | mDisabled = false; |
||
| 18 | mIsDown = false; |
||
| 19 | mIsOver = false; |
||
| 20 | mDoFinger = false; |
||
| 21 | mMouseVisible = true; |
||
| 22 | mHasFocus = false; |
||
| 23 | mHasTransparencies = false; |
||
| 24 | mWantsFocus = false; |
||
| 25 | mTabPrev = NULL; |
||
| 26 | mTabNext = NULL; |
||
| 27 | } |
||
| 28 | |||
| 29 | Widget::~Widget() |
||
| 30 | { |
||
| 31 | mColors.clear(); |
||
| 32 | } |
||
| 33 | |||
| 34 | void Widget::WidgetRemovedHelper() |
||
| 35 | { |
||
| 36 | if (mWidgetManager==NULL) |
||
| 37 | return; |
||
| 38 | |||
| 39 | // Call RemovedFromManager on all child widgets and disable them and stuff like that |
||
| 40 | for (WidgetList::iterator aWidgetItr = mWidgets.begin(); aWidgetItr != mWidgets.end(); ++aWidgetItr) |
||
| 41 | { |
||
| 42 | Widget *aWidget = *aWidgetItr; |
||
| 43 | aWidget->WidgetRemovedHelper(); |
||
| 44 | } |
||
| 45 | |||
| 46 | mWidgetManager->DisableWidget(this); |
||
| 47 | |||
| 48 | PreModalInfoList::iterator anItr = mWidgetManager->mPreModalInfoList.begin(); |
||
| 49 | while (anItr != mWidgetManager->mPreModalInfoList.end()) |
||
| 50 | { |
||
| 51 | PreModalInfo* aPreModalInfo = &(*anItr); |
||
| 52 | if (aPreModalInfo->mPrevBaseModalWidget == this) |
||
| 53 | aPreModalInfo->mPrevBaseModalWidget = NULL; |
||
| 54 | if (aPreModalInfo->mPrevFocusWidget == this) |
||
| 55 | aPreModalInfo->mPrevFocusWidget = NULL; |
||
| 56 | ++anItr; |
||
| 57 | } |
||
| 58 | |||
| 59 | RemovedFromManager(mWidgetManager); |
||
| 60 | MarkDirtyFull(this); |
||
| 61 | |||
| 62 | mWidgetManager = NULL; |
||
| 63 | } |
||
| 64 | |||
| 65 | void Widget::OrderInManagerChanged() |
||
| 66 | { |
||
| 67 | } |
||
| 68 | |||
| 69 | bool Widget::IsPointVisible(int x, int y) |
||
| 70 | { |
||
| 71 | return true; |
||
| 72 | } |
||
| 73 | |||
| 74 | void Widget::SetVisible(bool isVisible) |
||
| 75 | { |
||
| 76 | if (mVisible == isVisible) |
||
| 77 | return; |
||
| 78 | |||
| 79 | mVisible = isVisible; |
||
| 80 | |||
| 81 | if (mVisible) |
||
| 82 | MarkDirty(); |
||
| 83 | else |
||
| 84 | MarkDirtyFull(); |
||
| 85 | |||
| 86 | if (mWidgetManager != NULL) |
||
| 87 | mWidgetManager->RehupMouse(); |
||
| 88 | } |
||
| 89 | |||
| 90 | void Widget::Draw(Graphics* g) // Already translated |
||
| 91 | { |
||
| 92 | } |
||
| 93 | |||
| 94 | void Widget::DrawOverlay(Graphics* g) |
||
| 95 | { |
||
| 96 | } |
||
| 97 | |||
| 98 | void Widget::DrawOverlay(Graphics* g, int thePriority) |
||
| 99 | { |
||
| 100 | DrawOverlay(g); |
||
| 101 | } |
||
| 102 | |||
| 103 | void Widget::SetColors(int theColors[][3], int theNumColors) |
||
| 104 | { |
||
| 105 | mColors.clear(); |
||
| 106 | |||
| 107 | for (int i = 0; i < theNumColors; i++) |
||
| 108 | SetColor(i, Color(theColors[i][0], theColors[i][1], theColors[i][2])); |
||
| 109 | MarkDirty(); |
||
| 110 | } |
||
| 111 | |||
| 112 | void Widget::SetColors(int theColors[][4], int theNumColors) |
||
| 113 | { |
||
| 114 | mColors.clear(); |
||
| 115 | |||
| 116 | for (int i = 0; i < theNumColors; i++) |
||
| 117 | SetColor(i, Color(theColors[i][0], theColors[i][1], theColors[i][2], theColors[i][3])); |
||
| 118 | |||
| 119 | MarkDirty(); |
||
| 120 | } |
||
| 121 | |||
| 122 | void Widget::SetColor(int theIdx, const Color& theColor) |
||
| 123 | { |
||
| 124 | if (theIdx >= (int)mColors.size()) |
||
| 125 | mColors.resize(theIdx + 1); |
||
| 126 | |||
| 127 | mColors[theIdx] = theColor; |
||
| 128 | MarkDirty(); |
||
| 129 | } |
||
| 130 | |||
| 131 | const Color& Widget::GetColor(int theIdx) |
||
| 132 | { |
||
| 133 | static Color aColor; |
||
| 134 | if (theIdx < (int) mColors.size()) |
||
| 135 | return mColors[theIdx]; |
||
| 136 | return aColor; |
||
| 137 | } |
||
| 138 | |||
| 139 | Color Widget::GetColor(int theIdx, const Color& theDefaultColor) |
||
| 140 | { |
||
| 141 | if (theIdx < (int) mColors.size()) |
||
| 142 | return mColors[theIdx]; |
||
| 143 | return theDefaultColor; |
||
| 144 | } |
||
| 145 | |||
| 146 | void Widget::Resize(int theX, int theY, int theWidth, int theHeight) |
||
| 147 | { |
||
| 148 | if ((mX == theX) && (mY == theY) && (mWidth == theWidth) && (mHeight == theHeight)) |
||
| 149 | return; |
||
| 150 | |||
| 151 | // Mark everything dirty that is over or under the old position |
||
| 152 | MarkDirtyFull(); |
||
| 153 | |||
| 154 | mX = theX; |
||
| 155 | mY = theY; |
||
| 156 | mWidth = theWidth; |
||
| 157 | mHeight = theHeight; |
||
| 158 | |||
| 159 | // Mark things dirty that are over the new position |
||
| 160 | MarkDirty(); |
||
| 161 | |||
| 162 | if (mWidgetManager != NULL) |
||
| 163 | mWidgetManager->RehupMouse(); |
||
| 164 | } |
||
| 165 | |||
| 166 | void Widget::Resize(const Rect& theRect) |
||
| 167 | { |
||
| 168 | Resize(theRect.mX, theRect.mY, theRect.mWidth, theRect.mHeight); |
||
| 169 | } |
||
| 170 | |||
| 171 | void Widget::Move(int theNewX, int theNewY) |
||
| 172 | { |
||
| 173 | Resize(theNewX, theNewY, mWidth, mHeight); |
||
| 174 | } |
||
| 175 | |||
| 176 | bool Widget::WantsFocus() |
||
| 177 | { |
||
| 178 | return mWantsFocus; |
||
| 179 | } |
||
| 180 | |||
| 181 | void Widget::SetDisabled(bool isDisabled) |
||
| 182 | { |
||
| 183 | if (mDisabled == isDisabled) |
||
| 184 | return; |
||
| 185 | |||
| 186 | mDisabled = isDisabled; |
||
| 187 | |||
| 188 | if ((isDisabled) && (mWidgetManager != NULL)) |
||
| 189 | mWidgetManager->DisableWidget(this); |
||
| 190 | |||
| 191 | MarkDirty(); |
||
| 192 | |||
| 193 | // Incase a widget is enabled right under our cursor |
||
| 194 | if ((!isDisabled) && (mWidgetManager != NULL) && (Contains(mWidgetManager->mLastMouseX, mWidgetManager->mLastMouseY))) |
||
| 195 | mWidgetManager->MousePosition(mWidgetManager->mLastMouseX, mWidgetManager->mLastMouseY); |
||
| 196 | } |
||
| 197 | |||
| 198 | void Widget::GotFocus() |
||
| 199 | { |
||
| 200 | mHasFocus = true; |
||
| 201 | } |
||
| 202 | |||
| 203 | void Widget::LostFocus() |
||
| 204 | { |
||
| 205 | mHasFocus = false; |
||
| 206 | } |
||
| 207 | |||
| 208 | void Widget::Update() |
||
| 209 | { |
||
| 210 | WidgetContainer::Update(); |
||
| 211 | } |
||
| 212 | |||
| 213 | void Widget::UpdateF(float theFrac) |
||
| 214 | { |
||
| 215 | } |
||
| 216 | |||
| 217 | void Widget::KeyChar(SexyChar theChar) |
||
| 218 | { |
||
| 219 | } |
||
| 220 | |||
| 221 | void Widget::KeyDown(KeyCode theKey) |
||
| 222 | { |
||
| 223 | if (theKey == KEYCODE_TAB) |
||
| 224 | { |
||
| 225 | if (mWidgetManager->mKeyDown[KEYCODE_SHIFT]) |
||
| 226 | { |
||
| 227 | if (mTabPrev != NULL) |
||
| 228 | mWidgetManager->SetFocus(mTabPrev); |
||
| 229 | } |
||
| 230 | else |
||
| 231 | { |
||
| 232 | if (mTabNext != NULL) |
||
| 233 | mWidgetManager->SetFocus(mTabNext); |
||
| 234 | } |
||
| 235 | } |
||
| 236 | } |
||
| 237 | |||
| 238 | void Widget::KeyUp(KeyCode theKey) |
||
| 239 | { |
||
| 240 | } |
||
| 241 | |||
| 242 | void Widget::ShowFinger(bool on) |
||
| 243 | { |
||
| 244 | if (mWidgetManager == NULL) |
||
| 245 | return; |
||
| 246 | |||
| 247 | if (on) |
||
| 248 | mWidgetManager->mApp->SetCursor(CURSOR_HAND); |
||
| 249 | else |
||
| 250 | mWidgetManager->mApp->SetCursor(CURSOR_POINTER); |
||
| 251 | |||
| 252 | /*if (on) |
||
| 253 | mWidgetManager->mApplet.setCursor(new Cursor(Cursor.HAND_CURSOR)); |
||
| 254 | else |
||
| 255 | mWidgetManager->mApplet.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));*/ |
||
| 256 | } |
||
| 257 | |||
| 258 | void Widget::MouseEnter() |
||
| 259 | { |
||
| 260 | |||
| 261 | } |
||
| 262 | |||
| 263 | void Widget::MouseLeave() |
||
| 264 | { |
||
| 265 | |||
| 266 | } |
||
| 267 | |||
| 268 | void Widget::MouseMove(int x, int y) |
||
| 269 | { |
||
| 270 | } |
||
| 271 | |||
| 272 | void Widget::MouseDown(int x, int y, int theClickCount) |
||
| 273 | { |
||
| 274 | if (theClickCount == 3) |
||
| 275 | MouseDown(x, y, 2, 1); |
||
| 276 | else if (theClickCount >= 0) |
||
| 277 | MouseDown(x, y, 0, theClickCount); |
||
| 278 | else |
||
| 279 | MouseDown(x, y, 1, -theClickCount); |
||
| 280 | } |
||
| 281 | |||
| 282 | void Widget::MouseDown(int x, int y, int theBtnNum, int theClickCount) |
||
| 283 | { |
||
| 284 | } |
||
| 285 | |||
| 286 | void Widget::MouseUp(int x, int y) |
||
| 287 | { |
||
| 288 | } |
||
| 289 | |||
| 290 | void Widget::MouseUp(int x, int y, int theLastDownButtonId) |
||
| 291 | { |
||
| 292 | MouseUp(x, y); |
||
| 293 | |||
| 294 | if (theLastDownButtonId == 3) |
||
| 295 | MouseUp(x, y, 2, 1); |
||
| 296 | else if (theLastDownButtonId >= 0) |
||
| 297 | MouseUp(x, y, 0, theLastDownButtonId); |
||
| 298 | else |
||
| 299 | MouseUp(x, y, 1, -theLastDownButtonId); |
||
| 300 | } |
||
| 301 | |||
| 302 | void Widget::MouseUp(int x, int y, int theBtnNum, int theClickCount) |
||
| 303 | { |
||
| 304 | } |
||
| 305 | |||
| 306 | void Widget::MouseDrag(int x, int y) |
||
| 307 | { |
||
| 308 | } |
||
| 309 | |||
| 310 | void Widget::MouseWheel(int theDelta) |
||
| 311 | { |
||
| 312 | } |
||
| 313 | |||
| 314 | //////// Helper functions |
||
| 315 | |||
| 316 | Rect Widget::WriteCenteredLine(Graphics* g, int anOffset, const SexyString& theLine) |
||
| 317 | { |
||
| 318 | Font* aFont = g->GetFont(); |
||
| 319 | int aWidth = aFont->StringWidth(theLine); |
||
| 320 | int aX = (mWidth - aWidth) / 2; |
||
| 321 | |||
| 322 | g->DrawString(theLine, aX, anOffset); |
||
| 323 | |||
| 324 | return Rect(aX, anOffset - aFont->GetAscent(), aWidth, aFont->GetHeight()); |
||
| 325 | } |
||
| 326 | |||
| 327 | Rect Widget::WriteCenteredLine(Graphics* g, int anOffset, const SexyString& theLine, Color theColor1, Color theColor2, const Point& theShadowOffset) |
||
| 328 | { |
||
| 329 | Font* aFont = g->GetFont(); |
||
| 330 | int aWidth = aFont->StringWidth(theLine); |
||
| 331 | int aX = (mWidth - aWidth) / 2; |
||
| 332 | |||
| 333 | g->SetColor(theColor2); |
||
| 334 | g->DrawString(theLine, (mWidth - aWidth)/2 + theShadowOffset.mX, anOffset + theShadowOffset.mY); |
||
| 335 | |||
| 336 | g->SetColor(theColor1); |
||
| 337 | g->DrawString(theLine, (mWidth - aWidth)/2, anOffset); |
||
| 338 | |||
| 339 | // account for shadow in position and size |
||
| 340 | // TODO: this may not be necessary. |
||
| 341 | return Rect( |
||
| 342 | aX + min(0,theShadowOffset.mX), |
||
| 343 | anOffset - aFont->GetAscent() + min(0,theShadowOffset.mY), |
||
| 344 | aWidth + abs(theShadowOffset.mX), |
||
| 345 | aFont->GetHeight() + abs(theShadowOffset.mY)); |
||
| 346 | } |
||
| 347 | |||
| 348 | int Widget::WriteString(Graphics* g, const SexyString& theString, int theX, int theY, int theWidth, int theJustification, bool drawString, int theOffset, int theLength) |
||
| 349 | { |
||
| 350 | bool oldColored = g->mWriteColoredString; |
||
| 351 | g->mWriteColoredString = mWriteColoredString; |
||
| 352 | int aXOffset = g->WriteString(theString,theX,theY,theWidth,theJustification,drawString,theOffset,theLength); |
||
| 353 | g->mWriteColoredString = oldColored; |
||
| 354 | |||
| 355 | return aXOffset; |
||
| 356 | } |
||
| 357 | |||
| 358 | int Widget::WriteWordWrapped(Graphics* g, const Rect& theRect, const SexyString& theLine, int theLineSpacing, int theJustification) |
||
| 359 | { |
||
| 360 | bool oldColored = g->mWriteColoredString; |
||
| 361 | g->mWriteColoredString = mWriteColoredString; |
||
| 362 | int aReturn = g->WriteWordWrapped(theRect,theLine,theLineSpacing,theJustification); |
||
| 363 | g->mWriteColoredString = oldColored; |
||
| 364 | |||
| 365 | return aReturn; |
||
| 366 | } |
||
| 367 | |||
| 368 | int Widget::GetWordWrappedHeight(Graphics* g, int theWidth, const SexyString& theLine, int aLineSpacing) |
||
| 369 | { |
||
| 370 | return g->GetWordWrappedHeight(theWidth,theLine,aLineSpacing); |
||
| 371 | } |
||
| 372 | |||
| 373 | int Widget::GetNumDigits(int theNumber) |
||
| 374 | { |
||
| 375 | int aDivisor = 10; |
||
| 376 | int aNumDigits = 1; |
||
| 377 | while (theNumber >= aDivisor) |
||
| 378 | { |
||
| 379 | aNumDigits++; |
||
| 380 | aDivisor *= 10; |
||
| 381 | } |
||
| 382 | |||
| 383 | return aNumDigits; |
||
| 384 | } |
||
| 385 | |||
| 386 | void Widget::WriteNumberFromStrip(Graphics* g, int theNumber, int theX, int theY, Image* theNumberStrip, int aSpacing) |
||
| 387 | { |
||
| 388 | int aDivisor = 10; |
||
| 389 | int aNumDigits = 1; |
||
| 390 | while (theNumber >= aDivisor) |
||
| 391 | { |
||
| 392 | aNumDigits++; |
||
| 393 | aDivisor *= 10; |
||
| 394 | } |
||
| 395 | if (theNumber == 0) |
||
| 396 | aDivisor = 10; |
||
| 397 | |||
| 398 | int aDigitLen = theNumberStrip->GetWidth() / 10; |
||
| 399 | |||
| 400 | for (int aDigitIdx = 0; aDigitIdx < aNumDigits; aDigitIdx++) |
||
| 401 | { |
||
| 402 | aDivisor /= 10; |
||
| 403 | int aDigit = (theNumber / aDivisor) % 10; |
||
| 404 | |||
| 405 | Graphics* aClipG = g->Create(); |
||
| 406 | aClipG->ClipRect(theX + aDigitIdx*(aDigitLen + aSpacing), theY, aDigitLen, theNumberStrip->GetHeight()); |
||
| 407 | aClipG->DrawImage(theNumberStrip, theX + aDigitIdx*(aDigitLen + aSpacing) - aDigit*aDigitLen, theY); |
||
| 408 | delete aClipG; |
||
| 409 | } |
||
| 410 | } |
||
| 411 | |||
| 412 | bool Widget::Contains(int theX, int theY) |
||
| 413 | { |
||
| 414 | return ((theX >= mX) && (theX < mX + mWidth) && |
||
| 415 | (theY >= mY) && (theY < mY + mHeight)); |
||
| 416 | } |
||
| 417 | |||
| 418 | Rect Widget::GetInsetRect() |
||
| 419 | { |
||
| 420 | return Rect(mX + mMouseInsets.mLeft, mY + mMouseInsets.mTop, |
||
| 421 | mWidth - mMouseInsets.mLeft - mMouseInsets.mRight, |
||
| 422 | mHeight - mMouseInsets.mTop - mMouseInsets.mBottom); |
||
| 423 | } |
||
| 424 | |||
| 425 | void Widget::DeferOverlay(int thePriority) |
||
| 426 | { |
||
| 427 | mWidgetManager->DeferOverlay(this, thePriority); |
||
| 428 | } |
||
| 429 | |||
| 430 | void Widget::Layout(int theLayoutFlags, Widget *theRelativeWidget, int theLeftPad, int theTopPad, int theWidthPad, int theHeightPad) |
||
| 431 | { |
||
| 432 | int aRelLeft = theRelativeWidget->Left(); |
||
| 433 | int aRelTop = theRelativeWidget->Top(); |
||
| 434 | if (theRelativeWidget==mParent) |
||
| 435 | { |
||
| 436 | aRelLeft = 0; |
||
| 437 | aRelTop = 0; |
||
| 438 | } |
||
| 439 | |||
| 440 | int aRelWidth = theRelativeWidget->Width(); |
||
| 441 | int aRelHeight = theRelativeWidget->Height(); |
||
| 442 | int aRelRight = aRelLeft + aRelWidth; |
||
| 443 | int aRelBottom = aRelTop + aRelHeight; |
||
| 444 | |||
| 445 | int aLeft = Left(); |
||
| 446 | int aTop = Top(); |
||
| 447 | int aWidth = Width(); |
||
| 448 | int aHeight = Height(); |
||
| 449 | |||
| 450 | int aType = 1; |
||
| 451 | while(aType<LAY_Max) |
||
| 452 | { |
||
| 453 | if(theLayoutFlags&aType) |
||
| 454 | { |
||
| 455 | switch(aType) |
||
| 456 | { |
||
| 457 | case LAY_SameWidth: aWidth = aRelWidth+theWidthPad; break; |
||
| 458 | case LAY_SameHeight: aHeight = aRelHeight+theHeightPad; break; |
||
| 459 | |||
| 460 | case LAY_Above: aTop = aRelTop-aHeight+theTopPad; break; |
||
| 461 | case LAY_Below: aTop = aRelBottom+theTopPad; break; |
||
| 462 | case LAY_Right: aLeft = aRelRight+theLeftPad; break; |
||
| 463 | case LAY_Left: aLeft = aRelLeft-aWidth+theLeftPad; break; |
||
| 464 | |||
| 465 | case LAY_SameLeft: aLeft = aRelLeft+theLeftPad; break; |
||
| 466 | case LAY_SameRight: aLeft = aRelRight-aWidth+theLeftPad; break; |
||
| 467 | case LAY_SameTop: aTop = aRelTop+theTopPad; break; |
||
| 468 | case LAY_SameBottom: aTop = aRelBottom-aHeight+theTopPad; break; |
||
| 469 | |||
| 470 | case LAY_GrowToRight: aWidth = aRelRight-aLeft+theWidthPad; break; |
||
| 471 | case LAY_GrowToLeft: aWidth = aRelLeft-aLeft+theWidthPad; break; |
||
| 472 | case LAY_GrowToTop: aHeight = aRelTop-aTop+theHeightPad; break; |
||
| 473 | case LAY_GrowToBottom: aHeight = aRelBottom-aTop+theHeightPad; break; |
||
| 474 | |||
| 475 | case LAY_SetLeft: aLeft = theLeftPad; break; |
||
| 476 | case LAY_SetTop: aTop = theTopPad; break; |
||
| 477 | case LAY_SetWidth: aWidth = theWidthPad; break; |
||
| 478 | case LAY_SetHeight: aHeight = theHeightPad; break; |
||
| 479 | |||
| 480 | case LAY_HCenter: aLeft = aRelLeft+(aRelWidth-aWidth)/2 + theLeftPad; break; |
||
| 481 | case LAY_VCenter: aTop = aRelTop+(aRelHeight-aHeight)/2 + theTopPad; break; |
||
| 482 | } |
||
| 483 | } |
||
| 484 | |||
| 485 | aType<<=1; |
||
| 486 | } |
||
| 487 | |||
| 488 | Resize(aLeft,aTop,aWidth,aHeight); |
||
| 489 | } |