# widget.cpp

Go to the documentation of this file.

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