| 1 | //============================================================================ | 
|---|
| 2 | // | 
|---|
| 3 | //   SSSS    tt          lll  lll | 
|---|
| 4 | //  SS  SS   tt           ll   ll | 
|---|
| 5 | //  SS     tttttt  eeee   ll   ll   aaaa | 
|---|
| 6 | //   SSSS    tt   ee  ee  ll   ll      aa | 
|---|
| 7 | //      SS   tt   eeeeee  ll   ll   aaaaa  --  "An Atari 2600 VCS Emulator" | 
|---|
| 8 | //  SS  SS   tt   ee      ll   ll  aa  aa | 
|---|
| 9 | //   SSSS     ttt  eeeee llll llll  aaaaa | 
|---|
| 10 | // | 
|---|
| 11 | // Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony | 
|---|
| 12 | // and the Stella Team | 
|---|
| 13 | // | 
|---|
| 14 | // See the file "License.txt" for information on usage and redistribution of | 
|---|
| 15 | // this file, and for a DISCLAIMER OF ALL WARRANTIES. | 
|---|
| 16 | // | 
|---|
| 17 | //   Based on code from ScummVM - Scumm Interpreter | 
|---|
| 18 | //   Copyright (C) 2002-2004 The ScummVM project | 
|---|
| 19 | //============================================================================ | 
|---|
| 20 |  | 
|---|
| 21 | #include "bspf.hxx" | 
|---|
| 22 | #include "Command.hxx" | 
|---|
| 23 | #include "Dialog.hxx" | 
|---|
| 24 | #include "FBSurface.hxx" | 
|---|
| 25 | #include "GuiObject.hxx" | 
|---|
| 26 | #include "OSystem.hxx" | 
|---|
| 27 |  | 
|---|
| 28 | #include "Widget.hxx" | 
|---|
| 29 |  | 
|---|
| 30 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 31 | Widget::Widget(GuiObject* boss, const GUI::Font& font, | 
|---|
| 32 | int x, int y, int w, int h) | 
|---|
| 33 | : GuiObject(boss->instance(), boss->parent(), boss->dialog(), x, y, w, h), | 
|---|
| 34 | _boss(boss), | 
|---|
| 35 | _font(font), | 
|---|
| 36 | _id(0), | 
|---|
| 37 | _flags(0), | 
|---|
| 38 | _hasFocus(false), | 
|---|
| 39 | _bgcolor(kWidColor), | 
|---|
| 40 | _bgcolorhi(kWidColor), | 
|---|
| 41 | _bgcolorlo(kBGColorLo), | 
|---|
| 42 | _textcolor(kTextColor), | 
|---|
| 43 | _textcolorhi(kTextColorHi), | 
|---|
| 44 | _textcolorlo(kBGColorLo), | 
|---|
| 45 | _shadowcolor(kShadowColor) | 
|---|
| 46 | { | 
|---|
| 47 | // Insert into the widget list of the boss | 
|---|
| 48 | _next = _boss->_firstWidget; | 
|---|
| 49 | _boss->_firstWidget = this; | 
|---|
| 50 |  | 
|---|
| 51 | _fontWidth  = _font.getMaxCharWidth(); | 
|---|
| 52 | _fontHeight = _font.getLineHeight(); | 
|---|
| 53 |  | 
|---|
| 54 | setDirty(); | 
|---|
| 55 | } | 
|---|
| 56 |  | 
|---|
| 57 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 58 | Widget::~Widget() | 
|---|
| 59 | { | 
|---|
| 60 | delete _next; | 
|---|
| 61 | _next = nullptr; | 
|---|
| 62 |  | 
|---|
| 63 | _focusList.clear(); | 
|---|
| 64 | } | 
|---|
| 65 |  | 
|---|
| 66 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 67 | void Widget::setDirty() | 
|---|
| 68 | { | 
|---|
| 69 | // A widget being dirty indicates that its parent dialog is dirty | 
|---|
| 70 | // So we inform the parent about it | 
|---|
| 71 | _boss->dialog().setDirty(); | 
|---|
| 72 | } | 
|---|
| 73 |  | 
|---|
| 74 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 75 | void Widget::draw() | 
|---|
| 76 | { | 
|---|
| 77 | if(!isVisible() || !_boss->isVisible()) | 
|---|
| 78 | return; | 
|---|
| 79 |  | 
|---|
| 80 | FBSurface& s = _boss->dialog().surface(); | 
|---|
| 81 |  | 
|---|
| 82 | bool onTop = _boss->dialog().isOnTop(); | 
|---|
| 83 |  | 
|---|
| 84 | bool hasBorder = _flags & Widget::FLAG_BORDER; // currently only used by Dialog widget | 
|---|
| 85 | int oldX = _x, oldY = _y; | 
|---|
| 86 |  | 
|---|
| 87 | // Account for our relative position in the dialog | 
|---|
| 88 | _x = getAbsX(); | 
|---|
| 89 | _y = getAbsY(); | 
|---|
| 90 |  | 
|---|
| 91 | // Clear background (unless alpha blending is enabled) | 
|---|
| 92 | if(_flags & Widget::FLAG_CLEARBG) | 
|---|
| 93 | { | 
|---|
| 94 | int x = _x, y = _y, w = _w, h = _h; | 
|---|
| 95 | if(hasBorder) | 
|---|
| 96 | { | 
|---|
| 97 | x++; y++; w-=2; h-=2; | 
|---|
| 98 | } | 
|---|
| 99 | s.fillRect(x, y, w, h, !onTop ? _bgcolorlo : (_flags & Widget::FLAG_HILITED) && isEnabled() ? _bgcolorhi : _bgcolor); | 
|---|
| 100 | } | 
|---|
| 101 |  | 
|---|
| 102 | // Draw border | 
|---|
| 103 | if(hasBorder) | 
|---|
| 104 | { | 
|---|
| 105 | s.frameRect(_x, _y, _w, _h, !onTop ? kColor : (_flags & Widget::FLAG_HILITED) && isEnabled() ? kWidColorHi : kColor); | 
|---|
| 106 | _x += 4; | 
|---|
| 107 | _y += 4; | 
|---|
| 108 | _w -= 8; | 
|---|
| 109 | _h -= 8; | 
|---|
| 110 | } | 
|---|
| 111 |  | 
|---|
| 112 | // Now perform the actual widget draw | 
|---|
| 113 | drawWidget((_flags & Widget::FLAG_HILITED) ? true : false); | 
|---|
| 114 |  | 
|---|
| 115 | // Restore x/y | 
|---|
| 116 | if (hasBorder) | 
|---|
| 117 | { | 
|---|
| 118 | _x -= 4; | 
|---|
| 119 | _y -= 4; | 
|---|
| 120 | _w += 8; | 
|---|
| 121 | _h += 8; | 
|---|
| 122 | } | 
|---|
| 123 |  | 
|---|
| 124 | _x = oldX; | 
|---|
| 125 | _y = oldY; | 
|---|
| 126 |  | 
|---|
| 127 | // Draw all children | 
|---|
| 128 | Widget* w = _firstWidget; | 
|---|
| 129 | while(w) | 
|---|
| 130 | { | 
|---|
| 131 | w->draw(); | 
|---|
| 132 | w = w->_next; | 
|---|
| 133 | } | 
|---|
| 134 | } | 
|---|
| 135 |  | 
|---|
| 136 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 137 | void Widget::receivedFocus() | 
|---|
| 138 | { | 
|---|
| 139 | if(_hasFocus) | 
|---|
| 140 | return; | 
|---|
| 141 |  | 
|---|
| 142 | _hasFocus = true; | 
|---|
| 143 | setFlags(Widget::FLAG_HILITED); | 
|---|
| 144 | receivedFocusWidget(); | 
|---|
| 145 | } | 
|---|
| 146 |  | 
|---|
| 147 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 148 | void Widget::lostFocus() | 
|---|
| 149 | { | 
|---|
| 150 | if(!_hasFocus) | 
|---|
| 151 | return; | 
|---|
| 152 |  | 
|---|
| 153 | _hasFocus = false; | 
|---|
| 154 | clearFlags(Widget::FLAG_HILITED); | 
|---|
| 155 | lostFocusWidget(); | 
|---|
| 156 | } | 
|---|
| 157 |  | 
|---|
| 158 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 159 | void Widget::setEnabled(bool e) | 
|---|
| 160 | { | 
|---|
| 161 | if(e) setFlags(Widget::FLAG_ENABLED); | 
|---|
| 162 | else  clearFlags(Widget::FLAG_ENABLED); | 
|---|
| 163 | } | 
|---|
| 164 |  | 
|---|
| 165 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 166 | Widget* Widget::findWidgetInChain(Widget* w, int x, int y) | 
|---|
| 167 | { | 
|---|
| 168 | while(w) | 
|---|
| 169 | { | 
|---|
| 170 | // Stop as soon as we find a widget that contains the point (x,y) | 
|---|
| 171 | if(x >= w->_x && x < w->_x + w->_w && y >= w->_y && y < w->_y + w->_h) | 
|---|
| 172 | break; | 
|---|
| 173 | w = w->_next; | 
|---|
| 174 | } | 
|---|
| 175 |  | 
|---|
| 176 | if(w) | 
|---|
| 177 | w = w->findWidget(x - w->_x, y - w->_y); | 
|---|
| 178 |  | 
|---|
| 179 | return w; | 
|---|
| 180 | } | 
|---|
| 181 |  | 
|---|
| 182 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 183 | bool Widget::isWidgetInChain(Widget* w, Widget* find) | 
|---|
| 184 | { | 
|---|
| 185 | while(w) | 
|---|
| 186 | { | 
|---|
| 187 | // Stop as soon as we find the widget | 
|---|
| 188 | if(w == find)  return true; | 
|---|
| 189 | w = w->_next; | 
|---|
| 190 | } | 
|---|
| 191 | return false; | 
|---|
| 192 | } | 
|---|
| 193 |  | 
|---|
| 194 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 195 | bool Widget::isWidgetInChain(WidgetArray& list, Widget* find) | 
|---|
| 196 | { | 
|---|
| 197 | for(const auto& w: list) | 
|---|
| 198 | if(w == find) | 
|---|
| 199 | return true; | 
|---|
| 200 |  | 
|---|
| 201 | return false; | 
|---|
| 202 | } | 
|---|
| 203 |  | 
|---|
| 204 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 205 | Widget* Widget::setFocusForChain(GuiObject* boss, WidgetArray& arr, | 
|---|
| 206 | Widget* wid, int direction, | 
|---|
| 207 | bool emitFocusEvents) | 
|---|
| 208 | { | 
|---|
| 209 | FBSurface& s = boss->dialog().surface(); | 
|---|
| 210 | int size = int(arr.size()), pos = -1; | 
|---|
| 211 | Widget* tmp; | 
|---|
| 212 | bool onTop = boss->dialog().isOnTop(); | 
|---|
| 213 |  | 
|---|
| 214 | for(int i = 0; i < size; ++i) | 
|---|
| 215 | { | 
|---|
| 216 | tmp = arr[i]; | 
|---|
| 217 |  | 
|---|
| 218 | // Determine position of widget 'w' | 
|---|
| 219 | if(wid == tmp) | 
|---|
| 220 | pos = i; | 
|---|
| 221 |  | 
|---|
| 222 | // Get area around widget | 
|---|
| 223 | // Note: we must use getXXX() methods and not access the variables | 
|---|
| 224 | // directly, since in some cases (notably those widgets with embedded | 
|---|
| 225 | // ScrollBars) the two quantities may be different | 
|---|
| 226 | int x = tmp->getAbsX() - 1,  y = tmp->getAbsY() - 1, | 
|---|
| 227 | w = tmp->getWidth() + 2, h = tmp->getHeight() + 2; | 
|---|
| 228 |  | 
|---|
| 229 | // First clear area surrounding all widgets | 
|---|
| 230 | if(tmp->_hasFocus) | 
|---|
| 231 | { | 
|---|
| 232 | if(emitFocusEvents) | 
|---|
| 233 | tmp->lostFocus(); | 
|---|
| 234 | else | 
|---|
| 235 | tmp->_hasFocus = false; | 
|---|
| 236 |  | 
|---|
| 237 | s.frameRect(x, y, w, h, onTop ? kDlgColor : kBGColorLo); | 
|---|
| 238 |  | 
|---|
| 239 | tmp->setDirty(); | 
|---|
| 240 | } | 
|---|
| 241 | } | 
|---|
| 242 |  | 
|---|
| 243 | // Figure out which which should be active | 
|---|
| 244 | if(pos == -1) | 
|---|
| 245 | return nullptr; | 
|---|
| 246 | else | 
|---|
| 247 | { | 
|---|
| 248 | int oldPos = pos; | 
|---|
| 249 | do | 
|---|
| 250 | { | 
|---|
| 251 | switch(direction) | 
|---|
| 252 | { | 
|---|
| 253 | case -1:  // previous widget | 
|---|
| 254 | pos--; | 
|---|
| 255 | if(pos < 0) | 
|---|
| 256 | pos = size - 1; | 
|---|
| 257 | break; | 
|---|
| 258 |  | 
|---|
| 259 | case +1:  // next widget | 
|---|
| 260 | pos++; | 
|---|
| 261 | if(pos >= size) | 
|---|
| 262 | pos = 0; | 
|---|
| 263 | break; | 
|---|
| 264 |  | 
|---|
| 265 | default: | 
|---|
| 266 | // pos already set | 
|---|
| 267 | break; | 
|---|
| 268 | } | 
|---|
| 269 | // break if all widgets should be disabled | 
|---|
| 270 | if(oldPos == pos) | 
|---|
| 271 | break; | 
|---|
| 272 | } while(!arr[pos]->isEnabled()); | 
|---|
| 273 | } | 
|---|
| 274 |  | 
|---|
| 275 | // Now highlight the active widget | 
|---|
| 276 | tmp = arr[pos]; | 
|---|
| 277 |  | 
|---|
| 278 | // Get area around widget | 
|---|
| 279 | // Note: we must use getXXX() methods and not access the variables | 
|---|
| 280 | // directly, since in some cases (notably those widgets with embedded | 
|---|
| 281 | // ScrollBars) the two quantities may be different | 
|---|
| 282 | int x = tmp->getAbsX() - 1,  y = tmp->getAbsY() - 1, | 
|---|
| 283 | w = tmp->getWidth() + 2, h = tmp->getHeight() + 2; | 
|---|
| 284 |  | 
|---|
| 285 | if(emitFocusEvents) | 
|---|
| 286 | tmp->receivedFocus(); | 
|---|
| 287 | else { | 
|---|
| 288 | tmp->_hasFocus = true; | 
|---|
| 289 | tmp->setFlags(Widget::FLAG_HILITED); | 
|---|
| 290 | } | 
|---|
| 291 |  | 
|---|
| 292 | if (onTop) | 
|---|
| 293 | s.frameRect(x, y, w, h, kWidFrameColor, FrameStyle::Dashed); | 
|---|
| 294 |  | 
|---|
| 295 | tmp->setDirty(); | 
|---|
| 296 |  | 
|---|
| 297 | return tmp; | 
|---|
| 298 | } | 
|---|
| 299 |  | 
|---|
| 300 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 301 | void Widget::setDirtyInChain(Widget* start) | 
|---|
| 302 | { | 
|---|
| 303 | while(start) | 
|---|
| 304 | { | 
|---|
| 305 | start->setDirty(); | 
|---|
| 306 | start = start->_next; | 
|---|
| 307 | } | 
|---|
| 308 | } | 
|---|
| 309 |  | 
|---|
| 310 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 311 | StaticTextWidget::StaticTextWidget(GuiObject* boss, const GUI::Font& font, | 
|---|
| 312 | int x, int y, int w, int h, | 
|---|
| 313 | const string& text, TextAlign align, | 
|---|
| 314 | ColorId shadowColor) | 
|---|
| 315 | : Widget(boss, font, x, y, w, h), | 
|---|
| 316 | _align(align) | 
|---|
| 317 | { | 
|---|
| 318 | _flags = Widget::FLAG_ENABLED; | 
|---|
| 319 | _bgcolor = kDlgColor; | 
|---|
| 320 | _bgcolorhi = kDlgColor; | 
|---|
| 321 | _textcolor = kTextColor; | 
|---|
| 322 | _textcolorhi = kTextColor; | 
|---|
| 323 | _shadowcolor = shadowColor; | 
|---|
| 324 |  | 
|---|
| 325 | _label = text; | 
|---|
| 326 | _editable = false; | 
|---|
| 327 | } | 
|---|
| 328 |  | 
|---|
| 329 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 330 | StaticTextWidget::StaticTextWidget(GuiObject* boss, const GUI::Font& font, | 
|---|
| 331 | int x, int y, | 
|---|
| 332 | const string& text, TextAlign align, | 
|---|
| 333 | ColorId shadowColor) | 
|---|
| 334 | : StaticTextWidget(boss, font, x, y, font.getStringWidth(text), font.getLineHeight(), | 
|---|
| 335 | text, align, shadowColor) | 
|---|
| 336 | { | 
|---|
| 337 | } | 
|---|
| 338 |  | 
|---|
| 339 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 340 | void StaticTextWidget::setValue(int value) | 
|---|
| 341 | { | 
|---|
| 342 | char buf[256]; | 
|---|
| 343 | std::snprintf(buf, 255, "%d", value); | 
|---|
| 344 | _label = buf; | 
|---|
| 345 |  | 
|---|
| 346 | setDirty(); | 
|---|
| 347 | } | 
|---|
| 348 |  | 
|---|
| 349 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 350 | void StaticTextWidget::setLabel(const string& label) | 
|---|
| 351 | { | 
|---|
| 352 | _label = label; | 
|---|
| 353 |  | 
|---|
| 354 | setDirty(); | 
|---|
| 355 | } | 
|---|
| 356 |  | 
|---|
| 357 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 358 | void StaticTextWidget::drawWidget(bool hilite) | 
|---|
| 359 | { | 
|---|
| 360 | FBSurface& s = _boss->dialog().surface(); | 
|---|
| 361 | bool onTop = _boss->dialog().isOnTop(); | 
|---|
| 362 | s.drawString(_font, _label, _x, _y, _w, | 
|---|
| 363 | isEnabled() && onTop ? _textcolor : kColor, _align, 0, true, _shadowcolor); | 
|---|
| 364 |  | 
|---|
| 365 | setDirty(); | 
|---|
| 366 | } | 
|---|
| 367 |  | 
|---|
| 368 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 369 | ButtonWidget::ButtonWidget(GuiObject* boss, const GUI::Font& font, | 
|---|
| 370 | int x, int y, int w, int h, | 
|---|
| 371 | const string& label, int cmd, bool repeat) | 
|---|
| 372 | : StaticTextWidget(boss, font, x, y, w, h, label, TextAlign::Center), | 
|---|
| 373 | CommandSender(boss), | 
|---|
| 374 | _cmd(cmd), | 
|---|
| 375 | _repeat(repeat), | 
|---|
| 376 | _useBitmap(false), | 
|---|
| 377 | _bitmap(nullptr), | 
|---|
| 378 | _bmw(0), | 
|---|
| 379 | _bmh(0) | 
|---|
| 380 | { | 
|---|
| 381 | _flags = Widget::FLAG_ENABLED | Widget::FLAG_CLEARBG; | 
|---|
| 382 | _bgcolor = kBtnColor; | 
|---|
| 383 | _bgcolorhi = kBtnColorHi; | 
|---|
| 384 | _bgcolorlo = kColor; | 
|---|
| 385 | _textcolor = kBtnTextColor; | 
|---|
| 386 | _textcolorhi = kBtnTextColorHi; | 
|---|
| 387 | _textcolorlo = kBGColorLo; | 
|---|
| 388 |  | 
|---|
| 389 | _editable = false; | 
|---|
| 390 | } | 
|---|
| 391 |  | 
|---|
| 392 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 393 | ButtonWidget::ButtonWidget(GuiObject* boss, const GUI::Font& font, | 
|---|
| 394 | int x, int y, int dw, | 
|---|
| 395 | const string& label, int cmd, bool repeat) | 
|---|
| 396 | : ButtonWidget(boss, font, x, y, font.getStringWidth(label) + dw, font.getLineHeight() + 4, label, cmd, repeat) | 
|---|
| 397 | { | 
|---|
| 398 | } | 
|---|
| 399 |  | 
|---|
| 400 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 401 | ButtonWidget::ButtonWidget(GuiObject* boss, const GUI::Font& font, | 
|---|
| 402 | int x, int y, | 
|---|
| 403 | const string& label, int cmd, bool repeat) | 
|---|
| 404 | : ButtonWidget(boss, font, x, y, 20, label, cmd, repeat) | 
|---|
| 405 | { | 
|---|
| 406 | } | 
|---|
| 407 |  | 
|---|
| 408 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 409 | ButtonWidget::ButtonWidget(GuiObject* boss, const GUI::Font& font, | 
|---|
| 410 | int x, int y, int w, int h, | 
|---|
| 411 | uInt32* bitmap, int bmw, int bmh, | 
|---|
| 412 | int cmd, bool repeat) | 
|---|
| 413 | : ButtonWidget(boss, font, x, y, w, h, "", cmd, repeat) | 
|---|
| 414 | { | 
|---|
| 415 | _bitmap = bitmap; | 
|---|
| 416 | _bmh = bmh; | 
|---|
| 417 | _bmw = bmw; | 
|---|
| 418 | _useBitmap = true; | 
|---|
| 419 | } | 
|---|
| 420 |  | 
|---|
| 421 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 422 | void ButtonWidget::handleMouseEntered() | 
|---|
| 423 | { | 
|---|
| 424 | setFlags(Widget::FLAG_HILITED); | 
|---|
| 425 | } | 
|---|
| 426 |  | 
|---|
| 427 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 428 | void ButtonWidget::handleMouseLeft() | 
|---|
| 429 | { | 
|---|
| 430 | clearFlags(Widget::FLAG_HILITED); | 
|---|
| 431 | } | 
|---|
| 432 |  | 
|---|
| 433 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 434 | bool ButtonWidget::handleEvent(Event::Type e) | 
|---|
| 435 | { | 
|---|
| 436 | if(!isEnabled()) | 
|---|
| 437 | return false; | 
|---|
| 438 |  | 
|---|
| 439 | switch(e) | 
|---|
| 440 | { | 
|---|
| 441 | case Event::UISelect: | 
|---|
| 442 | // Simulate mouse event | 
|---|
| 443 | handleMouseUp(0, 0, MouseButton::LEFT, 0); | 
|---|
| 444 | return true; | 
|---|
| 445 | default: | 
|---|
| 446 | return false; | 
|---|
| 447 | } | 
|---|
| 448 | } | 
|---|
| 449 |  | 
|---|
| 450 | bool ButtonWidget::handleMouseClicks(int x, int y, MouseButton b) | 
|---|
| 451 | { | 
|---|
| 452 | return _repeat; | 
|---|
| 453 | } | 
|---|
| 454 |  | 
|---|
| 455 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 456 | void ButtonWidget::handleMouseDown(int x, int y, MouseButton b, int clickCount) | 
|---|
| 457 | { | 
|---|
| 458 | if(_repeat && isEnabled() && x >= 0 && x < _w && y >= 0 && y < _h) | 
|---|
| 459 | { | 
|---|
| 460 | clearFlags(Widget::FLAG_HILITED); | 
|---|
| 461 | sendCommand(_cmd, 0, _id); | 
|---|
| 462 | } | 
|---|
| 463 | } | 
|---|
| 464 |  | 
|---|
| 465 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 466 | void ButtonWidget::handleMouseUp(int x, int y, MouseButton b, int clickCount) | 
|---|
| 467 | { | 
|---|
| 468 | if (!_repeat && isEnabled() && x >= 0 && x < _w && y >= 0 && y < _h) | 
|---|
| 469 | { | 
|---|
| 470 | clearFlags(Widget::FLAG_HILITED); | 
|---|
| 471 | sendCommand(_cmd, 0, _id); | 
|---|
| 472 | } | 
|---|
| 473 | } | 
|---|
| 474 |  | 
|---|
| 475 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 476 | void ButtonWidget::setBitmap(uInt32* bitmap, int bmw, int bmh) | 
|---|
| 477 | { | 
|---|
| 478 | _bitmap = bitmap; | 
|---|
| 479 | _bmh = bmh; | 
|---|
| 480 | _bmw = bmw; | 
|---|
| 481 | _useBitmap = true; | 
|---|
| 482 |  | 
|---|
| 483 | setDirty(); | 
|---|
| 484 | } | 
|---|
| 485 |  | 
|---|
| 486 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 487 | void ButtonWidget::drawWidget(bool hilite) | 
|---|
| 488 | { | 
|---|
| 489 | FBSurface& s = _boss->dialog().surface(); | 
|---|
| 490 | bool onTop = _boss->dialog().isOnTop(); | 
|---|
| 491 |  | 
|---|
| 492 | s.frameRect(_x, _y, _w, _h, !onTop ? kShadowColor : hilite && isEnabled() ? kBtnBorderColorHi : kBtnBorderColor); | 
|---|
| 493 |  | 
|---|
| 494 | if (!_useBitmap) | 
|---|
| 495 | s.drawString(_font, _label, _x, _y + (_h - _fontHeight)/2 + 1, _w, | 
|---|
| 496 | !(isEnabled() && onTop) ? _textcolorlo : | 
|---|
| 497 | hilite ? _textcolorhi : _textcolor, _align); | 
|---|
| 498 | else | 
|---|
| 499 | s.drawBitmap(_bitmap, _x + (_w - _bmw) / 2, _y + (_h - _bmh) / 2, | 
|---|
| 500 | !(isEnabled() && onTop) ? _textcolorlo : | 
|---|
| 501 | hilite ? _textcolorhi : _textcolor, | 
|---|
| 502 | _bmw, _bmh); | 
|---|
| 503 |  | 
|---|
| 504 | setDirty(); | 
|---|
| 505 | } | 
|---|
| 506 |  | 
|---|
| 507 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 508 | /* 8x8 checkbox bitmap */ | 
|---|
| 509 | static uInt32 checked_img_active[10] = | 
|---|
| 510 | { | 
|---|
| 511 | 0b1111111111, | 
|---|
| 512 | 0b1111111111, | 
|---|
| 513 | 0b1111111111, | 
|---|
| 514 | 0b1111111111, | 
|---|
| 515 | 0b1111111111, | 
|---|
| 516 | 0b1111111111, | 
|---|
| 517 | 0b1111111111, | 
|---|
| 518 | 0b1111111111, | 
|---|
| 519 | 0b1111111111, | 
|---|
| 520 | 0b1111111111 | 
|---|
| 521 | }; | 
|---|
| 522 |  | 
|---|
| 523 | static uInt32 checked_img_inactive[10] = | 
|---|
| 524 | { | 
|---|
| 525 | 0b1111111111, | 
|---|
| 526 | 0b1111111111, | 
|---|
| 527 | 0b1111001111, | 
|---|
| 528 | 0b1110000111, | 
|---|
| 529 | 0b1100000011, | 
|---|
| 530 | 0b1100000011, | 
|---|
| 531 | 0b1110000111, | 
|---|
| 532 | 0b1111001111, | 
|---|
| 533 | 0b1111111111, | 
|---|
| 534 | 0b1111111111 | 
|---|
| 535 | }; | 
|---|
| 536 |  | 
|---|
| 537 | static uInt32 checked_img_circle[10] = | 
|---|
| 538 | { | 
|---|
| 539 | 0b0001111000, | 
|---|
| 540 | 0b0111111110, | 
|---|
| 541 | 0b0111111110, | 
|---|
| 542 | 0b1111111111, | 
|---|
| 543 | 0b1111111111, | 
|---|
| 544 | 0b1111111111, | 
|---|
| 545 | 0b1111111111, | 
|---|
| 546 | 0b0111111110, | 
|---|
| 547 | 0b0111111110, | 
|---|
| 548 | 0b0001111000 | 
|---|
| 549 | }; | 
|---|
| 550 |  | 
|---|
| 551 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 552 | CheckboxWidget::CheckboxWidget(GuiObject* boss, const GUI::Font& font, | 
|---|
| 553 | int x, int y, const string& label, | 
|---|
| 554 | int cmd) | 
|---|
| 555 | : ButtonWidget(boss, font, x, y, 16, 16, label, cmd), | 
|---|
| 556 | _state(false), | 
|---|
| 557 | _holdFocus(true), | 
|---|
| 558 | _drawBox(true), | 
|---|
| 559 | _changed(false), | 
|---|
| 560 | _fillColor(kColor), | 
|---|
| 561 | _boxY(0), | 
|---|
| 562 | _textY(0) | 
|---|
| 563 | { | 
|---|
| 564 | _flags = Widget::FLAG_ENABLED; | 
|---|
| 565 | _bgcolor = _bgcolorhi = kWidColor; | 
|---|
| 566 | _bgcolorlo = kDlgColor; | 
|---|
| 567 |  | 
|---|
| 568 | _editable = true; | 
|---|
| 569 |  | 
|---|
| 570 | if(label == "") | 
|---|
| 571 | _w = 14; | 
|---|
| 572 | else | 
|---|
| 573 | _w = font.getStringWidth(label) + 20; | 
|---|
| 574 | _h = font.getFontHeight() < 14 ? 14 : font.getFontHeight(); | 
|---|
| 575 |  | 
|---|
| 576 |  | 
|---|
| 577 | // Depending on font size, either the font or box will need to be | 
|---|
| 578 | // centered vertically | 
|---|
| 579 | if(_h > 14)  // center box | 
|---|
| 580 | _boxY = (_h - 14) / 2; | 
|---|
| 581 | else         // center text | 
|---|
| 582 | _textY = (14 - _font.getFontHeight()) / 2; | 
|---|
| 583 |  | 
|---|
| 584 | setFill(CheckboxWidget::FillType::Normal); | 
|---|
| 585 | } | 
|---|
| 586 |  | 
|---|
| 587 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 588 | void CheckboxWidget::handleMouseEntered() | 
|---|
| 589 | { | 
|---|
| 590 | setFlags(Widget::FLAG_HILITED); | 
|---|
| 591 | } | 
|---|
| 592 |  | 
|---|
| 593 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 594 | void CheckboxWidget::handleMouseLeft() | 
|---|
| 595 | { | 
|---|
| 596 | clearFlags(Widget::FLAG_HILITED); | 
|---|
| 597 | } | 
|---|
| 598 |  | 
|---|
| 599 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 600 | void CheckboxWidget::handleMouseUp(int x, int y, MouseButton b, int clickCount) | 
|---|
| 601 | { | 
|---|
| 602 | if(isEnabled() && _editable && x >= 0 && x < _w && y >= 0 && y < _h) | 
|---|
| 603 | { | 
|---|
| 604 | toggleState(); | 
|---|
| 605 |  | 
|---|
| 606 | // We only send a command when the widget has been changed interactively | 
|---|
| 607 | sendCommand(_cmd, _state, _id); | 
|---|
| 608 | } | 
|---|
| 609 | } | 
|---|
| 610 |  | 
|---|
| 611 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 612 | void CheckboxWidget::setEditable(bool editable) | 
|---|
| 613 | { | 
|---|
| 614 | _editable = editable; | 
|---|
| 615 | if(_editable) | 
|---|
| 616 | { | 
|---|
| 617 | _bgcolor = kWidColor; | 
|---|
| 618 | } | 
|---|
| 619 | else | 
|---|
| 620 | { | 
|---|
| 621 | _bgcolor = kBGColorHi; | 
|---|
| 622 | setFill(CheckboxWidget::FillType::Inactive); | 
|---|
| 623 | } | 
|---|
| 624 | setDirty(); | 
|---|
| 625 | } | 
|---|
| 626 |  | 
|---|
| 627 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 628 | void CheckboxWidget::setFill(FillType type) | 
|---|
| 629 | { | 
|---|
| 630 | switch(type) | 
|---|
| 631 | { | 
|---|
| 632 | case CheckboxWidget::FillType::Normal: | 
|---|
| 633 | _img = checked_img_active; | 
|---|
| 634 | _drawBox = true; | 
|---|
| 635 | break; | 
|---|
| 636 | case CheckboxWidget::FillType::Inactive: | 
|---|
| 637 | _img = checked_img_inactive; | 
|---|
| 638 | _drawBox = true; | 
|---|
| 639 | break; | 
|---|
| 640 | case CheckboxWidget::FillType::Circle: | 
|---|
| 641 | _img = checked_img_circle; | 
|---|
| 642 | _drawBox = false; | 
|---|
| 643 | break; | 
|---|
| 644 | } | 
|---|
| 645 | setDirty(); | 
|---|
| 646 | } | 
|---|
| 647 |  | 
|---|
| 648 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 649 | void CheckboxWidget::setState(bool state, bool changed) | 
|---|
| 650 | { | 
|---|
| 651 | if(_state != state) | 
|---|
| 652 | { | 
|---|
| 653 | _state = state; | 
|---|
| 654 | setDirty(); | 
|---|
| 655 | } | 
|---|
| 656 | _changed = changed; | 
|---|
| 657 | } | 
|---|
| 658 |  | 
|---|
| 659 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 660 | void CheckboxWidget::drawWidget(bool hilite) | 
|---|
| 661 | { | 
|---|
| 662 | FBSurface& s = _boss->dialog().surface(); | 
|---|
| 663 | bool onTop = _boss->dialog().isOnTop(); | 
|---|
| 664 |  | 
|---|
| 665 | if(_drawBox) | 
|---|
| 666 | s.frameRect(_x, _y + _boxY, 14, 14, onTop && hilite && isEnabled() && isEditable() ? kWidColorHi : kColor); | 
|---|
| 667 | // Do we draw a square or cross? | 
|---|
| 668 | s.fillRect(_x + 1, _y + _boxY + 1, 12, 12, | 
|---|
| 669 | _changed ? onTop ? kDbgChangedColor : kDlgColor : | 
|---|
| 670 | isEnabled() && onTop ? _bgcolor : kDlgColor); | 
|---|
| 671 | if(_state) | 
|---|
| 672 | s.drawBitmap(_img, _x + 2, _y + _boxY + 2, onTop && isEnabled() ? hilite && isEditable() ? kWidColorHi : kCheckColor | 
|---|
| 673 | : kColor, 10); | 
|---|
| 674 |  | 
|---|
| 675 | // Finally draw the label | 
|---|
| 676 | s.drawString(_font, _label, _x + 20, _y + _textY, _w, | 
|---|
| 677 | onTop && isEnabled() ? kTextColor : kColor); | 
|---|
| 678 |  | 
|---|
| 679 | setDirty(); | 
|---|
| 680 | } | 
|---|
| 681 |  | 
|---|
| 682 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 683 | SliderWidget::SliderWidget(GuiObject* boss, const GUI::Font& font, | 
|---|
| 684 | int x, int y, int w, int h, | 
|---|
| 685 | const string& label, int labelWidth, int cmd, | 
|---|
| 686 | int valueLabelWidth, const string& valueUnit, int valueLabelGap) | 
|---|
| 687 | : ButtonWidget(boss, font, x, y, w, h, label, cmd), | 
|---|
| 688 | _value(-1), | 
|---|
| 689 | _stepValue(1), | 
|---|
| 690 | _valueMin(0), | 
|---|
| 691 | _valueMax(100), | 
|---|
| 692 | _isDragging(false), | 
|---|
| 693 | _labelWidth(labelWidth), | 
|---|
| 694 | _valueLabel( ""), | 
|---|
| 695 | _valueUnit(valueUnit), | 
|---|
| 696 | _valueLabelGap(valueLabelGap), | 
|---|
| 697 | _valueLabelWidth(valueLabelWidth), | 
|---|
| 698 | _numIntervals(0) | 
|---|
| 699 | { | 
|---|
| 700 | _flags = Widget::FLAG_ENABLED | Widget::FLAG_TRACK_MOUSE; | 
|---|
| 701 | _bgcolor = kDlgColor; | 
|---|
| 702 | _bgcolorhi = kDlgColor; | 
|---|
| 703 |  | 
|---|
| 704 | if(!_label.empty() && _labelWidth == 0) | 
|---|
| 705 | _labelWidth = _font.getStringWidth(_label); | 
|---|
| 706 |  | 
|---|
| 707 | if(_valueLabelWidth == 0) | 
|---|
| 708 | _valueLabelGap = 0; | 
|---|
| 709 |  | 
|---|
| 710 | _w = w + _labelWidth + _valueLabelGap + _valueLabelWidth; | 
|---|
| 711 | } | 
|---|
| 712 |  | 
|---|
| 713 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 714 | SliderWidget::SliderWidget(GuiObject* boss, const GUI::Font& font, | 
|---|
| 715 | int x, int y, | 
|---|
| 716 | const string& label, int labelWidth, int cmd, | 
|---|
| 717 | int valueLabelWidth, const string& valueUnit, int valueLabelGap) | 
|---|
| 718 | : SliderWidget(boss, font, x, y, font.getMaxCharWidth() * 10, font.getLineHeight(), | 
|---|
| 719 | label, labelWidth, cmd, valueLabelWidth, valueUnit, valueLabelGap) | 
|---|
| 720 | { | 
|---|
| 721 | } | 
|---|
| 722 |  | 
|---|
| 723 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 724 | void SliderWidget::setValue(int value) | 
|---|
| 725 | { | 
|---|
| 726 | if(value < _valueMin)      value = _valueMin; | 
|---|
| 727 | else if(value > _valueMax) value = _valueMax; | 
|---|
| 728 |  | 
|---|
| 729 | if(value != _value) | 
|---|
| 730 | { | 
|---|
| 731 | _value = value; | 
|---|
| 732 | setDirty(); | 
|---|
| 733 | if (_valueLabelWidth) | 
|---|
| 734 | setValueLabel(_value); // update label | 
|---|
| 735 | sendCommand(_cmd, _value, _id); | 
|---|
| 736 | } | 
|---|
| 737 | } | 
|---|
| 738 |  | 
|---|
| 739 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 740 | void SliderWidget::setMinValue(int value) | 
|---|
| 741 | { | 
|---|
| 742 | _valueMin = value; | 
|---|
| 743 | setDirty(); | 
|---|
| 744 | } | 
|---|
| 745 |  | 
|---|
| 746 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 747 | void SliderWidget::setMaxValue(int value) | 
|---|
| 748 | { | 
|---|
| 749 | _valueMax = value; | 
|---|
| 750 | setDirty(); | 
|---|
| 751 | } | 
|---|
| 752 |  | 
|---|
| 753 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 754 | void SliderWidget::setStepValue(int value) | 
|---|
| 755 | { | 
|---|
| 756 | _stepValue = value; | 
|---|
| 757 | setDirty(); | 
|---|
| 758 | } | 
|---|
| 759 |  | 
|---|
| 760 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 761 | void SliderWidget::setValueLabel(const string& valueLabel) | 
|---|
| 762 | { | 
|---|
| 763 | _valueLabel = valueLabel; | 
|---|
| 764 | setDirty(); | 
|---|
| 765 | } | 
|---|
| 766 |  | 
|---|
| 767 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 768 | void SliderWidget::setValueLabel(int value) | 
|---|
| 769 | { | 
|---|
| 770 | char buf[256]; | 
|---|
| 771 | std::snprintf(buf, 255, "%d", value); | 
|---|
| 772 | _valueLabel = buf; | 
|---|
| 773 |  | 
|---|
| 774 | setDirty(); | 
|---|
| 775 | } | 
|---|
| 776 |  | 
|---|
| 777 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 778 | void SliderWidget::setValueUnit(const string& valueUnit) | 
|---|
| 779 | { | 
|---|
| 780 | _valueUnit = valueUnit; | 
|---|
| 781 | setDirty(); | 
|---|
| 782 | } | 
|---|
| 783 |  | 
|---|
| 784 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 785 | void SliderWidget::setTickmarkIntervals(int numIntervals) | 
|---|
| 786 | { | 
|---|
| 787 | _numIntervals = numIntervals; | 
|---|
| 788 | setDirty(); | 
|---|
| 789 | } | 
|---|
| 790 |  | 
|---|
| 791 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 792 | void SliderWidget::handleMouseMoved(int x, int y) | 
|---|
| 793 | { | 
|---|
| 794 | // TODO: when the mouse is dragged outside the widget, the slider should | 
|---|
| 795 | // snap back to the old value. | 
|---|
| 796 | if(isEnabled() && _isDragging && | 
|---|
| 797 | x >= int(_labelWidth - 4) && x <= int(_w - _valueLabelGap - _valueLabelWidth + 4)) | 
|---|
| 798 | setValue(posToValue(x - _labelWidth)); | 
|---|
| 799 | } | 
|---|
| 800 |  | 
|---|
| 801 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 802 | void SliderWidget::handleMouseDown(int x, int y, MouseButton b, int clickCount) | 
|---|
| 803 | { | 
|---|
| 804 | if(isEnabled() && b == MouseButton::LEFT) | 
|---|
| 805 | { | 
|---|
| 806 | _isDragging = true; | 
|---|
| 807 | handleMouseMoved(x, y); | 
|---|
| 808 | } | 
|---|
| 809 | } | 
|---|
| 810 |  | 
|---|
| 811 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 812 | void SliderWidget::handleMouseUp(int x, int y, MouseButton b, int clickCount) | 
|---|
| 813 | { | 
|---|
| 814 | if(isEnabled() && _isDragging) | 
|---|
| 815 | sendCommand(_cmd, _value, _id); | 
|---|
| 816 |  | 
|---|
| 817 | _isDragging = false; | 
|---|
| 818 | } | 
|---|
| 819 |  | 
|---|
| 820 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 821 | void SliderWidget::handleMouseWheel(int x, int y, int direction) | 
|---|
| 822 | { | 
|---|
| 823 | if(isEnabled()) | 
|---|
| 824 | { | 
|---|
| 825 | if(direction < 0) | 
|---|
| 826 | handleEvent(Event::UIUp); | 
|---|
| 827 | else if(direction > 0) | 
|---|
| 828 | handleEvent(Event::UIDown); | 
|---|
| 829 | } | 
|---|
| 830 | } | 
|---|
| 831 |  | 
|---|
| 832 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 833 | bool SliderWidget::handleEvent(Event::Type e) | 
|---|
| 834 | { | 
|---|
| 835 | if(!isEnabled()) | 
|---|
| 836 | return false; | 
|---|
| 837 |  | 
|---|
| 838 | switch(e) | 
|---|
| 839 | { | 
|---|
| 840 | case Event::UIDown: | 
|---|
| 841 | case Event::UILeft: | 
|---|
| 842 | case Event::UIPgDown: | 
|---|
| 843 | setValue(_value - _stepValue); | 
|---|
| 844 | break; | 
|---|
| 845 |  | 
|---|
| 846 | case Event::UIUp: | 
|---|
| 847 | case Event::UIRight: | 
|---|
| 848 | case Event::UIPgUp: | 
|---|
| 849 | setValue(_value + _stepValue); | 
|---|
| 850 | break; | 
|---|
| 851 |  | 
|---|
| 852 | case Event::UIHome: | 
|---|
| 853 | setValue(_valueMin); | 
|---|
| 854 | break; | 
|---|
| 855 |  | 
|---|
| 856 | case Event::UIEnd: | 
|---|
| 857 | setValue(_valueMax); | 
|---|
| 858 | break; | 
|---|
| 859 |  | 
|---|
| 860 | default: | 
|---|
| 861 | return false; | 
|---|
| 862 | } | 
|---|
| 863 | return true; | 
|---|
| 864 | } | 
|---|
| 865 |  | 
|---|
| 866 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 867 | void SliderWidget::drawWidget(bool hilite) | 
|---|
| 868 | { | 
|---|
| 869 | FBSurface& s = _boss->dialog().surface(); | 
|---|
| 870 |  | 
|---|
| 871 | // Draw the label, if any | 
|---|
| 872 | if(_labelWidth > 0) | 
|---|
| 873 | s.drawString(_font, _label, _x, _y + 2, _labelWidth, isEnabled() ? kTextColor : kColor); | 
|---|
| 874 |  | 
|---|
| 875 | int p = valueToPos(_value), | 
|---|
| 876 | h = _h - 10, | 
|---|
| 877 | x = _x + _labelWidth, | 
|---|
| 878 | y = _y + (_h - h) / 2 + 1; | 
|---|
| 879 |  | 
|---|
| 880 | // Fill the box | 
|---|
| 881 | s.fillRect(x, y, _w - _labelWidth - _valueLabelGap - _valueLabelWidth, h, | 
|---|
| 882 | !isEnabled() ? kSliderBGColorLo : hilite ? kSliderBGColorHi : kSliderBGColor); | 
|---|
| 883 | // Draw the 'bar' | 
|---|
| 884 | s.fillRect(x, y, p, h, | 
|---|
| 885 | !isEnabled() ? kColor : hilite ? kSliderColorHi : kSliderColor); | 
|---|
| 886 |  | 
|---|
| 887 | // Draw the 'tickmarks' | 
|---|
| 888 | for(int i = 1; i < _numIntervals; ++i) | 
|---|
| 889 | { | 
|---|
| 890 | int xt = x + (_w - _labelWidth - _valueLabelGap - _valueLabelWidth) * i / _numIntervals - 1; | 
|---|
| 891 | ColorId color = kNone; | 
|---|
| 892 |  | 
|---|
| 893 | if(isEnabled()) | 
|---|
| 894 | { | 
|---|
| 895 | if(xt > x + p) | 
|---|
| 896 | color = hilite ? kSliderColorHi : kSliderColor; | 
|---|
| 897 | else | 
|---|
| 898 | color = hilite ? kSliderBGColorHi : kSliderBGColor; | 
|---|
| 899 | } | 
|---|
| 900 | else | 
|---|
| 901 | { | 
|---|
| 902 | if(xt > x + p) | 
|---|
| 903 | color = kColor; | 
|---|
| 904 | else | 
|---|
| 905 | color = kSliderBGColorLo; | 
|---|
| 906 | } | 
|---|
| 907 | s.vLine(xt, y + h / 2, y + h - 1, color); | 
|---|
| 908 | } | 
|---|
| 909 |  | 
|---|
| 910 | // Draw the 'handle' | 
|---|
| 911 | s.fillRect(x + p, y - 2, 2, h + 4, | 
|---|
| 912 | !isEnabled() ? kColor : hilite ? kSliderColorHi : kSliderColor); | 
|---|
| 913 |  | 
|---|
| 914 | if(_valueLabelWidth > 0) | 
|---|
| 915 | s.drawString(_font, _valueLabel + _valueUnit, _x + _w - _valueLabelWidth, _y + 2, | 
|---|
| 916 | _valueLabelWidth, isEnabled() ? kTextColor : kColor); | 
|---|
| 917 |  | 
|---|
| 918 | setDirty(); | 
|---|
| 919 | } | 
|---|
| 920 |  | 
|---|
| 921 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 922 | int SliderWidget::valueToPos(int value) const | 
|---|
| 923 | { | 
|---|
| 924 | if(value < _valueMin)      value = _valueMin; | 
|---|
| 925 | else if(value > _valueMax) value = _valueMax; | 
|---|
| 926 | int range = std::max(_valueMax - _valueMin, 1);  // don't divide by zero | 
|---|
| 927 |  | 
|---|
| 928 | return ((_w - _labelWidth - _valueLabelGap - _valueLabelWidth - 2) * (value - _valueMin) / range); | 
|---|
| 929 | } | 
|---|
| 930 |  | 
|---|
| 931 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 932 | int SliderWidget::posToValue(int pos) const | 
|---|
| 933 | { | 
|---|
| 934 | int value = (pos) * (_valueMax - _valueMin) / (_w - _labelWidth - _valueLabelGap - _valueLabelWidth - 4) + _valueMin; | 
|---|
| 935 |  | 
|---|
| 936 | // Scale the position to the correct interval (according to step value) | 
|---|
| 937 | return value - (value % _stepValue); | 
|---|
| 938 | } | 
|---|
| 939 |  | 
|---|