(svn r17575) -Codechange: Adding a new combined button+dropdown widget.

This commit is contained in:
alberth 2009-09-19 13:08:37 +00:00
parent 86395277d3
commit 8d7498b82c
3 changed files with 86 additions and 16 deletions

View File

@ -562,21 +562,43 @@ static inline void DrawCaption(const Rect &r, Colours colour, Owner owner, Strin
if (str != STR_NULL) DrawString(r.left + WD_CAPTIONTEXT_LEFT, r.right - WD_CAPTIONTEXT_RIGHT, r.top + WD_CAPTIONTEXT_TOP, str, TC_FROMSTRING, SA_CENTER);
}
static inline void DrawDropdown(const Rect &r, Colours colour, bool clicked, StringID str)
/**
* Draw a button with a dropdown (#WWT_DROPDOWN and #NWID_BUTTON_DRPDOWN).
* @param r Rectangle containing the widget.
* @param colour Background colour of the widget.
* @param clicked_button The button-part is lowered.
* @param clicked_dropdown The drop-down part is lowered.
* @param str Text of the button.
*
* @note Magic constants are also used in #NWidgetLeaf::ButtonHit.
*/
static inline void DrawButtonDropdown(const Rect &r, Colours colour, bool clicked_button, bool clicked_dropdown, StringID str)
{
if (_dynlang.text_dir == TD_LTR) {
DrawFrameRect(r.left, r.top, r.right - 12, r.bottom, colour, FR_NONE);
DrawFrameRect(r.right - 11, r.top, r.right, r.bottom, colour, clicked ? FR_LOWERED : FR_NONE);
DrawString(r.right - (clicked ? 10 : 11), r.right, r.top + (clicked ? 2 : 1), STR_BLACK_ARROW_DOWN, TC_FROMSTRING, SA_CENTER);
if (str != STR_NULL) DrawString(r.left + WD_DROPDOWNTEXT_LEFT, r.right - WD_DROPDOWNTEXT_RIGHT, r.top + WD_DROPDOWNTEXT_TOP, str, TC_BLACK);
DrawFrameRect(r.left, r.top, r.right - 12, r.bottom, colour, clicked_button ? FR_LOWERED : FR_NONE);
DrawFrameRect(r.right - 11, r.top, r.right, r.bottom, colour, clicked_dropdown ? FR_LOWERED : FR_NONE);
DrawString(r.right - (clicked_dropdown ? 10 : 11), r.right, r.top + (clicked_dropdown ? 2 : 1), STR_BLACK_ARROW_DOWN, TC_FROMSTRING, SA_CENTER);
if (str != STR_NULL) DrawString(r.left + WD_DROPDOWNTEXT_LEFT + clicked_button, r.right - WD_DROPDOWNTEXT_RIGHT + clicked_button, r.top + WD_DROPDOWNTEXT_TOP + clicked_button, str, TC_BLACK);
} else {
DrawFrameRect(r.left + 12, r.top, r.right, r.bottom, colour, FR_NONE);
DrawFrameRect(r.left, r.top, r.left + 11, r.bottom, colour, clicked ? FR_LOWERED : FR_NONE);
DrawString(r.left + clicked, r.left + 11, r.top + (clicked ? 2 : 1), STR_BLACK_ARROW_DOWN, TC_FROMSTRING, SA_CENTER);
if (str != STR_NULL) DrawString(r.left + WD_DROPDOWNTEXT_RIGHT, r.right - WD_DROPDOWNTEXT_LEFT, r.top + WD_DROPDOWNTEXT_TOP, str, TC_BLACK);
DrawFrameRect(r.left + 12, r.top, r.right, r.bottom, colour, clicked_button ? FR_LOWERED : FR_NONE);
DrawFrameRect(r.left, r.top, r.left + 11, r.bottom, colour, clicked_dropdown ? FR_LOWERED : FR_NONE);
DrawString(r.left + clicked_dropdown, r.left + 11, r.top + (clicked_dropdown ? 2 : 1), STR_BLACK_ARROW_DOWN, TC_FROMSTRING, SA_CENTER);
if (str != STR_NULL) DrawString(r.left + WD_DROPDOWNTEXT_RIGHT + clicked_button, r.right - WD_DROPDOWNTEXT_LEFT + clicked_button, r.top + WD_DROPDOWNTEXT_TOP + clicked_button, str, TC_BLACK);
}
}
/**
* Draw a dropdown #WWT_DROPDOWN widget.
* @param r Rectangle containing the widget.
* @param colour Background colour of the widget.
* @param clicked The widget is lowered.
* @param str Text of the button.
*/
static inline void DrawDropdown(const Rect &r, Colours colour, bool clicked, StringID str)
{
DrawButtonDropdown(r, colour, false, clicked, str);
}
/**
* Paint all widgets of a window.
*/
@ -2003,6 +2025,7 @@ NWidgetLeaf::NWidgetLeaf(WidgetType tp, Colours colour, int index, uint16 data,
case WWT_TEXT:
case WWT_MATRIX:
case WWT_EDITBOX:
case NWID_BUTTON_DRPDOWN:
this->SetFill(false, false);
break;
@ -2177,7 +2200,8 @@ void NWidgetLeaf::SetupSmallestSize(Window *w, bool init_array)
size = maxdim(size, d2);
break;
}
case WWT_DROPDOWN: {
case WWT_DROPDOWN:
case NWID_BUTTON_DRPDOWN: {
static const Dimension extra = {WD_DROPDOWNTEXT_LEFT + WD_DROPDOWNTEXT_RIGHT, WD_DROPDOWNTEXT_TOP + WD_DROPDOWNTEXT_BOTTOM};
padding = &extra;
if (this->index >= 0) w->SetStringParameters(this->index);
@ -2300,6 +2324,11 @@ void NWidgetLeaf::Draw(const Window *w)
DrawDropdown(r, this->colour, clicked, this->widget_data);
break;
case NWID_BUTTON_DRPDOWN:
if (this->index >= 0) w->SetStringParameters(this->index);
DrawButtonDropdown(r, this->colour, clicked, (this->disp_flags & ND_DROPDOWN_ACTIVE) != 0, this->widget_data);
break;
default:
NOT_REACHED();
}
@ -2322,6 +2351,24 @@ Scrollbar *NWidgetLeaf::FindScrollbar(Window *w, bool allow_next)
return NULL;
}
/**
* For a #NWID_BUTTON_DRPDOWN, test whether \a pt refers to the button or to the drop-down.
* @param pt Point in the widget.
* @return The point refers to the button.
*
* @param The magic constants are also used at #DrawButtonDropdown.
*/
bool NWidgetLeaf::ButtonHit(const Point &pt)
{
if (_dynlang.text_dir == TD_LTR) {
int button_width = this->pos_x + this->current_x - 12;
return pt.x < button_width;
} else {
int button_left = this->pos_x + 12;
return pt.x >= button_left;
}
}
/**
* Intialize nested widget tree and convert to widget array.
* @param nwid Nested widget tree.
@ -2545,7 +2592,7 @@ static int MakeNWidget(const NWidgetPart *parts, int count, NWidgetBase **dest,
default:
if (*dest != NULL) return num_used;
assert((parts->type & WWT_MASK) < WWT_LAST);
assert((parts->type & WWT_MASK) < WWT_LAST || parts->type == NWID_BUTTON_DRPDOWN);
*dest = new NWidgetLeaf(parts->type, parts->u.widget.colour, parts->u.widget.index, 0x0, STR_NULL);
*biggest_index = max(*biggest_index, (int)parts->u.widget.index);
break;

View File

@ -121,6 +121,7 @@ enum WidgetType {
NWID_SELECTION, ///< Stacked widgets, only one visible at a time (eg in a panel with tabs).
NWID_LAYERED, ///< Widgets layered on top of each other, all visible at the same time.
NWID_VIEWPORT, ///< Nested widget containing a viewport.
NWID_BUTTON_DRPDOWN, ///< Button with a drop-down.
/* Nested widget part types. */
WPT_RESIZE, ///< Widget part for specifying resizing.
@ -278,17 +279,22 @@ public:
/** Nested widget flags that affect display and interaction withe 'real' widgets. */
enum NWidgetDisplay {
/* Generic. */
NDB_LOWERED = 0, ///< Widget is lowered (pressed down) bit.
NDB_DISABLED = 1, ///< Widget is disabled (greyed out) bit.
/* Viewport widget. */
NDB_NO_TRANSPARENCY = 2, ///< Viewport is never transparent.
NDB_SHADE_GREY = 3, ///< Shade viewport to grey-scale.
NDB_SHADE_DIMMED = 4, ///< Display dimmed colours in the viewport.
/* Button dropdown widget. */
NDB_DROPDOWN_ACTIVE = 5, ///< Dropdown menu of the button dropdown widget is active. @see #NWID_BUTTON_DRPDOWN
ND_LOWERED = 1 << NDB_LOWERED, ///< Bit value of the lowered flag.
ND_DISABLED = 1 << NDB_DISABLED, ///< Bit value of the disabled flag.
ND_NO_TRANSPARENCY = 1 << NDB_NO_TRANSPARENCY, ///< Bit value of the 'no transparency' flag.
ND_SHADE_GREY = 1 << NDB_SHADE_GREY, ///< Bit value of the 'shade to grey' flag.
ND_SHADE_DIMMED = 1 << NDB_SHADE_DIMMED, ///< Bit value of the 'dimmed colours' flag.
ND_DROPDOWN_ACTIVE = 1 << NDB_DROPDOWN_ACTIVE, ///< Bit value of the 'dropdown active' flag.
};
DECLARE_ENUM_AS_BIT_SET(NWidgetDisplay);
@ -526,6 +532,8 @@ public:
/* virtual */ void Draw(const Window *w);
/* virtual */ Scrollbar *FindScrollbar(Window *w, bool allow_next = true);
bool ButtonHit(const Point &pt);
static void InvalidateDimensionCache();
private:
static Dimension stickybox_dimension; ///< Cached size of a stickybox widget.

