tron@2186: /* $Id$ */ tron@2186: rubidium@9111: /** @file widget.cpp Handling of the default/simple widgets. */ belugas@6432: truelight@0: #include "stdafx.h" Darkvater@1891: #include "openttd.h" rubidium@8254: #include "core/math_func.hpp" rubidium@8254: #include "player_func.h" rubidium@8224: #include "gfx_func.h" rubidium@8106: #include "window_gui.h" rubidium@8131: #include "window_func.h" peter1138@8284: #include "widgets/dropdown_func.h" rubidium@8131: rubidium@8264: #include "table/sprites.h" rubidium@8264: #include "table/strings.h" truelight@0: peter1138@8411: static const char *UPARROW = "\xEE\x8A\xA0"; peter1138@8349: static const char *DOWNARROW = "\xEE\x8A\xAA"; peter1138@8349: Darkvater@2436: static Point HandleScrollbarHittest(const Scrollbar *sb, int top, int bottom) truelight@0: { truelight@0: Point pt; truelight@0: int height, count, pos, cap; truelight@0: truelight@0: top += 10; truelight@0: bottom -= 9; truelight@193: truelight@0: height = (bottom - top); truelight@0: truelight@0: pos = sb->pos; truelight@0: count = sb->count; truelight@0: cap = sb->cap; truelight@0: tron@2026: if (count != 0) top += height * pos / count; truelight@193: truelight@0: if (cap > count) cap = count; tron@2639: if (count != 0) bottom -= (count - pos - cap) * height / count; truelight@0: truelight@0: pt.x = top; truelight@0: pt.y = bottom - 1; truelight@0: return pt; truelight@0: } truelight@0: belugas@6481: /** Special handling for the scrollbar widget type. truelight@0: * Handles the special scrolling buttons and other truelight@0: * scrolling. belugas@6481: * @param w Window on which a scroll was performed. belugas@6481: * @param wi Pointer to the scrollbar widget. belugas@6481: * @param x The X coordinate of the mouse click. belugas@6481: * @param y The Y coordinate of the mouse click. */ truelight@0: void ScrollbarClickHandler(Window *w, const Widget *wi, int x, int y) truelight@0: { truelight@0: int mi, ma, pos; truelight@0: Scrollbar *sb; truelight@0: bjarni@842: switch (wi->type) { rubidium@8729: case WWT_SCROLLBAR: belugas@6432: /* vertical scroller */ bjarni@842: w->flags4 &= ~WF_HSCROLL; bjarni@842: w->flags4 &= ~WF_SCROLL2; bjarni@842: mi = wi->top; bjarni@842: ma = wi->bottom; bjarni@842: pos = y; bjarni@842: sb = &w->vscroll; bjarni@842: break; rubidium@8729: rubidium@8729: case WWT_SCROLL2BAR: belugas@6432: /* 2nd vertical scroller */ bjarni@842: w->flags4 &= ~WF_HSCROLL; bjarni@842: w->flags4 |= WF_SCROLL2; bjarni@842: mi = wi->top; bjarni@842: ma = wi->bottom; bjarni@842: pos = y; bjarni@842: sb = &w->vscroll2; bjarni@842: break; rubidium@8729: rubidium@8729: case WWT_HSCROLLBAR: belugas@6432: /* horizontal scroller */ truelight@867: w->flags4 &= ~WF_SCROLL2; bjarni@842: w->flags4 |= WF_HSCROLL; bjarni@842: mi = wi->left; bjarni@842: ma = wi->right; bjarni@842: pos = x; bjarni@842: sb = &w->hscroll; truelight@867: break; rubidium@8729: rubidium@8729: default: NOT_REACHED(); truelight@0: } rubidium@8969: if (pos <= mi + 9) { belugas@6432: /* Pressing the upper button? */ tron@2597: w->flags4 |= WF_SCROLL_UP; tron@2597: if (_scroller_click_timeout == 0) { tron@2597: _scroller_click_timeout = 6; tron@2597: if (sb->pos != 0) sb->pos--; truelight@0: } tron@2597: _left_button_clicked = false; rubidium@8729: } else if (pos >= ma - 10) { belugas@6432: /* Pressing the lower button? */ tron@2597: w->flags4 |= WF_SCROLL_DOWN; truelight@193: tron@2597: if (_scroller_click_timeout == 0) { tron@2597: _scroller_click_timeout = 6; tron@2597: if ((byte)(sb->pos + sb->cap) < sb->count) tron@2597: sb->pos++; truelight@0: } tron@2597: _left_button_clicked = false; truelight@0: } else { truelight@0: Point pt = HandleScrollbarHittest(sb, mi, ma); truelight@0: truelight@0: if (pos < pt.x) { truelight@0: sb->pos = max(sb->pos - sb->cap, 0); truelight@0: } else if (pos > pt.y) { truelight@0: sb->pos = min( truelight@193: sb->pos + sb->cap, truelight@0: max(sb->count - sb->cap, 0) truelight@0: ); truelight@0: } else { truelight@0: _scrollbar_start_pos = pt.x - mi - 9; truelight@0: _scrollbar_size = ma - mi - 23; truelight@0: w->flags4 |= WF_SCROLL_MIDDLE; truelight@0: _scrolling_scrollbar = true; truelight@0: _cursorpos_drag_start = _cursor.pos; truelight@0: } truelight@0: } truelight@0: rubidium@9116: w->SetDirty(); truelight@0: } truelight@0: Darkvater@2021: /** Returns the index for the widget located at the given position Darkvater@2021: * relative to the window. It includes all widget-corner pixels as well. Darkvater@2021: * @param *w Window to look inside belugas@6481: * @param x The Window client X coordinate belugas@6481: * @param y The Window client y coordinate Darkvater@2021: * @return A widget index, or -1 if no widget was found. truelight@0: */ Darkvater@2436: int GetWidgetFromPos(const Window *w, int x, int y) truelight@0: { rubidium@5236: uint index; rubidium@5236: int found_index = -1; truelight@0: belugas@6432: /* Go through the widgets and check if we find the widget that the coordinate is belugas@6432: * inside. */ rubidium@5236: for (index = 0; index < w->widget_count; index++) { rubidium@5236: const Widget *wi = &w->widget[index]; tron@2639: if (wi->type == WWT_EMPTY || wi->type == WWT_FRAME) continue; truelight@0: Darkvater@2021: if (x >= wi->left && x <= wi->right && y >= wi->top && y <= wi->bottom && rubidium@7997: !w->IsWidgetHidden(index)) { tron@2639: found_index = index; truelight@0: } truelight@0: } truelight@0: truelight@0: return found_index; truelight@0: } truelight@0: truelight@0: tron@4437: void DrawFrameRect(int left, int top, int right, int bottom, int ctab, FrameFlags flags) tron@4437: { tron@4444: uint dark = _colour_gradient[ctab][3]; tron@4444: uint medium_dark = _colour_gradient[ctab][5]; tron@4444: uint medium_light = _colour_gradient[ctab][6]; tron@4444: uint light = _colour_gradient[ctab][7]; tron@4437: tron@4438: if (flags & FR_TRANSPARENT) { peter1138@5668: GfxFillRect(left, top, right, bottom, PALETTE_TO_TRANSPARENT | (1 << USE_COLORTABLE)); tron@4437: } else { tron@4437: uint interior; tron@4437: tron@4437: if (flags & FR_LOWERED) { tron@4437: GfxFillRect(left, top, left, bottom, dark); tron@4437: GfxFillRect(left + 1, top, right, top, dark); tron@4437: GfxFillRect(right, top + 1, right, bottom - 1, light); tron@4437: GfxFillRect(left + 1, bottom, right, bottom, light); tron@4437: interior = (flags & FR_DARKENED ? medium_dark : medium_light); tron@4437: } else { tron@4437: GfxFillRect(left, top, left, bottom - 1, light); tron@4437: GfxFillRect(left + 1, top, right - 1, top, light); tron@4437: GfxFillRect(right, top, right, bottom - 1, dark); tron@4437: GfxFillRect(left, bottom, right, bottom, dark); tron@4437: interior = medium_dark; tron@4437: } tron@4437: if (!(flags & FR_BORDERONLY)) { tron@4437: GfxFillRect(left + 1, top + 1, right - 1, bottom - 1, interior); tron@4437: } tron@4437: } tron@4437: } tron@4437: tron@4437: rubidium@8857: /** rubidium@8857: * Paint all widgets of a window. rubidium@8857: * @param w Window rubidium@8857: */ Darkvater@2436: void DrawWindowWidgets(const Window *w) truelight@0: { tron@2548: const DrawPixelInfo* dpi = _cur_dpi; truelight@193: smatz@7962: for (uint i = 0; i < w->widget_count; i++) { rubidium@5236: const Widget *wi = &w->widget[i]; rubidium@7997: bool clicked = w->IsWidgetLowered(i); smatz@7962: Rect r; Darkvater@1657: smatz@7962: if (dpi->left > (r.right = wi->right) || smatz@7962: dpi->left + dpi->width <= (r.left = wi->left) || smatz@7962: dpi->top > (r.bottom = wi->bottom) || smatz@7962: dpi->top + dpi->height <= (r.top = wi->top) || rubidium@7997: w->IsWidgetHidden(i)) { tron@2639: continue; tron@2639: } truelight@0: Darkvater@1657: switch (wi->type & WWT_MASK) { Darkvater@4938: case WWT_IMGBTN: Darkvater@4938: case WWT_IMGBTN_2: { smatz@7962: SpriteID img = wi->data; Darkvater@4938: assert(img != 0); rubidium@5587: DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : FR_NONE); truelight@0: Darkvater@4938: /* show different image when clicked for WWT_IMGBTN_2 */ Darkvater@4938: if ((wi->type & WWT_MASK) == WWT_IMGBTN_2 && clicked) img++; peter1138@5668: DrawSprite(img, PAL_NONE, r.left + 1 + clicked, r.top + 1 + clicked); peter1138@8320: break; Darkvater@4938: } Darkvater@1657: rubidium@8729: case WWT_PANEL: Darkvater@4938: assert(wi->data == 0); rubidium@5587: DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : FR_NONE); peter1138@8320: break; truelight@0: rubidium@8737: case WWT_EDITBOX: rubidium@8737: DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, FR_LOWERED | FR_DARKENED); rubidium@8737: break; rubidium@8737: Darkvater@4939: case WWT_TEXTBTN: rubidium@8729: case WWT_TEXTBTN_2: rubidium@5587: DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : FR_NONE); rubidium@8729: /* FALL THROUGH */ truelight@0: belugas@4345: case WWT_LABEL: { Darkvater@4547: StringID str = wi->data; truelight@0: Darkvater@4939: if ((wi->type & WWT_MASK) == WWT_TEXTBTN_2 && clicked) str++; truelight@193: belugas@7824: DrawStringCentered(((r.left + r.right + 1) >> 1) + clicked, ((r.top + r.bottom + 1) >> 1) - 5 + clicked, str, TC_FROMSTRING); peter1138@8320: break; truelight@0: } truelight@0: belugas@6278: case WWT_TEXT: { smatz@7962: const StringID str = wi->data; belugas@6278: belugas@6278: if (str != STR_NULL) DrawStringTruncated(r.left, r.top, str, wi->color, r.right - r.left); belugas@6278: break; belugas@6278: } belugas@6278: Darkvater@4939: case WWT_INSET: { smatz@7962: const StringID str = wi->data; hackykid@1938: DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, FR_LOWERED | FR_DARKENED); truelight@0: belugas@7824: if (str != STR_NULL) DrawStringTruncated(r.left + 2, r.top + 1, str, TC_FROMSTRING, r.right - r.left - 10); peter1138@8320: break; truelight@0: } truelight@0: truelight@0: case WWT_MATRIX: { rubidium@5587: DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : FR_NONE); truelight@193: rubidium@8729: int c = GB(wi->data, 0, 8); rubidium@8729: int amt1 = (wi->right - wi->left + 1) / c; truelight@0: rubidium@8729: int d = GB(wi->data, 8, 8); rubidium@8729: int amt2 = (wi->bottom - wi->top + 1) / d; truelight@0: rubidium@8729: int color = _colour_gradient[wi->color & 0xF][6]; truelight@193: rubidium@8729: int x = r.left; rubidium@8729: for (int ctr = c; ctr > 1; ctr--) { truelight@0: x += amt1; tron@2639: GfxFillRect(x, r.top + 1, x, r.bottom - 1, color); truelight@0: } truelight@0: truelight@0: x = r.top; rubidium@8729: for (int ctr = d; ctr > 1; ctr--) { truelight@0: x += amt2; tron@2639: GfxFillRect(r.left + 1, x, r.right - 1, x, color); truelight@0: } truelight@0: smatz@7962: color = _colour_gradient[wi->color & 0xF][4]; truelight@0: tron@2639: x = r.left - 1; rubidium@8729: for (int ctr = c; ctr > 1; ctr--) { truelight@0: x += amt1; tron@2639: GfxFillRect(x, r.top + 1, x, r.bottom - 1, color); truelight@0: } truelight@0: tron@2639: x = r.top - 1; rubidium@8729: for (int ctr = d; ctr > 1; ctr--) { truelight@0: x += amt2; smatz@7962: GfxFillRect(r.left + 1, x, r.right - 1, x, color); truelight@0: } truelight@0: peter1138@8320: break; truelight@0: } truelight@0: belugas@6432: /* vertical scrollbar */ truelight@0: case WWT_SCROLLBAR: { smatz@7962: assert(wi->data == 0); rubidium@8729: assert(r.right - r.left == 11); // To ensure the same sizes are used everywhere! darkvater@893: belugas@6432: /* draw up/down buttons */ Darkvater@4940: clicked = ((w->flags4 & (WF_SCROLL_UP | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_UP); rubidium@5587: DrawFrameRect(r.left, r.top, r.right, r.top + 9, wi->color, (clicked) ? FR_LOWERED : FR_NONE); belugas@7824: DoDrawString(UPARROW, r.left + 2 + clicked, r.top + clicked, TC_BLACK); truelight@0: Darkvater@4940: clicked = (((w->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_DOWN)); rubidium@5587: DrawFrameRect(r.left, r.bottom - 9, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : FR_NONE); belugas@7824: DoDrawString(DOWNARROW, r.left + 2 + clicked, r.bottom - 9 + clicked, TC_BLACK); truelight@0: rubidium@8729: int c1 = _colour_gradient[wi->color & 0xF][3]; rubidium@8729: int c2 = _colour_gradient[wi->color & 0xF][7]; truelight@0: belugas@6432: /* draw "shaded" background */ smatz@7962: GfxFillRect(r.left, r.top + 10, r.right, r.bottom - 10, c2); smatz@7962: GfxFillRect(r.left, r.top + 10, r.right, r.bottom - 10, c1 | (1 << PALETTE_MODIFIER_GREYOUT)); truelight@0: belugas@6432: /* draw shaded lines */ smatz@7962: GfxFillRect(r.left + 2, r.top + 10, r.left + 2, r.bottom - 10, c1); smatz@7962: GfxFillRect(r.left + 3, r.top + 10, r.left + 3, r.bottom - 10, c2); smatz@7962: GfxFillRect(r.left + 7, r.top + 10, r.left + 7, r.bottom - 10, c1); smatz@7962: GfxFillRect(r.left + 8, r.top + 10, r.left + 8, r.bottom - 10, c2); truelight@193: rubidium@8729: Point pt = HandleScrollbarHittest(&w->vscroll, r.top, r.bottom); rubidium@5587: DrawFrameRect(r.left, pt.x, r.right, pt.y, wi->color, (w->flags4 & (WF_SCROLL_MIDDLE | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_MIDDLE ? FR_LOWERED : FR_NONE); bjarni@842: break; bjarni@842: } rubidium@8729: bjarni@842: case WWT_SCROLL2BAR: { smatz@7962: assert(wi->data == 0); rubidium@8729: assert(r.right - r.left == 11); // To ensure the same sizes are used everywhere! darkvater@893: belugas@6432: /* draw up/down buttons */ Darkvater@4940: clicked = ((w->flags4 & (WF_SCROLL_UP | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_UP | WF_SCROLL2)); rubidium@5587: DrawFrameRect(r.left, r.top, r.right, r.top + 9, wi->color, (clicked) ? FR_LOWERED : FR_NONE); belugas@7824: DoDrawString(UPARROW, r.left + 2 + clicked, r.top + clicked, TC_BLACK); bjarni@842: Darkvater@4940: clicked = ((w->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_DOWN | WF_SCROLL2)); rubidium@5587: DrawFrameRect(r.left, r.bottom - 9, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : FR_NONE); belugas@7824: DoDrawString(DOWNARROW, r.left + 2 + clicked, r.bottom - 9 + clicked, TC_BLACK); bjarni@842: rubidium@8729: int c1 = _colour_gradient[wi->color & 0xF][3]; rubidium@8729: int c2 = _colour_gradient[wi->color & 0xF][7]; bjarni@842: belugas@6432: /* draw "shaded" background */ smatz@7962: GfxFillRect(r.left, r.top + 10, r.right, r.bottom - 10, c2); smatz@7962: GfxFillRect(r.left, r.top + 10, r.right, r.bottom - 10, c1 | (1 << PALETTE_MODIFIER_GREYOUT)); bjarni@842: belugas@6432: /* draw shaded lines */ smatz@7962: GfxFillRect(r.left + 2, r.top + 10, r.left + 2, r.bottom - 10, c1); smatz@7962: GfxFillRect(r.left + 3, r.top + 10, r.left + 3, r.bottom - 10, c2); smatz@7962: GfxFillRect(r.left + 7, r.top + 10, r.left + 7, r.bottom - 10, c1); smatz@7962: GfxFillRect(r.left + 8, r.top + 10, r.left + 8, r.bottom - 10, c2); bjarni@842: rubidium@8729: Point pt = HandleScrollbarHittest(&w->vscroll2, r.top, r.bottom); rubidium@5587: DrawFrameRect(r.left, pt.x, r.right, pt.y, wi->color, (w->flags4 & (WF_SCROLL_MIDDLE | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_MIDDLE | WF_SCROLL2) ? FR_LOWERED : FR_NONE); truelight@0: break; truelight@0: } truelight@0: belugas@6432: /* horizontal scrollbar */ truelight@0: case WWT_HSCROLLBAR: { smatz@7962: assert(wi->data == 0); rubidium@8729: assert(r.bottom - r.top == 11); // To ensure the same sizes are used everywhere! darkvater@893: Darkvater@4940: clicked = ((w->flags4 & (WF_SCROLL_UP | WF_HSCROLL)) == (WF_SCROLL_UP | WF_HSCROLL)); rubidium@5587: DrawFrameRect(r.left, r.top, r.left + 9, r.bottom, wi->color, (clicked) ? FR_LOWERED : FR_NONE); peter1138@5668: DrawSprite(SPR_ARROW_LEFT, PAL_NONE, r.left + 1 + clicked, r.top + 1 + clicked); truelight@0: Darkvater@4940: clicked = ((w->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL)) == (WF_SCROLL_DOWN | WF_HSCROLL)); smatz@7962: DrawFrameRect(r.right - 9, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : FR_NONE); peter1138@5668: DrawSprite(SPR_ARROW_RIGHT, PAL_NONE, r.right - 8 + clicked, r.top + 1 + clicked); truelight@0: rubidium@8729: int c1 = _colour_gradient[wi->color & 0xF][3]; rubidium@8729: int c2 = _colour_gradient[wi->color & 0xF][7]; truelight@0: belugas@6432: /* draw "shaded" background */ smatz@7962: GfxFillRect(r.left + 10, r.top, r.right - 10, r.bottom, c2); smatz@7962: GfxFillRect(r.left + 10, r.top, r.right - 10, r.bottom, c1 | (1 << PALETTE_MODIFIER_GREYOUT)); truelight@0: belugas@6432: /* draw shaded lines */ smatz@7962: GfxFillRect(r.left + 10, r.top + 2, r.right - 10, r.top + 2, c1); smatz@7962: GfxFillRect(r.left + 10, r.top + 3, r.right - 10, r.top + 3, c2); smatz@7962: GfxFillRect(r.left + 10, r.top + 7, r.right - 10, r.top + 7, c1); smatz@7962: GfxFillRect(r.left + 10, r.top + 8, r.right - 10, r.top + 8, c2); truelight@0: belugas@6432: /* draw actual scrollbar */ rubidium@8729: Point pt = HandleScrollbarHittest(&w->hscroll, r.left, r.right); rubidium@5587: DrawFrameRect(pt.x, r.top, pt.y, r.bottom, wi->color, (w->flags4 & (WF_SCROLL_MIDDLE | WF_HSCROLL)) == (WF_SCROLL_MIDDLE | WF_HSCROLL) ? FR_LOWERED : FR_NONE); truelight@0: truelight@0: break; truelight@0: } truelight@0: truelight@0: case WWT_FRAME: { smatz@7962: const StringID str = wi->data; darkvater@860: int x2 = r.left; // by default the left side is the left side of the widget truelight@0: smatz@7962: if (str != STR_NULL) x2 = DrawString(r.left + 6, r.top, str, TC_FROMSTRING); truelight@0: rubidium@8729: int c1 = _colour_gradient[wi->color][3]; rubidium@8729: int c2 = _colour_gradient[wi->color][7]; truelight@0: smatz@7962: /* Line from upper left corner to start of text */ smatz@7962: GfxFillRect(r.left, r.top + 4, r.left + 4, r.top + 4, c1); smatz@7962: GfxFillRect(r.left + 1, r.top + 5, r.left + 4, r.top + 5, c2); truelight@0: belugas@6432: /* Line from end of text to upper right corner */ smatz@7962: GfxFillRect(x2, r.top + 4, r.right - 1, r.top + 4, c1); smatz@7962: GfxFillRect(x2, r.top + 5, r.right - 2, r.top + 5, c2); truelight@0: belugas@6432: /* Line from upper left corner to bottom left corner */ smatz@7962: GfxFillRect(r.left, r.top + 5, r.left, r.bottom - 1, c1); smatz@7962: GfxFillRect(r.left + 1, r.top + 6, r.left + 1, r.bottom - 2, c2); truelight@0: belugas@6432: /*Line from upper right corner to bottom right corner */ smatz@7962: GfxFillRect(r.right - 1, r.top + 5, r.right - 1, r.bottom - 2, c1); smatz@7962: GfxFillRect(r.right, r.top + 4, r.right, r.bottom - 1, c2); truelight@0: smatz@7962: GfxFillRect(r.left + 1, r.bottom - 1, r.right - 1, r.bottom - 1, c1); truelight@0: GfxFillRect(r.left, r.bottom, r.right, r.bottom, c2); truelight@0: peter1138@8320: break; truelight@0: } truelight@0: rubidium@8729: case WWT_STICKYBOX: smatz@7962: assert(wi->data == 0); rubidium@8729: assert(r.right - r.left == 11); // To ensure the same sizes are used everywhere! peter1138@2703: peter1138@2703: clicked = !!(w->flags4 & WF_STICKY); rubidium@5587: DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : FR_NONE); peter1138@5668: DrawSprite((clicked) ? SPR_PIN_UP : SPR_PIN_DOWN, PAL_NONE, r.left + 2 + clicked, r.top + 3 + clicked); darkvater@682: break; truelight@867: rubidium@8729: case WWT_RESIZEBOX: smatz@7962: assert(wi->data == 0); rubidium@8729: assert(r.right - r.left == 11); // To ensure the same sizes are used everywhere! tron@915: Darkvater@1657: clicked = !!(w->flags4 & WF_SIZING); rubidium@5587: DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : FR_NONE); peter1138@5668: DrawSprite(SPR_WINDOW_RESIZE, PAL_NONE, r.left + 3 + clicked, r.top + 3 + clicked); truelight@867: break; truelight@867: peter1138@2757: case WWT_CLOSEBOX: { smatz@7962: const StringID str = wi->data; smatz@7962: smatz@7962: assert(str == STR_00C5 || str == STR_00C6); // black or silver cross rubidium@8729: assert(r.right - r.left == 10); // To ensure the same sizes are used everywhere peter1138@2757: rubidium@5587: DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, FR_NONE); smatz@7962: DrawString(r.left + 2, r.top + 2, str, TC_FROMSTRING); peter1138@2757: break; peter1138@2757: } peter1138@2757: rubidium@8729: case WWT_CAPTION: rubidium@8729: assert(r.bottom - r.top == 13); // To ensure the same sizes are used everywhere! hackykid@1938: DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, FR_BORDERONLY); smatz@7962: DrawFrameRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, wi->color, (w->caption_color == 0xFF) ? FR_LOWERED | FR_DARKENED : FR_LOWERED | FR_DARKENED | FR_BORDERONLY); truelight@193: truelight@0: if (w->caption_color != 0xFF) { smatz@7962: GfxFillRect(r.left + 2, r.top + 2, r.right - 2, r.bottom - 2, _colour_gradient[_player_colors[w->caption_color]][4]); truelight@0: } truelight@0: smatz@7962: DrawStringCenteredTruncated(r.left + 2, r.right - 2, r.top + 2, wi->data, 0x84); peter1138@8320: break; peter1138@8335: peter1138@8335: case WWT_DROPDOWN: { peter1138@8335: assert(r.bottom - r.top == 11); // ensure consistent size peter1138@8335: peter1138@8335: StringID str = wi->data; peter1138@8335: DrawFrameRect(r.left, r.top, r.right - 12, r.bottom, wi->color, FR_NONE); peter1138@8335: DrawFrameRect(r.right - 11, r.top, r.right, r.bottom, wi->color, clicked ? FR_LOWERED : FR_NONE); peter1138@8335: DrawString(r.right - (clicked ? 8 : 9), r.top + (clicked ? 2 : 1), STR_0225, TC_BLACK); peter1138@8335: if (str != STR_NULL) DrawStringTruncated(r.left + 2, r.top + 1, str, TC_BLACK, r.right - r.left - 12); peter1138@8335: break; peter1138@8335: } peter1138@8335: peter1138@8335: case WWT_DROPDOWNIN: { peter1138@8335: assert(r.bottom - r.top == 11); // ensure consistent size peter1138@8335: peter1138@8335: StringID str = wi->data; peter1138@8335: DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, FR_LOWERED | FR_DARKENED); peter1138@8335: DrawFrameRect(r.right - 11, r.top + 1, r.right - 1, r.bottom - 1, wi->color, clicked ? FR_LOWERED : FR_NONE); peter1138@8335: DrawString(r.right - (clicked ? 8 : 9), r.top + (clicked ? 2 : 1), STR_0225, TC_BLACK); peter1138@8335: if (str != STR_NULL) DrawStringTruncated(r.left + 2, r.top + 2, str, TC_BLACK, r.right - r.left - 12); peter1138@8335: break; peter1138@8335: } truelight@0: } peter1138@8320: peter1138@8320: if (w->IsWidgetDisabled(i)) { peter1138@8320: GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, _colour_gradient[wi->color & 0xF][2] | (1 << PALETTE_MODIFIER_GREYOUT)); peter1138@8320: } rubidium@5236: } truelight@193: truelight@0: truelight@0: if (w->flags4 & WF_WHITE_BORDER_MASK) { smatz@7962: DrawFrameRect(0, 0, w->width - 1, w->height - 1, 0xF, FR_BORDERONLY); truelight@0: } truelight@0: truelight@0: } darkvater@164: bjarni@5824: static void ResizeWidgets(Window *w, byte a, byte b) bjarni@5824: { bjarni@5824: int16 offset = w->widget[a].left; bjarni@5824: int16 length = w->widget[b].right - offset; bjarni@5824: rubidium@8729: w->widget[a].right = (length / 2) + offset; bjarni@5824: bjarni@5822: w->widget[b].left = w->widget[a].right + 1; bjarni@5822: } bjarni@5822: bjarni@5824: static void ResizeWidgets(Window *w, byte a, byte b, byte c) bjarni@5822: { bjarni@5824: int16 offset = w->widget[a].left; bjarni@5824: int16 length = w->widget[c].right - offset; bjarni@5822: bjarni@5824: w->widget[a].right = length / 3; bjarni@5822: w->widget[b].right = w->widget[a].right * 2; bjarni@5822: bjarni@5824: w->widget[a].right += offset; bjarni@5824: w->widget[b].right += offset; bjarni@5824: bjarni@5822: /* Now the right side of the buttons are set. We will now set the left sides next to them */ bjarni@5822: w->widget[b].left = w->widget[a].right + 1; bjarni@5822: w->widget[c].left = w->widget[b].right + 1; bjarni@5822: } bjarni@5822: bjarni@5824: /** Evenly distribute some widgets when resizing horizontally (often a button row) bjarni@5824: * When only two arguments are given, the widgets are presumed to be on a line and only the ends are given belugas@6481: * @param w Window to modify bjarni@5824: * @param left The leftmost widget to resize bjarni@5824: * @param right The rightmost widget to resize. Since right side of it is used, remember to set it to RESIZE_RIGHT bjarni@5824: */ bjarni@5822: void ResizeButtons(Window *w, byte left, byte right) bjarni@5822: { bjarni@5824: int16 num_widgets = right - left + 1; bjarni@5824: bjarni@5824: if (num_widgets < 2) NOT_REACHED(); bjarni@5824: bjarni@5824: switch (num_widgets) { bjarni@5824: case 2: ResizeWidgets(w, left, right); break; bjarni@5824: case 3: ResizeWidgets(w, left, left + 1, right); break; bjarni@5824: default: { bjarni@5824: /* Looks like we got more than 3 widgets to resize bjarni@5824: * Now we will find the middle of the space desinated for the widgets bjarni@5824: * and place half of the widgets on each side of it and call recursively. bjarni@5824: * Eventually we will get down to blocks of 2-3 widgets and we got code to handle those cases */ bjarni@5824: int16 offset = w->widget[left].left; bjarni@5824: int16 length = w->widget[right].right - offset; bjarni@5824: byte widget = ((num_widgets - 1)/ 2) + left; // rightmost widget of the left side bjarni@5824: bjarni@5824: /* Now we need to find the middle of the widgets. bjarni@5824: * It will not always be the middle because if we got an uneven number of widgets, bjarni@5824: * we will need it to be 2/5, 3/7 and so on bjarni@5824: * To get this, we multiply with num_widgets/num_widgets. Since we calculate in int, we will get: bjarni@5824: * bjarni@5824: * num_widgets/2 (rounding down) bjarni@5824: * --------------- bjarni@5824: * num_widgets bjarni@5824: * bjarni@5824: * as multiplier to length. We just multiply before divide to that we stay in the int area though */ bjarni@5824: int16 middle = ((length * num_widgets) / (2 * num_widgets)) + offset; bjarni@5824: bjarni@5824: /* Set left and right on the widgets, that's next to our "middle" */ bjarni@5824: w->widget[widget].right = middle; bjarni@5824: w->widget[widget + 1].left = w->widget[widget].right + 1; bjarni@5824: /* Now resize the left and right of the middle */ bjarni@5824: ResizeButtons(w, left, widget); bjarni@5824: ResizeButtons(w, widget + 1, right); bjarni@5824: } bjarni@5822: } bjarni@5822: } peter1138@8349: rubidium@8857: /** Resize a widget and shuffle other widgets around to fit. */ peter1138@8418: void ResizeWindowForWidget(Window *w, int widget, int delta_x, int delta_y) peter1138@8418: { peter1138@8418: int right = w->widget[widget].right; peter1138@8418: int bottom = w->widget[widget].bottom; peter1138@8418: peter1138@8418: for (uint i = 0; i < w->widget_count; i++) { peter1138@8418: if (w->widget[i].left >= right) w->widget[i].left += delta_x; peter1138@8418: if (w->widget[i].right >= right) w->widget[i].right += delta_x; peter1138@8418: if (w->widget[i].top >= bottom) w->widget[i].top += delta_y; peter1138@8418: if (w->widget[i].bottom >= bottom) w->widget[i].bottom += delta_y; peter1138@8418: } peter1138@8418: peter1138@8418: w->width += delta_x; peter1138@8418: w->height += delta_y; peter1138@8418: w->resize.width += delta_x; peter1138@8418: w->resize.height += delta_y; peter1138@8418: } peter1138@8418: peter1138@8349: /** Draw a sort button's up or down arrow symbol. peter1138@8349: * @param w Window of widget peter1138@8349: * @param widget Sort button widget peter1138@8349: * @param state State of sort button peter1138@8349: */ peter1138@8349: void DrawSortButtonState(const Window *w, int widget, SortButtonState state) peter1138@8349: { peter1138@8349: if (state == SBS_OFF) return; peter1138@8349: peter1138@8349: int offset = w->IsWidgetLowered(widget) ? 1 : 0; peter1138@8349: DoDrawString(state == SBS_DOWN ? DOWNARROW : UPARROW, w->widget[widget].right - 11 + offset, w->widget[widget].top + 1 + offset, TC_BLACK); peter1138@8349: }