00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "company_func.h"
00014 #include "window_gui.h"
00015 #include "viewport_func.h"
00016 #include "zoom_func.h"
00017 #include "strings_func.h"
00018 #include "transparency.h"
00019 #include "core/geometry_func.hpp"
00020 #include "settings_type.h"
00021 #include "querystring_gui.h"
00022
00023 #include "table/sprites.h"
00024 #include "table/strings.h"
00025 #include "table/palettes.h"
00026
00027 static const char *UPARROW = "\xEE\x8A\xA0";
00028 static const char *DOWNARROW = "\xEE\x8A\xAA";
00029
00039 static Point HandleScrollbarHittest(const Scrollbar *sb, int top, int bottom, bool horizontal)
00040 {
00041
00042 int rev_base = top + bottom;
00043 int button_size;
00044 if (horizontal) {
00045 button_size = NWidgetScrollbar::GetHorizontalDimension().width;
00046 } else {
00047 button_size = NWidgetScrollbar::GetVerticalDimension().height;
00048 }
00049 top += button_size;
00050 bottom -= button_size;
00051
00052 int height = (bottom - top);
00053 int pos = sb->GetPosition();
00054 int count = sb->GetCount();
00055 int cap = sb->GetCapacity();
00056
00057 if (count != 0) top += height * pos / count;
00058
00059 if (cap > count) cap = count;
00060 if (count != 0) bottom -= (count - pos - cap) * height / count;
00061
00062 Point pt;
00063 if (horizontal && _current_text_dir == TD_RTL) {
00064 pt.x = rev_base - bottom;
00065 pt.y = rev_base - top;
00066 } else {
00067 pt.x = top;
00068 pt.y = bottom;
00069 }
00070 return pt;
00071 }
00072
00082 static void ScrollbarClickPositioning(Window *w, NWidgetScrollbar *sb, int x, int y, int mi, int ma)
00083 {
00084 int pos;
00085 int button_size;
00086 bool rtl = false;
00087
00088 if (sb->type == NWID_HSCROLLBAR) {
00089 pos = x;
00090 rtl = _current_text_dir == TD_RTL;
00091 button_size = NWidgetScrollbar::GetHorizontalDimension().width;
00092 } else {
00093 pos = y;
00094 button_size = NWidgetScrollbar::GetVerticalDimension().height;
00095 }
00096 if (pos < mi + button_size) {
00097
00098 SetBit(sb->disp_flags, NDB_SCROLLBAR_UP);
00099 if (_scroller_click_timeout <= 1) {
00100 _scroller_click_timeout = 3;
00101 sb->UpdatePosition(rtl ? 1 : -1);
00102 }
00103 w->scrolling_scrollbar = sb->index;
00104 } else if (pos >= ma - button_size) {
00105
00106 SetBit(sb->disp_flags, NDB_SCROLLBAR_DOWN);
00107
00108 if (_scroller_click_timeout <= 1) {
00109 _scroller_click_timeout = 3;
00110 sb->UpdatePosition(rtl ? -1 : 1);
00111 }
00112 w->scrolling_scrollbar = sb->index;
00113 } else {
00114 Point pt = HandleScrollbarHittest(sb, mi, ma, sb->type == NWID_HSCROLLBAR);
00115
00116 if (pos < pt.x) {
00117 sb->UpdatePosition(rtl ? 1 : -1, Scrollbar::SS_BIG);
00118 } else if (pos > pt.y) {
00119 sb->UpdatePosition(rtl ? -1 : 1, Scrollbar::SS_BIG);
00120 } else {
00121 _scrollbar_start_pos = pt.x - mi - button_size;
00122 _scrollbar_size = ma - mi - button_size * 2;
00123 w->scrolling_scrollbar = sb->index;
00124 _cursorpos_drag_start = _cursor.pos;
00125 }
00126 }
00127
00128 w->SetDirty();
00129 }
00130
00139 void ScrollbarClickHandler(Window *w, NWidgetCore *nw, int x, int y)
00140 {
00141 int mi, ma;
00142
00143 if (nw->type == NWID_HSCROLLBAR) {
00144 mi = nw->pos_x;
00145 ma = nw->pos_x + nw->current_x;
00146 } else {
00147 mi = nw->pos_y;
00148 ma = nw->pos_y + nw->current_y;
00149 }
00150 ScrollbarClickPositioning(w, dynamic_cast<NWidgetScrollbar*>(nw), x, y, mi, ma);
00151 }
00152
00161 int GetWidgetFromPos(const Window *w, int x, int y)
00162 {
00163 NWidgetCore *nw = w->nested_root->GetWidgetFromPos(x, y);
00164 return (nw != NULL) ? nw->index : -1;
00165 }
00166
00176 void DrawFrameRect(int left, int top, int right, int bottom, Colours colour, FrameFlags flags)
00177 {
00178 uint dark = _colour_gradient[colour][3];
00179 uint medium_dark = _colour_gradient[colour][5];
00180 uint medium_light = _colour_gradient[colour][6];
00181 uint light = _colour_gradient[colour][7];
00182
00183 if (flags & FR_TRANSPARENT) {
00184 GfxFillRect(left, top, right, bottom, PALETTE_TO_TRANSPARENT, FILLRECT_RECOLOUR);
00185 } else {
00186 uint interior;
00187
00188 if (flags & FR_LOWERED) {
00189 GfxFillRect(left, top, left, bottom, dark);
00190 GfxFillRect(left + WD_BEVEL_LEFT, top, right, top, dark);
00191 GfxFillRect(right, top + WD_BEVEL_TOP, right, bottom - WD_BEVEL_BOTTOM, light);
00192 GfxFillRect(left + WD_BEVEL_LEFT, bottom, right, bottom, light);
00193 interior = (flags & FR_DARKENED ? medium_dark : medium_light);
00194 } else {
00195 GfxFillRect(left, top, left, bottom - WD_BEVEL_BOTTOM, light);
00196 GfxFillRect(left + WD_BEVEL_LEFT, top, right - WD_BEVEL_RIGHT, top, light);
00197 GfxFillRect(right, top, right, bottom - WD_BEVEL_BOTTOM, dark);
00198 GfxFillRect(left, bottom, right, bottom, dark);
00199 interior = medium_dark;
00200 }
00201 if (!(flags & FR_BORDERONLY)) {
00202 GfxFillRect(left + WD_BEVEL_LEFT, top + WD_BEVEL_TOP, right - WD_BEVEL_RIGHT, bottom - WD_BEVEL_BOTTOM, interior);
00203 }
00204 }
00205 }
00206
00215 static inline void DrawImageButtons(const Rect &r, WidgetType type, Colours colour, bool clicked, SpriteID img)
00216 {
00217 assert(img != 0);
00218 DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, (clicked) ? FR_LOWERED : FR_NONE);
00219
00220 if ((type & WWT_MASK) == WWT_IMGBTN_2 && clicked) img++;
00221 DrawSprite(img, PAL_NONE, r.left + WD_IMGBTN_LEFT + clicked, r.top + WD_IMGBTN_TOP + clicked);
00222 }
00223
00231 static inline void DrawLabel(const Rect &r, WidgetType type, bool clicked, StringID str)
00232 {
00233 if (str == STR_NULL) return;
00234 if ((type & WWT_MASK) == WWT_TEXTBTN_2 && clicked) str++;
00235 Dimension d = GetStringBoundingBox(str);
00236 int offset = max(0, ((int)(r.bottom - r.top + 1) - (int)d.height) / 2);
00237 DrawString(r.left + clicked, r.right + clicked, r.top + offset + clicked, str, TC_FROMSTRING, SA_HOR_CENTER);
00238 }
00239
00246 static inline void DrawText(const Rect &r, TextColour colour, StringID str)
00247 {
00248 Dimension d = GetStringBoundingBox(str);
00249 int offset = max(0, ((int)(r.bottom - r.top + 1) - (int)d.height) / 2);
00250 if (str != STR_NULL) DrawString(r.left, r.right, r.top + offset, str, colour);
00251 }
00252
00259 static inline void DrawInset(const Rect &r, Colours colour, StringID str)
00260 {
00261 DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, FR_LOWERED | FR_DARKENED);
00262 if (str != STR_NULL) DrawString(r.left + WD_INSET_LEFT, r.right - WD_INSET_RIGHT, r.top + WD_INSET_TOP, str);
00263 }
00264
00272 static inline void DrawMatrix(const Rect &r, Colours colour, bool clicked, uint16 data)
00273 {
00274 DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, (clicked) ? FR_LOWERED : FR_NONE);
00275
00276 int num_columns = GB(data, MAT_COL_START, MAT_COL_BITS);
00277 int column_width = (r.right - r.left + 1) / num_columns;
00278
00279 int num_rows = GB(data, MAT_ROW_START, MAT_ROW_BITS);
00280 int row_height = (r.bottom - r.top + 1) / num_rows;
00281
00282 int col = _colour_gradient[colour & 0xF][6];
00283
00284 int x = r.left;
00285 for (int ctr = num_columns; ctr > 1; ctr--) {
00286 x += column_width;
00287 GfxFillRect(x, r.top + 1, x, r.bottom - 1, col);
00288 }
00289
00290 x = r.top;
00291 for (int ctr = num_rows; ctr > 1; ctr--) {
00292 x += row_height;
00293 GfxFillRect(r.left + 1, x, r.right - 1, x, col);
00294 }
00295
00296 col = _colour_gradient[colour & 0xF][4];
00297
00298 x = r.left - 1;
00299 for (int ctr = num_columns; ctr > 1; ctr--) {
00300 x += column_width;
00301 GfxFillRect(x, r.top + 1, x, r.bottom - 1, col);
00302 }
00303
00304 x = r.top - 1;
00305 for (int ctr = num_rows; ctr > 1; ctr--) {
00306 x += row_height;
00307 GfxFillRect(r.left + 1, x, r.right - 1, x, col);
00308 }
00309 }
00310
00320 static inline void DrawVerticalScrollbar(const Rect &r, Colours colour, bool up_clicked, bool bar_dragged, bool down_clicked, const Scrollbar *scrollbar)
00321 {
00322 int centre = (r.right - r.left) / 2;
00323 int height = NWidgetScrollbar::GetVerticalDimension().height;
00324
00325
00326 DrawFrameRect(r.left, r.top, r.right, r.top + height - 1, colour, (up_clicked) ? FR_LOWERED : FR_NONE);
00327 DrawString(r.left + up_clicked, r.right + up_clicked, r.top + up_clicked, UPARROW, TC_BLACK, SA_HOR_CENTER);
00328
00329 DrawFrameRect(r.left, r.bottom - (height - 1), r.right, r.bottom, colour, (down_clicked) ? FR_LOWERED : FR_NONE);
00330 DrawString(r.left + down_clicked, r.right + down_clicked, r.bottom - (height - 1) + down_clicked, DOWNARROW, TC_BLACK, SA_HOR_CENTER);
00331
00332 int c1 = _colour_gradient[colour & 0xF][3];
00333 int c2 = _colour_gradient[colour & 0xF][7];
00334
00335
00336 GfxFillRect(r.left, r.top + height, r.right, r.bottom - height, c2);
00337 GfxFillRect(r.left, r.top + height, r.right, r.bottom - height, c1, FILLRECT_CHECKER);
00338
00339
00340 GfxFillRect(r.left + centre - 3, r.top + height, r.left + centre - 3, r.bottom - height, c1);
00341 GfxFillRect(r.left + centre - 2, r.top + height, r.left + centre - 2, r.bottom - height, c2);
00342 GfxFillRect(r.left + centre + 2, r.top + height, r.left + centre + 2, r.bottom - height, c1);
00343 GfxFillRect(r.left + centre + 3, r.top + height, r.left + centre + 3, r.bottom - height, c2);
00344
00345 Point pt = HandleScrollbarHittest(scrollbar, r.top, r.bottom, false);
00346 DrawFrameRect(r.left, pt.x, r.right, pt.y, colour, bar_dragged ? FR_LOWERED : FR_NONE);
00347 }
00348
00358 static inline void DrawHorizontalScrollbar(const Rect &r, Colours colour, bool left_clicked, bool bar_dragged, bool right_clicked, const Scrollbar *scrollbar)
00359 {
00360 int centre = (r.bottom - r.top) / 2;
00361 int width = NWidgetScrollbar::GetHorizontalDimension().width;
00362
00363 DrawFrameRect(r.left, r.top, r.left + width - 1, r.bottom, colour, left_clicked ? FR_LOWERED : FR_NONE);
00364 DrawSprite(SPR_ARROW_LEFT, PAL_NONE, r.left + 1 + left_clicked, r.top + 1 + left_clicked);
00365
00366 DrawFrameRect(r.right - (width - 1), r.top, r.right, r.bottom, colour, right_clicked ? FR_LOWERED : FR_NONE);
00367 DrawSprite(SPR_ARROW_RIGHT, PAL_NONE, r.right - (width - 2) + right_clicked, r.top + 1 + right_clicked);
00368
00369 int c1 = _colour_gradient[colour & 0xF][3];
00370 int c2 = _colour_gradient[colour & 0xF][7];
00371
00372
00373 GfxFillRect(r.left + width, r.top, r.right - width, r.bottom, c2);
00374 GfxFillRect(r.left + width, r.top, r.right - width, r.bottom, c1, FILLRECT_CHECKER);
00375
00376
00377 GfxFillRect(r.left + width, r.top + centre - 3, r.right - width, r.top + centre - 3, c1);
00378 GfxFillRect(r.left + width, r.top + centre - 2, r.right - width, r.top + centre - 2, c2);
00379 GfxFillRect(r.left + width, r.top + centre + 2, r.right - width, r.top + centre + 2, c1);
00380 GfxFillRect(r.left + width, r.top + centre + 3, r.right - width, r.top + centre + 3, c2);
00381
00382
00383 Point pt = HandleScrollbarHittest(scrollbar, r.left, r.right, true);
00384 DrawFrameRect(pt.x, r.top, pt.y, r.bottom, colour, bar_dragged ? FR_LOWERED : FR_NONE);
00385 }
00386
00393 static inline void DrawFrame(const Rect &r, Colours colour, StringID str)
00394 {
00395 int x2 = r.left;
00396
00397 if (str != STR_NULL) x2 = DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, r.top, str);
00398
00399 int c1 = _colour_gradient[colour][3];
00400 int c2 = _colour_gradient[colour][7];
00401
00402
00403 int dy1 = 4;
00404 if (str != STR_NULL) dy1 = FONT_HEIGHT_NORMAL / 2 - 1;
00405 int dy2 = dy1 + 1;
00406
00407 if (_current_text_dir == TD_LTR) {
00408
00409 GfxFillRect(r.left, r.top + dy1, r.left + 4, r.top + dy1, c1);
00410 GfxFillRect(r.left + 1, r.top + dy2, r.left + 4, r.top + dy2, c2);
00411
00412
00413 GfxFillRect(x2, r.top + dy1, r.right - 1, r.top + dy1, c1);
00414 GfxFillRect(x2, r.top + dy2, r.right - 2, r.top + dy2, c2);
00415 } else {
00416
00417 GfxFillRect(r.left, r.top + dy1, x2 - 2, r.top + dy1, c1);
00418 GfxFillRect(r.left + 1, r.top + dy2, x2 - 2, r.top + dy2, c2);
00419
00420
00421 GfxFillRect(r.right - 5, r.top + dy1, r.right - 1, r.top + dy1, c1);
00422 GfxFillRect(r.right - 5, r.top + dy2, r.right - 2, r.top + dy2, c2);
00423 }
00424
00425
00426 GfxFillRect(r.left, r.top + dy2, r.left, r.bottom - 1, c1);
00427 GfxFillRect(r.left + 1, r.top + dy2 + 1, r.left + 1, r.bottom - 2, c2);
00428
00429
00430 GfxFillRect(r.right - 1, r.top + dy2, r.right - 1, r.bottom - 2, c1);
00431 GfxFillRect(r.right, r.top + dy1, 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
00443 static inline void DrawShadeBox(const Rect &r, Colours colour, bool clicked)
00444 {
00445 DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, (clicked) ? FR_LOWERED : FR_NONE);
00446 DrawSprite((clicked) ? SPR_WINDOW_SHADE : SPR_WINDOW_UNSHADE, PAL_NONE, r.left + WD_SHADEBOX_LEFT + clicked, r.top + WD_SHADEBOX_TOP + clicked);
00447 }
00448
00455 static inline void DrawStickyBox(const Rect &r, Colours colour, bool clicked)
00456 {
00457 DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, (clicked) ? FR_LOWERED : FR_NONE);
00458 DrawSprite((clicked) ? SPR_PIN_UP : SPR_PIN_DOWN, PAL_NONE, r.left + WD_STICKYBOX_LEFT + clicked, r.top + WD_STICKYBOX_TOP + clicked);
00459 }
00460
00467 static inline void DrawDebugBox(const Rect &r, Colours colour, bool clicked)
00468 {
00469 DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, (clicked) ? FR_LOWERED : FR_NONE);
00470 DrawSprite(SPR_WINDOW_DEBUG, PAL_NONE, r.left + WD_DEBUGBOX_LEFT + clicked, r.top + WD_DEBUGBOX_TOP + clicked);
00471 }
00472
00480 static inline void DrawResizeBox(const Rect &r, Colours colour, bool at_left, bool clicked)
00481 {
00482 DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, (clicked) ? FR_LOWERED : FR_NONE);
00483 if (at_left) {
00484 DrawSprite(SPR_WINDOW_RESIZE_LEFT, PAL_NONE, r.left + WD_RESIZEBOX_RIGHT + clicked,
00485 r.bottom - WD_RESIZEBOX_BOTTOM - GetSpriteSize(SPR_WINDOW_RESIZE_LEFT).height + clicked);
00486 } else {
00487 DrawSprite(SPR_WINDOW_RESIZE_RIGHT, PAL_NONE, r.left + WD_RESIZEBOX_LEFT + clicked,
00488 r.bottom - WD_RESIZEBOX_BOTTOM - GetSpriteSize(SPR_WINDOW_RESIZE_RIGHT).height + clicked);
00489 }
00490 }
00491
00498 static inline void DrawCloseBox(const Rect &r, Colours colour, StringID str)
00499 {
00500 assert(str == STR_BLACK_CROSS || str == STR_SILVER_CROSS);
00501 DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, FR_NONE);
00502 DrawString(r.left + WD_CLOSEBOX_LEFT, r.right - WD_CLOSEBOX_RIGHT, r.top + WD_CLOSEBOX_TOP, str, TC_FROMSTRING, SA_HOR_CENTER);
00503 }
00504
00512 void DrawCaption(const Rect &r, Colours colour, Owner owner, StringID str)
00513 {
00514 DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, FR_BORDERONLY);
00515 DrawFrameRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, colour, (owner == INVALID_OWNER) ? FR_LOWERED | FR_DARKENED : FR_LOWERED | FR_DARKENED | FR_BORDERONLY);
00516
00517 if (owner != INVALID_OWNER) {
00518 GfxFillRect(r.left + 2, r.top + 2, r.right - 2, r.bottom - 2, _colour_gradient[_company_colours[owner]][4]);
00519 }
00520
00521 if (str != STR_NULL) {
00522 Dimension d = GetStringBoundingBox(str);
00523 int offset = max(0, ((int)(r.bottom - r.top + 1) - (int)d.height) / 2);
00524 DrawString(r.left + WD_CAPTIONTEXT_LEFT, r.right - WD_CAPTIONTEXT_RIGHT, r.top + offset, str, TC_FROMSTRING, SA_HOR_CENTER);
00525 }
00526 }
00527
00538 static inline void DrawButtonDropdown(const Rect &r, Colours colour, bool clicked_button, bool clicked_dropdown, StringID str)
00539 {
00540 int text_offset = max(0, ((int)(r.bottom - r.top + 1) - FONT_HEIGHT_NORMAL) / 2);
00541
00542 if (_current_text_dir == TD_LTR) {
00543 DrawFrameRect(r.left, r.top, r.right - 12, r.bottom, colour, clicked_button ? FR_LOWERED : FR_NONE);
00544 DrawFrameRect(r.right - 11, r.top, r.right, r.bottom, colour, clicked_dropdown ? FR_LOWERED : FR_NONE);
00545 DrawString(r.right - (clicked_dropdown ? 10 : 11), r.right, r.top + (clicked_dropdown ? 2 : 1), DOWNARROW, TC_BLACK, SA_HOR_CENTER);
00546 if (str != STR_NULL) DrawString(r.left + WD_DROPDOWNTEXT_LEFT + clicked_button, r.right - WD_DROPDOWNTEXT_RIGHT + clicked_button, r.top + text_offset + clicked_button, str, TC_BLACK);
00547 } else {
00548 DrawFrameRect(r.left + 12, r.top, r.right, r.bottom, colour, clicked_button ? FR_LOWERED : FR_NONE);
00549 DrawFrameRect(r.left, r.top, r.left + 11, r.bottom, colour, clicked_dropdown ? FR_LOWERED : FR_NONE);
00550 DrawString(r.left + clicked_dropdown, r.left + 11, r.top + (clicked_dropdown ? 2 : 1), DOWNARROW, TC_BLACK, SA_HOR_CENTER);
00551 if (str != STR_NULL) DrawString(r.left + WD_DROPDOWNTEXT_RIGHT + clicked_button, r.right - WD_DROPDOWNTEXT_LEFT + clicked_button, r.top + text_offset + clicked_button, str, TC_BLACK);
00552 }
00553 }
00554
00562 static inline void DrawDropdown(const Rect &r, Colours colour, bool clicked, StringID str)
00563 {
00564 DrawButtonDropdown(r, colour, false, clicked, str);
00565 }
00566
00570 void Window::DrawWidgets() const
00571 {
00572 this->nested_root->Draw(this);
00573
00574 if (this->flags & WF_WHITE_BORDER) {
00575 DrawFrameRect(0, 0, this->width - 1, this->height - 1, COLOUR_WHITE, FR_BORDERONLY);
00576 }
00577
00578 if (this->flags & WF_HIGHLIGHTED) {
00579 extern bool _window_highlight_colour;
00580 for (uint i = 0; i < this->nested_array_size; i++) {
00581 const NWidgetBase *widget = this->GetWidget<NWidgetBase>(i);
00582 if (widget == NULL || !widget->IsHighlighted()) continue;
00583
00584 int left = widget->pos_x;
00585 int top = widget->pos_y;
00586 int right = left + widget->current_x - 1;
00587 int bottom = top + widget->current_y - 1;
00588
00589 int colour = _string_colourmap[_window_highlight_colour ? widget->GetHighlightColour() : TC_WHITE];
00590
00591 GfxFillRect(left, top, left, bottom - WD_BEVEL_BOTTOM, colour);
00592 GfxFillRect(left + WD_BEVEL_LEFT, top, right - WD_BEVEL_RIGHT, top, colour);
00593 GfxFillRect(right, top, right, bottom - WD_BEVEL_BOTTOM, colour);
00594 GfxFillRect(left, bottom, right, bottom, colour);
00595 }
00596 }
00597 }
00598
00604 void Window::DrawSortButtonState(int widget, SortButtonState state) const
00605 {
00606 if (state == SBS_OFF) return;
00607
00608 assert(this->nested_array != NULL);
00609 const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(widget);
00610
00611 int offset = this->IsWidgetLowered(widget) ? 1 : 0;
00612 int base = offset + nwid->pos_x + (_current_text_dir == TD_LTR ? nwid->current_x - WD_SORTBUTTON_ARROW_WIDTH : 0);
00613 int top = nwid->pos_y;
00614
00615 DrawString(base, base + WD_SORTBUTTON_ARROW_WIDTH, top + 1 + offset, state == SBS_DOWN ? DOWNARROW : UPARROW, TC_BLACK, SA_HOR_CENTER);
00616 }
00617
00618
00676 NWidgetBase::NWidgetBase(WidgetType tp) : ZeroedMemoryAllocator()
00677 {
00678 this->type = tp;
00679 }
00680
00681
00682
00730 void NWidgetBase::SetDirty(const Window *w) const
00731 {
00732 int abs_left = w->left + this->pos_x;
00733 int abs_top = w->top + this->pos_y;
00734 SetDirtyBlocks(abs_left, abs_top, abs_left + this->current_x, abs_top + this->current_y);
00735 }
00736
00750 NWidgetBase *NWidgetBase::GetWidgetOfType(WidgetType tp)
00751 {
00752 return (this->type == tp) ? this : NULL;
00753 }
00754
00761 NWidgetResizeBase::NWidgetResizeBase(WidgetType tp, uint fill_x, uint fill_y) : NWidgetBase(tp)
00762 {
00763 this->fill_x = fill_x;
00764 this->fill_y = fill_y;
00765 }
00766
00772 void NWidgetResizeBase::SetMinimalSize(uint min_x, uint min_y)
00773 {
00774 this->min_x = min_x;
00775 this->min_y = min_y;
00776 }
00777
00784 void NWidgetResizeBase::SetMinimalTextLines(uint8 min_lines, uint8 spacing, FontSize size)
00785 {
00786 this->min_y = min_lines * GetCharacterHeight(size) + spacing;
00787 }
00788
00794 void NWidgetResizeBase::SetFill(uint fill_x, uint fill_y)
00795 {
00796 this->fill_x = fill_x;
00797 this->fill_y = fill_y;
00798 }
00799
00805 void NWidgetResizeBase::SetResize(uint resize_x, uint resize_y)
00806 {
00807 this->resize_x = resize_x;
00808 this->resize_y = resize_y;
00809 }
00810
00811 void NWidgetResizeBase::AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl)
00812 {
00813 this->StoreSizePosition(sizing, x, y, given_width, given_height);
00814 }
00815
00825 NWidgetCore::NWidgetCore(WidgetType tp, Colours colour, uint fill_x, uint fill_y, uint16 widget_data, StringID tool_tip) : NWidgetResizeBase(tp, fill_x, fill_y)
00826 {
00827 this->colour = colour;
00828 this->index = -1;
00829 this->widget_data = widget_data;
00830 this->tool_tip = tool_tip;
00831 this->scrollbar_index = -1;
00832 }
00833
00838 void NWidgetCore::SetIndex(int index)
00839 {
00840 assert(index >= 0);
00841 this->index = index;
00842 }
00843
00849 void NWidgetCore::SetDataTip(uint16 widget_data, StringID tool_tip)
00850 {
00851 this->widget_data = widget_data;
00852 this->tool_tip = tool_tip;
00853 }
00854
00855 void NWidgetCore::FillNestedArray(NWidgetBase **array, uint length)
00856 {
00857 if (this->index >= 0 && (uint)(this->index) < length) array[this->index] = this;
00858 }
00859
00860 NWidgetCore *NWidgetCore::GetWidgetFromPos(int x, int y)
00861 {
00862 return (IsInsideBS(x, this->pos_x, this->current_x) && IsInsideBS(y, this->pos_y, this->current_y)) ? this : NULL;
00863 }
00864
00869 NWidgetContainer::NWidgetContainer(WidgetType tp) : NWidgetBase(tp)
00870 {
00871 this->head = NULL;
00872 this->tail = NULL;
00873 }
00874
00875 NWidgetContainer::~NWidgetContainer()
00876 {
00877 while (this->head != NULL) {
00878 NWidgetBase *wid = this->head->next;
00879 delete this->head;
00880 this->head = wid;
00881 }
00882 this->tail = NULL;
00883 }
00884
00885 NWidgetBase *NWidgetContainer::GetWidgetOfType(WidgetType tp)
00886 {
00887 if (this->type == tp) return this;
00888 for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
00889 NWidgetBase *nwid = child_wid->GetWidgetOfType(tp);
00890 if (nwid != NULL) return nwid;
00891 }
00892 return NULL;
00893 }
00894
00899 void NWidgetContainer::Add(NWidgetBase *wid)
00900 {
00901 assert(wid->next == NULL && wid->prev == NULL);
00902
00903 if (this->head == NULL) {
00904 this->head = wid;
00905 this->tail = wid;
00906 } else {
00907 assert(this->tail != NULL);
00908 assert(this->tail->next == NULL);
00909
00910 this->tail->next = wid;
00911 wid->prev = this->tail;
00912 this->tail = wid;
00913 }
00914 }
00915
00916 void NWidgetContainer::FillNestedArray(NWidgetBase **array, uint length)
00917 {
00918 for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
00919 child_wid->FillNestedArray(array, length);
00920 }
00921 }
00922
00926 NWidgetStacked::NWidgetStacked() : NWidgetContainer(NWID_SELECTION)
00927 {
00928 this->index = -1;
00929 }
00930
00931 void NWidgetStacked::SetIndex(int index)
00932 {
00933 this->index = index;
00934 }
00935
00936 void NWidgetStacked::SetupSmallestSize(Window *w, bool init_array)
00937 {
00938 if (this->index >= 0 && init_array) {
00939 assert(w->nested_array_size > (uint)this->index);
00940 w->nested_array[this->index] = this;
00941 }
00942
00943
00944 if (this->shown_plane >= SZSP_BEGIN) {
00945 Dimension size = {0, 0};
00946 Dimension padding = {0, 0};
00947 Dimension fill = {(this->shown_plane == SZSP_HORIZONTAL), (this->shown_plane == SZSP_VERTICAL)};
00948 Dimension resize = {(this->shown_plane == SZSP_HORIZONTAL), (this->shown_plane == SZSP_VERTICAL)};
00949
00950 if (this->index >= 0) w->UpdateWidgetSize(this->index, &size, padding, &fill, &resize);
00951
00952 this->smallest_x = size.width;
00953 this->smallest_y = size.height;
00954 this->fill_x = fill.width;
00955 this->fill_y = fill.height;
00956 this->resize_x = resize.width;
00957 this->resize_y = resize.height;
00958 return;
00959 }
00960
00961
00962 this->smallest_x = 0;
00963 this->smallest_y = 0;
00964 this->fill_x = (this->head != NULL) ? 1 : 0;
00965 this->fill_y = (this->head != NULL) ? 1 : 0;
00966 this->resize_x = (this->head != NULL) ? 1 : 0;
00967 this->resize_y = (this->head != NULL) ? 1 : 0;
00968 for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
00969 child_wid->SetupSmallestSize(w, init_array);
00970
00971 this->smallest_x = max(this->smallest_x, child_wid->smallest_x + child_wid->padding_left + child_wid->padding_right);
00972 this->smallest_y = max(this->smallest_y, child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom);
00973 this->fill_x = LeastCommonMultiple(this->fill_x, child_wid->fill_x);
00974 this->fill_y = LeastCommonMultiple(this->fill_y, child_wid->fill_y);
00975 this->resize_x = LeastCommonMultiple(this->resize_x, child_wid->resize_x);
00976 this->resize_y = LeastCommonMultiple(this->resize_y, child_wid->resize_y);
00977 }
00978 }
00979
00980 void NWidgetStacked::AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl)
00981 {
00982 assert(given_width >= this->smallest_x && given_height >= this->smallest_y);
00983 this->StoreSizePosition(sizing, x, y, given_width, given_height);
00984
00985 if (this->shown_plane >= SZSP_BEGIN) return;
00986
00987 for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
00988 uint hor_step = (sizing == ST_SMALLEST) ? 1 : child_wid->GetHorizontalStepSize(sizing);
00989 uint child_width = ComputeMaxSize(child_wid->smallest_x, given_width - child_wid->padding_left - child_wid->padding_right, hor_step);
00990 uint child_pos_x = (rtl ? child_wid->padding_right : child_wid->padding_left);
00991
00992 uint vert_step = (sizing == ST_SMALLEST) ? 1 : child_wid->GetVerticalStepSize(sizing);
00993 uint child_height = ComputeMaxSize(child_wid->smallest_y, given_height - child_wid->padding_top - child_wid->padding_bottom, vert_step);
00994 uint child_pos_y = child_wid->padding_top;
00995
00996 child_wid->AssignSizePosition(sizing, x + child_pos_x, y + child_pos_y, child_width, child_height, rtl);
00997 }
00998 }
00999
01000 void NWidgetStacked::FillNestedArray(NWidgetBase **array, uint length)
01001 {
01002 if (this->index >= 0 && (uint)(this->index) < length) array[this->index] = this;
01003 NWidgetContainer::FillNestedArray(array, length);
01004 }
01005
01006 void NWidgetStacked::Draw(const Window *w)
01007 {
01008 if (this->shown_plane >= SZSP_BEGIN) return;
01009
01010 int plane = 0;
01011 for (NWidgetBase *child_wid = this->head; child_wid != NULL; plane++, child_wid = child_wid->next) {
01012 if (plane == this->shown_plane) {
01013 child_wid->Draw(w);
01014 return;
01015 }
01016 }
01017
01018 NOT_REACHED();
01019 }
01020
01021 NWidgetCore *NWidgetStacked::GetWidgetFromPos(int x, int y)
01022 {
01023 if (this->shown_plane >= SZSP_BEGIN) return NULL;
01024
01025 if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL;
01026 int plane = 0;
01027 for (NWidgetBase *child_wid = this->head; child_wid != NULL; plane++, child_wid = child_wid->next) {
01028 if (plane == this->shown_plane) {
01029 return child_wid->GetWidgetFromPos(x, y);
01030 }
01031 }
01032 return NULL;
01033 }
01034
01039 void NWidgetStacked::SetDisplayedPlane(int plane)
01040 {
01041 this->shown_plane = plane;
01042 }
01043
01044 NWidgetPIPContainer::NWidgetPIPContainer(WidgetType tp, NWidContainerFlags flags) : NWidgetContainer(tp)
01045 {
01046 this->flags = flags;
01047 }
01048
01058 void NWidgetPIPContainer::SetPIP(uint8 pip_pre, uint8 pip_inter, uint8 pip_post)
01059 {
01060 this->pip_pre = pip_pre;
01061 this->pip_inter = pip_inter;
01062 this->pip_post = pip_post;
01063 }
01064
01065 void NWidgetPIPContainer::Draw(const Window *w)
01066 {
01067 for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
01068 child_wid->Draw(w);
01069 }
01070 }
01071
01072 NWidgetCore *NWidgetPIPContainer::GetWidgetFromPos(int x, int y)
01073 {
01074 if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL;
01075
01076 for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
01077 NWidgetCore *nwid = child_wid->GetWidgetFromPos(x, y);
01078 if (nwid != NULL) return nwid;
01079 }
01080 return NULL;
01081 }
01082
01084 NWidgetHorizontal::NWidgetHorizontal(NWidContainerFlags flags) : NWidgetPIPContainer(NWID_HORIZONTAL, flags)
01085 {
01086 }
01087
01088 void NWidgetHorizontal::SetupSmallestSize(Window *w, bool init_array)
01089 {
01090 this->smallest_x = 0;
01091 this->smallest_y = 0;
01092 this->fill_x = 0;
01093 this->fill_y = 1;
01094 this->resize_x = 0;
01095 this->resize_y = 1;
01096
01097
01098 uint longest = 0;
01099 uint max_vert_fill = 0;
01100 for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
01101 child_wid->SetupSmallestSize(w, init_array);
01102 longest = max(longest, child_wid->smallest_x);
01103 max_vert_fill = max(max_vert_fill, child_wid->GetVerticalStepSize(ST_SMALLEST));
01104 this->smallest_y = max(this->smallest_y, child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom);
01105 }
01106
01107 uint max_smallest = this->smallest_y + 3 * max_vert_fill;
01108 uint cur_height = this->smallest_y;
01109 for (;;) {
01110 for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
01111 uint step_size = child_wid->GetVerticalStepSize(ST_SMALLEST);
01112 uint child_height = child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom;
01113 if (step_size > 1 && child_height < cur_height) {
01114 uint remainder = (cur_height - child_height) % step_size;
01115 if (remainder > 0) {
01116 cur_height += step_size - remainder;
01117 assert(cur_height < max_smallest);
01118
01119 }
01120 }
01121 }
01122 if (this->smallest_y == cur_height) break;
01123 this->smallest_y = cur_height;
01124 }
01125
01126 if (this->flags & NC_EQUALSIZE) {
01127 for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
01128 if (child_wid->fill_x == 1) child_wid->smallest_x = longest;
01129 }
01130 }
01131
01132 if (this->head != NULL) this->head->padding_left += this->pip_pre;
01133 for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
01134 if (child_wid->next != NULL) {
01135 child_wid->padding_right += this->pip_inter;
01136 } else {
01137 child_wid->padding_right += this->pip_post;
01138 }
01139
01140 this->smallest_x += child_wid->smallest_x + child_wid->padding_left + child_wid->padding_right;
01141 if (child_wid->fill_x > 0) {
01142 if (this->fill_x == 0 || this->fill_x > child_wid->fill_x) this->fill_x = child_wid->fill_x;
01143 }
01144 this->fill_y = LeastCommonMultiple(this->fill_y, child_wid->fill_y);
01145
01146 if (child_wid->resize_x > 0) {
01147 if (this->resize_x == 0 || this->resize_x > child_wid->resize_x) this->resize_x = child_wid->resize_x;
01148 }
01149 this->resize_y = LeastCommonMultiple(this->resize_y, child_wid->resize_y);
01150 }
01151
01152 this->pip_pre = this->pip_inter = this->pip_post = 0;
01153 }
01154
01155 void NWidgetHorizontal::AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl)
01156 {
01157 assert(given_width >= this->smallest_x && given_height >= this->smallest_y);
01158
01159
01160 uint additional_length = given_width;
01161 if (sizing == ST_SMALLEST && (this->flags & NC_EQUALSIZE)) {
01162
01163 for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
01164 additional_length -= child_wid->smallest_x + child_wid->padding_right + child_wid->padding_left;
01165 }
01166 } else {
01167 additional_length -= this->smallest_x;
01168 }
01169
01170 this->StoreSizePosition(sizing, x, y, given_width, given_height);
01171
01172
01173
01174
01175
01176
01177
01178
01179
01180
01181
01182
01183
01184 int num_changing_childs = 0;
01185 uint biggest_stepsize = 0;
01186 for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
01187 uint hor_step = child_wid->GetHorizontalStepSize(sizing);
01188 if (hor_step > 0) {
01189 num_changing_childs++;
01190 biggest_stepsize = max(biggest_stepsize, hor_step);
01191 } else {
01192 child_wid->current_x = child_wid->smallest_x;
01193 }
01194
01195 uint vert_step = (sizing == ST_SMALLEST) ? 1 : child_wid->GetVerticalStepSize(sizing);
01196 child_wid->current_y = ComputeMaxSize(child_wid->smallest_y, given_height - child_wid->padding_top - child_wid->padding_bottom, vert_step);
01197 }
01198
01199
01200 while (biggest_stepsize > 0) {
01201 uint next_biggest_stepsize = 0;
01202 for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
01203 uint hor_step = child_wid->GetHorizontalStepSize(sizing);
01204 if (hor_step > biggest_stepsize) continue;
01205 if (hor_step == biggest_stepsize) {
01206 uint increment = additional_length / num_changing_childs;
01207 num_changing_childs--;
01208 if (hor_step > 1) increment -= increment % hor_step;
01209 child_wid->current_x = child_wid->smallest_x + increment;
01210 additional_length -= increment;
01211 continue;
01212 }
01213 next_biggest_stepsize = max(next_biggest_stepsize, hor_step);
01214 }
01215 biggest_stepsize = next_biggest_stepsize;
01216 }
01217 assert(num_changing_childs == 0);
01218
01219
01220 uint position = 0;
01221 NWidgetBase *child_wid = rtl ? this->tail : this->head;
01222 while (child_wid != NULL) {
01223 uint child_width = child_wid->current_x;
01224 uint child_x = x + position + (rtl ? child_wid->padding_right : child_wid->padding_left);
01225 uint child_y = y + child_wid->padding_top;
01226
01227 child_wid->AssignSizePosition(sizing, child_x, child_y, child_width, child_wid->current_y, rtl);
01228 position += child_width + child_wid->padding_right + child_wid->padding_left;
01229
01230 child_wid = rtl ? child_wid->prev : child_wid->next;
01231 }
01232 }
01233
01235 NWidgetHorizontalLTR::NWidgetHorizontalLTR(NWidContainerFlags flags) : NWidgetHorizontal(flags)
01236 {
01237 this->type = NWID_HORIZONTAL_LTR;
01238 }
01239
01240 void NWidgetHorizontalLTR::AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl)
01241 {
01242 NWidgetHorizontal::AssignSizePosition(sizing, x, y, given_width, given_height, false);
01243 }
01244
01246 NWidgetVertical::NWidgetVertical(NWidContainerFlags flags) : NWidgetPIPContainer(NWID_VERTICAL, flags)
01247 {
01248 }
01249
01250 void NWidgetVertical::SetupSmallestSize(Window *w, bool init_array)
01251 {
01252 this->smallest_x = 0;
01253 this->smallest_y = 0;
01254 this->fill_x = 1;
01255 this->fill_y = 0;
01256 this->resize_x = 1;
01257 this->resize_y = 0;
01258
01259
01260 uint highest = 0;
01261 uint max_hor_fill = 0;
01262 for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
01263 child_wid->SetupSmallestSize(w, init_array);
01264 highest = max(highest, child_wid->smallest_y);
01265 max_hor_fill = max(max_hor_fill, child_wid->GetHorizontalStepSize(ST_SMALLEST));
01266 this->smallest_x = max(this->smallest_x, child_wid->smallest_x + child_wid->padding_left + child_wid->padding_right);
01267 }
01268
01269 uint max_smallest = this->smallest_x + 3 * max_hor_fill;
01270 uint cur_width = this->smallest_x;
01271 for (;;) {
01272 for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
01273 uint step_size = child_wid->GetHorizontalStepSize(ST_SMALLEST);
01274 uint child_width = child_wid->smallest_x + child_wid->padding_left + child_wid->padding_right;
01275 if (step_size > 1 && child_width < cur_width) {
01276 uint remainder = (cur_width - child_width) % step_size;
01277 if (remainder > 0) {
01278 cur_width += step_size - remainder;
01279 assert(cur_width < max_smallest);
01280
01281 }
01282 }
01283 }
01284 if (this->smallest_x == cur_width) break;
01285 this->smallest_x = cur_width;
01286 }
01287
01288 if (this->flags & NC_EQUALSIZE) {
01289 for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
01290 if (child_wid->fill_y == 1) child_wid->smallest_y = highest;
01291 }
01292 }
01293
01294 if (this->head != NULL) this->head->padding_top += this->pip_pre;
01295 for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
01296 if (child_wid->next != NULL) {
01297 child_wid->padding_bottom += this->pip_inter;
01298 } else {
01299 child_wid->padding_bottom += this->pip_post;
01300 }
01301
01302 this->smallest_y += child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom;
01303 if (child_wid->fill_y > 0) {
01304 if (this->fill_y == 0 || this->fill_y > child_wid->fill_y) this->fill_y = child_wid->fill_y;
01305 }
01306 this->fill_x = LeastCommonMultiple(this->fill_x, child_wid->fill_x);
01307
01308 if (child_wid->resize_y > 0) {
01309 if (this->resize_y == 0 || this->resize_y > child_wid->resize_y) this->resize_y = child_wid->resize_y;
01310 }
01311 this->resize_x = LeastCommonMultiple(this->resize_x, child_wid->resize_x);
01312 }
01313
01314 this->pip_pre = this->pip_inter = this->pip_post = 0;
01315 }
01316
01317 void NWidgetVertical::AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl)
01318 {
01319 assert(given_width >= this->smallest_x && given_height >= this->smallest_y);
01320
01321
01322 uint additional_length = given_height;
01323 if (sizing == ST_SMALLEST && (this->flags & NC_EQUALSIZE)) {
01324
01325 for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
01326 additional_length -= child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom;
01327 }
01328 } else {
01329 additional_length -= this->smallest_y;
01330 }
01331
01332 this->StoreSizePosition(sizing, x, y, given_width, given_height);
01333
01334
01335
01336
01337
01338
01339 int num_changing_childs = 0;
01340 uint biggest_stepsize = 0;
01341 for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
01342 uint vert_step = child_wid->GetVerticalStepSize(sizing);
01343 if (vert_step > 0) {
01344 num_changing_childs++;
01345 biggest_stepsize = max(biggest_stepsize, vert_step);
01346 } else {
01347 child_wid->current_y = child_wid->smallest_y;
01348 }
01349
01350 uint hor_step = (sizing == ST_SMALLEST) ? 1 : child_wid->GetHorizontalStepSize(sizing);
01351 child_wid->current_x = ComputeMaxSize(child_wid->smallest_x, given_width - child_wid->padding_left - child_wid->padding_right, hor_step);
01352 }
01353
01354
01355 while (biggest_stepsize > 0) {
01356 uint next_biggest_stepsize = 0;
01357 for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
01358 uint vert_step = child_wid->GetVerticalStepSize(sizing);
01359 if (vert_step > biggest_stepsize) continue;
01360 if (vert_step == biggest_stepsize) {
01361 uint increment = additional_length / num_changing_childs;
01362 num_changing_childs--;
01363 if (vert_step > 1) increment -= increment % vert_step;
01364 child_wid->current_y = child_wid->smallest_y + increment;
01365 additional_length -= increment;
01366 continue;
01367 }
01368 next_biggest_stepsize = max(next_biggest_stepsize, vert_step);
01369 }
01370 biggest_stepsize = next_biggest_stepsize;
01371 }
01372 assert(num_changing_childs == 0);
01373
01374
01375 uint position = 0;
01376 for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
01377 uint child_x = x + (rtl ? child_wid->padding_right : child_wid->padding_left);
01378 uint child_height = child_wid->current_y;
01379
01380 child_wid->AssignSizePosition(sizing, child_x, y + position + child_wid->padding_top, child_wid->current_x, child_height, rtl);
01381 position += child_height + child_wid->padding_top + child_wid->padding_bottom;
01382 }
01383 }
01384
01390 NWidgetSpacer::NWidgetSpacer(int length, int height) : NWidgetResizeBase(NWID_SPACER, 0, 0)
01391 {
01392 this->SetMinimalSize(length, height);
01393 this->SetResize(0, 0);
01394 }
01395
01396 void NWidgetSpacer::SetupSmallestSize(Window *w, bool init_array)
01397 {
01398 this->smallest_x = this->min_x;
01399 this->smallest_y = this->min_y;
01400 }
01401
01402 void NWidgetSpacer::FillNestedArray(NWidgetBase **array, uint length)
01403 {
01404 }
01405
01406 void NWidgetSpacer::Draw(const Window *w)
01407 {
01408
01409 }
01410
01411 void NWidgetSpacer::SetDirty(const Window *w) const
01412 {
01413
01414 }
01415
01416 NWidgetCore *NWidgetSpacer::GetWidgetFromPos(int x, int y)
01417 {
01418 return NULL;
01419 }
01420
01421 NWidgetMatrix::NWidgetMatrix() : NWidgetPIPContainer(NWID_MATRIX, NC_EQUALSIZE), index(-1), clicked(-1), count(-1)
01422 {
01423 }
01424
01425 void NWidgetMatrix::SetIndex(int index)
01426 {
01427 this->index = index;
01428 }
01429
01430 void NWidgetMatrix::SetColour(Colours colour)
01431 {
01432 this->colour = colour;
01433 }
01434
01439 void NWidgetMatrix::SetClicked(int clicked)
01440 {
01441 this->clicked = clicked;
01442 if (this->clicked >= 0 && this->sb != NULL && this->widgets_x != 0) {
01443 int vpos = (this->clicked / this->widgets_x) * this->widget_h;
01444
01445
01446 if (this->sb->GetPosition() < vpos) vpos += this->widget_h - this->pip_inter - 1;
01447 this->sb->ScrollTowards(vpos);
01448 }
01449 }
01450
01456 void NWidgetMatrix::SetCount(int count)
01457 {
01458 this->count = count;
01459
01460 if (this->sb == NULL || this->widgets_x == 0) return;
01461
01462
01463
01464
01465
01466
01467 count = CeilDiv(count, this->sb->IsVertical() ? this->widgets_x : this->widgets_y);
01468 count *= (this->sb->IsVertical() ? this->head->smallest_y : this->head->smallest_x) + this->pip_inter;
01469 count += -this->pip_inter + this->pip_pre + this->pip_post;
01470 this->sb->SetCount(count);
01471 this->sb->SetCapacity(this->sb->IsVertical() ? this->current_y : this->current_x);
01472 this->sb->SetStepSize(this->sb->IsVertical() ? this->widget_h : this->widget_w);
01473 }
01474
01479 void NWidgetMatrix::SetScrollbar(Scrollbar *sb)
01480 {
01481 this->sb = sb;
01482 }
01483
01484 void NWidgetMatrix::SetupSmallestSize(Window *w, bool init_array)
01485 {
01486 assert(this->head != NULL);
01487 assert(this->head->next == NULL);
01488
01489 if (this->index >= 0 && init_array) {
01490 assert(w->nested_array_size > (uint)this->index);
01491 w->nested_array[this->index] = this;
01492 }
01493
01494
01495 SB(dynamic_cast<NWidgetCore *>(this->head)->index, 16, 16, 0);
01496 this->head->SetupSmallestSize(w, init_array);
01497
01498 Dimension padding = {this->pip_pre + this->pip_post, this->pip_pre + this->pip_post};
01499 Dimension size = {this->head->smallest_x + padding.width, this->head->smallest_y + padding.height};
01500 Dimension fill = {0, 0};
01501 Dimension resize = {this->pip_inter + this->head->smallest_x, this->pip_inter + this->head->smallest_y};
01502
01503 if (this->index >= 0) w->UpdateWidgetSize(this->index, &size, padding, &fill, &resize);
01504
01505 this->smallest_x = size.width;
01506 this->smallest_y = size.height;
01507 this->fill_x = fill.width;
01508 this->fill_y = fill.height;
01509 this->resize_x = resize.width;
01510 this->resize_y = resize.height;
01511 }
01512
01513 void NWidgetMatrix::AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl)
01514 {
01515 assert(given_width >= this->smallest_x && given_height >= this->smallest_y);
01516
01517 this->pos_x = x;
01518 this->pos_y = y;
01519 this->current_x = given_width;
01520 this->current_y = given_height;
01521
01522
01523 this->widget_w = this->head->smallest_x + this->pip_inter;
01524 this->widget_h = this->head->smallest_y + this->pip_inter;
01525
01526
01527
01528 this->widgets_x = CeilDiv(this->current_x - this->pip_pre - this->pip_post + this->pip_inter, this->widget_w);
01529 this->widgets_y = CeilDiv(this->current_y - this->pip_pre - this->pip_post + this->pip_inter, this->widget_h);
01530
01531
01532
01533
01534 this->SetCount(this->count);
01535 }
01536
01537 void NWidgetMatrix::FillNestedArray(NWidgetBase **array, uint length)
01538 {
01539 if (this->index >= 0 && (uint)(this->index) < length) array[this->index] = this;
01540 NWidgetContainer::FillNestedArray(array, length);
01541 }
01542
01543 NWidgetCore *NWidgetMatrix::GetWidgetFromPos(int x, int y)
01544 {
01545
01546 if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL;
01547
01548 int start_x, start_y, base_offs_x, base_offs_y;
01549 this->GetScrollOffsets(start_x, start_y, base_offs_x, base_offs_y);
01550
01551
01552 bool rtl = _current_text_dir == TD_RTL;
01553 if (rtl) base_offs_x -= (this->widgets_x - 1) * this->widget_w;
01554
01555 int widget_col = (x - base_offs_x - (int)this->pip_pre - (int)this->pos_x) / this->widget_w;
01556 int widget_row = (y - base_offs_y - (int)this->pip_pre - (int)this->pos_y) / this->widget_h;
01557
01558 if (widget_row * this->widgets_x + widget_col >= this->count) return NULL;
01559
01560 NWidgetCore *child = dynamic_cast<NWidgetCore *>(this->head);
01561 child->AssignSizePosition(ST_RESIZE,
01562 this->pos_x + this->pip_pre + widget_col * this->widget_w + base_offs_x,
01563 this->pos_y + this->pip_pre + widget_row * this->widget_h + base_offs_y,
01564 child->smallest_x, child->smallest_y, rtl);
01565
01566
01567 if (rtl) widget_col = this->widgets_x - widget_col - 1;
01568 SB(child->index, 16, 16, (widget_row + start_y) * this->widgets_x + widget_col + start_x);
01569
01570 return child->GetWidgetFromPos(x, y);
01571 }
01572
01573 void NWidgetMatrix::Draw(const Window *w)
01574 {
01575
01576 GfxFillRect(this->pos_x, this->pos_y, this->pos_x + this->current_x - 1, this->pos_y + this->current_y - 1, _colour_gradient[this->colour & 0xF][5]);
01577
01578
01579 DrawPixelInfo tmp_dpi;
01580 if (!FillDrawPixelInfo(&tmp_dpi, this->pos_x + this->pip_pre, this->pos_y + this->pip_pre, this->current_x - this->pip_pre - this->pip_post, this->current_y - this->pip_pre - this->pip_post)) return;
01581 DrawPixelInfo *old_dpi = _cur_dpi;
01582 _cur_dpi = &tmp_dpi;
01583
01584
01585 NWidgetCore *child = dynamic_cast<NWidgetCore *>(this->head);
01586 bool rtl = _current_text_dir == TD_RTL;
01587 int start_x, start_y, base_offs_x, base_offs_y;
01588 this->GetScrollOffsets(start_x, start_y, base_offs_x, base_offs_y);
01589
01590 int offs_y = base_offs_y;
01591 for (int y = start_y; y < start_y + this->widgets_y + 1; y++, offs_y += this->widget_h) {
01592
01593 if (offs_y + child->smallest_y <= 0) continue;
01594 if (offs_y >= (int)this->current_y) break;
01595
01596
01597 if (y * this->widgets_x >= this->count) break;
01598
01599 int offs_x = base_offs_x;
01600 for (int x = start_x; x < start_x + this->widgets_x + 1; x++, offs_x += rtl ? -this->widget_w : this->widget_w) {
01601
01602 if (offs_x + child->smallest_x <= 0) continue;
01603 if (offs_x >= (int)this->current_x) continue;
01604
01605
01606 int sub_wid = y * this->widgets_x + x;
01607 if (sub_wid >= this->count) break;
01608
01609 child->AssignSizePosition(ST_RESIZE, offs_x, offs_y, child->smallest_x, child->smallest_y, rtl);
01610 child->SetLowered(this->clicked == sub_wid);
01611 SB(child->index, 16, 16, sub_wid);
01612 child->Draw(w);
01613 }
01614 }
01615
01616
01617 _cur_dpi = old_dpi;
01618 }
01619
01627 void NWidgetMatrix::GetScrollOffsets(int &start_x, int &start_y, int &base_offs_x, int &base_offs_y)
01628 {
01629 base_offs_x = 0;
01630 base_offs_y = 0;
01631 start_x = 0;
01632 start_y = 0;
01633 if (this->sb != NULL) {
01634 if (this->sb->IsVertical()) {
01635 start_y = this->sb->GetPosition() / this->widget_h;
01636 base_offs_y = -this->sb->GetPosition() + start_y * this->widget_h;
01637 if (_current_text_dir == TD_RTL) base_offs_x = this->pip_pre + this->widget_w * (this->widgets_x - 1) - this->pip_inter;
01638 } else {
01639 start_x = this->sb->GetPosition() / this->widget_w;
01640 if (_current_text_dir == TD_RTL) {
01641 base_offs_x = this->sb->GetCapacity() + this->sb->GetPosition() - (start_x + 1) * this->widget_w + this->pip_inter - this->pip_post - this->pip_pre;
01642 } else {
01643 base_offs_x = -this->sb->GetPosition() + start_x * this->widget_w;
01644 }
01645 }
01646 }
01647 }
01648
01658 NWidgetBackground::NWidgetBackground(WidgetType tp, Colours colour, int index, NWidgetPIPContainer *child) : NWidgetCore(tp, colour, 1, 1, 0x0, STR_NULL)
01659 {
01660 assert(tp == WWT_PANEL || tp == WWT_INSET || tp == WWT_FRAME);
01661 if (index >= 0) this->SetIndex(index);
01662 this->child = child;
01663 }
01664
01665 NWidgetBackground::~NWidgetBackground()
01666 {
01667 if (this->child != NULL) delete this->child;
01668 }
01669
01677 void NWidgetBackground::Add(NWidgetBase *nwid)
01678 {
01679 if (this->child == NULL) {
01680 this->child = new NWidgetVertical();
01681 }
01682 this->child->Add(nwid);
01683 }
01684
01695 void NWidgetBackground::SetPIP(uint8 pip_pre, uint8 pip_inter, uint8 pip_post)
01696 {
01697 if (this->child == NULL) {
01698 this->child = new NWidgetVertical();
01699 }
01700 this->child->SetPIP(pip_pre, pip_inter, pip_post);
01701 }
01702
01703 void NWidgetBackground::SetupSmallestSize(Window *w, bool init_array)
01704 {
01705 if (init_array && this->index >= 0) {
01706 assert(w->nested_array_size > (uint)this->index);
01707 w->nested_array[this->index] = this;
01708 }
01709 if (this->child != NULL) {
01710 this->child->SetupSmallestSize(w, init_array);
01711
01712 this->smallest_x = this->child->smallest_x;
01713 this->smallest_y = this->child->smallest_y;
01714 this->fill_x = this->child->fill_x;
01715 this->fill_y = this->child->fill_y;
01716 this->resize_x = this->child->resize_x;
01717 this->resize_y = this->child->resize_y;
01718
01719
01720 if (w != NULL && this->type == WWT_FRAME) {
01721 this->child->padding_left = WD_FRAMETEXT_LEFT;
01722 this->child->padding_right = WD_FRAMETEXT_RIGHT;
01723 this->child->padding_top = max((int)WD_FRAMETEXT_TOP, this->widget_data != STR_NULL ? FONT_HEIGHT_NORMAL + WD_FRAMETEXT_TOP / 2 : 0);
01724 this->child->padding_bottom = WD_FRAMETEXT_BOTTOM;
01725
01726 this->smallest_x += this->child->padding_left + this->child->padding_right;
01727 this->smallest_y += this->child->padding_top + this->child->padding_bottom;
01728
01729 if (this->index >= 0) w->SetStringParameters(this->index);
01730 this->smallest_x = max(this->smallest_x, GetStringBoundingBox(this->widget_data).width + WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT);
01731 }
01732 } else {
01733 Dimension d = {this->min_x, this->min_y};
01734 Dimension fill = {this->fill_x, this->fill_y};
01735 Dimension resize = {this->resize_x, this->resize_y};
01736 if (w != NULL) {
01737 if (this->type == WWT_FRAME || this->type == WWT_INSET) {
01738 if (this->index >= 0) w->SetStringParameters(this->index);
01739 Dimension background = GetStringBoundingBox(this->widget_data);
01740 background.width += (this->type == WWT_FRAME) ? (WD_FRAMETEXT_LEFT + WD_FRAMERECT_RIGHT) : (WD_INSET_LEFT + WD_INSET_RIGHT);
01741 d = maxdim(d, background);
01742 }
01743 if (this->index >= 0) {
01744 static const Dimension padding = {0, 0};
01745 w->UpdateWidgetSize(this->index, &d, padding, &fill, &resize);
01746 }
01747 }
01748 this->smallest_x = d.width;
01749 this->smallest_y = d.height;
01750 this->fill_x = fill.width;
01751 this->fill_y = fill.height;
01752 this->resize_x = resize.width;
01753 this->resize_y = resize.height;
01754 }
01755 }
01756
01757 void NWidgetBackground::AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl)
01758 {
01759 this->StoreSizePosition(sizing, x, y, given_width, given_height);
01760
01761 if (this->child != NULL) {
01762 uint x_offset = (rtl ? this->child->padding_right : this->child->padding_left);
01763 uint width = given_width - this->child->padding_right - this->child->padding_left;
01764 uint height = given_height - this->child->padding_top - this->child->padding_bottom;
01765 this->child->AssignSizePosition(sizing, x + x_offset, y + this->child->padding_top, width, height, rtl);
01766 }
01767 }
01768
01769 void NWidgetBackground::FillNestedArray(NWidgetBase **array, uint length)
01770 {
01771 if (this->index >= 0 && (uint)(this->index) < length) array[this->index] = this;
01772 if (this->child != NULL) this->child->FillNestedArray(array, length);
01773 }
01774
01775 void NWidgetBackground::Draw(const Window *w)
01776 {
01777 if (this->current_x == 0 || this->current_y == 0) return;
01778
01779 Rect r;
01780 r.left = this->pos_x;
01781 r.right = this->pos_x + this->current_x - 1;
01782 r.top = this->pos_y;
01783 r.bottom = this->pos_y + this->current_y - 1;
01784
01785 const DrawPixelInfo *dpi = _cur_dpi;
01786 if (dpi->left > r.right || dpi->left + dpi->width <= r.left || dpi->top > r.bottom || dpi->top + dpi->height <= r.top) return;
01787
01788 switch (this->type) {
01789 case WWT_PANEL:
01790 assert(this->widget_data == 0);
01791 DrawFrameRect(r.left, r.top, r.right, r.bottom, this->colour, this->IsLowered() ? FR_LOWERED : FR_NONE);
01792 break;
01793
01794 case WWT_FRAME:
01795 if (this->index >= 0) w->SetStringParameters(this->index);
01796 DrawFrame(r, this->colour, this->widget_data);
01797 break;
01798
01799 case WWT_INSET:
01800 if (this->index >= 0) w->SetStringParameters(this->index);
01801 DrawInset(r, this->colour, this->widget_data);
01802 break;
01803
01804 default:
01805 NOT_REACHED();
01806 }
01807
01808 if (this->index >= 0) w->DrawWidget(r, this->index);
01809 if (this->child != NULL) this->child->Draw(w);
01810
01811 if (this->IsDisabled()) {
01812 GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, _colour_gradient[this->colour & 0xF][2], FILLRECT_CHECKER);
01813 }
01814 }
01815
01816 NWidgetCore *NWidgetBackground::GetWidgetFromPos(int x, int y)
01817 {
01818 NWidgetCore *nwid = NULL;
01819 if (IsInsideBS(x, this->pos_x, this->current_x) && IsInsideBS(y, this->pos_y, this->current_y)) {
01820 if (this->child != NULL) nwid = this->child->GetWidgetFromPos(x, y);
01821 if (nwid == NULL) nwid = this;
01822 }
01823 return nwid;
01824 }
01825
01826 NWidgetBase *NWidgetBackground::GetWidgetOfType(WidgetType tp)
01827 {
01828 NWidgetBase *nwid = NULL;
01829 if (this->child != NULL) nwid = this->child->GetWidgetOfType(tp);
01830 if (nwid == NULL && this->type == tp) nwid = this;
01831 return nwid;
01832 }
01833
01834 NWidgetViewport::NWidgetViewport(int index) : NWidgetCore(NWID_VIEWPORT, INVALID_COLOUR, 1, 1, 0x0, STR_NULL)
01835 {
01836 this->SetIndex(index);
01837 }
01838
01839 void NWidgetViewport::SetupSmallestSize(Window *w, bool init_array)
01840 {
01841 if (init_array && this->index >= 0) {
01842 assert(w->nested_array_size > (uint)this->index);
01843 w->nested_array[this->index] = this;
01844 }
01845 this->smallest_x = this->min_x;
01846 this->smallest_y = this->min_y;
01847 }
01848
01849 void NWidgetViewport::Draw(const Window *w)
01850 {
01851 if (this->disp_flags & ND_NO_TRANSPARENCY) {
01852 TransparencyOptionBits to_backup = _transparency_opt;
01853 _transparency_opt &= (1 << TO_SIGNS) | (1 << TO_LOADING);
01854 w->DrawViewport();
01855 _transparency_opt = to_backup;
01856 } else {
01857 w->DrawViewport();
01858 }
01859
01860
01861 if (this->disp_flags & (ND_SHADE_GREY | ND_SHADE_DIMMED)) {
01862 GfxFillRect(this->pos_x, this->pos_y, this->pos_x + this->current_x - 1, this->pos_y + this->current_y - 1,
01863 (this->disp_flags & ND_SHADE_DIMMED) ? PALETTE_TO_TRANSPARENT : PALETTE_NEWSPAPER, FILLRECT_RECOLOUR);
01864 }
01865 }
01866
01873 void NWidgetViewport::InitializeViewport(Window *w, uint32 follow_flags, ZoomLevel zoom)
01874 {
01875 InitializeWindowViewport(w, this->pos_x, this->pos_y, this->current_x, this->current_y, follow_flags, zoom);
01876 }
01877
01882 void NWidgetViewport::UpdateViewportCoordinates(Window *w)
01883 {
01884 ViewPort *vp = w->viewport;
01885 if (vp != NULL) {
01886 vp->left = w->left + this->pos_x;
01887 vp->top = w->top + this->pos_y;
01888 vp->width = this->current_x;
01889 vp->height = this->current_y;
01890
01891 vp->virtual_width = ScaleByZoom(vp->width, vp->zoom);
01892 vp->virtual_height = ScaleByZoom(vp->height, vp->zoom);
01893 }
01894 }
01895
01905 int Scrollbar::GetScrolledRowFromWidget(int clickpos, const Window * const w, int widget, int padding, int line_height) const
01906 {
01907 uint pos = w->GetRowFromWidget(clickpos, widget, padding, line_height);
01908 if (pos != INT_MAX) pos += this->GetPosition();
01909 return (pos >= this->GetCount()) ? INT_MAX : pos;
01910 }
01911
01919 void Scrollbar::SetCapacityFromWidget(Window *w, int widget, int padding)
01920 {
01921 NWidgetBase *nwid = w->GetWidget<NWidgetBase>(widget);
01922 if (this->IsVertical()) {
01923 this->SetCapacity(((int)nwid->current_y - padding) / (int)nwid->resize_y);
01924 } else {
01925 this->SetCapacity(((int)nwid->current_x - padding) / (int)nwid->resize_x);
01926 }
01927 }
01928
01935 NWidgetScrollbar::NWidgetScrollbar(WidgetType tp, Colours colour, int index) : NWidgetCore(tp, colour, 1, 1, 0x0, STR_NULL), Scrollbar(tp != NWID_HSCROLLBAR)
01936 {
01937 assert(tp == NWID_HSCROLLBAR || tp == NWID_VSCROLLBAR);
01938 this->SetIndex(index);
01939
01940 switch (this->type) {
01941 case NWID_HSCROLLBAR:
01942 this->SetMinimalSize(0, NWidgetScrollbar::GetHorizontalDimension().height);
01943 this->SetResize(1, 0);
01944 this->SetFill(1, 0);
01945 this->SetDataTip(0x0, STR_TOOLTIP_HSCROLL_BAR_SCROLLS_LIST);
01946 break;
01947
01948 case NWID_VSCROLLBAR:
01949 this->SetMinimalSize(NWidgetScrollbar::GetVerticalDimension().width, 0);
01950 this->SetResize(0, 1);
01951 this->SetFill(0, 1);
01952 this->SetDataTip(0x0, STR_TOOLTIP_VSCROLL_BAR_SCROLLS_LIST);
01953 break;
01954
01955 default: NOT_REACHED();
01956 }
01957 }
01958
01959 void NWidgetScrollbar::SetupSmallestSize(Window *w, bool init_array)
01960 {
01961 if (init_array && this->index >= 0) {
01962 assert(w->nested_array_size > (uint)this->index);
01963 w->nested_array[this->index] = this;
01964 }
01965 this->smallest_x = this->min_x;
01966 this->smallest_y = this->min_y;
01967 }
01968
01969 void NWidgetScrollbar::Draw(const Window *w)
01970 {
01971 if (this->current_x == 0 || this->current_y == 0) return;
01972
01973 Rect r;
01974 r.left = this->pos_x;
01975 r.right = this->pos_x + this->current_x - 1;
01976 r.top = this->pos_y;
01977 r.bottom = this->pos_y + this->current_y - 1;
01978
01979 const DrawPixelInfo *dpi = _cur_dpi;
01980 if (dpi->left > r.right || dpi->left + dpi->width <= r.left || dpi->top > r.bottom || dpi->top + dpi->height <= r.top) return;
01981
01982 bool up_lowered = HasBit(this->disp_flags, NDB_SCROLLBAR_UP);
01983 bool down_lowered = HasBit(this->disp_flags, NDB_SCROLLBAR_DOWN);
01984 bool middle_lowered = !(this->disp_flags & ND_SCROLLBAR_BTN) && w->scrolling_scrollbar == this->index;
01985
01986 if (this->type == NWID_HSCROLLBAR) {
01987 DrawHorizontalScrollbar(r, this->colour, up_lowered, middle_lowered, down_lowered, this);
01988 } else {
01989 DrawVerticalScrollbar(r, this->colour, up_lowered, middle_lowered, down_lowered, this);
01990 }
01991
01992 if (this->IsDisabled()) {
01993 GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, _colour_gradient[this->colour & 0xF][2], FILLRECT_CHECKER);
01994 }
01995 }
01996
01997 void NWidgetScrollbar::InvalidateDimensionCache()
01998 {
01999 vertical_dimension.width = vertical_dimension.height = 0;
02000 horizontal_dimension.width = horizontal_dimension.height = 0;
02001 }
02002
02003 Dimension NWidgetScrollbar::GetVerticalDimension()
02004 {
02005 static const Dimension extra = {WD_SCROLLBAR_LEFT + WD_SCROLLBAR_RIGHT, WD_SCROLLBAR_TOP + WD_SCROLLBAR_BOTTOM};
02006 if (vertical_dimension.width == 0) {
02007 vertical_dimension = maxdim(GetSpriteSize(SPR_ARROW_UP), GetSpriteSize(SPR_ARROW_DOWN));
02008 vertical_dimension.width += extra.width;
02009 vertical_dimension.height += extra.height;
02010 }
02011 return vertical_dimension;
02012 }
02013
02014 Dimension NWidgetScrollbar::GetHorizontalDimension()
02015 {
02016 static const Dimension extra = {WD_SCROLLBAR_LEFT + WD_SCROLLBAR_RIGHT, WD_SCROLLBAR_TOP + WD_SCROLLBAR_BOTTOM};
02017 if (horizontal_dimension.width == 0) {
02018 horizontal_dimension = maxdim(GetSpriteSize(SPR_ARROW_LEFT), GetSpriteSize(SPR_ARROW_RIGHT));
02019 horizontal_dimension.width += extra.width;
02020 horizontal_dimension.height += extra.height;
02021 }
02022 return horizontal_dimension;
02023 }
02024
02025 Dimension NWidgetScrollbar::vertical_dimension = {0, 0};
02026 Dimension NWidgetScrollbar::horizontal_dimension = {0, 0};
02027
02029 void NWidgetLeaf::InvalidateDimensionCache()
02030 {
02031 shadebox_dimension.width = shadebox_dimension.height = 0;
02032 debugbox_dimension.width = debugbox_dimension.height = 0;
02033 stickybox_dimension.width = stickybox_dimension.height = 0;
02034 resizebox_dimension.width = resizebox_dimension.height = 0;
02035 closebox_dimension.width = closebox_dimension.height = 0;
02036 }
02037
02038 Dimension NWidgetLeaf::shadebox_dimension = {0, 0};
02039 Dimension NWidgetLeaf::debugbox_dimension = {0, 0};
02040 Dimension NWidgetLeaf::stickybox_dimension = {0, 0};
02041 Dimension NWidgetLeaf::resizebox_dimension = {0, 0};
02042 Dimension NWidgetLeaf::closebox_dimension = {0, 0};
02043
02052 NWidgetLeaf::NWidgetLeaf(WidgetType tp, Colours colour, int index, uint16 data, StringID tip) : NWidgetCore(tp, colour, 1, 1, data, tip)
02053 {
02054 assert(index >= 0 || tp == WWT_LABEL || tp == WWT_TEXT || tp == WWT_CAPTION || tp == WWT_RESIZEBOX || tp == WWT_SHADEBOX || tp == WWT_DEBUGBOX || tp == WWT_STICKYBOX || tp == WWT_CLOSEBOX);
02055 if (index >= 0) this->SetIndex(index);
02056 this->SetMinimalSize(0, 0);
02057 this->SetResize(0, 0);
02058
02059 switch (tp) {
02060 case WWT_EMPTY:
02061 break;
02062
02063 case WWT_PUSHBTN:
02064 case WWT_IMGBTN:
02065 case WWT_PUSHIMGBTN:
02066 case WWT_IMGBTN_2:
02067 case WWT_TEXTBTN:
02068 case WWT_PUSHTXTBTN:
02069 case WWT_TEXTBTN_2:
02070 case WWT_LABEL:
02071 case WWT_TEXT:
02072 case WWT_MATRIX:
02073 case NWID_BUTTON_DROPDOWN:
02074 case NWID_PUSHBUTTON_DROPDOWN:
02075 case WWT_ARROWBTN:
02076 case WWT_PUSHARROWBTN:
02077 this->SetFill(0, 0);
02078 break;
02079
02080 case WWT_EDITBOX:
02081 this->SetMinimalSize(10, 0);
02082 this->SetFill(0, 0);
02083 break;
02084
02085 case WWT_CAPTION:
02086 this->SetFill(1, 0);
02087 this->SetResize(1, 0);
02088 this->min_y = WD_CAPTION_HEIGHT;
02089 this->SetDataTip(data, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS);
02090 break;
02091
02092 case WWT_STICKYBOX:
02093 this->SetFill(0, 0);
02094 this->SetMinimalSize(WD_STICKYBOX_WIDTH, WD_CAPTION_HEIGHT);
02095 this->SetDataTip(STR_NULL, STR_TOOLTIP_STICKY);
02096 break;
02097
02098 case WWT_SHADEBOX:
02099 this->SetFill(0, 0);
02100 this->SetMinimalSize(WD_SHADEBOX_TOP, WD_CAPTION_HEIGHT);
02101 this->SetDataTip(STR_NULL, STR_TOOLTIP_SHADE);
02102 break;
02103
02104 case WWT_DEBUGBOX:
02105 this->SetFill(0, 0);
02106 this->SetMinimalSize(WD_DEBUGBOX_TOP, WD_CAPTION_HEIGHT);
02107 this->SetDataTip(STR_NULL, STR_TOOLTIP_DEBUG);
02108 break;
02109
02110 case WWT_RESIZEBOX:
02111 this->SetFill(0, 0);
02112 this->SetMinimalSize(WD_RESIZEBOX_WIDTH, 12);
02113 this->SetDataTip(STR_NULL, STR_TOOLTIP_RESIZE);
02114 break;
02115
02116 case WWT_CLOSEBOX:
02117 this->SetFill(0, 0);
02118 this->SetMinimalSize(WD_CLOSEBOX_WIDTH, WD_CAPTION_HEIGHT);
02119 this->SetDataTip(STR_BLACK_CROSS, STR_TOOLTIP_CLOSE_WINDOW);
02120 break;
02121
02122 case WWT_DROPDOWN:
02123 this->SetFill(0, 0);
02124 this->min_y = WD_DROPDOWN_HEIGHT;
02125 break;
02126
02127 default:
02128 NOT_REACHED();
02129 }
02130 }
02131
02132 void NWidgetLeaf::SetupSmallestSize(Window *w, bool init_array)
02133 {
02134 if (this->index >= 0 && init_array) {
02135 assert(w->nested_array_size > (uint)this->index);
02136 w->nested_array[this->index] = this;
02137 }
02138
02139 Dimension size = {this->min_x, this->min_y};
02140 Dimension fill = {this->fill_x, this->fill_y};
02141 Dimension resize = {this->resize_x, this->resize_y};
02142
02143 const Dimension *padding = NULL;
02144 switch (this->type) {
02145 case WWT_EMPTY: {
02146 static const Dimension extra = {0, 0};
02147 padding = &extra;
02148 break;
02149 }
02150 case WWT_MATRIX: {
02151 static const Dimension extra = {WD_MATRIX_LEFT + WD_MATRIX_RIGHT, WD_MATRIX_TOP + WD_MATRIX_BOTTOM};
02152 padding = &extra;
02153 break;
02154 }
02155 case WWT_SHADEBOX: {
02156 static const Dimension extra = {WD_SHADEBOX_LEFT + WD_SHADEBOX_RIGHT, WD_SHADEBOX_TOP + WD_SHADEBOX_BOTTOM};
02157 padding = &extra;
02158 if (NWidgetLeaf::shadebox_dimension.width == 0) {
02159 NWidgetLeaf::shadebox_dimension = maxdim(GetSpriteSize(SPR_WINDOW_SHADE), GetSpriteSize(SPR_WINDOW_UNSHADE));
02160 NWidgetLeaf::shadebox_dimension.width += extra.width;
02161 NWidgetLeaf::shadebox_dimension.height += extra.height;
02162 }
02163 size = maxdim(size, NWidgetLeaf::shadebox_dimension);
02164 break;
02165 }
02166 case WWT_DEBUGBOX:
02167 if (_settings_client.gui.newgrf_developer_tools && w->IsNewGRFInspectable()) {
02168 static const Dimension extra = {WD_DEBUGBOX_LEFT + WD_DEBUGBOX_RIGHT, WD_DEBUGBOX_TOP + WD_DEBUGBOX_BOTTOM};
02169 padding = &extra;
02170 if (NWidgetLeaf::debugbox_dimension.width == 0) {
02171 NWidgetLeaf::debugbox_dimension = GetSpriteSize(SPR_WINDOW_DEBUG);
02172 NWidgetLeaf::debugbox_dimension.width += extra.width;
02173 NWidgetLeaf::debugbox_dimension.height += extra.height;
02174 }
02175 size = maxdim(size, NWidgetLeaf::debugbox_dimension);
02176 } else {
02177
02178 size.width = 0;
02179 fill.width = 0;
02180 resize.width = 0;
02181 }
02182 break;
02183
02184 case WWT_STICKYBOX: {
02185 static const Dimension extra = {WD_STICKYBOX_LEFT + WD_STICKYBOX_RIGHT, WD_STICKYBOX_TOP + WD_STICKYBOX_BOTTOM};
02186 padding = &extra;
02187 if (NWidgetLeaf::stickybox_dimension.width == 0) {
02188 NWidgetLeaf::stickybox_dimension = maxdim(GetSpriteSize(SPR_PIN_UP), GetSpriteSize(SPR_PIN_DOWN));
02189 NWidgetLeaf::stickybox_dimension.width += extra.width;
02190 NWidgetLeaf::stickybox_dimension.height += extra.height;
02191 }
02192 size = maxdim(size, NWidgetLeaf::stickybox_dimension);
02193 break;
02194 }
02195 case WWT_RESIZEBOX: {
02196 static const Dimension extra = {WD_RESIZEBOX_LEFT + WD_RESIZEBOX_RIGHT, WD_RESIZEBOX_TOP + WD_RESIZEBOX_BOTTOM};
02197 padding = &extra;
02198 if (NWidgetLeaf::resizebox_dimension.width == 0) {
02199 NWidgetLeaf::resizebox_dimension = maxdim(GetSpriteSize(SPR_WINDOW_RESIZE_LEFT), GetSpriteSize(SPR_WINDOW_RESIZE_RIGHT));
02200 NWidgetLeaf::resizebox_dimension.width += extra.width;
02201 NWidgetLeaf::resizebox_dimension.height += extra.height;
02202 }
02203 size = maxdim(size, NWidgetLeaf::resizebox_dimension);
02204 break;
02205 }
02206 case WWT_EDITBOX:
02207 size.height = max(size.height, GetStringBoundingBox("_").height + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM);
02208
02209 case WWT_PUSHBTN: {
02210 static const Dimension extra = {WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM};
02211 padding = &extra;
02212 break;
02213 }
02214 case WWT_IMGBTN:
02215 case WWT_IMGBTN_2:
02216 case WWT_PUSHIMGBTN: {
02217 static const Dimension extra = {WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT, WD_IMGBTN_TOP + WD_IMGBTN_BOTTOM};
02218 padding = &extra;
02219 Dimension d2 = GetSpriteSize(this->widget_data);
02220 if (this->type == WWT_IMGBTN_2) d2 = maxdim(d2, GetSpriteSize(this->widget_data + 1));
02221 d2.width += extra.width;
02222 d2.height += extra.height;
02223 size = maxdim(size, d2);
02224 break;
02225 }
02226 case WWT_ARROWBTN:
02227 case WWT_PUSHARROWBTN: {
02228 static const Dimension extra = {WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT, WD_IMGBTN_TOP + WD_IMGBTN_BOTTOM};
02229 padding = &extra;
02230 Dimension d2 = maxdim(GetSpriteSize(SPR_ARROW_LEFT), GetSpriteSize(SPR_ARROW_RIGHT));
02231 d2.width += extra.width;
02232 d2.height += extra.height;
02233 size = maxdim(size, d2);
02234 break;
02235 }
02236
02237 case WWT_CLOSEBOX: {
02238 static const Dimension extra = {WD_CLOSEBOX_LEFT + WD_CLOSEBOX_RIGHT, WD_CLOSEBOX_TOP + WD_CLOSEBOX_BOTTOM};
02239 padding = &extra;
02240 if (NWidgetLeaf::closebox_dimension.width == 0) {
02241 NWidgetLeaf::closebox_dimension = maxdim(GetStringBoundingBox(STR_BLACK_CROSS), GetStringBoundingBox(STR_SILVER_CROSS));
02242 NWidgetLeaf::closebox_dimension.width += extra.width;
02243 NWidgetLeaf::closebox_dimension.height += extra.height;
02244 }
02245 size = maxdim(size, NWidgetLeaf::closebox_dimension);
02246 break;
02247 }
02248 case WWT_TEXTBTN:
02249 case WWT_PUSHTXTBTN:
02250 case WWT_TEXTBTN_2: {
02251 static const Dimension extra = {WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM};
02252 padding = &extra;
02253 if (this->index >= 0) w->SetStringParameters(this->index);
02254 Dimension d2 = GetStringBoundingBox(this->widget_data);
02255 d2.width += extra.width;
02256 d2.height += extra.height;
02257 size = maxdim(size, d2);
02258 break;
02259 }
02260 case WWT_LABEL:
02261 case WWT_TEXT: {
02262 static const Dimension extra = {0, 0};
02263 padding = &extra;
02264 if (this->index >= 0) w->SetStringParameters(this->index);
02265 size = maxdim(size, GetStringBoundingBox(this->widget_data));
02266 break;
02267 }
02268 case WWT_CAPTION: {
02269 static const Dimension extra = {WD_CAPTIONTEXT_LEFT + WD_CAPTIONTEXT_RIGHT, WD_CAPTIONTEXT_TOP + WD_CAPTIONTEXT_BOTTOM};
02270 padding = &extra;
02271 if (this->index >= 0) w->SetStringParameters(this->index);
02272 Dimension d2 = GetStringBoundingBox(this->widget_data);
02273 d2.width += extra.width;
02274 d2.height += extra.height;
02275 size = maxdim(size, d2);
02276 break;
02277 }
02278 case WWT_DROPDOWN:
02279 case NWID_BUTTON_DROPDOWN:
02280 case NWID_PUSHBUTTON_DROPDOWN: {
02281 static const Dimension extra = {WD_DROPDOWNTEXT_LEFT + WD_DROPDOWNTEXT_RIGHT, WD_DROPDOWNTEXT_TOP + WD_DROPDOWNTEXT_BOTTOM};
02282 padding = &extra;
02283 if (this->index >= 0) w->SetStringParameters(this->index);
02284 Dimension d2 = GetStringBoundingBox(this->widget_data);
02285 d2.width += extra.width;
02286 d2.height += extra.height;
02287 size = maxdim(size, d2);
02288 break;
02289 }
02290 default:
02291 NOT_REACHED();
02292 }
02293
02294 if (this->index >= 0) w->UpdateWidgetSize(this->index, &size, *padding, &fill, &resize);
02295
02296 this->smallest_x = size.width;
02297 this->smallest_y = size.height;
02298 this->fill_x = fill.width;
02299 this->fill_y = fill.height;
02300 this->resize_x = resize.width;
02301 this->resize_y = resize.height;
02302 }
02303
02304 void NWidgetLeaf::Draw(const Window *w)
02305 {
02306 if (this->current_x == 0 || this->current_y == 0) return;
02307
02308 Rect r;
02309 r.left = this->pos_x;
02310 r.right = this->pos_x + this->current_x - 1;
02311 r.top = this->pos_y;
02312 r.bottom = this->pos_y + this->current_y - 1;
02313
02314 const DrawPixelInfo *dpi = _cur_dpi;
02315 if (dpi->left > r.right || dpi->left + dpi->width <= r.left || dpi->top > r.bottom || dpi->top + dpi->height <= r.top) return;
02316
02317 bool clicked = this->IsLowered();
02318 switch (this->type) {
02319 case WWT_EMPTY:
02320 break;
02321
02322 case WWT_PUSHBTN:
02323 assert(this->widget_data == 0);
02324 DrawFrameRect(r.left, r.top, r.right, r.bottom, this->colour, (clicked) ? FR_LOWERED : FR_NONE);
02325 break;
02326
02327 case WWT_IMGBTN:
02328 case WWT_PUSHIMGBTN:
02329 case WWT_IMGBTN_2:
02330 DrawImageButtons(r, this->type, this->colour, clicked, this->widget_data);
02331 break;
02332
02333 case WWT_TEXTBTN:
02334 case WWT_PUSHTXTBTN:
02335 case WWT_TEXTBTN_2:
02336 if (this->index >= 0) w->SetStringParameters(this->index);
02337 DrawFrameRect(r.left, r.top, r.right, r.bottom, this->colour, (clicked) ? FR_LOWERED : FR_NONE);
02338 DrawLabel(r, this->type, clicked, this->widget_data);
02339 break;
02340
02341 case WWT_ARROWBTN:
02342 case WWT_PUSHARROWBTN: {
02343 SpriteID sprite;
02344 switch (this->widget_data) {
02345 case AWV_DECREASE: sprite = _current_text_dir != TD_RTL ? SPR_ARROW_LEFT : SPR_ARROW_RIGHT; break;
02346 case AWV_INCREASE: sprite = _current_text_dir == TD_RTL ? SPR_ARROW_LEFT : SPR_ARROW_RIGHT; break;
02347 case AWV_LEFT: sprite = SPR_ARROW_LEFT; break;
02348 case AWV_RIGHT: sprite = SPR_ARROW_RIGHT; break;
02349 default: NOT_REACHED();
02350 }
02351 DrawImageButtons(r, WWT_PUSHIMGBTN, this->colour, clicked, sprite);
02352 }
02353
02354 case WWT_LABEL:
02355 if (this->index >= 0) w->SetStringParameters(this->index);
02356 DrawLabel(r, this->type, clicked, this->widget_data);
02357 break;
02358
02359 case WWT_TEXT:
02360 if (this->index >= 0) w->SetStringParameters(this->index);
02361 DrawText(r, (TextColour)this->colour, this->widget_data);
02362 break;
02363
02364 case WWT_MATRIX:
02365 DrawMatrix(r, this->colour, clicked, this->widget_data);
02366 break;
02367
02368 case WWT_EDITBOX: {
02369 const QueryString *query = w->GetQueryString(this->index);
02370 if (query != NULL) query->DrawEditBox(w, this->index);
02371 break;
02372 }
02373
02374 case WWT_CAPTION:
02375 if (this->index >= 0) w->SetStringParameters(this->index);
02376 DrawCaption(r, this->colour, w->owner, this->widget_data);
02377 break;
02378
02379 case WWT_SHADEBOX:
02380 assert(this->widget_data == 0);
02381 DrawShadeBox(r, this->colour, w->IsShaded());
02382 break;
02383
02384 case WWT_DEBUGBOX:
02385 DrawDebugBox(r, this->colour, clicked);
02386 break;
02387
02388 case WWT_STICKYBOX:
02389 assert(this->widget_data == 0);
02390 DrawStickyBox(r, this->colour, !!(w->flags & WF_STICKY));
02391 break;
02392
02393 case WWT_RESIZEBOX:
02394 assert(this->widget_data == 0);
02395 DrawResizeBox(r, this->colour, this->pos_x < (uint)(w->width / 2), !!(w->flags & WF_SIZING));
02396 break;
02397
02398 case WWT_CLOSEBOX:
02399 DrawCloseBox(r, this->colour, this->widget_data);
02400 break;
02401
02402 case WWT_DROPDOWN:
02403 if (this->index >= 0) w->SetStringParameters(this->index);
02404 DrawDropdown(r, this->colour, clicked, this->widget_data);
02405 break;
02406
02407 case NWID_BUTTON_DROPDOWN:
02408 case NWID_PUSHBUTTON_DROPDOWN:
02409 if (this->index >= 0) w->SetStringParameters(this->index);
02410 DrawButtonDropdown(r, this->colour, clicked, (this->disp_flags & ND_DROPDOWN_ACTIVE) != 0, this->widget_data);
02411 break;
02412
02413 default:
02414 NOT_REACHED();
02415 }
02416 if (this->index >= 0) w->DrawWidget(r, this->index);
02417
02418 if (this->IsDisabled()) {
02419 GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, _colour_gradient[this->colour & 0xF][2], FILLRECT_CHECKER);
02420 }
02421 }
02422
02430 bool NWidgetLeaf::ButtonHit(const Point &pt)
02431 {
02432 if (_current_text_dir == TD_LTR) {
02433 int button_width = this->pos_x + this->current_x - 12;
02434 return pt.x < button_width;
02435 } else {
02436 int button_left = this->pos_x + 12;
02437 return pt.x >= button_left;
02438 }
02439 }
02440
02441
02442
02458 static int MakeNWidget(const NWidgetPart *parts, int count, NWidgetBase **dest, bool *fill_dest, int *biggest_index)
02459 {
02460 int num_used = 0;
02461
02462 *dest = NULL;
02463 *fill_dest = false;
02464
02465 while (count > num_used) {
02466 switch (parts->type) {
02467 case NWID_SPACER:
02468 if (*dest != NULL) return num_used;
02469 *dest = new NWidgetSpacer(0, 0);
02470 break;
02471
02472 case NWID_HORIZONTAL:
02473 if (*dest != NULL) return num_used;
02474 *dest = new NWidgetHorizontal(parts->u.cont_flags);
02475 *fill_dest = true;
02476 break;
02477
02478 case NWID_HORIZONTAL_LTR:
02479 if (*dest != NULL) return num_used;
02480 *dest = new NWidgetHorizontalLTR(parts->u.cont_flags);
02481 *fill_dest = true;
02482 break;
02483
02484 case WWT_PANEL:
02485 case WWT_INSET:
02486 case WWT_FRAME:
02487 if (*dest != NULL) return num_used;
02488 *dest = new NWidgetBackground(parts->type, parts->u.widget.colour, parts->u.widget.index);
02489 *biggest_index = max(*biggest_index, (int)parts->u.widget.index);
02490 *fill_dest = true;
02491 break;
02492
02493 case NWID_VERTICAL:
02494 if (*dest != NULL) return num_used;
02495 *dest = new NWidgetVertical(parts->u.cont_flags);
02496 *fill_dest = true;
02497 break;
02498
02499 case NWID_MATRIX: {
02500 if (*dest != NULL) return num_used;
02501 NWidgetMatrix *nwm = new NWidgetMatrix();
02502 *dest = nwm;
02503 *fill_dest = true;
02504 nwm->SetIndex(parts->u.widget.index);
02505 nwm->SetColour(parts->u.widget.colour);
02506 *biggest_index = max(*biggest_index, (int)parts->u.widget.index);
02507 break;
02508 }
02509
02510 case WPT_FUNCTION: {
02511 if (*dest != NULL) return num_used;
02512
02513 int biggest = -1;
02514 *dest = parts->u.func_ptr(&biggest);
02515 *biggest_index = max(*biggest_index, biggest);
02516 *fill_dest = false;
02517 break;
02518 }
02519
02520 case WPT_RESIZE: {
02521 NWidgetResizeBase *nwrb = dynamic_cast<NWidgetResizeBase *>(*dest);
02522 if (nwrb != NULL) {
02523 assert(parts->u.xy.x >= 0 && parts->u.xy.y >= 0);
02524 nwrb->SetResize(parts->u.xy.x, parts->u.xy.y);
02525 }
02526 break;
02527 }
02528
02529 case WPT_MINSIZE: {
02530 NWidgetResizeBase *nwrb = dynamic_cast<NWidgetResizeBase *>(*dest);
02531 if (nwrb != NULL) {
02532 assert(parts->u.xy.x >= 0 && parts->u.xy.y >= 0);
02533 nwrb->SetMinimalSize(parts->u.xy.x, parts->u.xy.y);
02534 }
02535 break;
02536 }
02537
02538 case WPT_MINTEXTLINES: {
02539 NWidgetResizeBase *nwrb = dynamic_cast<NWidgetResizeBase *>(*dest);
02540 if (nwrb != NULL) {
02541 assert(parts->u.text_lines.size >= FS_BEGIN && parts->u.text_lines.size < FS_END);
02542 nwrb->SetMinimalTextLines(parts->u.text_lines.lines, parts->u.text_lines.spacing, parts->u.text_lines.size);
02543 }
02544 break;
02545 }
02546
02547 case WPT_FILL: {
02548 NWidgetResizeBase *nwrb = dynamic_cast<NWidgetResizeBase *>(*dest);
02549 if (nwrb != NULL) nwrb->SetFill(parts->u.xy.x, parts->u.xy.y);
02550 break;
02551 }
02552
02553 case WPT_DATATIP: {
02554 NWidgetCore *nwc = dynamic_cast<NWidgetCore *>(*dest);
02555 if (nwc != NULL) {
02556 nwc->widget_data = parts->u.data_tip.data;
02557 nwc->tool_tip = parts->u.data_tip.tooltip;
02558 }
02559 break;
02560 }
02561
02562 case WPT_PADDING:
02563 if (*dest != NULL) (*dest)->SetPadding(parts->u.padding.top, parts->u.padding.right, parts->u.padding.bottom, parts->u.padding.left);
02564 break;
02565
02566 case WPT_PIPSPACE: {
02567 NWidgetPIPContainer *nwc = dynamic_cast<NWidgetPIPContainer *>(*dest);
02568 if (nwc != NULL) nwc->SetPIP(parts->u.pip.pre, parts->u.pip.inter, parts->u.pip.post);
02569
02570 NWidgetBackground *nwb = dynamic_cast<NWidgetBackground *>(*dest);
02571 if (nwb != NULL) nwb->SetPIP(parts->u.pip.pre, parts->u.pip.inter, parts->u.pip.post);
02572 break;
02573 }
02574
02575 case WPT_SCROLLBAR: {
02576 NWidgetCore *nwc = dynamic_cast<NWidgetCore *>(*dest);
02577 if (nwc != NULL) {
02578 nwc->scrollbar_index = parts->u.widget.index;
02579 }
02580 break;
02581 }
02582
02583 case WPT_ENDCONTAINER:
02584 return num_used;
02585
02586 case NWID_VIEWPORT:
02587 if (*dest != NULL) return num_used;
02588 *dest = new NWidgetViewport(parts->u.widget.index);
02589 *biggest_index = max(*biggest_index, (int)parts->u.widget.index);
02590 break;
02591
02592 case NWID_HSCROLLBAR:
02593 case NWID_VSCROLLBAR:
02594 if (*dest != NULL) return num_used;
02595 *dest = new NWidgetScrollbar(parts->type, parts->u.widget.colour, parts->u.widget.index);
02596 *biggest_index = max(*biggest_index, (int)parts->u.widget.index);
02597 break;
02598
02599 case NWID_SELECTION: {
02600 if (*dest != NULL) return num_used;
02601 NWidgetStacked *nws = new NWidgetStacked();
02602 *dest = nws;
02603 *fill_dest = true;
02604 nws->SetIndex(parts->u.widget.index);
02605 *biggest_index = max(*biggest_index, (int)parts->u.widget.index);
02606 break;
02607 }
02608
02609 default:
02610 if (*dest != NULL) return num_used;
02611 assert((parts->type & WWT_MASK) < WWT_LAST || (parts->type & WWT_MASK) == NWID_BUTTON_DROPDOWN);
02612 *dest = new NWidgetLeaf(parts->type, parts->u.widget.colour, parts->u.widget.index, 0x0, STR_NULL);
02613 *biggest_index = max(*biggest_index, (int)parts->u.widget.index);
02614 break;
02615 }
02616 num_used++;
02617 parts++;
02618 }
02619
02620 return num_used;
02621 }
02622
02632 static int MakeWidgetTree(const NWidgetPart *parts, int count, NWidgetBase **parent, int *biggest_index)
02633 {
02634
02635
02636 NWidgetContainer *nwid_cont = dynamic_cast<NWidgetContainer *>(*parent);
02637 NWidgetBackground *nwid_parent = dynamic_cast<NWidgetBackground *>(*parent);
02638 assert(*parent == NULL || (nwid_cont != NULL && nwid_parent == NULL) || (nwid_cont == NULL && nwid_parent != NULL));
02639
02640 int total_used = 0;
02641 for (;;) {
02642 NWidgetBase *sub_widget = NULL;
02643 bool fill_sub = false;
02644 int num_used = MakeNWidget(parts, count - total_used, &sub_widget, &fill_sub, biggest_index);
02645 parts += num_used;
02646 total_used += num_used;
02647
02648
02649 if (sub_widget == NULL) break;
02650
02651
02652 WidgetType tp = sub_widget->type;
02653 if (fill_sub && (tp == NWID_HORIZONTAL || tp == NWID_HORIZONTAL_LTR || tp == NWID_VERTICAL || tp == NWID_MATRIX
02654 || tp == WWT_PANEL || tp == WWT_FRAME || tp == WWT_INSET || tp == NWID_SELECTION)) {
02655 NWidgetBase *sub_ptr = sub_widget;
02656 int num_used = MakeWidgetTree(parts, count - total_used, &sub_ptr, biggest_index);
02657 parts += num_used;
02658 total_used += num_used;
02659 }
02660
02661
02662 if (nwid_cont != NULL) nwid_cont->Add(sub_widget);
02663 if (nwid_parent != NULL) nwid_parent->Add(sub_widget);
02664 if (nwid_cont == NULL && nwid_parent == NULL) {
02665 *parent = sub_widget;
02666 return total_used;
02667 }
02668 }
02669
02670 if (count == total_used) return total_used;
02671
02672 assert(total_used < count);
02673 assert(parts->type == WPT_ENDCONTAINER);
02674 return total_used + 1;
02675 }
02676
02688 NWidgetContainer *MakeNWidgets(const NWidgetPart *parts, int count, int *biggest_index, NWidgetContainer *container)
02689 {
02690 *biggest_index = -1;
02691 if (container == NULL) container = new NWidgetVertical();
02692 NWidgetBase *cont_ptr = container;
02693 MakeWidgetTree(parts, count, &cont_ptr, biggest_index);
02694 return container;
02695 }
02696
02710 NWidgetContainer *MakeWindowNWidgetTree(const NWidgetPart *parts, int count, int *biggest_index, NWidgetStacked **shade_select)
02711 {
02712 *biggest_index = -1;
02713
02714
02715 NWidgetBase *nwid = NULL;
02716 int num_used = MakeWidgetTree(parts, count, &nwid, biggest_index);
02717 assert(nwid != NULL);
02718 parts += num_used;
02719 count -= num_used;
02720
02721 NWidgetContainer *root = new NWidgetVertical;
02722 root->Add(nwid);
02723 if (count == 0) {
02724 *shade_select = NULL;
02725 return root;
02726 }
02727
02728
02729
02730 NWidgetHorizontal *hor_cont = dynamic_cast<NWidgetHorizontal *>(nwid);
02731 NWidgetContainer *body;
02732 if (hor_cont != NULL && hor_cont->GetWidgetOfType(WWT_CAPTION) != NULL && hor_cont->GetWidgetOfType(WWT_SHADEBOX) != NULL) {
02733 *shade_select = new NWidgetStacked;
02734 root->Add(*shade_select);
02735 body = new NWidgetVertical;
02736 (*shade_select)->Add(body);
02737 } else {
02738 *shade_select = NULL;
02739 body = root;
02740 }
02741
02742
02743 int biggest2 = -1;
02744 MakeNWidgets(parts, count, &biggest2, body);
02745
02746 *biggest_index = max(*biggest_index, biggest2);
02747 return root;
02748 }
02749
02760 NWidgetBase *MakeCompanyButtonRows(int *biggest_index, int widget_first, int widget_last, int max_length, StringID button_tooltip)
02761 {
02762 NWidgetVertical *vert = NULL;
02763 NWidgetHorizontal *hor = NULL;
02764 int hor_length = 0;
02765
02766 Dimension sprite_size = GetSpriteSize(SPR_COMPANY_ICON);
02767 sprite_size.width += WD_MATRIX_LEFT + WD_MATRIX_RIGHT;
02768 sprite_size.height += WD_MATRIX_TOP + WD_MATRIX_BOTTOM + 1;
02769
02770 for (int widnum = widget_first; widnum <= widget_last; widnum++) {
02771
02772 if (hor_length == max_length) {
02773 if (vert == NULL) vert = new NWidgetVertical();
02774 vert->Add(hor);
02775 hor = NULL;
02776 hor_length = 0;
02777 }
02778 if (hor == NULL) {
02779 hor = new NWidgetHorizontal();
02780 hor_length = 0;
02781 }
02782
02783 NWidgetBackground *panel = new NWidgetBackground(WWT_PANEL, COLOUR_GREY, widnum);
02784 panel->SetMinimalSize(sprite_size.width, sprite_size.height);
02785 panel->SetFill(1, 0);
02786 panel->SetResize(1, 0);
02787 panel->SetDataTip(0x0, button_tooltip);
02788 hor->Add(panel);
02789 hor_length++;
02790 }
02791 *biggest_index = widget_last;
02792 if (vert == NULL) return hor;
02793
02794 if (hor_length > 0 && hor_length < max_length) {
02795
02796 NWidgetSpacer *spc = new NWidgetSpacer(sprite_size.width, sprite_size.height);
02797 spc->SetFill(1, 0);
02798 spc->SetResize(1, 0);
02799 hor->Add(spc);
02800 }
02801 if (hor != NULL) vert->Add(hor);
02802 return vert;
02803 }