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: { truelight@0: const Widget *wi; truelight@0: int index, 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. Darkvater@2021: for (index = 0,wi = w->widget; wi->type != WWT_LAST; index++, wi++) { 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 && belugas@4749: !IsWidgetHidden(wi)) { 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: { truelight@0: const Widget *wi; tron@2548: const DrawPixelInfo* dpi = _cur_dpi; truelight@0: Rect r; belugas@4719: int i = 0; truelight@193: truelight@0: wi = w->widget; truelight@0: truelight@0: do { belugas@4719: bool clicked = IsWindowWidgetLowered((Window*)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) || belugas@4749: IsWidgetHidden(wi)) { tron@2639: continue; tron@2639: } truelight@0: Darkvater@1657: switch (wi->type & WWT_MASK) { Darkvater@1657: case WWT_PANEL: /* WWT_IMGBTN */ truelight@0: case WWT_PANEL_2: { Darkvater@4547: int img = wi->data; truelight@0: hackykid@1938: DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : 0); truelight@0: tron@2639: if (img != 0) { // has an image tron@2639: // show diff image when clicked tron@2639: if ((wi->type & WWT_MASK) == WWT_PANEL_2 && clicked) img++; Darkvater@1657: Darkvater@1657: DrawSprite(img, r.left + 1 + clicked, r.top + 1 + clicked); truelight@0: } truelight@0: goto draw_default; truelight@0: } truelight@0: peter1138@2757: case WWT_TEXTBTN: /* WWT_TEXTBTN */ truelight@0: case WWT_4: { 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@1657: if ((wi->type&WWT_MASK) == WWT_4 && clicked) str++; truelight@193: Darkvater@1657: DrawStringCentered(((r.left + r.right + 1) >> 1) + clicked, ((r.top + r.bottom + 1) >> 1) - 5 + clicked, str, 0); Darkvater@1657: //DrawStringCentered((r.left + r.right+1)>>1, ((r.top+r.bottom + 1)>>1) - 5, str, 0); ludde@2064: goto draw_default; truelight@0: } truelight@0: truelight@0: case WWT_6: { 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@1657: 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@1657: 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@1657: 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@1657: 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@1657: 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@1657: 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: Darkvater@4547: DrawStringCentered( (r.left+r.right+1)>>1, r.top+2, wi->data, 0x84); truelight@0: draw_default:; belugas@4749: if (IsWidgetDisabled(wi)) { 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: } belugas@4749: } while (i++, (++wi)->type != WWT_LAST); 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[] = { truelight@867: { WWT_IMGBTN, RESIZE_NONE, 0, 0, 0, 0, 0, 0x0, STR_NULL}, 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: darkvater@164: y = _cursor.pos.y - w->top - 2; 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; darkvater@164: bjarni@842: DrawWindowWidgets(w); darkvater@164: bjarni@842: x = 1; bjarni@842: y = 2; peter1138@2636: sel = WP(w,dropdown_d).selected_index; darkvater@164: peter1138@2636: for (i = 0; WP(w,dropdown_d).items[i] != INVALID_STRING_ID; i++) { peter1138@2683: if (HASBIT(WP(w,dropdown_d).hidden_state, i)) { bjarni@1177: sel--; bjarni@1177: continue; bjarni@1177: } belugas@4573: if (WP(w,dropdown_d).items[i] != STR_NULL) { tron@2639: if (sel == 0) GfxFillRect(x + 1, y, x + w->width - 4, y + 9, 0); peter1138@3762: DrawStringTruncated(x + 2, y, WP(w,dropdown_d).items[i], sel == 0 ? 12 : 16, w->width - 4); darkvater@164: peter1138@2683: if (HASBIT(WP(w,dropdown_d).disabled_state, i)) { tron@2639: GfxFillRect(x, y, x + w->width - 3, y + 9, tron@4444: PALETTE_MODIFIER_GREYOUT | _colour_gradient[_dropdown_menu_widgets[0].color][5] tron@2639: ); bjarni@842: } bjarni@1177: } else { tron@4444: int c1 = _colour_gradient[_dropdown_menu_widgets[0].color][3]; tron@4444: int c2 = _colour_gradient[_dropdown_menu_widgets[0].color][7]; tron@2639: tron@2639: GfxFillRect(x + 1, y + 3, x + w->width - 5, y + 3, c1); tron@2639: GfxFillRect(x + 1, y + 4, x + w->width - 5, y + 4, c2); bjarni@842: } bjarni@1177: y += 10; bjarni@1177: sel--; bjarni@842: } bjarni@842: } break; bjarni@842: bjarni@842: case WE_CLICK: { 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: { darkvater@164: WindowNumber num; darkvater@164: WindowClass cls; truelight@867: int i; darkvater@164: const Widget *wi; darkvater@164: Window *w2; belugas@4719: bool is_dropdown_menu_shown = IsWindowWidgetLowered(w, button); truelight@193: darkvater@164: cls = w->window_class; darkvater@164: num = w->window_number; darkvater@164: DeleteWindowById(WC_DROPDOWN_MENU, 0); darkvater@164: w = FindWindowById(cls, num); 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: darkvater@164: w2 = AllocateWindow( darkvater@164: w->left + wi[-1].left + 1, darkvater@164: w->top + wi->bottom + 2, truelight@867: wi->right - wi[-1].left + 1, truelight@867: i * 10 + 4, 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; truelight@867: w2->widget[0].bottom = i * 10 + 3; darkvater@164: 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: }