# widget.cpp

Go to the documentation of this file.

    00001 /* $Id: widget.cpp 15428 2009-02-09 02:57:15Z rubidium $ */
    00002
    00005 #include "stdafx.h"
    00006 #include "company_func.h"
    00007 #include "gfx_func.h"
    00008 #include "window_gui.h"
    00009
    00010 #include "table/sprites.h"
    00011 #include "table/strings.h"
    00012
    00013 static const char *UPARROW   = "\xEE\x8A\xA0";
    00014 static const char *DOWNARROW = "\xEE\x8A\xAA";
    00015
    00024 static Point HandleScrollbarHittest(const Scrollbar *sb, int top, int bottom)
    00025 {
    00026   Point pt;
    00027   int height, count, pos, cap;
    00028
    00029   top += 10;   // top    points to just below the up-button
    00030   bottom -= 9; // bottom points to top of the down-button
    00031
    00032   height = (bottom - top);
    00033
    00034   pos = sb->pos;
    00035   count = sb->count;
    00036   cap = sb->cap;
    00037
    00038   if (count != 0) top += height * pos / count;
    00039
    00040   if (cap > count) cap = count;
    00041   if (count != 0) bottom -= (count - pos - cap) * height / count;
    00042
    00043   pt.x = top;
    00044   pt.y = bottom - 1;
    00045   return pt;
    00046 }
    00047
    00055 void ScrollbarClickHandler(Window *w, const Widget *wi, int x, int y)
    00056 {
    00057   int mi, ma, pos;
    00058   Scrollbar *sb;
    00059
    00060   switch (wi->type) {
    00061     case WWT_SCROLLBAR:
    00062       /* vertical scroller */
    00063       w->flags4 &= ~WF_HSCROLL;
    00064       w->flags4 &= ~WF_SCROLL2;
    00065       mi = wi->top;
    00066       ma = wi->bottom;
    00067       pos = y;
    00068       sb = &w->vscroll;
    00069       break;
    00070
    00071     case WWT_SCROLL2BAR:
    00072       /* 2nd vertical scroller */
    00073       w->flags4 &= ~WF_HSCROLL;
    00074       w->flags4 |= WF_SCROLL2;
    00075       mi = wi->top;
    00076       ma = wi->bottom;
    00077       pos = y;
    00078       sb = &w->vscroll2;
    00079       break;
    00080
    00081     case  WWT_HSCROLLBAR:
    00082       /* horizontal scroller */
    00083       w->flags4 &= ~WF_SCROLL2;
    00084       w->flags4 |= WF_HSCROLL;
    00085       mi = wi->left;
    00086       ma = wi->right;
    00087       pos = x;
    00088       sb = &w->hscroll;
    00089       break;
    00090
    00091     default: NOT_REACHED();
    00092   }
    00093   if (pos <= mi + 9) {
    00094     /* Pressing the upper button? */
    00095     w->flags4 |= WF_SCROLL_UP;
    00096     if (_scroller_click_timeout == 0) {
    00097       _scroller_click_timeout = 6;
    00098       if (sb->pos != 0) sb->pos--;
    00099     }
    00100     _left_button_clicked = false;
    00101   } else if (pos >= ma - 10) {
    00102     /* Pressing the lower button? */
    00103     w->flags4 |= WF_SCROLL_DOWN;
    00104
    00105     if (_scroller_click_timeout == 0) {
    00106       _scroller_click_timeout = 6;
    00107       if ((byte)(sb->pos + sb->cap) < sb->count)
    00108         sb->pos++;
    00109     }
    00110     _left_button_clicked = false;
    00111   } else {
    00112     Point pt = HandleScrollbarHittest(sb, mi, ma);
    00113
    00114     if (pos < pt.x) {
    00115       sb->pos = max(sb->pos - sb->cap, 0);
    00116     } else if (pos > pt.y) {
    00117       sb->pos = min(
    00118         sb->pos + sb->cap,
    00119         max(sb->count - sb->cap, 0)
    00120       );
    00121     } else {
    00122       _scrollbar_start_pos = pt.x - mi - 9;
    00123       _scrollbar_size = ma - mi - 23;
    00124       w->flags4 |= WF_SCROLL_MIDDLE;
    00125       _scrolling_scrollbar = true;
    00126       _cursorpos_drag_start = _cursor.pos;
    00127     }
    00128   }
    00129
    00130   w->SetDirty();
    00131 }
    00132
    00140 int GetWidgetFromPos(const Window *w, int x, int y)
    00141 {
    00142   uint index;
    00143   int found_index = -1;
    00144
    00145   /* Go through the widgets and check if we find the widget that the coordinate is
    00146    * inside. */
    00147   for (index = 0; index < w->widget_count; index++) {
    00148     const Widget *wi = &w->widget[index];
    00149     if (wi->type == WWT_EMPTY || wi->type == WWT_FRAME) continue;
    00150
    00151     if (x >= wi->left && x <= wi->right && y >= wi->top &&  y <= wi->bottom &&
    00152         !w->IsWidgetHidden(index)) {
    00153       found_index = index;
    00154     }
    00155   }
    00156
    00157   return found_index;
    00158 }
    00159
    00169 void DrawFrameRect(int left, int top, int right, int bottom, Colours colour, FrameFlags flags)
    00170 {
    00171   uint dark         = _colour_gradient[colour][3];
    00172   uint medium_dark  = _colour_gradient[colour][5];
    00173   uint medium_light = _colour_gradient[colour][6];
    00174   uint light        = _colour_gradient[colour][7];
    00175
    00176   if (flags & FR_TRANSPARENT) {
    00177     GfxFillRect(left, top, right, bottom, PALETTE_TO_TRANSPARENT, FILLRECT_RECOLOUR);
    00178   } else {
    00179     uint interior;
    00180
    00181     if (flags & FR_LOWERED) {
    00182       GfxFillRect(left,     top,     left,  bottom,     dark);
    00183       GfxFillRect(left + 1, top,     right, top,        dark);
    00184       GfxFillRect(right,    top + 1, right, bottom - 1, light);
    00185       GfxFillRect(left + 1, bottom,  right, bottom,     light);
    00186       interior = (flags & FR_DARKENED ? medium_dark : medium_light);
    00187     } else {
    00188       GfxFillRect(left,     top,    left,      bottom - 1, light);
    00189       GfxFillRect(left + 1, top,    right - 1, top,        light);
    00190       GfxFillRect(right,    top,    right,     bottom - 1, dark);
    00191       GfxFillRect(left,     bottom, right,     bottom,     dark);
    00192       interior = medium_dark;
    00193     }
    00194     if (!(flags & FR_BORDERONLY)) {
    00195       GfxFillRect(left + 1, top + 1, right - 1, bottom - 1, interior);
    00196     }
    00197   }
    00198 }
    00199
    00200
    00204 void Window::DrawWidgets() const
    00205 {
    00206   const DrawPixelInfo *dpi = _cur_dpi;
    00207
    00208   for (uint i = 0; i < this->widget_count; i++) {
    00209     const Widget *wi = &this->widget[i];
    00210     bool clicked = this->IsWidgetLowered(i);
    00211     Rect r;
    00212
    00213     if (dpi->left > (r.right = wi->right) ||
    00214         dpi->left + dpi->width <= (r.left = wi->left) ||
    00215         dpi->top > (r.bottom = wi->bottom) ||
    00216         dpi->top + dpi->height <= (r.top = wi->top) ||
    00217         this->IsWidgetHidden(i)) {
    00218       continue;
    00219     }
    00220
    00221     switch (wi->type & WWT_MASK) {
    00222     case WWT_IMGBTN:
    00223     case WWT_IMGBTN_2: {
    00224       SpriteID img = wi->data;
    00225       assert(img != 0);
    00226       DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->colour, (clicked) ? FR_LOWERED : FR_NONE);
    00227
    00228       /* show different image when clicked for WWT_IMGBTN_2 */
    00229       if ((wi->type & WWT_MASK) == WWT_IMGBTN_2 && clicked) img++;
    00230       DrawSprite(img, PAL_NONE, r.left + 1 + clicked, r.top + 1 + clicked);
    00231       break;
    00232     }
    00233
    00234     case WWT_PANEL:
    00235       assert(wi->data == 0);
    00236       DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->colour, (clicked) ? FR_LOWERED : FR_NONE);
    00237       break;
    00238
    00239     case WWT_EDITBOX:
    00240       DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->colour, FR_LOWERED | FR_DARKENED);
    00241       break;
    00242
    00243     case WWT_TEXTBTN:
    00244     case WWT_TEXTBTN_2:
    00245       DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->colour, (clicked) ? FR_LOWERED : FR_NONE);
    00246       /* FALL THROUGH */
    00247
    00248     case WWT_LABEL: {
    00249       StringID str = wi->data;
    00250
    00251       if ((wi->type & WWT_MASK) == WWT_TEXTBTN_2 && clicked) str++;
    00252
    00253       DrawStringCentered(((r.left + r.right + 1) >> 1) + clicked, ((r.top + r.bottom + 1) >> 1) - 5 + clicked, str, TC_FROMSTRING);
    00254       break;
    00255     }
    00256
    00257     case WWT_TEXT: {
    00258       const StringID str = wi->data;
    00259
    00260       if (str != STR_NULL) DrawStringTruncated(r.left, r.top, str, (TextColour)wi->colour, r.right - r.left);
    00261       break;
    00262     }
    00263
    00264     case WWT_INSET: {
    00265       const StringID str = wi->data;
    00266       DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->colour, FR_LOWERED | FR_DARKENED);
    00267
    00268       if (str != STR_NULL) DrawStringTruncated(r.left + 2, r.top + 1, str, TC_FROMSTRING, r.right - r.left - 10);
    00269       break;
    00270     }
    00271
    00272     case WWT_MATRIX: {
    00273       DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->colour, (clicked) ? FR_LOWERED : FR_NONE);
    00274
    00275       int c = GB(wi->data, 0, 8);
    00276       int amt1 = (wi->right - wi->left + 1) / c;
    00277
    00278       int d = GB(wi->data, 8, 8);
    00279       int amt2 = (wi->bottom - wi->top + 1) / d;
    00280
    00281       int colour = _colour_gradient[wi->colour & 0xF][6];
    00282
    00283       int x = r.left;
    00284       for (int ctr = c; ctr > 1; ctr--) {
    00285         x += amt1;
    00286         GfxFillRect(x, r.top + 1, x, r.bottom - 1, colour);
    00287       }
    00288
    00289       x = r.top;
    00290       for (int ctr = d; ctr > 1; ctr--) {
    00291         x += amt2;
    00292         GfxFillRect(r.left + 1, x, r.right - 1, x, colour);
    00293       }
    00294
    00295       colour = _colour_gradient[wi->colour & 0xF][4];
    00296
    00297       x = r.left - 1;
    00298       for (int ctr = c; ctr > 1; ctr--) {
    00299         x += amt1;
    00300         GfxFillRect(x, r.top + 1, x, r.bottom - 1, colour);
    00301       }
    00302
    00303       x = r.top - 1;
    00304       for (int ctr = d; ctr > 1; ctr--) {
    00305         x += amt2;
    00306         GfxFillRect(r.left + 1, x, r.right - 1, x, colour);
    00307       }
    00308
    00309       break;
    00310     }
    00311
    00312     /* vertical scrollbar */
    00313     case WWT_SCROLLBAR: {
    00314       assert(wi->data == 0);
    00315       assert(r.right - r.left == 11); // To ensure the same sizes are used everywhere!
    00316
    00317       /* draw up/down buttons */
    00318       clicked = ((this->flags4 & (WF_SCROLL_UP | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_UP);
    00319       DrawFrameRect(r.left, r.top, r.right, r.top + 9, wi->colour, (clicked) ? FR_LOWERED : FR_NONE);
    00320       DoDrawString(UPARROW, r.left + 2 + clicked, r.top + clicked, TC_BLACK);
    00321
    00322       clicked = (((this->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_DOWN));
    00323       DrawFrameRect(r.left, r.bottom - 9, r.right, r.bottom, wi->colour, (clicked) ? FR_LOWERED : FR_NONE);
    00324       DoDrawString(DOWNARROW, r.left + 2 + clicked, r.bottom - 9 + clicked, TC_BLACK);
    00325
    00326       int c1 = _colour_gradient[wi->colour & 0xF][3];
    00327       int c2 = _colour_gradient[wi->colour & 0xF][7];
    00328
    00329       /* draw "shaded" background */
    00330       GfxFillRect(r.left, r.top + 10, r.right, r.bottom - 10, c2);
    00331       GfxFillRect(r.left, r.top + 10, r.right, r.bottom - 10, c1, FILLRECT_CHECKER);
    00332
    00333       /* draw shaded lines */
    00334       GfxFillRect(r.left + 2, r.top + 10, r.left + 2, r.bottom - 10, c1);
    00335       GfxFillRect(r.left + 3, r.top + 10, r.left + 3, r.bottom - 10, c2);
    00336       GfxFillRect(r.left + 7, r.top + 10, r.left + 7, r.bottom - 10, c1);
    00337       GfxFillRect(r.left + 8, r.top + 10, r.left + 8, r.bottom - 10, c2);
    00338
    00339       Point pt = HandleScrollbarHittest(&this->vscroll, r.top, r.bottom);
    00340       DrawFrameRect(r.left, pt.x, r.right, pt.y, wi->colour, (this->flags4 & (WF_SCROLL_MIDDLE | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_MIDDLE ? FR_LOWERED : FR_NONE);
    00341       break;
    00342     }
    00343
    00344     case WWT_SCROLL2BAR: {
    00345       assert(wi->data == 0);
    00346       assert(r.right - r.left == 11); // To ensure the same sizes are used everywhere!
    00347
    00348       /* draw up/down buttons */
    00349       clicked = ((this->flags4 & (WF_SCROLL_UP | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_UP | WF_SCROLL2));
    00350       DrawFrameRect(r.left, r.top, r.right, r.top + 9, wi->colour,  (clicked) ? FR_LOWERED : FR_NONE);
    00351       DoDrawString(UPARROW, r.left + 2 + clicked, r.top + clicked, TC_BLACK);
    00352
    00353       clicked = ((this->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_DOWN | WF_SCROLL2));
    00354       DrawFrameRect(r.left, r.bottom - 9, r.right, r.bottom, wi->colour,  (clicked) ? FR_LOWERED : FR_NONE);
    00355       DoDrawString(DOWNARROW, r.left + 2 + clicked, r.bottom - 9 + clicked, TC_BLACK);
    00356
    00357       int c1 = _colour_gradient[wi->colour & 0xF][3];
    00358       int c2 = _colour_gradient[wi->colour & 0xF][7];
    00359
    00360       /* draw "shaded" background */
    00361       GfxFillRect(r.left, r.top + 10, r.right, r.bottom - 10, c2);
    00362       GfxFillRect(r.left, r.top + 10, r.right, r.bottom - 10, c1, FILLRECT_CHECKER);
    00363
    00364       /* draw shaded lines */
    00365       GfxFillRect(r.left + 2, r.top + 10, r.left + 2, r.bottom - 10, c1);
    00366       GfxFillRect(r.left + 3, r.top + 10, r.left + 3, r.bottom - 10, c2);
    00367       GfxFillRect(r.left + 7, r.top + 10, r.left + 7, r.bottom - 10, c1);
    00368       GfxFillRect(r.left + 8, r.top + 10, r.left + 8, r.bottom - 10, c2);
    00369
    00370       Point pt = HandleScrollbarHittest(&this->vscroll2, r.top, r.bottom);
    00371       DrawFrameRect(r.left, pt.x, r.right, pt.y, wi->colour, (this->flags4 & (WF_SCROLL_MIDDLE | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_MIDDLE | WF_SCROLL2) ? FR_LOWERED : FR_NONE);
    00372       break;
    00373     }
    00374
    00375     /* horizontal scrollbar */
    00376     case WWT_HSCROLLBAR: {
    00377       assert(wi->data == 0);
    00378       assert(r.bottom - r.top == 11); // To ensure the same sizes are used everywhere!
    00379
    00380       clicked = ((this->flags4 & (WF_SCROLL_UP | WF_HSCROLL)) == (WF_SCROLL_UP | WF_HSCROLL));
    00381       DrawFrameRect(r.left, r.top, r.left + 9, r.bottom, wi->colour, (clicked) ? FR_LOWERED : FR_NONE);
    00382       DrawSprite(SPR_ARROW_LEFT, PAL_NONE, r.left + 1 + clicked, r.top + 1 + clicked);
    00383
    00384       clicked = ((this->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL)) == (WF_SCROLL_DOWN | WF_HSCROLL));
    00385       DrawFrameRect(r.right - 9, r.top, r.right, r.bottom, wi->colour, (clicked) ? FR_LOWERED : FR_NONE);
    00386       DrawSprite(SPR_ARROW_RIGHT, PAL_NONE, r.right - 8 + clicked, r.top + 1 + clicked);
    00387
    00388       int c1 = _colour_gradient[wi->colour & 0xF][3];
    00389       int c2 = _colour_gradient[wi->colour & 0xF][7];
    00390
    00391       /* draw "shaded" background */
    00392       GfxFillRect(r.left + 10, r.top, r.right - 10, r.bottom, c2);
    00393       GfxFillRect(r.left + 10, r.top, r.right - 10, r.bottom, c1, FILLRECT_CHECKER);
    00394
    00395       /* draw shaded lines */
    00396       GfxFillRect(r.left + 10, r.top + 2, r.right - 10, r.top + 2, c1);
    00397       GfxFillRect(r.left + 10, r.top + 3, r.right - 10, r.top + 3, c2);
    00398       GfxFillRect(r.left + 10, r.top + 7, r.right - 10, r.top + 7, c1);
    00399       GfxFillRect(r.left + 10, r.top + 8, r.right - 10, r.top + 8, c2);
    00400
    00401       /* draw actual scrollbar */
    00402       Point pt = HandleScrollbarHittest(&this->hscroll, r.left, r.right);
    00403       DrawFrameRect(pt.x, r.top, pt.y, r.bottom, wi->colour, (this->flags4 & (WF_SCROLL_MIDDLE | WF_HSCROLL)) == (WF_SCROLL_MIDDLE | WF_HSCROLL) ? FR_LOWERED : FR_NONE);
    00404
    00405       break;
    00406     }
    00407
    00408     case WWT_FRAME: {
    00409       const StringID str = wi->data;
    00410       int x2 = r.left; // by default the left side is the left side of the widget
    00411
    00412       if (str != STR_NULL) x2 = DrawString(r.left + 6, r.top, str, TC_FROMSTRING);
    00413
    00414       int c1 = _colour_gradient[wi->colour][3];
    00415       int c2 = _colour_gradient[wi->colour][7];
    00416
    00417       /* Line from upper left corner to start of text */
    00418       GfxFillRect(r.left, r.top + 4, r.left + 4, r.top + 4, c1);
    00419       GfxFillRect(r.left + 1, r.top + 5, r.left + 4, r.top + 5, c2);
    00420
    00421       /* Line from end of text to upper right corner */
    00422       GfxFillRect(x2, r.top + 4, r.right - 1, r.top + 4, c1);
    00423       GfxFillRect(x2, r.top + 5, r.right - 2, r.top + 5, c2);
    00424
    00425       /* Line from upper left corner to bottom left corner */
    00426       GfxFillRect(r.left, r.top + 5, r.left, r.bottom - 1, c1);
    00427       GfxFillRect(r.left + 1, r.top + 6, r.left + 1, r.bottom - 2, c2);
    00428
    00429       /*Line from upper right corner to bottom right corner */
    00430       GfxFillRect(r.right - 1, r.top + 5, r.right - 1, r.bottom - 2, c1);
    00431       GfxFillRect(r.right, r.top + 4, r.right, r.bottom - 1, c2);
    00432
    00433       GfxFillRect(r.left + 1, r.bottom - 1, r.right - 1, r.bottom - 1, c1);
    00434       GfxFillRect(r.left, r.bottom, r.right, r.bottom, c2);
    00435
    00436       break;
    00437     }
    00438
    00439     case WWT_STICKYBOX:
    00440       assert(wi->data == 0);
    00441       assert(r.right - r.left == 11); // To ensure the same sizes are used everywhere!
    00442
    00443       clicked = !!(this->flags4 & WF_STICKY);
    00444       DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->colour, (clicked) ? FR_LOWERED : FR_NONE);
    00445       DrawSprite((clicked) ? SPR_PIN_UP : SPR_PIN_DOWN, PAL_NONE, r.left + 2 + clicked, r.top + 3 + clicked);
    00446       break;
    00447
    00448     case WWT_RESIZEBOX:
    00449       assert(wi->data == 0);
    00450       assert(r.right - r.left == 11); // To ensure the same sizes are used everywhere!
    00451
    00452       clicked = !!(this->flags4 & WF_SIZING);
    00453       DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->colour, (clicked) ? FR_LOWERED : FR_NONE);
    00454       DrawSprite(SPR_WINDOW_RESIZE, PAL_NONE, r.left + 3 + clicked, r.top + 3 + clicked);
    00455       break;
    00456
    00457     case WWT_CLOSEBOX: {
    00458       const StringID str = wi->data;
    00459
    00460       assert(str == STR_00C5 || str == STR_00C6); // black or silver cross
    00461       assert(r.right - r.left == 10); // To ensure the same sizes are used everywhere
    00462
    00463       DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->colour, FR_NONE);
    00464       DrawString(r.left + 2, r.top + 2, str, TC_FROMSTRING);
    00465       break;
    00466     }
    00467
    00468     case WWT_CAPTION:
    00469       assert(r.bottom - r.top == 13); // To ensure the same sizes are used everywhere!
    00470       DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->colour, FR_BORDERONLY);
    00471       DrawFrameRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, wi->colour, (this->owner == INVALID_OWNER) ? FR_LOWERED | FR_DARKENED : FR_LOWERED | FR_DARKENED | FR_BORDERONLY);
    00472
    00473       if (this->owner != INVALID_OWNER) {
    00474         GfxFillRect(r.left + 2, r.top + 2, r.right - 2, r.bottom - 2, _colour_gradient[_company_colours[this->owner]][4]);
    00475       }
    00476
    00477       DrawStringCenteredTruncated(r.left + 2, r.right - 2, r.top + 2, wi->data, TC_FROMSTRING);
    00478       break;
    00479
    00480     case WWT_DROPDOWN: {
    00481       assert(r.bottom - r.top == 11); // ensure consistent size
    00482
    00483       StringID str = wi->data;
    00484       DrawFrameRect(r.left, r.top, r.right - 12, r.bottom, wi->colour, FR_NONE);
    00485       DrawFrameRect(r.right - 11, r.top, r.right, r.bottom, wi->colour, clicked ? FR_LOWERED : FR_NONE);
    00486       DrawString(r.right - (clicked ? 8 : 9), r.top + (clicked ? 2 : 1), STR_0225, TC_BLACK);
    00487       if (str != STR_NULL) DrawStringTruncated(r.left + 2, r.top + 1, str, TC_BLACK, r.right - r.left - 12);
    00488       break;
    00489     }
    00490
    00491     case WWT_DROPDOWNIN: {
    00492       assert(r.bottom - r.top == 11); // ensure consistent size
    00493
    00494       StringID str = wi->data;
    00495       DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->colour, FR_LOWERED | FR_DARKENED);
    00496       DrawFrameRect(r.right - 11, r.top + 1, r.right - 1, r.bottom - 1, wi->colour, clicked ? FR_LOWERED : FR_NONE);
    00497       DrawString(r.right - (clicked ? 8 : 9), r.top + (clicked ? 2 : 1), STR_0225, TC_BLACK);
    00498       if (str != STR_NULL) DrawStringTruncated(r.left + 2, r.top + 2, str, TC_BLACK, r.right - r.left - 12);
    00499       break;
    00500     }
    00501     }
    00502
    00503     if (this->IsWidgetDisabled(i)) {
    00504       GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, _colour_gradient[wi->colour & 0xF][2], FILLRECT_CHECKER);
    00505     }
    00506   }
    00507
    00508
    00509   if (this->flags4 & WF_WHITE_BORDER_MASK) {
    00510     DrawFrameRect(0, 0, this->width - 1, this->height - 1, COLOUR_WHITE, FR_BORDERONLY);
    00511   }
    00512
    00513 }
    00514
    00515 static void ResizeWidgets(Window *w, byte a, byte b)
    00516 {
    00517   int16 offset = w->widget[a].left;
    00518   int16 length = w->widget[b].right - offset;
    00519
    00520   w->widget[a].right = (length / 2) + offset;
    00521
    00522   w->widget[b].left  = w->widget[a].right + 1;
    00523 }
    00524
    00525 static void ResizeWidgets(Window *w, byte a, byte b, byte c)
    00526 {
    00527   int16 offset = w->widget[a].left;
    00528   int16 length = w->widget[c].right - offset;
    00529
    00530   w->widget[a].right = length / 3;
    00531   w->widget[b].right = w->widget[a].right * 2;
    00532
    00533   w->widget[a].right += offset;
    00534   w->widget[b].right += offset;
    00535
    00536   /* Now the right side of the buttons are set. We will now set the left sides next to them */
    00537   w->widget[b].left  = w->widget[a].right + 1;
    00538   w->widget[c].left  = w->widget[b].right + 1;
    00539 }
    00540
    00547 void ResizeButtons(Window *w, byte left, byte right)
    00548 {
    00549   int16 num_widgets = right - left + 1;
    00550
    00551   if (num_widgets < 2) NOT_REACHED();
    00552
    00553   switch (num_widgets) {
    00554     case 2: ResizeWidgets(w, left, right); break;
    00555     case 3: ResizeWidgets(w, left, left + 1, right); break;
    00556     default: {
    00557       /* Looks like we got more than 3 widgets to resize
    00558        * Now we will find the middle of the space desinated for the widgets
    00559        * and place half of the widgets on each side of it and call recursively.
    00560        * Eventually we will get down to blocks of 2-3 widgets and we got code to handle those cases */
    00561       int16 offset = w->widget[left].left;
    00562       int16 length = w->widget[right].right - offset;
    00563       byte widget = ((num_widgets - 1)/ 2) + left; // rightmost widget of the left side
    00564
    00565       /* Now we need to find the middle of the widgets.
    00566        * It will not always be the middle because if we got an uneven number of widgets,
    00567        *   we will need it to be 2/5, 3/7 and so on
    00568        * To get this, we multiply with num_widgets/num_widgets. Since we calculate in int, we will get:
    00569        *
    00570        *    num_widgets/2 (rounding down)
    00571        *   ---------------
    00572        *     num_widgets
    00573        *
    00574        * as multiplier to length. We just multiply before divide to that we stay in the int area though */
    00575       int16 middle = ((length * num_widgets) / (2 * num_widgets)) + offset;
    00576
    00577       /* Set left and right on the widgets, that's next to our "middle" */
    00578       w->widget[widget].right = middle;
    00579       w->widget[widget + 1].left = w->widget[widget].right + 1;
    00580       /* Now resize the left and right of the middle */
    00581       ResizeButtons(w, left, widget);
    00582       ResizeButtons(w, widget + 1, right);
    00583     }
    00584   }
    00585 }
    00586
    00588 void ResizeWindowForWidget(Window *w, uint widget, int delta_x, int delta_y)
    00589 {
    00590   int right  = w->widget[widget].right;
    00591   int bottom = w->widget[widget].bottom;
    00592
    00593   for (uint i = 0; i < w->widget_count; i++) {
    00594     if (w->widget[i].left >= right && i != widget) w->widget[i].left += delta_x;
    00595     if (w->widget[i].right >= right) w->widget[i].right += delta_x;
    00596     if (w->widget[i].top >= bottom && i != widget) w->widget[i].top += delta_y;
    00597     if (w->widget[i].bottom >= bottom) w->widget[i].bottom += delta_y;
    00598   }
    00599
    00600   /* A hidden widget has bottom == top or right == left, we need to make it
    00601    * one less to fit in its new gap. */
    00602   if (right  == w->widget[widget].left) w->widget[widget].right--;
    00603   if (bottom == w->widget[widget].top)  w->widget[widget].bottom--;
    00604
    00605   if (w->widget[widget].left > w->widget[widget].right)  w->widget[widget].right  = w->widget[widget].left;
    00606   if (w->widget[widget].top  > w->widget[widget].bottom) w->widget[widget].bottom = w->widget[widget].top;
    00607
    00608   w->width  += delta_x;
    00609   w->height += delta_y;
    00610   w->resize.width  += delta_x;
    00611   w->resize.height += delta_y;
    00612 }
    00613
    00619 void Window::DrawSortButtonState(int widget, SortButtonState state) const
    00620 {
    00621   if (state == SBS_OFF) return;
    00622
    00623   int offset = this->IsWidgetLowered(widget) ? 1 : 0;
    00624   DoDrawString(state == SBS_DOWN ? DOWNARROW : UPARROW, this->widget[widget].right - 11 + offset, this->widget[widget].top + 1 + offset, TC_BLACK);
    00625 }