tron@2186: /* $Id$ */ tron@2186: truelight@0: #include "stdafx.h" Darkvater@1891: #include "openttd.h" tron@2163: #include "functions.h" tron@2154: #include "player.h" tron@1363: #include "table/sprites.h" tron@507: #include "table/strings.h" truelight@0: #include "window.h" truelight@0: #include "gfx.h" truelight@0: #include "viewport.h" truelight@0: 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: truelight@0: /***************************************************** truelight@0: * Special handling for the scrollbar widget type. truelight@0: * Handles the special scrolling buttons and other truelight@0: * scrolling. truelight@0: * Parameters: truelight@0: * w - Window. truelight@0: * wi - Pointer to the scrollbar widget. truelight@0: * x - The X coordinate of the mouse click. truelight@0: * y - The Y coordinate of the mouse click. truelight@0: */ truelight@0: 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) { bjarni@842: case WWT_SCROLLBAR: { bjarni@842: // 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; bjarni@842: } bjarni@842: case WWT_SCROLL2BAR: { bjarni@842: // 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; bjarni@842: } bjarni@842: case WWT_HSCROLLBAR: { bjarni@842: // 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; bjarni@842: } bjarni@845: default: return; //this should never happen truelight@0: } truelight@0: if (pos <= mi+9) { truelight@0: // 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; truelight@0: } else if (pos >= ma-10) { truelight@0: // 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@193: // 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: truelight@0: SetWindowDirty(w); 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 Darkvater@2021: * @param x,y Window client coordinates 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: truelight@0: // Go through the widgets and check if we find the widget that the coordinate is truelight@0: // 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@5236: !IsWindowWidgetHidden(w, 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) { tron@4438: GfxFillRect(left, top, right, bottom, 0x322 | 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: Darkvater@2436: void DrawWindowWidgets(const Window *w) truelight@0: { tron@2548: const DrawPixelInfo* dpi = _cur_dpi; truelight@0: Rect r; rubidium@5236: uint i; truelight@193: rubidium@5236: for (i = 0; i < w->widget_count; i++) { rubidium@5236: const Widget *wi = &w->widget[i]; rubidium@5236: bool clicked = IsWindowWidgetLowered(w, i); Darkvater@1657: truelight@0: if (dpi->left > (r.right=/*w->left + */wi->right) || tron@2639: dpi->left + dpi->width <= (r.left=wi->left/* + w->left*/) || truelight@0: dpi->top > (r.bottom=/*w->top +*/ wi->bottom) || truelight@0: dpi->top + dpi->height <= (r.top = /*w->top +*/ wi->top) || rubidium@5236: IsWindowWidgetHidden(w, 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: { Darkvater@4547: int img = wi->data; Darkvater@4938: assert(img != 0); hackykid@1938: DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : 0); 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++; Darkvater@4938: DrawSprite(img, r.left + 1 + clicked, r.top + 1 + clicked); Darkvater@4938: goto draw_default; Darkvater@4938: } Darkvater@1657: Darkvater@4938: case WWT_PANEL: { Darkvater@4938: assert(wi->data == 0); Darkvater@4938: DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : 0); truelight@0: goto draw_default; truelight@0: } truelight@0: Darkvater@4939: case WWT_TEXTBTN: Darkvater@4939: case WWT_TEXTBTN_2: { hackykid@1938: DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : 0); truelight@0: } truelight@0: /* 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: Darkvater@1657: DrawStringCentered(((r.left + r.right + 1) >> 1) + clicked, ((r.top + r.bottom + 1) >> 1) - 5 + clicked, str, 0); ludde@2064: goto draw_default; truelight@0: } truelight@0: Darkvater@4939: case WWT_INSET: { Darkvater@4547: StringID str = wi->data; hackykid@1938: DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, FR_LOWERED | FR_DARKENED); truelight@0: Darkvater@4547: if (str != STR_NULL) DrawStringTruncated(r.left + 2, r.top + 1, str, 0, r.right - r.left - 10); truelight@0: goto draw_default; truelight@0: } truelight@0: truelight@0: case WWT_MATRIX: { truelight@193: int c, d, ctr; truelight@0: int x, amt1, amt2; truelight@0: int color; truelight@193: hackykid@1938: DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : 0); truelight@193: Darkvater@4547: c = GB(wi->data, 0, 8); truelight@0: amt1 = (wi->right - wi->left + 1) / c; truelight@0: Darkvater@4547: d = GB(wi->data, 8, 8); truelight@0: amt2 = (wi->bottom - wi->top + 1) / d; truelight@0: tron@4444: color = _colour_gradient[wi->color & 0xF][6]; truelight@193: truelight@0: x = r.left; peter1138@2801: for (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; peter1138@2801: for (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: tron@4444: color = _colour_gradient[wi->color&0xF][4]; truelight@0: tron@2639: x = r.left - 1; peter1138@2801: for (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; peter1138@2801: for (ctr = d; ctr > 1; ctr--) { truelight@0: x += amt2; truelight@0: GfxFillRect(r.left+1, x, r.right-1, x, color); truelight@0: } truelight@0: truelight@193: goto draw_default; truelight@0: } truelight@0: truelight@0: // vertical scrollbar truelight@0: case WWT_SCROLLBAR: { truelight@0: Point pt; truelight@0: int c1,c2; truelight@0: darkvater@893: assert(r.right - r.left == 11); // XXX - to ensure the same sizes are used everywhere! darkvater@893: truelight@0: // draw up/down buttons Darkvater@4940: clicked = ((w->flags4 & (WF_SCROLL_UP | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_UP); hackykid@1938: DrawFrameRect(r.left, r.top, r.right, r.top + 9, wi->color, (clicked) ? FR_LOWERED : 0); tron@2406: DoDrawString(UPARROW, r.left + 2 + clicked, r.top + clicked, 0x10); truelight@0: Darkvater@4940: clicked = (((w->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_DOWN)); hackykid@1938: DrawFrameRect(r.left, r.bottom - 9, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : 0); tron@2406: DoDrawString(DOWNARROW, r.left + 2 + clicked, r.bottom - 9 + clicked, 0x10); truelight@0: tron@4444: c1 = _colour_gradient[wi->color&0xF][3]; tron@4444: c2 = _colour_gradient[wi->color&0xF][7]; truelight@0: truelight@0: // draw "shaded" background truelight@0: GfxFillRect(r.left, r.top+10, r.right, r.bottom-10, c2); celestar@2218: GfxFillRect(r.left, r.top+10, r.right, r.bottom-10, c1 | PALETTE_MODIFIER_GREYOUT); truelight@0: truelight@0: // draw shaded lines truelight@0: GfxFillRect(r.left+2, r.top+10, r.left+2, r.bottom-10, c1); truelight@0: GfxFillRect(r.left+3, r.top+10, r.left+3, r.bottom-10, c2); truelight@0: GfxFillRect(r.left+7, r.top+10, r.left+7, r.bottom-10, c1); truelight@0: GfxFillRect(r.left+8, r.top+10, r.left+8, r.bottom-10, c2); truelight@193: truelight@0: pt = HandleScrollbarHittest(&w->vscroll, r.top, r.bottom); hackykid@1938: 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 : 0); bjarni@842: break; bjarni@842: } bjarni@842: case WWT_SCROLL2BAR: { bjarni@842: Point pt; bjarni@842: int c1,c2; bjarni@842: darkvater@893: assert(r.right - r.left == 11); // XXX - to ensure the same sizes are used everywhere! darkvater@893: bjarni@842: // draw up/down buttons Darkvater@4940: clicked = ((w->flags4 & (WF_SCROLL_UP | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_UP | WF_SCROLL2)); hackykid@1938: DrawFrameRect(r.left, r.top, r.right, r.top + 9, wi->color, (clicked) ? FR_LOWERED : 0); tron@2406: DoDrawString(UPARROW, r.left + 2 + clicked, r.top + clicked, 0x10); bjarni@842: Darkvater@4940: clicked = ((w->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_DOWN | WF_SCROLL2)); hackykid@1938: DrawFrameRect(r.left, r.bottom - 9, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : 0); tron@2406: DoDrawString(DOWNARROW, r.left + 2 + clicked, r.bottom - 9 + clicked, 0x10); bjarni@842: tron@4444: c1 = _colour_gradient[wi->color&0xF][3]; tron@4444: c2 = _colour_gradient[wi->color&0xF][7]; bjarni@842: bjarni@842: // draw "shaded" background bjarni@842: GfxFillRect(r.left, r.top+10, r.right, r.bottom-10, c2); celestar@2218: GfxFillRect(r.left, r.top+10, r.right, r.bottom-10, c1 | PALETTE_MODIFIER_GREYOUT); bjarni@842: bjarni@842: // draw shaded lines bjarni@842: GfxFillRect(r.left+2, r.top+10, r.left+2, r.bottom-10, c1); bjarni@842: GfxFillRect(r.left+3, r.top+10, r.left+3, r.bottom-10, c2); bjarni@842: GfxFillRect(r.left+7, r.top+10, r.left+7, r.bottom-10, c1); bjarni@842: GfxFillRect(r.left+8, r.top+10, r.left+8, r.bottom-10, c2); bjarni@842: bjarni@842: pt = HandleScrollbarHittest(&w->vscroll2, r.top, r.bottom); hackykid@1938: 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 : 0); truelight@0: break; truelight@0: } truelight@0: truelight@0: // horizontal scrollbar truelight@0: case WWT_HSCROLLBAR: { truelight@0: Point pt; truelight@0: int c1,c2; truelight@0: darkvater@894: assert(r.bottom - r.top == 11); // XXX - 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)); hackykid@1938: DrawFrameRect(r.left, r.top, r.left + 9, r.bottom, wi->color, (clicked) ? FR_LOWERED : 0); Darkvater@1657: DrawSprite(SPR_ARROW_LEFT, 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)); hackykid@1938: DrawFrameRect(r.right-9, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : 0); Darkvater@1657: DrawSprite(SPR_ARROW_RIGHT, r.right - 8 + clicked, r.top + 1 + clicked); truelight@0: tron@4444: c1 = _colour_gradient[wi->color&0xF][3]; tron@4444: c2 = _colour_gradient[wi->color&0xF][7]; truelight@0: truelight@0: // draw "shaded" background truelight@0: GfxFillRect(r.left+10, r.top, r.right-10, r.bottom, c2); celestar@2218: GfxFillRect(r.left+10, r.top, r.right-10, r.bottom, c1 | PALETTE_MODIFIER_GREYOUT); truelight@0: truelight@0: // draw shaded lines truelight@0: GfxFillRect(r.left+10, r.top+2, r.right-10, r.top+2, c1); truelight@0: GfxFillRect(r.left+10, r.top+3, r.right-10, r.top+3, c2); truelight@0: GfxFillRect(r.left+10, r.top+7, r.right-10, r.top+7, c1); truelight@0: GfxFillRect(r.left+10, r.top+8, r.right-10, r.top+8, c2); truelight@0: truelight@0: // draw actual scrollbar truelight@0: pt = HandleScrollbarHittest(&w->hscroll, r.left, r.right); hackykid@1938: 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 : 0); truelight@0: truelight@0: break; truelight@0: } truelight@0: truelight@0: case WWT_FRAME: { truelight@0: int c1,c2; darkvater@860: int x2 = r.left; // by default the left side is the left side of the widget truelight@0: Darkvater@4547: if (wi->data != 0) x2 = DrawString(r.left + 6, r.top, wi->data, 0); truelight@0: tron@4444: c1 = _colour_gradient[wi->color][3]; tron@4444: c2 = _colour_gradient[wi->color][7]; truelight@0: truelight@0: //Line from upper left corner to start of text truelight@0: GfxFillRect(r.left, r.top+4, r.left+4,r.top+4, c1); truelight@0: GfxFillRect(r.left+1, r.top+5, r.left+4,r.top+5, c2); truelight@0: truelight@0: // Line from end of text to upper right corner truelight@0: GfxFillRect(x2, r.top+4, r.right-1,r.top+4,c1); truelight@0: GfxFillRect(x2, r.top+5, r.right-2,r.top+5,c2); truelight@0: truelight@0: // Line from upper left corner to bottom left corner truelight@0: GfxFillRect(r.left, r.top+5, r.left, r.bottom-1, c1); truelight@0: GfxFillRect(r.left+1, r.top+6, r.left+1, r.bottom-2, c2); truelight@0: truelight@0: //Line from upper right corner to bottom right corner truelight@0: GfxFillRect(r.right-1, r.top+5, r.right-1, r.bottom-2, c1); truelight@0: GfxFillRect(r.right, r.top+4, r.right, r.bottom-1, c2); truelight@0: truelight@0: 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: ludde@2064: goto draw_default; truelight@0: } truelight@0: darkvater@682: case WWT_STICKYBOX: { darkvater@893: assert(r.right - r.left == 11); // XXX - to ensure the same sizes are used everywhere! peter1138@2703: peter1138@2703: clicked = !!(w->flags4 & WF_STICKY); hackykid@1938: DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : 0); Darkvater@1657: DrawSprite((clicked) ? SPR_PIN_UP : SPR_PIN_DOWN, r.left + 2 + clicked, r.top + 3 + clicked); darkvater@682: break; darkvater@682: } truelight@867: truelight@867: case WWT_RESIZEBOX: { darkvater@893: assert(r.right - r.left == 11); // XXX - to ensure the same sizes are used everywhere! tron@915: Darkvater@1657: clicked = !!(w->flags4 & WF_SIZING); hackykid@1938: DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : 0); Darkvater@1657: DrawSprite(SPR_WINDOW_RESIZE, r.left + 3 + clicked, r.top + 3 + clicked); truelight@867: break; truelight@867: } truelight@867: peter1138@2757: case WWT_CLOSEBOX: { peter1138@2757: assert(r.right - r.left == 10); // ensure the same sizes are used everywhere peter1138@2757: peter1138@2757: DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, 0); peter1138@2757: DrawString(r.left + 2, r.top + 2, STR_00C5, 0); peter1138@2757: break; peter1138@2757: } peter1138@2757: truelight@0: case WWT_CAPTION: { darkvater@893: assert(r.bottom - r.top == 13); // XXX - to ensure the same sizes are used everywhere! hackykid@1938: DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, FR_BORDERONLY); hackykid@1938: 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) { tron@4444: 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: peter1138@5017: DrawStringCenteredTruncated(r.left + 2, r.right - 2, r.top+2, wi->data, 0x84); truelight@0: draw_default:; rubidium@5236: if (IsWindowWidgetDisabled(w, i)) { tron@4444: GfxFillRect(r.left+1, r.top+1, r.right-1, r.bottom-1, _colour_gradient[wi->color&0xF][2] | PALETTE_MODIFIER_GREYOUT); truelight@0: } truelight@0: } truelight@0: } rubidium@5236: } truelight@193: truelight@0: truelight@0: if (w->flags4 & WF_WHITE_BORDER_MASK) { truelight@0: //DrawFrameRect(w->left, w->top, w->left + w->width-1, w->top+w->height-1, 0xF, 0x10); hackykid@1938: DrawFrameRect(0, 0, w->width-1, w->height-1, 0xF, FR_BORDERONLY); truelight@0: } truelight@0: truelight@0: } darkvater@164: truelight@883: static const Widget _dropdown_menu_widgets[] = { Darkvater@4938: { WWT_PANEL, RESIZE_NONE, 0, 0, 0, 0, 0, 0x0, STR_NULL}, peter1138@5041: { WWT_SCROLLBAR, RESIZE_NONE, 0, 0, 0, 0, 0, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, darkvater@176: { WIDGETS_END}, darkvater@164: }; darkvater@164: Darkvater@2436: static int GetDropdownItem(const Window *w) darkvater@164: { peter1138@2448: byte item, counter; darkvater@164: int y; darkvater@164: darkvater@164: if (GetWidgetFromPos(w, _cursor.pos.x - w->left, _cursor.pos.y - w->top) < 0) darkvater@164: return -1; truelight@193: peter1138@5196: y = _cursor.pos.y - w->top - 2 + w->vscroll.pos * 10; darkvater@164: darkvater@164: if (y < 0) darkvater@164: return - 1; darkvater@164: darkvater@164: item = y / 10; peter1138@2683: if (item >= WP(w,dropdown_d).num_items || (HASBIT(WP(w,dropdown_d).disabled_state, item) && !HASBIT(WP(w,dropdown_d).hidden_state, item)) || WP(w,dropdown_d).items[item] == 0) darkvater@164: return - 1; darkvater@164: peter1138@2448: // Skip hidden items -- +1 for each hidden item before the clicked item. peter1138@2448: for (counter = 0; item >= counter; ++counter) peter1138@2683: if (HASBIT(WP(w,dropdown_d).hidden_state, counter)) item++; peter1138@2448: darkvater@164: return item; darkvater@164: } darkvater@164: tron@1095: static void DropdownMenuWndProc(Window *w, WindowEvent *e) darkvater@164: { darkvater@164: int item; darkvater@164: tron@2952: switch (e->event) { bjarni@842: case WE_PAINT: { bjarni@842: int x,y,i,sel; peter1138@5196: int width, height; darkvater@164: bjarni@842: DrawWindowWidgets(w); darkvater@164: bjarni@842: x = 1; peter1138@5196: y = 2 - w->vscroll.pos * 10; darkvater@164: peter1138@5196: sel = WP(w,dropdown_d).selected_index; peter1138@5196: width = w->widget[0].right - 3; peter1138@5196: height = w->widget[0].bottom - 3; darkvater@164: peter1138@5196: for (i = 0; WP(w,dropdown_d).items[i] != INVALID_STRING_ID; i++, sel--) { peter1138@5196: if (HASBIT(WP(w,dropdown_d).hidden_state, i)) continue; peter1138@5196: peter1138@5196: if (y >= 0 && y <= height) { peter1138@5196: if (WP(w,dropdown_d).items[i] != STR_NULL) { peter1138@5196: if (sel == 0) GfxFillRect(x + 1, y, x + width, y + 9, 0); peter1138@5196: DrawStringTruncated(x + 2, y, WP(w,dropdown_d).items[i], sel == 0 ? 12 : 16, x + width); peter1138@5196: peter1138@5196: if (HASBIT(WP(w,dropdown_d).disabled_state, i)) { peter1138@5196: GfxFillRect(x, y, x + width, y + 9, peter1138@5196: PALETTE_MODIFIER_GREYOUT | _colour_gradient[_dropdown_menu_widgets[0].color][5] peter1138@5196: ); peter1138@5196: } peter1138@5196: } else { peter1138@5196: int c1 = _colour_gradient[_dropdown_menu_widgets[0].color][3]; peter1138@5196: int c2 = _colour_gradient[_dropdown_menu_widgets[0].color][7]; peter1138@5196: peter1138@5196: GfxFillRect(x + 1, y + 3, x + w->width - 5, y + 3, c1); peter1138@5196: GfxFillRect(x + 1, y + 4, x + w->width - 5, y + 4, c2); bjarni@842: } bjarni@842: } bjarni@1177: y += 10; bjarni@842: } bjarni@842: } break; bjarni@842: bjarni@842: case WE_CLICK: { peter1138@5041: if (e->we.click.widget != 0) break; bjarni@842: item = GetDropdownItem(w); bjarni@842: if (item >= 0) { peter1138@2636: WP(w,dropdown_d).click_delay = 4; peter1138@2636: WP(w,dropdown_d).selected_index = item; bjarni@842: SetWindowDirty(w); bjarni@842: } bjarni@842: } break; bjarni@842: bjarni@842: case WE_MOUSELOOP: { peter1138@2636: Window *w2 = FindWindowById(WP(w,dropdown_d).parent_wnd_class, WP(w,dropdown_d).parent_wnd_num); bjarni@842: if (w2 == NULL) { bjarni@842: DeleteWindow(w); bjarni@842: return; darkvater@164: } darkvater@164: peter1138@2636: if (WP(w,dropdown_d).click_delay != 0 && --WP(w,dropdown_d).click_delay == 0) { bjarni@842: WindowEvent e; bjarni@842: e.event = WE_DROPDOWN_SELECT; belugas@4634: e.we.dropdown.button = WP(w,dropdown_d).parent_button; belugas@4634: e.we.dropdown.index = WP(w,dropdown_d).selected_index; bjarni@842: w2->wndproc(w2, &e); bjarni@842: DeleteWindow(w); bjarni@842: return; bjarni@842: } truelight@193: peter1138@2636: if (WP(w,dropdown_d).drag_mode) { bjarni@842: item = GetDropdownItem(w); bjarni@842: bjarni@842: if (!_left_button_clicked) { peter1138@2636: WP(w,dropdown_d).drag_mode = false; tron@2639: if (item < 0) return; peter1138@2636: WP(w,dropdown_d).click_delay = 2; bjarni@842: } else { tron@2639: if (item < 0) return; bjarni@842: } bjarni@842: peter1138@2636: WP(w,dropdown_d).selected_index = item; bjarni@842: SetWindowDirty(w); bjarni@842: } bjarni@842: } break; bjarni@842: bjarni@842: case WE_DESTROY: { peter1138@2636: Window *w2 = FindWindowById(WP(w,dropdown_d).parent_wnd_class, WP(w,dropdown_d).parent_wnd_num); bjarni@842: if (w2 != NULL) { belugas@4719: RaiseWindowWidget(w2, WP(w,dropdown_d).parent_button); peter1138@2636: InvalidateWidget(w2, WP(w,dropdown_d).parent_button); bjarni@842: } bjarni@842: } break; darkvater@164: } darkvater@164: } darkvater@164: peter1138@2448: void ShowDropDownMenu(Window *w, const StringID *strings, int selected, int button, uint32 disabled_mask, uint32 hidden_mask) darkvater@164: { truelight@867: int i; darkvater@164: const Widget *wi; darkvater@164: Window *w2; peter1138@5041: const Window *w3; belugas@4719: bool is_dropdown_menu_shown = IsWindowWidgetLowered(w, button); peter1138@5041: int top, height; peter1138@5041: int screen_top, screen_bottom; peter1138@5041: bool scroll = false; truelight@193: darkvater@164: DeleteWindowById(WC_DROPDOWN_MENU, 0); darkvater@164: belugas@4719: if (is_dropdown_menu_shown) return; darkvater@164: belugas@4719: LowerWindowWidget(w, button); darkvater@164: darkvater@164: InvalidateWidget(w, button); truelight@193: tron@2639: for (i = 0; strings[i] != INVALID_STRING_ID; i++) {} tron@2639: if (i == 0) return; darkvater@164: darkvater@164: wi = &w->widget[button]; darkvater@164: peter1138@2448: if (hidden_mask != 0) { tron@2639: uint j; tron@2639: peter1138@2636: for (j = 0; strings[j] != INVALID_STRING_ID; j++) { tron@2639: if (HASBIT(hidden_mask, j)) i--; bjarni@842: } bjarni@842: } bjarni@842: peter1138@5041: /* The preferred position is just below the dropdown calling widget */ peter1138@5041: top = w->top + wi->bottom + 2; peter1138@5041: height = i * 10 + 4; peter1138@5041: peter1138@5041: w3 = FindWindowById(WC_STATUS_BAR, 0); peter1138@5041: screen_bottom = w3 == NULL ? _screen.height : w3->top; peter1138@5041: peter1138@5041: /* Check if the dropdown will fully fit below the widget */ peter1138@5041: if (top + height >= screen_bottom) { peter1138@5041: w3 = FindWindowById(WC_MAIN_TOOLBAR, 0); peter1138@5041: screen_top = w3 == NULL ? 0 : w3->top + w3->height; peter1138@5041: peter1138@5041: /* If not, check if it will fit above the widget */ peter1138@5041: if (w->top + wi->top - height - 1 > screen_top) { peter1138@5041: top = w->top + wi->top - height - 1; peter1138@5041: } else { peter1138@5041: /* ... and lastly if it won't, enable the scroll bar and fit the peter1138@5041: * list in below the widget */ peter1138@5196: int rows = (screen_bottom - 4 - top) / 10; peter1138@5196: height = rows * 10 + 4; peter1138@5041: scroll = true; peter1138@5041: } peter1138@5041: } peter1138@5041: darkvater@164: w2 = AllocateWindow( darkvater@164: w->left + wi[-1].left + 1, peter1138@5041: top, truelight@867: wi->right - wi[-1].left + 1, peter1138@5041: height, darkvater@164: DropdownMenuWndProc, belugas@4573: WC_DROPDOWN_MENU, darkvater@164: _dropdown_menu_widgets); darkvater@164: truelight@867: w2->widget[0].color = wi->color; truelight@867: w2->widget[0].right = wi->right - wi[-1].left; peter1138@5041: w2->widget[0].bottom = height - 1; darkvater@164: peter1138@5041: SetWindowWidgetHiddenState(w2, 1, !scroll); peter1138@5041: peter1138@5041: if (scroll) { peter1138@5041: /* We're scrolling, so enable the scroll bar and shrink the list by peter1138@5041: * the scrollbar's width */ peter1138@5041: w2->widget[1].color = wi->color; peter1138@5041: w2->widget[1].right = w2->widget[0].right; peter1138@5041: w2->widget[1].left = w2->widget[1].right - 11; peter1138@5041: w2->widget[1].bottom = height - 1; peter1138@5041: w2->widget[0].right -= 12; peter1138@5041: peter1138@5196: w2->vscroll.cap = (height - 4) / 10; peter1138@5196: w2->vscroll.count = i; peter1138@5041: } peter1138@5041: peter1138@5041: w2->desc_flags = WDF_DEF_WIDGET; darkvater@164: w2->flags4 &= ~WF_WHITE_BORDER_MASK; peter1138@2629: peter1138@2683: WP(w2,dropdown_d).disabled_state = disabled_mask; peter1138@2683: WP(w2,dropdown_d).hidden_state = hidden_mask; peter1138@2636: peter1138@2636: WP(w2,dropdown_d).parent_wnd_class = w->window_class; peter1138@2636: WP(w2,dropdown_d).parent_wnd_num = w->window_number; peter1138@2636: WP(w2,dropdown_d).parent_button = button; peter1138@2636: peter1138@2636: WP(w2,dropdown_d).num_items = i; peter1138@2636: WP(w2,dropdown_d).selected_index = selected; peter1138@2636: WP(w2,dropdown_d).items = strings; peter1138@2636: peter1138@2636: WP(w2,dropdown_d).click_delay = 0; peter1138@2636: WP(w2,dropdown_d).drag_mode = true; darkvater@164: }