diff --git a/src/widget.cpp b/src/widget.cpp index 9238f8174f..3375a3a2a5 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -199,318 +199,413 @@ void DrawFrameRect(int left, int top, int right, int bottom, Colours colour, Fra } } - /** - * Paint all widgets of a window. + * Draw an image button. + * @param r Rectangle of the button. + * @param type Widget type (#WWT_IMGBTN or #WWT_IMGBTN_2). + * @param colour Colour of the button. + * @param clicked Button is lowered. + * @param img Sprite to draw. */ -void Window::DrawWidgets() const +static inline void DrawImageButtons(const Rect &r, WidgetType type, Colours colour, bool clicked, SpriteID img) { - const DrawPixelInfo *dpi = _cur_dpi; + assert(img != 0); + DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, (clicked) ? FR_LOWERED : FR_NONE); - for (uint i = 0; i < this->widget_count; i++) { - const Widget *wi = &this->widget[i]; - bool clicked = this->IsWidgetLowered(i); - Rect r; + /* show different image when clicked for WWT_IMGBTN_2 */ + if ((type & WWT_MASK) == WWT_IMGBTN_2 && clicked) img++; + DrawSprite(img, PAL_NONE, r.left + 1 + clicked, r.top + 1 + clicked); +} - if (dpi->left > (r.right = wi->right) || - dpi->left + dpi->width <= (r.left = wi->left) || - dpi->top > (r.bottom = wi->bottom) || - dpi->top + dpi->height <= (r.top = wi->top) || - this->IsWidgetHidden(i)) { - continue; - } +/** + * Draw the label-part of a widget. + * @param r Rectangle of the label background. + * @param type Widget type (#WWT_TEXTBTN, #WWT_TEXTBTN_2, or #WWT_LABEL). + * @param clicked Label is rendered lowered. + * @param str Text to draw. + */ +static inline void DrawLabel(const Rect &r, WidgetType type, bool clicked, StringID str) +{ + if ((type & WWT_MASK) == WWT_TEXTBTN_2 && clicked) str++; + DrawString(r.left + clicked, r.right + clicked, ((r.top + r.bottom + 1) >> 1) - 5 + clicked, str, TC_FROMSTRING, SA_CENTER); +} - switch (wi->type & WWT_MASK) { - case WWT_IMGBTN: - case WWT_IMGBTN_2: { - SpriteID img = wi->data; - assert(img != 0); - DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->colour, (clicked) ? FR_LOWERED : FR_NONE); +/** + * Draw text. + * @param r Rectangle of the background. + * @param colour Colour of the text. + * @param str Text to draw. + */ +static inline void DrawText(const Rect &r, TextColour colour, StringID str) +{ + if (str != STR_NULL) DrawString(r.left, r.right, r.top, str, colour); +} - /* show different image when clicked for WWT_IMGBTN_2 */ - if ((wi->type & WWT_MASK) == WWT_IMGBTN_2 && clicked) img++; - DrawSprite(img, PAL_NONE, r.left + 1 + clicked, r.top + 1 + clicked); - break; - } +/** + * Draw an inset widget. + * @param r Rectangle of the background. + * @param colour Colour of the inset. + * @param str Text to draw. + */ +static inline void DrawInset(const Rect &r, Colours colour, StringID str) +{ + DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, FR_LOWERED | FR_DARKENED); + if (str != STR_NULL) DrawString(r.left + 2, r.right - 2, r.top + 1, str); +} - case WWT_PANEL: - assert(wi->data == 0); - DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->colour, (clicked) ? FR_LOWERED : FR_NONE); - break; +/** + * Draw a matrix widget. + * @param r Rectangle of the matrix background. + * @param colour Colour of the background. + * @param clicked Matrix is rendered lowered. + * @param data Data of the widget. + */ +static inline void DrawMatrix(const Rect &r, Colours colour, bool clicked, uint16 data) +{ + DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, (clicked) ? FR_LOWERED : FR_NONE); - case WWT_EDITBOX: - DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->colour, FR_LOWERED | FR_DARKENED); - break; + int c = GB(data, 0, 8); + int amt1 = (r.right - r.left + 1) / c; - case WWT_TEXTBTN: - case WWT_TEXTBTN_2: - DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->colour, (clicked) ? FR_LOWERED : FR_NONE); - /* FALL THROUGH */ + int d = GB(data, 8, 8); + int amt2 = (r.bottom - r.top + 1) / d; - case WWT_LABEL: { - StringID str = wi->data; + int col = _colour_gradient[colour & 0xF][6]; - if ((wi->type & WWT_MASK) == WWT_TEXTBTN_2 && clicked) str++; + int x = r.left; + for (int ctr = c; ctr > 1; ctr--) { + x += amt1; + GfxFillRect(x, r.top + 1, x, r.bottom - 1, col); + } - DrawString(r.left + clicked, r.right + clicked, ((r.top + r.bottom + 1) >> 1) - 5 + clicked, str, TC_FROMSTRING, SA_CENTER); - break; - } + x = r.top; + for (int ctr = d; ctr > 1; ctr--) { + x += amt2; + GfxFillRect(r.left + 1, x, r.right - 1, x, col); + } - case WWT_TEXT: { - const StringID str = wi->data; + col = _colour_gradient[colour & 0xF][4]; - if (str != STR_NULL) DrawString(r.left, r.right, r.top, str, (TextColour)wi->colour); - break; - } + x = r.left - 1; + for (int ctr = c; ctr > 1; ctr--) { + x += amt1; + GfxFillRect(x, r.top + 1, x, r.bottom - 1, col); + } - case WWT_INSET: { - const StringID str = wi->data; - DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->colour, FR_LOWERED | FR_DARKENED); + x = r.top - 1; + for (int ctr = d; ctr > 1; ctr--) { + x += amt2; + GfxFillRect(r.left + 1, x, r.right - 1, x, col); + } +} - if (str != STR_NULL) DrawString(r.left + 2, r.right - 2, r.top + 1, str); - break; - } +/** + * Draw a vertical scrollbar. + * @param r Rectangle of the scrollbar widget. + * @param colour Colour of the scrollbar widget. + * @param up_clicked Up-arrow is clicked. + * @param bar_dragged Bar is dragged. + * @param down_clicked Down-arrow is clicked. + * @param scrollbar Scrollbar size, offset, and capacity information. + */ +static inline void DrawVerticalScrollbar(const Rect &r, Colours colour, bool up_clicked, bool bar_dragged, bool down_clicked, const Scrollbar *scrollbar) +{ + assert(r.right - r.left == 11); // To ensure the same sizes are used everywhere! - case WWT_MATRIX: { - DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->colour, (clicked) ? FR_LOWERED : FR_NONE); + /* draw up/down buttons */ + DrawFrameRect(r.left, r.top, r.right, r.top + 9, colour, (up_clicked) ? FR_LOWERED : FR_NONE); + DrawString(r.left + up_clicked, r.right + up_clicked, r.top + up_clicked, UPARROW, TC_BLACK, SA_CENTER); - int c = GB(wi->data, 0, 8); - int amt1 = (wi->right - wi->left + 1) / c; + DrawFrameRect(r.left, r.bottom - 9, r.right, r.bottom, colour, (down_clicked) ? FR_LOWERED : FR_NONE); + DrawString(r.left + down_clicked, r.right + down_clicked, r.bottom - 9 + down_clicked, DOWNARROW, TC_BLACK, SA_CENTER); - int d = GB(wi->data, 8, 8); - int amt2 = (wi->bottom - wi->top + 1) / d; + int c1 = _colour_gradient[colour & 0xF][3]; + int c2 = _colour_gradient[colour & 0xF][7]; - int colour = _colour_gradient[wi->colour & 0xF][6]; + /* draw "shaded" background */ + GfxFillRect(r.left, r.top + 10, r.right, r.bottom - 10, c2); + GfxFillRect(r.left, r.top + 10, r.right, r.bottom - 10, c1, FILLRECT_CHECKER); - int x = r.left; - for (int ctr = c; ctr > 1; ctr--) { - x += amt1; - GfxFillRect(x, r.top + 1, x, r.bottom - 1, colour); - } + /* draw shaded lines */ + GfxFillRect(r.left + 2, r.top + 10, r.left + 2, r.bottom - 10, c1); + GfxFillRect(r.left + 3, r.top + 10, r.left + 3, r.bottom - 10, c2); + GfxFillRect(r.left + 7, r.top + 10, r.left + 7, r.bottom - 10, c1); + GfxFillRect(r.left + 8, r.top + 10, r.left + 8, r.bottom - 10, c2); - x = r.top; - for (int ctr = d; ctr > 1; ctr--) { - x += amt2; - GfxFillRect(r.left + 1, x, r.right - 1, x, colour); - } + Point pt = HandleScrollbarHittest(scrollbar, r.top, r.bottom); + DrawFrameRect(r.left, pt.x, r.right, pt.y, colour, bar_dragged ? FR_LOWERED : FR_NONE); +} - colour = _colour_gradient[wi->colour & 0xF][4]; +/** + * Draw a horizontal scrollbar. + * @param r Rectangle of the scrollbar widget. + * @param colour Colour of the scrollbar widget. + * @param left_clicked Left-arrow is clicked. + * @param bar_dragged Bar is dragged. + * @param right_clicked Right-arrow is clicked. + * @param scrollbar Scrollbar size, offset, and capacity information. + */ +static inline void DrawHorizontalScrollbar(const Rect &r, Colours colour, bool left_clicked, bool bar_dragged, bool right_clicked, const Scrollbar *scrollbar) +{ + assert(r.bottom - r.top == 11); // To ensure the same sizes are used everywhere! - x = r.left - 1; - for (int ctr = c; ctr > 1; ctr--) { - x += amt1; - GfxFillRect(x, r.top + 1, x, r.bottom - 1, colour); - } + DrawFrameRect(r.left, r.top, r.left + 9, r.bottom, colour, left_clicked ? FR_LOWERED : FR_NONE); + DrawSprite(SPR_ARROW_LEFT, PAL_NONE, r.left + 1 + left_clicked, r.top + 1 + left_clicked); - x = r.top - 1; - for (int ctr = d; ctr > 1; ctr--) { - x += amt2; - GfxFillRect(r.left + 1, x, r.right - 1, x, colour); - } + DrawFrameRect(r.right - 9, r.top, r.right, r.bottom, colour, right_clicked ? FR_LOWERED : FR_NONE); + DrawSprite(SPR_ARROW_RIGHT, PAL_NONE, r.right - 8 + right_clicked, r.top + 1 + right_clicked); - break; - } + int c1 = _colour_gradient[colour & 0xF][3]; + int c2 = _colour_gradient[colour & 0xF][7]; - /* vertical scrollbar */ - case WWT_SCROLLBAR: { - assert(wi->data == 0); - assert(r.right - r.left == 11); // To ensure the same sizes are used everywhere! + /* draw "shaded" background */ + GfxFillRect(r.left + 10, r.top, r.right - 10, r.bottom, c2); + GfxFillRect(r.left + 10, r.top, r.right - 10, r.bottom, c1, FILLRECT_CHECKER); - /* draw up/down buttons */ - clicked = ((this->flags4 & (WF_SCROLL_UP | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_UP); - DrawFrameRect(r.left, r.top, r.right, r.top + 9, wi->colour, (clicked) ? FR_LOWERED : FR_NONE); - DrawString(r.left + clicked, r.right + clicked, r.top + clicked, UPARROW, TC_BLACK, SA_CENTER); + /* draw shaded lines */ + GfxFillRect(r.left + 10, r.top + 2, r.right - 10, r.top + 2, c1); + GfxFillRect(r.left + 10, r.top + 3, r.right - 10, r.top + 3, c2); + GfxFillRect(r.left + 10, r.top + 7, r.right - 10, r.top + 7, c1); + GfxFillRect(r.left + 10, r.top + 8, r.right - 10, r.top + 8, c2); - clicked = (((this->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_DOWN)); - DrawFrameRect(r.left, r.bottom - 9, r.right, r.bottom, wi->colour, (clicked) ? FR_LOWERED : FR_NONE); - DrawString(r.left + clicked, r.right + clicked, r.bottom - 9 + clicked, DOWNARROW, TC_BLACK, SA_CENTER); + /* draw actual scrollbar */ + Point pt = HandleScrollbarHittest(scrollbar, r.left, r.right); + DrawFrameRect(pt.x, r.top, pt.y, r.bottom, colour, bar_dragged ? FR_LOWERED : FR_NONE); +} - int c1 = _colour_gradient[wi->colour & 0xF][3]; - int c2 = _colour_gradient[wi->colour & 0xF][7]; +/** + * Draw a frame widget. + * @param r Rectangle of the frame. + * @param colour Colour of the frame. + * @param str Text of the frame. + */ +static inline void DrawFrame(const Rect &r, Colours colour, StringID str) +{ + int x2 = r.left; // by default the left side is the left side of the widget - /* draw "shaded" background */ - GfxFillRect(r.left, r.top + 10, r.right, r.bottom - 10, c2); - GfxFillRect(r.left, r.top + 10, r.right, r.bottom - 10, c1, FILLRECT_CHECKER); + if (str != STR_NULL) x2 = DrawString(r.left + 6, r.right - 6, r.top, str); - /* draw shaded lines */ - GfxFillRect(r.left + 2, r.top + 10, r.left + 2, r.bottom - 10, c1); - GfxFillRect(r.left + 3, r.top + 10, r.left + 3, r.bottom - 10, c2); - GfxFillRect(r.left + 7, r.top + 10, r.left + 7, r.bottom - 10, c1); - GfxFillRect(r.left + 8, r.top + 10, r.left + 8, r.bottom - 10, c2); + int c1 = _colour_gradient[colour][3]; + int c2 = _colour_gradient[colour][7]; - Point pt = HandleScrollbarHittest(&this->vscroll, r.top, r.bottom); - DrawFrameRect(r.left, pt.x, r.right, pt.y, wi->colour, (this->flags4 & (WF_SCROLL_MIDDLE | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_MIDDLE ? FR_LOWERED : FR_NONE); - break; - } + if (_dynlang.text_dir == TD_LTR) { + /* Line from upper left corner to start of text */ + GfxFillRect(r.left, r.top + 4, r.left + 4, r.top + 4, c1); + GfxFillRect(r.left + 1, r.top + 5, r.left + 4, r.top + 5, c2); - case WWT_SCROLL2BAR: { - assert(wi->data == 0); - assert(r.right - r.left == 11); // To ensure the same sizes are used everywhere! + /* Line from end of text to upper right corner */ + GfxFillRect(x2, r.top + 4, r.right - 1, r.top + 4, c1); + GfxFillRect(x2, r.top + 5, r.right - 2, r.top + 5, c2); + } else { + /* Line from upper left corner to start of text */ + GfxFillRect(r.left, r.top + 4, x2 - 2, r.top + 4, c1); + GfxFillRect(r.left + 1, r.top + 5, x2 - 2, r.top + 5, c2); - /* draw up/down buttons */ - clicked = ((this->flags4 & (WF_SCROLL_UP | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_UP | WF_SCROLL2)); - DrawFrameRect(r.left, r.top, r.right, r.top + 9, wi->colour, (clicked) ? FR_LOWERED : FR_NONE); - DrawString(r.left + clicked, r.right + clicked, r.top + clicked, UPARROW, TC_BLACK, SA_CENTER); + /* Line from end of text to upper right corner */ + GfxFillRect(r.right - 5, r.top + 4, r.right - 1, r.top + 4, c1); + GfxFillRect(r.right - 5, r.top + 5, r.right - 2, r.top + 5, c2); + } - clicked = ((this->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_DOWN | WF_SCROLL2)); - DrawFrameRect(r.left, r.bottom - 9, r.right, r.bottom, wi->colour, (clicked) ? FR_LOWERED : FR_NONE); - DrawString(r.left + clicked, r.right + clicked, r.bottom - 9 + clicked, DOWNARROW, TC_BLACK, SA_CENTER); + /* Line from upper left corner to bottom left corner */ + GfxFillRect(r.left, r.top + 5, r.left, r.bottom - 1, c1); + GfxFillRect(r.left + 1, r.top + 6, r.left + 1, r.bottom - 2, c2); - int c1 = _colour_gradient[wi->colour & 0xF][3]; - int c2 = _colour_gradient[wi->colour & 0xF][7]; + /* Line from upper right corner to bottom right corner */ + GfxFillRect(r.right - 1, r.top + 5, r.right - 1, r.bottom - 2, c1); + GfxFillRect(r.right, r.top + 4, r.right, r.bottom - 1, c2); - /* draw "shaded" background */ - GfxFillRect(r.left, r.top + 10, r.right, r.bottom - 10, c2); - GfxFillRect(r.left, r.top + 10, r.right, r.bottom - 10, c1, FILLRECT_CHECKER); + GfxFillRect(r.left + 1, r.bottom - 1, r.right - 1, r.bottom - 1, c1); + GfxFillRect(r.left, r.bottom, r.right, r.bottom, c2); +} - /* draw shaded lines */ - GfxFillRect(r.left + 2, r.top + 10, r.left + 2, r.bottom - 10, c1); - GfxFillRect(r.left + 3, r.top + 10, r.left + 3, r.bottom - 10, c2); - GfxFillRect(r.left + 7, r.top + 10, r.left + 7, r.bottom - 10, c1); - GfxFillRect(r.left + 8, r.top + 10, r.left + 8, r.bottom - 10, c2); +/** + * Draw a sticky box. + * @param r Rectangle of the box. + * @param colour Colour of the sticky box. + * @param clicked Box is lowered. + */ +static inline void DrawStickyBox(const Rect &r, Colours colour, bool clicked) +{ + assert(r.right - r.left == 11); // To ensure the same sizes are used everywhere! + DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, (clicked) ? FR_LOWERED : FR_NONE); + DrawSprite((clicked) ? SPR_PIN_UP : SPR_PIN_DOWN, PAL_NONE, r.left + 2 + clicked, r.top + 3 + clicked); +} - Point pt = HandleScrollbarHittest(&this->vscroll2, r.top, r.bottom); - DrawFrameRect(r.left, pt.x, r.right, pt.y, wi->colour, (this->flags4 & (WF_SCROLL_MIDDLE | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_MIDDLE | WF_SCROLL2) ? FR_LOWERED : FR_NONE); - break; - } +/** + * Draw a resize box. + * @param r Rectangle of the box. + * @param colour Colour of the resize box. + * @param at_left Resize box is at left-side of the window, + * @param clicked Box is lowered. + */ +static inline void DrawResizeBox(const Rect &r, Colours colour, bool at_left, bool clicked) +{ + assert(r.right - r.left == 11); // To ensure the same sizes are used everywhere! + DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, (clicked) ? FR_LOWERED : FR_NONE); + if (at_left) { + DrawSprite(SPR_WINDOW_RESIZE_LEFT, PAL_NONE, r.left + 2, r.top + 3 + clicked); + } else { + DrawSprite(SPR_WINDOW_RESIZE_RIGHT, PAL_NONE, r.left + 3 + clicked, r.top + 3 + clicked); + } +} - /* horizontal scrollbar */ - case WWT_HSCROLLBAR: { - assert(wi->data == 0); - assert(r.bottom - r.top == 11); // To ensure the same sizes are used everywhere! +/** + * Draw a close box. + * @param r Rectangle of the box. + * @param colour Colour of the close box. + * @param str Cross to draw (#STR_BLACK_CROSS or #STR_SILVER_CROSS). + */ +static inline void DrawCloseBox(const Rect &r, Colours colour, StringID str) +{ + assert(str == STR_BLACK_CROSS || str == STR_SILVER_CROSS); // black or silver cross + assert(r.right - r.left == 10); // To ensure the same sizes are used everywhere - clicked = ((this->flags4 & (WF_SCROLL_UP | WF_HSCROLL)) == (WF_SCROLL_UP | WF_HSCROLL)); - DrawFrameRect(r.left, r.top, r.left + 9, r.bottom, wi->colour, (clicked) ? FR_LOWERED : FR_NONE); - DrawSprite(SPR_ARROW_LEFT, PAL_NONE, r.left + 1 + clicked, r.top + 1 + clicked); + DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, FR_NONE); + DrawString(r.left, r.right, r.top + 2, str, TC_FROMSTRING, SA_CENTER); +} - clicked = ((this->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL)) == (WF_SCROLL_DOWN | WF_HSCROLL)); - DrawFrameRect(r.right - 9, r.top, r.right, r.bottom, wi->colour, (clicked) ? FR_LOWERED : FR_NONE); - DrawSprite(SPR_ARROW_RIGHT, PAL_NONE, r.right - 8 + clicked, r.top + 1 + clicked); +/** + * Draw a caption bar. + * @param r Rectangle of the bar. + * @param colour Colour of the window. + * @param owner 'Owner' of the window. + * @param str Text to draw in the bar. + */ +static inline void DrawCaption(const Rect &r, Colours colour, Owner owner, StringID str) +{ + assert(r.bottom - r.top == 13); // To ensure the same sizes are used everywhere! + DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, FR_BORDERONLY); + 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); - int c1 = _colour_gradient[wi->colour & 0xF][3]; - int c2 = _colour_gradient[wi->colour & 0xF][7]; + if (owner != INVALID_OWNER) { + GfxFillRect(r.left + 2, r.top + 2, r.right - 2, r.bottom - 2, _colour_gradient[_company_colours[owner]][4]); + } - /* draw "shaded" background */ - GfxFillRect(r.left + 10, r.top, r.right - 10, r.bottom, c2); - GfxFillRect(r.left + 10, r.top, r.right - 10, r.bottom, c1, FILLRECT_CHECKER); + DrawString(r.left + 2, r.right - 2, r.top + 2, str, TC_FROMSTRING, SA_CENTER); +} - /* draw shaded lines */ - GfxFillRect(r.left + 10, r.top + 2, r.right - 10, r.top + 2, c1); - GfxFillRect(r.left + 10, r.top + 3, r.right - 10, r.top + 3, c2); - GfxFillRect(r.left + 10, r.top + 7, r.right - 10, r.top + 7, c1); - GfxFillRect(r.left + 10, r.top + 8, r.right - 10, r.top + 8, c2); +static inline void DrawDropdown(const Rect &r, Colours colour, bool clicked, StringID str) +{ + assert(r.bottom - r.top == 11); // ensure consistent size - /* draw actual scrollbar */ - Point pt = HandleScrollbarHittest(&this->hscroll, r.left, r.right); - DrawFrameRect(pt.x, r.top, pt.y, r.bottom, wi->colour, (this->flags4 & (WF_SCROLL_MIDDLE | WF_HSCROLL)) == (WF_SCROLL_MIDDLE | WF_HSCROLL) ? FR_LOWERED : FR_NONE); + if (_dynlang.text_dir == TD_LTR) { + DrawFrameRect(r.left, r.top, r.right - 12, r.bottom, colour, FR_NONE); + DrawFrameRect(r.right - 11, r.top, r.right, r.bottom, colour, clicked ? FR_LOWERED : FR_NONE); + DrawString(r.right - (clicked ? 10 : 11), r.right, r.top + (clicked ? 2 : 1), STR_ARROW_DOWN, TC_BLACK, SA_CENTER); + if (str != STR_NULL) DrawString(r.left + 2, r.right - 14, r.top + 1, str, TC_BLACK); + } else { + DrawFrameRect(r.left + 12, r.top, r.right, r.bottom, colour, FR_NONE); + DrawFrameRect(r.left, r.top, r.left + 11, r.bottom, colour, clicked ? FR_LOWERED : FR_NONE); + DrawString(r.left + clicked, r.left + 11, r.top + (clicked ? 2 : 1), STR_ARROW_DOWN, TC_BLACK, SA_CENTER); + if (str != STR_NULL) DrawString(r.left + 14, r.right - 2, r.top + 1, str, TC_BLACK); + } +} - break; - } +/** + * Paint all widgets of a window. + */ +void Window::DrawWidgets() const +{ + const DrawPixelInfo *dpi = _cur_dpi; - case WWT_FRAME: { - const StringID str = wi->data; - int x2 = r.left; // by default the left side is the left side of the widget + for (uint i = 0; i < this->widget_count; i++) { + const Widget *wi = &this->widget[i]; + bool clicked = this->IsWidgetLowered(i); + Rect r; - if (str != STR_NULL) x2 = DrawString(r.left + 6, r.right - 6, r.top, str); + if (dpi->left > (r.right = wi->right) || + dpi->left + dpi->width <= (r.left = wi->left) || + dpi->top > (r.bottom = wi->bottom) || + dpi->top + dpi->height <= (r.top = wi->top) || + this->IsWidgetHidden(i)) { + continue; + } - int c1 = _colour_gradient[wi->colour][3]; - int c2 = _colour_gradient[wi->colour][7]; + switch (wi->type & WWT_MASK) { + case WWT_IMGBTN: + case WWT_IMGBTN_2: + DrawImageButtons(r, wi->type,wi->colour, clicked, wi->data); + break; - if (_dynlang.text_dir == TD_LTR) { - /* Line from upper left corner to start of text */ - GfxFillRect(r.left, r.top + 4, r.left + 4, r.top + 4, c1); - GfxFillRect(r.left + 1, r.top + 5, r.left + 4, r.top + 5, c2); + case WWT_PANEL: + assert(wi->data == 0); + DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->colour, (clicked) ? FR_LOWERED : FR_NONE); + break; - /* Line from end of text to upper right corner */ - GfxFillRect(x2, r.top + 4, r.right - 1, r.top + 4, c1); - GfxFillRect(x2, r.top + 5, r.right - 2, r.top + 5, c2); - } else { - /* Line from upper left corner to start of text */ - GfxFillRect(r.left, r.top + 4, x2 - 2, r.top + 4, c1); - GfxFillRect(r.left + 1, r.top + 5, x2 - 2, r.top + 5, c2); + case WWT_EDITBOX: + DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->colour, FR_LOWERED | FR_DARKENED); + break; - /* Line from end of text to upper right corner */ - GfxFillRect(r.right - 5, r.top + 4, r.right - 1, r.top + 4, c1); - GfxFillRect(r.right - 5, r.top + 5, r.right - 2, r.top + 5, c2); - } + case WWT_TEXTBTN: + case WWT_TEXTBTN_2: + DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->colour, (clicked) ? FR_LOWERED : FR_NONE); + /* FALL THROUGH */ - /* Line from upper left corner to bottom left corner */ - GfxFillRect(r.left, r.top + 5, r.left, r.bottom - 1, c1); - GfxFillRect(r.left + 1, r.top + 6, r.left + 1, r.bottom - 2, c2); + case WWT_LABEL: + DrawLabel(r, wi->type, clicked, wi->data); + break; - /* Line from upper right corner to bottom right corner */ - GfxFillRect(r.right - 1, r.top + 5, r.right - 1, r.bottom - 2, c1); - GfxFillRect(r.right, r.top + 4, r.right, r.bottom - 1, c2); + case WWT_TEXT: + DrawText(r, (TextColour)wi->colour, wi->data); + break; - GfxFillRect(r.left + 1, r.bottom - 1, r.right - 1, r.bottom - 1, c1); - GfxFillRect(r.left, r.bottom, r.right, r.bottom, c2); + case WWT_INSET: + DrawInset(r, wi->colour, wi->data); + break; + case WWT_MATRIX: + DrawMatrix(r, wi->colour, clicked, wi->data); break; - } - case WWT_STICKYBOX: + /* vertical scrollbar */ + case WWT_SCROLLBAR: assert(wi->data == 0); - assert(r.right - r.left == 11); // To ensure the same sizes are used everywhere! + DrawVerticalScrollbar(r, wi->colour, (this->flags4 & (WF_SCROLL_UP | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_UP, + (this->flags4 & (WF_SCROLL_MIDDLE | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_MIDDLE, + (this->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_DOWN, &this->vscroll); + break; - clicked = !!(this->flags4 & WF_STICKY); - DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->colour, (clicked) ? FR_LOWERED : FR_NONE); - DrawSprite((clicked) ? SPR_PIN_UP : SPR_PIN_DOWN, PAL_NONE, r.left + 2 + clicked, r.top + 3 + clicked); + case WWT_SCROLL2BAR: + assert(wi->data == 0); + DrawVerticalScrollbar(r, wi->colour, (this->flags4 & (WF_SCROLL_UP | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_UP | WF_SCROLL2), + (this->flags4 & (WF_SCROLL_MIDDLE | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_MIDDLE | WF_SCROLL2), + (this->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_DOWN | WF_SCROLL2), &this->vscroll2); break; - case WWT_RESIZEBOX: + /* horizontal scrollbar */ + case WWT_HSCROLLBAR: assert(wi->data == 0); - assert(r.right - r.left == 11); // To ensure the same sizes are used everywhere! + DrawHorizontalScrollbar(r, wi->colour, (this->flags4 & (WF_SCROLL_UP | WF_HSCROLL)) == (WF_SCROLL_UP | WF_HSCROLL), + (this->flags4 & (WF_SCROLL_MIDDLE | WF_HSCROLL)) == (WF_SCROLL_MIDDLE | WF_HSCROLL), + (this->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL)) == (WF_SCROLL_DOWN | WF_HSCROLL), &this->hscroll); + break; - clicked = !!(this->flags4 & WF_SIZING); - DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->colour, (clicked) ? FR_LOWERED : FR_NONE); - if (wi->left < (this->width / 2)) { - DrawSprite(SPR_WINDOW_RESIZE_LEFT, PAL_NONE, r.left + 2, r.top + 3 + clicked); - } else { - DrawSprite(SPR_WINDOW_RESIZE_RIGHT, PAL_NONE, r.left + 3 + clicked, r.top + 3 + clicked); - } + case WWT_FRAME: + DrawFrame(r, wi->colour, wi->data); break; - case WWT_CLOSEBOX: { - const StringID str = wi->data; + case WWT_STICKYBOX: + assert(wi->data == 0); + DrawStickyBox(r, wi->colour, !!(this->flags4 & WF_STICKY)); + break; - assert(str == STR_BLACK_CROSS || str == STR_SILVER_CROSS); // black or silver cross - assert(r.right - r.left == 10); // To ensure the same sizes are used everywhere + case WWT_RESIZEBOX: + assert(wi->data == 0); + DrawResizeBox(r, wi->colour, wi->left < (this->width / 2), !!(this->flags4 & WF_SIZING)); + break; - DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->colour, FR_NONE); - DrawString(r.left, r.right, r.top + 2, str, TC_FROMSTRING, SA_CENTER); + case WWT_CLOSEBOX: + DrawCloseBox(r, wi->colour, wi->data); break; - } case WWT_CAPTION: - assert(r.bottom - r.top == 13); // To ensure the same sizes are used everywhere! - DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->colour, FR_BORDERONLY); - DrawFrameRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, wi->colour, (this->owner == INVALID_OWNER) ? FR_LOWERED | FR_DARKENED : FR_LOWERED | FR_DARKENED | FR_BORDERONLY); - - if (this->owner != INVALID_OWNER) { - GfxFillRect(r.left + 2, r.top + 2, r.right - 2, r.bottom - 2, _colour_gradient[_company_colours[this->owner]][4]); - } - - DrawString(r.left + 2, r.right - 2, r.top + 2, wi->data, TC_FROMSTRING, SA_CENTER); + DrawCaption(r, wi->colour, this->owner, wi->data); break; - case WWT_DROPDOWN: { - assert(r.bottom - r.top == 11); // ensure consistent size - - StringID str = wi->data; - if (_dynlang.text_dir == TD_LTR) { - DrawFrameRect(r.left, r.top, r.right - 12, r.bottom, wi->colour, FR_NONE); - DrawFrameRect(r.right - 11, r.top, r.right, r.bottom, wi->colour, clicked ? FR_LOWERED : FR_NONE); - DrawString(r.right - (clicked ? 10 : 11), r.right, r.top + (clicked ? 2 : 1), STR_ARROW_DOWN, TC_BLACK, SA_CENTER); - if (str != STR_NULL) DrawString(r.left + 2, r.right - 14, r.top + 1, str, TC_BLACK); - } else { - DrawFrameRect(r.left + 12, r.top, r.right, r.bottom, wi->colour, FR_NONE); - DrawFrameRect(r.left, r.top, r.left + 11, r.bottom, wi->colour, clicked ? FR_LOWERED : FR_NONE); - DrawString(r.left + clicked, r.left + 11, r.top + (clicked ? 2 : 1), STR_ARROW_DOWN, TC_BLACK, SA_CENTER); - if (str != STR_NULL) DrawString(r.left + 14, r.right - 2, r.top + 1, str, TC_BLACK); - } + case WWT_DROPDOWN: + DrawDropdown(r, wi->colour, clicked, wi->data); break; } - } if (this->IsWidgetDisabled(i)) { GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, _colour_gradient[wi->colour & 0xF][2], FILLRECT_CHECKER);