/* $Id$ */ #include "stdafx.h" #include "openttd.h" #include "functions.h" #include "player.h" #include "table/sprites.h" #include "table/strings.h" #include "window.h" #include "gfx.h" #include "viewport.h" static Point HandleScrollbarHittest(const Scrollbar *sb, int top, int bottom) { Point pt; int height, count, pos, cap; top += 10; bottom -= 9; height = (bottom - top); pos = sb->pos; count = sb->count; cap = sb->cap; if (count != 0) top += height * pos / count; if (cap > count) cap = count; if (count != 0) bottom -= (count - pos - cap) * height / count; pt.x = top; pt.y = bottom - 1; return pt; } /***************************************************** * Special handling for the scrollbar widget type. * Handles the special scrolling buttons and other * scrolling. * Parameters: * w - Window. * wi - Pointer to the scrollbar widget. * x - The X coordinate of the mouse click. * y - The Y coordinate of the mouse click. */ void ScrollbarClickHandler(Window *w, const Widget *wi, int x, int y) { int mi, ma, pos; Scrollbar *sb; switch (wi->type) { case WWT_SCROLLBAR: { // vertical scroller w->flags4 &= ~WF_HSCROLL; w->flags4 &= ~WF_SCROLL2; mi = wi->top; ma = wi->bottom; pos = y; sb = &w->vscroll; break; } case WWT_SCROLL2BAR: { // 2nd vertical scroller w->flags4 &= ~WF_HSCROLL; w->flags4 |= WF_SCROLL2; mi = wi->top; ma = wi->bottom; pos = y; sb = &w->vscroll2; break; } case WWT_HSCROLLBAR: { // horizontal scroller w->flags4 &= ~WF_SCROLL2; w->flags4 |= WF_HSCROLL; mi = wi->left; ma = wi->right; pos = x; sb = &w->hscroll; break; } default: return; //this should never happen } if (pos <= mi+9) { // Pressing the upper button? w->flags4 |= WF_SCROLL_UP; if (_scroller_click_timeout == 0) { _scroller_click_timeout = 6; if (sb->pos != 0) sb->pos--; } _left_button_clicked = false; } else if (pos >= ma-10) { // Pressing the lower button? w->flags4 |= WF_SCROLL_DOWN; if (_scroller_click_timeout == 0) { _scroller_click_timeout = 6; if ((byte)(sb->pos + sb->cap) < sb->count) sb->pos++; } _left_button_clicked = false; } else { // Point pt = HandleScrollbarHittest(sb, mi, ma); if (pos < pt.x) { sb->pos = max(sb->pos - sb->cap, 0); } else if (pos > pt.y) { sb->pos = min( sb->pos + sb->cap, max(sb->count - sb->cap, 0) ); } else { _scrollbar_start_pos = pt.x - mi - 9; _scrollbar_size = ma - mi - 23; w->flags4 |= WF_SCROLL_MIDDLE; _scrolling_scrollbar = true; _cursorpos_drag_start = _cursor.pos; } } SetWindowDirty(w); } /** Returns the index for the widget located at the given position * relative to the window. It includes all widget-corner pixels as well. * @param *w Window to look inside * @param x,y Window client coordinates * @return A widget index, or -1 if no widget was found. */ int GetWidgetFromPos(const Window *w, int x, int y) { const Widget *wi; int index, found_index = -1; // Go through the widgets and check if we find the widget that the coordinate is // inside. for (index = 0,wi = w->widget; wi->type != WWT_LAST; index++, wi++) { if (wi->type == WWT_EMPTY || wi->type == WWT_FRAME) continue; if (x >= wi->left && x <= wi->right && y >= wi->top && y <= wi->bottom && !IsWidgetHidden(wi)) { found_index = index; } } return found_index; } void DrawFrameRect(int left, int top, int right, int bottom, int ctab, FrameFlags flags) { uint dark = _colour_gradient[ctab][3]; uint medium_dark = _colour_gradient[ctab][5]; uint medium_light = _colour_gradient[ctab][6]; uint light = _colour_gradient[ctab][7]; if (flags & FR_TRANSPARENT) { GfxFillRect(left, top, right, bottom, 0x322 | USE_COLORTABLE); } else { uint interior; if (flags & FR_LOWERED) { GfxFillRect(left, top, left, bottom, dark); GfxFillRect(left + 1, top, right, top, dark); GfxFillRect(right, top + 1, right, bottom - 1, light); GfxFillRect(left + 1, bottom, right, bottom, light); interior = (flags & FR_DARKENED ? medium_dark : medium_light); } else { GfxFillRect(left, top, left, bottom - 1, light); GfxFillRect(left + 1, top, right - 1, top, light); GfxFillRect(right, top, right, bottom - 1, dark); GfxFillRect(left, bottom, right, bottom, dark); interior = medium_dark; } if (!(flags & FR_BORDERONLY)) { GfxFillRect(left + 1, top + 1, right - 1, bottom - 1, interior); } } } void DrawWindowWidgets(const Window *w) { const Widget *wi; const DrawPixelInfo* dpi = _cur_dpi; Rect r; int i = 0; wi = w->widget; do { bool clicked = IsWindowWidgetLowered((Window*)w, i); if (dpi->left > (r.right=/*w->left + */wi->right) || dpi->left + dpi->width <= (r.left=wi->left/* + w->left*/) || dpi->top > (r.bottom=/*w->top +*/ wi->bottom) || dpi->top + dpi->height <= (r.top = /*w->top +*/ wi->top) || IsWidgetHidden(wi)) { continue; } switch (wi->type & WWT_MASK) { case WWT_IMGBTN: case WWT_IMGBTN_2: { int img = wi->data; assert(img != 0); DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : 0); /* show different image when clicked for WWT_IMGBTN_2 */ if ((wi->type & WWT_MASK) == WWT_IMGBTN_2 && clicked) img++; DrawSprite(img, r.left + 1 + clicked, r.top + 1 + clicked); goto draw_default; } case WWT_PANEL: { assert(wi->data == 0); DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : 0); goto draw_default; } case WWT_TEXTBTN: case WWT_TEXTBTN_2: { DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : 0); } /* fall through */ case WWT_LABEL: { StringID str = wi->data; if ((wi->type & WWT_MASK) == WWT_TEXTBTN_2 && clicked) str++; DrawStringCentered(((r.left + r.right + 1) >> 1) + clicked, ((r.top + r.bottom + 1) >> 1) - 5 + clicked, str, 0); goto draw_default; } case WWT_INSET: { StringID str = wi->data; DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, FR_LOWERED | FR_DARKENED); if (str != STR_NULL) DrawStringTruncated(r.left + 2, r.top + 1, str, 0, r.right - r.left - 10); goto draw_default; } case WWT_MATRIX: { int c, d, ctr; int x, amt1, amt2; int color; DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : 0); c = GB(wi->data, 0, 8); amt1 = (wi->right - wi->left + 1) / c; d = GB(wi->data, 8, 8); amt2 = (wi->bottom - wi->top + 1) / d; color = _colour_gradient[wi->color & 0xF][6]; x = r.left; for (ctr = c; ctr > 1; ctr--) { x += amt1; GfxFillRect(x, r.top + 1, x, r.bottom - 1, color); } x = r.top; for (ctr = d; ctr > 1; ctr--) { x += amt2; GfxFillRect(r.left + 1, x, r.right - 1, x, color); } color = _colour_gradient[wi->color&0xF][4]; x = r.left - 1; for (ctr = c; ctr > 1; ctr--) { x += amt1; GfxFillRect(x, r.top + 1, x, r.bottom - 1, color); } x = r.top - 1; for (ctr = d; ctr > 1; ctr--) { x += amt2; GfxFillRect(r.left+1, x, r.right-1, x, color); } goto draw_default; } // vertical scrollbar case WWT_SCROLLBAR: { Point pt; int c1,c2; assert(r.right - r.left == 11); // XXX - to ensure the same sizes are used everywhere! // draw up/down buttons clicked = ((w->flags4 & (WF_SCROLL_UP | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_UP); DrawFrameRect(r.left, r.top, r.right, r.top + 9, wi->color, (clicked) ? FR_LOWERED : 0); DoDrawString(UPARROW, r.left + 2 + clicked, r.top + clicked, 0x10); clicked = (((w->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_DOWN)); DrawFrameRect(r.left, r.bottom - 9, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : 0); DoDrawString(DOWNARROW, r.left + 2 + clicked, r.bottom - 9 + clicked, 0x10); c1 = _colour_gradient[wi->color&0xF][3]; c2 = _colour_gradient[wi->color&0xF][7]; // 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 | PALETTE_MODIFIER_GREYOUT); // 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); pt = HandleScrollbarHittest(&w->vscroll, r.top, r.bottom); 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); break; } case WWT_SCROLL2BAR: { Point pt; int c1,c2; assert(r.right - r.left == 11); // XXX - to ensure the same sizes are used everywhere! // draw up/down buttons clicked = ((w->flags4 & (WF_SCROLL_UP | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_UP | WF_SCROLL2)); DrawFrameRect(r.left, r.top, r.right, r.top + 9, wi->color, (clicked) ? FR_LOWERED : 0); DoDrawString(UPARROW, r.left + 2 + clicked, r.top + clicked, 0x10); clicked = ((w->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_DOWN | WF_SCROLL2)); DrawFrameRect(r.left, r.bottom - 9, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : 0); DoDrawString(DOWNARROW, r.left + 2 + clicked, r.bottom - 9 + clicked, 0x10); c1 = _colour_gradient[wi->color&0xF][3]; c2 = _colour_gradient[wi->color&0xF][7]; // 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 | PALETTE_MODIFIER_GREYOUT); // 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); pt = HandleScrollbarHittest(&w->vscroll2, r.top, r.bottom); 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); break; } // horizontal scrollbar case WWT_HSCROLLBAR: { Point pt; int c1,c2; assert(r.bottom - r.top == 11); // XXX - to ensure the same sizes are used everywhere! clicked = ((w->flags4 & (WF_SCROLL_UP | WF_HSCROLL)) == (WF_SCROLL_UP | WF_HSCROLL)); DrawFrameRect(r.left, r.top, r.left + 9, r.bottom, wi->color, (clicked) ? FR_LOWERED : 0); DrawSprite(SPR_ARROW_LEFT, r.left + 1 + clicked, r.top + 1 + clicked); clicked = ((w->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL)) == (WF_SCROLL_DOWN | WF_HSCROLL)); DrawFrameRect(r.right-9, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : 0); DrawSprite(SPR_ARROW_RIGHT, r.right - 8 + clicked, r.top + 1 + clicked); c1 = _colour_gradient[wi->color&0xF][3]; c2 = _colour_gradient[wi->color&0xF][7]; // 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 | PALETTE_MODIFIER_GREYOUT); // 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); // draw actual scrollbar pt = HandleScrollbarHittest(&w->hscroll, r.left, r.right); 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); break; } case WWT_FRAME: { int c1,c2; int x2 = r.left; // by default the left side is the left side of the widget if (wi->data != 0) x2 = DrawString(r.left + 6, r.top, wi->data, 0); c1 = _colour_gradient[wi->color][3]; c2 = _colour_gradient[wi->color][7]; //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); // 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); // 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); //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); GfxFillRect(r.left+1, r.bottom-1, r.right-1, r.bottom-1, c1); GfxFillRect(r.left, r.bottom, r.right, r.bottom, c2); goto draw_default; } case WWT_STICKYBOX: { assert(r.right - r.left == 11); // XXX - to ensure the same sizes are used everywhere! clicked = !!(w->flags4 & WF_STICKY); DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : 0); DrawSprite((clicked) ? SPR_PIN_UP : SPR_PIN_DOWN, r.left + 2 + clicked, r.top + 3 + clicked); break; } case WWT_RESIZEBOX: { assert(r.right - r.left == 11); // XXX - to ensure the same sizes are used everywhere! clicked = !!(w->flags4 & WF_SIZING); DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : 0); DrawSprite(SPR_WINDOW_RESIZE, r.left + 3 + clicked, r.top + 3 + clicked); break; } case WWT_CLOSEBOX: { assert(r.right - r.left == 10); // ensure the same sizes are used everywhere DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, 0); DrawString(r.left + 2, r.top + 2, STR_00C5, 0); break; } case WWT_CAPTION: { assert(r.bottom - r.top == 13); // XXX - to ensure the same sizes are used everywhere! DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, FR_BORDERONLY); 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); if (w->caption_color != 0xFF) { GfxFillRect(r.left+2, r.top+2, r.right-2, r.bottom-2, _colour_gradient[_player_colors[w->caption_color]][4]); } DrawStringCenteredTruncated(r.left + 2, r.right - 2, r.top+2, wi->data, 0x84); draw_default:; if (IsWidgetDisabled(wi)) { GfxFillRect(r.left+1, r.top+1, r.right-1, r.bottom-1, _colour_gradient[wi->color&0xF][2] | PALETTE_MODIFIER_GREYOUT); } } } } while (i++, (++wi)->type != WWT_LAST); if (w->flags4 & WF_WHITE_BORDER_MASK) { //DrawFrameRect(w->left, w->top, w->left + w->width-1, w->top+w->height-1, 0xF, 0x10); DrawFrameRect(0, 0, w->width-1, w->height-1, 0xF, FR_BORDERONLY); } } static const Widget _dropdown_menu_widgets[] = { { WWT_PANEL, RESIZE_NONE, 0, 0, 0, 0, 0, 0x0, STR_NULL}, { WWT_SCROLLBAR, RESIZE_NONE, 0, 0, 0, 0, 0, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, { WIDGETS_END}, }; static int GetDropdownItem(const Window *w) { byte item, counter; int y; if (GetWidgetFromPos(w, _cursor.pos.x - w->left, _cursor.pos.y - w->top) < 0) return -1; y = _cursor.pos.y - w->top - 2 + w->vscroll.pos * 10; if (y < 0) return - 1; item = y / 10; 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) return - 1; // Skip hidden items -- +1 for each hidden item before the clicked item. for (counter = 0; item >= counter; ++counter) if (HASBIT(WP(w,dropdown_d).hidden_state, counter)) item++; return item; } static void DropdownMenuWndProc(Window *w, WindowEvent *e) { int item; switch (e->event) { case WE_PAINT: { int x,y,i,sel; int width, height; DrawWindowWidgets(w); x = 1; y = 2 - w->vscroll.pos * 10; sel = WP(w,dropdown_d).selected_index; width = w->widget[0].right - 3; height = w->widget[0].bottom - 3; for (i = 0; WP(w,dropdown_d).items[i] != INVALID_STRING_ID; i++, sel--) { if (HASBIT(WP(w,dropdown_d).hidden_state, i)) continue; if (y >= 0 && y <= height) { if (WP(w,dropdown_d).items[i] != STR_NULL) { if (sel == 0) GfxFillRect(x + 1, y, x + width, y + 9, 0); DrawStringTruncated(x + 2, y, WP(w,dropdown_d).items[i], sel == 0 ? 12 : 16, x + width); if (HASBIT(WP(w,dropdown_d).disabled_state, i)) { GfxFillRect(x, y, x + width, y + 9, PALETTE_MODIFIER_GREYOUT | _colour_gradient[_dropdown_menu_widgets[0].color][5] ); } } else { int c1 = _colour_gradient[_dropdown_menu_widgets[0].color][3]; int c2 = _colour_gradient[_dropdown_menu_widgets[0].color][7]; GfxFillRect(x + 1, y + 3, x + w->width - 5, y + 3, c1); GfxFillRect(x + 1, y + 4, x + w->width - 5, y + 4, c2); } } y += 10; } } break; case WE_CLICK: { if (e->we.click.widget != 0) break; item = GetDropdownItem(w); if (item >= 0) { WP(w,dropdown_d).click_delay = 4; WP(w,dropdown_d).selected_index = item; SetWindowDirty(w); } } break; case WE_MOUSELOOP: { Window *w2 = FindWindowById(WP(w,dropdown_d).parent_wnd_class, WP(w,dropdown_d).parent_wnd_num); if (w2 == NULL) { DeleteWindow(w); return; } if (WP(w,dropdown_d).click_delay != 0 && --WP(w,dropdown_d).click_delay == 0) { WindowEvent e; e.event = WE_DROPDOWN_SELECT; e.we.dropdown.button = WP(w,dropdown_d).parent_button; e.we.dropdown.index = WP(w,dropdown_d).selected_index; w2->wndproc(w2, &e); DeleteWindow(w); return; } if (WP(w,dropdown_d).drag_mode) { item = GetDropdownItem(w); if (!_left_button_clicked) { WP(w,dropdown_d).drag_mode = false; if (item < 0) return; WP(w,dropdown_d).click_delay = 2; } else { if (item < 0) return; } WP(w,dropdown_d).selected_index = item; SetWindowDirty(w); } } break; case WE_DESTROY: { Window *w2 = FindWindowById(WP(w,dropdown_d).parent_wnd_class, WP(w,dropdown_d).parent_wnd_num); if (w2 != NULL) { RaiseWindowWidget(w2, WP(w,dropdown_d).parent_button); InvalidateWidget(w2, WP(w,dropdown_d).parent_button); } } break; } } void ShowDropDownMenu(Window *w, const StringID *strings, int selected, int button, uint32 disabled_mask, uint32 hidden_mask) { int i; const Widget *wi; Window *w2; const Window *w3; bool is_dropdown_menu_shown = IsWindowWidgetLowered(w, button); int top, height; int screen_top, screen_bottom; bool scroll = false; DeleteWindowById(WC_DROPDOWN_MENU, 0); if (is_dropdown_menu_shown) return; LowerWindowWidget(w, button); InvalidateWidget(w, button); for (i = 0; strings[i] != INVALID_STRING_ID; i++) {} if (i == 0) return; wi = &w->widget[button]; if (hidden_mask != 0) { uint j; for (j = 0; strings[j] != INVALID_STRING_ID; j++) { if (HASBIT(hidden_mask, j)) i--; } } /* The preferred position is just below the dropdown calling widget */ top = w->top + wi->bottom + 2; height = i * 10 + 4; w3 = FindWindowById(WC_STATUS_BAR, 0); screen_bottom = w3 == NULL ? _screen.height : w3->top; /* Check if the dropdown will fully fit below the widget */ if (top + height >= screen_bottom) { w3 = FindWindowById(WC_MAIN_TOOLBAR, 0); screen_top = w3 == NULL ? 0 : w3->top + w3->height; /* If not, check if it will fit above the widget */ if (w->top + wi->top - height - 1 > screen_top) { top = w->top + wi->top - height - 1; } else { /* ... and lastly if it won't, enable the scroll bar and fit the * list in below the widget */ int rows = (screen_bottom - 4 - top) / 10; height = rows * 10 + 4; scroll = true; } } w2 = AllocateWindow( w->left + wi[-1].left + 1, top, wi->right - wi[-1].left + 1, height, DropdownMenuWndProc, WC_DROPDOWN_MENU, _dropdown_menu_widgets); w2->widget[0].color = wi->color; w2->widget[0].right = wi->right - wi[-1].left; w2->widget[0].bottom = height - 1; SetWindowWidgetHiddenState(w2, 1, !scroll); if (scroll) { /* We're scrolling, so enable the scroll bar and shrink the list by * the scrollbar's width */ w2->widget[1].color = wi->color; w2->widget[1].right = w2->widget[0].right; w2->widget[1].left = w2->widget[1].right - 11; w2->widget[1].bottom = height - 1; w2->widget[0].right -= 12; w2->vscroll.cap = (height - 4) / 10; w2->vscroll.count = i; } w2->desc_flags = WDF_DEF_WIDGET; w2->flags4 &= ~WF_WHITE_BORDER_MASK; WP(w2,dropdown_d).disabled_state = disabled_mask; WP(w2,dropdown_d).hidden_state = hidden_mask; WP(w2,dropdown_d).parent_wnd_class = w->window_class; WP(w2,dropdown_d).parent_wnd_num = w->window_number; WP(w2,dropdown_d).parent_button = button; WP(w2,dropdown_d).num_items = i; WP(w2,dropdown_d).selected_index = selected; WP(w2,dropdown_d).items = strings; WP(w2,dropdown_d).click_delay = 0; WP(w2,dropdown_d).drag_mode = true; }