View File

@ -103,7 +103,16 @@ struct DropdownWindow : Window {
{
Window *w2 = FindWindowById(this->parent_wnd_class, this->parent_wnd_num);
if (w2 != NULL) {
w2->RaiseWidget(this->parent_button);
if (w2->nested_array != NULL) {
NWidgetCore *nwi2 = w2->GetWidget<NWidgetCore>(this->parent_button);
if (nwi2->type == NWID_BUTTON_DRPDOWN) {
nwi2->disp_flags &= ~ND_DROPDOWN_ACTIVE;
} else {
w2->RaiseWidget(this->parent_button);
}
} else {
w2->RaiseWidget(this->parent_button);
}
w2->SetWidgetDirty(this->parent_button);
}
@ -251,20 +260,23 @@ void ShowDropDownList(Window *w, DropDownList *list, int selected, int button, u
DeleteWindowById(WC_DROPDOWN_MENU, 0);
w->LowerWidget(button);
w->SetWidgetDirty(button);
/* Our parent's button widget is used to determine where to place the drop
* down list window. */
Rect wi_rect;
Colours wi_colour;
if (w->nested_array != NULL) {
const NWidgetCore *nwi = w->GetWidget<NWidgetCore>(button);
NWidgetCore *nwi = w->GetWidget<NWidgetCore>(button);
wi_rect.left = nwi->pos_x;
wi_rect.right = nwi->pos_x + nwi->current_x - 1;
wi_rect.top = nwi->pos_y;
wi_rect.bottom = nwi->pos_y + nwi->current_y - 1;
wi_colour = nwi->colour;
if (nwi->type == NWID_BUTTON_DRPDOWN) {
nwi->disp_flags |= ND_DROPDOWN_ACTIVE;
} else {
w->LowerWidget(button);
}
} else {
const Widget *wi = &w->widget[button];
wi_rect.left = wi->left;
@ -272,7 +284,10 @@ void ShowDropDownList(Window *w, DropDownList *list, int selected, int button, u
wi_rect.top = wi->top;
wi_rect.bottom = wi->bottom;
wi_colour = wi->colour;
w->LowerWidget(button);
}
w->SetWidgetDirty(button);
/* The preferred position is just below the dropdown calling widget */
int top = w->top + wi_rect.bottom + 1;