Changeset - r8284:d769847bf11d
[Not reviewed]
master
0 14 3
peter1138 - 17 years ago 2008-01-14 16:10:58
peter1138@openttd.org
(svn r11848) -Codechange: New class-based drop down list functionality. Lists are now dynamically generated, and can include parameters, or be extended however needed.
17 files changed with 379 insertions and 252 deletions:
0 comments (0 inline, 0 general)
source.list
Show inline comments
 
@@ -84,24 +84,25 @@ tile_map.cpp
 
	#else
 
		#if OS2
 
			os2.cpp
 
		#else
 
			unix.cpp
 
		#end
 
	#end
 
#end
 
vehicle.cpp
 
viewport.cpp
 
waypoint.cpp
 
widget.cpp
 
widgets/dropdown.cpp
 
#if WIN32
 
	win32.cpp
 
#end
 
window.cpp
 

	
 
# Header Files
 
aircraft.h
 
airport.h
 
airport_movement.h
 
articulated_vehicles.h
 
autoslope.h
 
aystar.h
 
@@ -201,24 +202,25 @@ town.h
 
train.h
 
transparency.h
 
transparency_gui.h
 
variables.h
 
vehicle.h
 
vehicle_gui.h
 
viewport.h
 
waypoint.h
 
music/win32_m.h
 
sound/win32_s.h
 
video/win32_v.h
 
window.h
 
widgets/dropdown.h
 
zoom.hpp
 

	
 
# GUI Source Code
 
aircraft_gui.cpp
 
airport_gui.cpp
 
autoreplace_gui.cpp
 
bridge_gui.cpp
 
build_vehicle_gui.cpp
 
depot_gui.cpp
 
dock_gui.cpp
 
engine_gui.cpp
 
genworld_gui.cpp
src/autoreplace_gui.cpp
Show inline comments
 
@@ -9,24 +9,25 @@
 
#include "command_func.h"
 
#include "variables.h"
 
#include "vehicle_gui.h"
 
#include "newgrf_engine.h"
 
#include "group.h"
 
#include "rail.h"
 
#include "strings_func.h"
 
#include "window_func.h"
 
#include "vehicle_func.h"
 
#include "autoreplace_func.h"
 
#include "gfx_func.h"
 
#include "player_func.h"
 
#include "widgets/dropdown_func.h"
 

	
 
#include "table/sprites.h"
 
#include "table/strings.h"
 

	
 
static RailType _railtype_selected_in_replace_gui;
 

	
 
static bool _rebuild_left_list;
 
static bool _rebuild_right_list;
 

	
 
static const StringID _rail_types_list[] = {
 
	STR_RAIL_VEHICLES,
 
	STR_ELRAIL_VEHICLES,
src/build_vehicle_gui.cpp
Show inline comments
 
@@ -20,24 +20,25 @@
 
#include "airport.h"
 
#include "vehicle_gui.h"
 
#include "newgrf_engine.h"
 
#include "cargotype.h"
 
#include "group.h"
 
#include "road_map.h"
 
#include "strings_func.h"
 
#include "window_func.h"
 
#include "date_func.h"
 
#include "vehicle_func.h"
 
#include "settings_type.h"
 
#include "gfx_func.h"
 
#include "widgets/dropdown_func.h"
 

	
 
#include "table/sprites.h"
 
#include "table/strings.h"
 

	
 
struct buildvehicle_d {
 
	VehicleType vehicle_type;
 
	union {
 
		RailTypeByte railtype;
 
		AirportFTAClass::Flags flags;
 
		RoadTypes roadtypes;
 
	} filter;
 
	byte sel_index;  ///< deprecated value, used for 'unified' ship and road
src/genworld_gui.cpp
Show inline comments
 
@@ -16,24 +16,25 @@
 
#include "genworld.h"
 
#include "network/network.h"
 
#include "thread.h"
 
#include "newgrf_config.h"
 
#include "strings_func.h"
 
#include "window_func.h"
 
#include "date_func.h"
 
#include "sound_func.h"
 
#include "fios.h"
 
#include "string_func.h"
 
#include "gfx_func.h"
 
#include "settings_type.h"
 
#include "widgets/dropdown_func.h"
 

	
 
#include "table/strings.h"
 
#include "table/sprites.h"
 

	
 
/**
 
 * In what 'mode' the GenerateLandscapeWindowProc is.
 
 */
 
enum glwp_modes {
 
	GLWP_GENERATE,
 
	GLWP_HEIGHTMAP,
 
	GLWP_SCENARIO,
 
	GLWP_END
src/group_gui.cpp
Show inline comments
 
@@ -14,24 +14,25 @@
 
#include "train.h"
 
#include "group.h"
 
#include "debug.h"
 
#include "strings_func.h"
 
#include "core/alloc_func.hpp"
 
#include "window_func.h"
 
#include "vehicle_func.h"
 
#include "autoreplace_gui.h"
 
#include "string_func.h"
 
#include "viewport_func.h"
 
#include "gfx_func.h"
 
#include "player_func.h"
 
#include "widgets/dropdown_func.h"
 

	
 
#include "table/strings.h"
 
#include "table/sprites.h"
 

	
 
struct Sorting {
 
	Listing aircraft;
 
	Listing roadveh;
 
	Listing ship;
 
	Listing train;
 
};
 

	
 
static Sorting _sorting;
 
@@ -319,32 +320,25 @@ static void GroupWndProc(Window *w, Wind
 
			SortVehicleList(gv);
 

	
 

	
 
			BuildGroupList(gl, owner, gv->vehicle_type);
 
			SortGroupList(gl);
 

	
 
			SetVScrollCount(w, gl->l.list_length);
 
			SetVScroll2Count(w, gv->l.list_length);
 

	
 
			/* The drop down menu is out, *but* it may not be used, retract it. */
 
			if (gv->l.list_length == 0 && w->IsWidgetLowered(GRP_WIDGET_MANAGE_VEHICLES_DROPDOWN)) {
 
				w->RaiseWidget(GRP_WIDGET_MANAGE_VEHICLES_DROPDOWN);
 
				Window **w2;
 
				FOR_ALL_WINDOWS(w2) {
 
					if (w->window_class  == WP(*w2, dropdown_d).parent_wnd_class &&
 
							w->window_number == WP(*w2, dropdown_d).parent_wnd_num) {
 
						DeleteWindow(*w2);
 
						break;
 
					}
 
				}
 
				HideDropDownMenu(w);
 
			}
 

	
 
			/* Disable all lists management button when the list is empty */
 
			w->SetWidgetsDisabledState(gv->l.list_length == 0 || _local_player != owner,
 
					GRP_WIDGET_STOP_ALL,
 
					GRP_WIDGET_START_ALL,
 
					GRP_WIDGET_MANAGE_VEHICLES,
 
					GRP_WIDGET_MANAGE_VEHICLES_DROPDOWN,
 
					WIDGET_LIST_END);
 

	
 
			/* Disable the group specific function when we select the default group or all vehicles */
 
			w->SetWidgetsDisabledState(IsDefaultGroupID(gv->group_sel) || IsAllGroupID(gv->group_sel) || _local_player != owner,
src/network/network_gui.cpp
Show inline comments
 
@@ -17,24 +17,25 @@
 
#include "../variables.h"
 
#include "network_server.h"
 
#include "network_udp.h"
 
#include "../town.h"
 
#include "../newgrf.h"
 
#include "../functions.h"
 
#include "../window_func.h"
 
#include "../core/alloc_func.hpp"
 
#include "../string_func.h"
 
#include "../gfx_func.h"
 
#include "../player_func.h"
 
#include "../settings_type.h"
 
#include "../widgets/dropdown_func.h"
 

	
 
#include "table/strings.h"
 
#include "../table/sprites.h"
 

	
 
#define BGC 5
 
#define BTC 15
 

	
 
struct chatquerystr_d : public querystr_d {
 
	int dest;
 
};
 
assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(chatquerystr_d));
 

	
src/news_gui.cpp
Show inline comments
 
@@ -6,24 +6,25 @@
 
#include "gui.h"
 
#include "window_gui.h"
 
#include "viewport_func.h"
 
#include "news.h"
 
#include "settings_type.h"
 
#include "transparency.h"
 
#include "strings_func.h"
 
#include "window_func.h"
 
#include "date_func.h"
 
#include "vehicle_base.h"
 
#include "sound_func.h"
 
#include "string_func.h"
 
#include "widgets/dropdown_func.h"
 

	
 
#include "table/sprites.h"
 
#include "table/strings.h"
 

	
 
/** @file news_gui.cpp
 
 *
 
 * News system is realized as a FIFO queue (in an array)
 
 * The positions in the queue can't be rearranged, we only access
 
 * the array elements through pointers to the elements. Once the
 
 * array is full, the oldest entry (\a _oldest_news) is being overwritten
 
 * by the newest (\a _latest_news).
 
 *
src/player_gui.cpp
Show inline comments
 
@@ -19,24 +19,25 @@
 
#include "aircraft.h"
 
#include "newgrf.h"
 
#include "network/network_data.h"
 
#include "network/network_client.h"
 
#include "network/network_gui.h"
 
#include "player_face.h"
 
#include "strings_func.h"
 
#include "functions.h"
 
#include "window_func.h"
 
#include "date_func.h"
 
#include "string_func.h"
 
#include "settings_type.h"
 
#include "widgets/dropdown_func.h"
 

	
 
#include "table/sprites.h"
 
#include "table/strings.h"
 

	
 
/* player face selection window */
 
struct facesel_d {
 
	PlayerFace face; // player face bits
 
	bool advanced;   // advance player face selection window
 
};
 
assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(facesel_d));
 

	
 
static void DoShowPlayerFinances(PlayerID player, bool show_small, bool show_stickied);
src/rail_gui.cpp
Show inline comments
 
@@ -18,24 +18,25 @@
 
#include "debug.h"
 
#include "variables.h"
 
#include "newgrf_callbacks.h"
 
#include "newgrf_station.h"
 
#include "train.h"
 
#include "strings_func.h"
 
#include "functions.h"
 
#include "window_func.h"
 
#include "date_func.h"
 
#include "sound_func.h"
 
#include "player_func.h"
 
#include "settings_type.h"
 
#include "widgets/dropdown_func.h"
 

	
 
#include "bridge_map.h"
 
#include "rail_map.h"
 
#include "road_map.h"
 
#include "station_map.h"
 
#include "tunnel_map.h"
 
#include "tunnelbridge_map.h"
 

	
 
#include "table/sprites.h"
 
#include "table/strings.h"
 

	
 
static RailType _cur_railtype;
src/settings_gui.cpp
Show inline comments
 
@@ -15,24 +15,25 @@
 
#include "network/network.h"
 
#include "town.h"
 
#include "variables.h"
 
#include "settings_internal.h"
 
#include "newgrf_townname.h"
 
#include "strings_func.h"
 
#include "functions.h"
 
#include "window_func.h"
 
#include "vehicle_base.h"
 
#include "core/alloc_func.hpp"
 
#include "string_func.h"
 
#include "gfx_func.h"
 
#include "widgets/dropdown_func.h"
 

	
 
#include "table/sprites.h"
 
#include "table/strings.h"
 

	
 
static uint32 _difficulty_click_a;
 
static uint32 _difficulty_click_b;
 
static byte _difficulty_timeout;
 

	
 
static const StringID _units_dropdown[] = {
 
	STR_UNITS_IMPERIAL,
 
	STR_UNITS_METRIC,
 
	STR_UNITS_SI,
src/station_gui.cpp
Show inline comments
 
@@ -14,24 +14,25 @@
 
#include "town.h"
 
#include "command_func.h"
 
#include "variables.h"
 
#include "vehicle_gui.h"
 
#include "cargotype.h"
 
#include "station_gui.h"
 
#include "station.h"
 
#include "strings_func.h"
 
#include "core/alloc_func.hpp"
 
#include "window_func.h"
 
#include "viewport_func.h"
 
#include "gfx_func.h"
 
#include "widgets/dropdown_func.h"
 

	
 
#include "table/strings.h"
 
#include "table/sprites.h"
 

	
 
typedef int CDECL StationSortListingTypeFunction(const void*, const void*);
 

	
 
static StationSortListingTypeFunction StationNameSorter;
 
static StationSortListingTypeFunction StationTypeSorter;
 
static StationSortListingTypeFunction StationWaitingSorter;
 
static StationSortListingTypeFunction StationRatingMaxSorter;
 

	
 
bool _station_show_coverage;
src/vehicle_gui.cpp
Show inline comments
 
@@ -26,24 +26,25 @@
 
#include "depot.h"
 
#include "cargotype.h"
 
#include "group.h"
 
#include "group_gui.h"
 
#include "strings_func.h"
 
#include "functions.h"
 
#include "window_func.h"
 
#include "vehicle_func.h"
 
#include "autoreplace_gui.h"
 
#include "core/alloc_func.hpp"
 
#include "string_func.h"
 
#include "settings_type.h"
 
#include "widgets/dropdown_func.h"
 

	
 
#include "table/sprites.h"
 
#include "table/strings.h"
 

	
 
struct Sorting {
 
	Listing aircraft;
 
	Listing roadveh;
 
	Listing ship;
 
	Listing train;
 
};
 

	
 
static Sorting _sorting;
src/widget.cpp
Show inline comments
 
/* $Id$ */
 

	
 
/** @file widget.cpp */
 

	
 
#include "stdafx.h"
 
#include "openttd.h"
 
#include "core/math_func.hpp"
 
#include "player_func.h"
 
#include "gfx_func.h"
 
#include "window_gui.h"
 
#include "window_func.h"
 
#include "widgets/dropdown_func.h"
 

	
 
#include "table/sprites.h"
 
#include "table/strings.h"
 

	
 
static Point HandleScrollbarHittest(const Scrollbar *sb, int top, int bottom)
 
{
 
	Point pt;
 
	int height, count, pos, cap;
 

	
 
	top += 10;
 
	bottom -= 9;
 

	
 
@@ -475,253 +476,24 @@ draw_default:;
 
			}
 
		}
 
		}
 
	}
 

	
 

	
 
	if (w->flags4 & WF_WHITE_BORDER_MASK) {
 
		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 ? TC_WHITE : TC_BLACK, x + width);
 

	
 
						if (HasBit(WP(w, dropdown_d).disabled_state, i)) {
 
							GfxFillRect(x, y, x + width, y + 9,
 
								(1 << 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) {
 
				w2->RaiseWidget(WP(w, dropdown_d).parent_button);
 
				w2->InvalidateWidget(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 = w->IsWidgetLowered(button);
 
	int top, height;
 
	int screen_top, screen_bottom;
 
	bool scroll = false;
 

	
 
	DeleteWindowById(WC_DROPDOWN_MENU, 0);
 

	
 
	if (is_dropdown_menu_shown) return;
 

	
 
	w->LowerWidget(button);
 

	
 
	w->InvalidateWidget(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;
 

	
 
	w2->SetWidgetHiddenState(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;
 
}
 

	
 

	
 
static void ResizeWidgets(Window *w, byte a, byte b)
 
{
 
	int16 offset = w->widget[a].left;
 
	int16 length = w->widget[b].right - offset;
 

	
 
	w->widget[a].right  = (length / 2) + offset;
 

	
 
	w->widget[b].left  = w->widget[a].right + 1;
 
}
 

	
 
static void ResizeWidgets(Window *w, byte a, byte b, byte c)
 
{
src/widgets/dropdown.cpp
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
#include "../stdafx.h"
 
#include "../openttd.h"
 
#include "../strings_type.h"
 
#include "../window_gui.h"
 
#include "../strings_func.h"
 
#include "../strings_type.h"
 
#include "../gfx_func.h"
 
#include "../window_func.h"
 
#include "dropdown_type.h"
 
#include "dropdown_func.h"
 

	
 
#include "../table/sprites.h"
 
#include "table/strings.h"
 

	
 
StringID DropDownListItem::String() const
 
{
 
	return STR_NULL;
 
}
 

	
 
StringID DropDownListStringItem::String() const
 
{
 
	return this->string;
 
}
 

	
 
StringID DropDownListParamStringItem::String() const
 
{
 
	for (uint i = 0; i < lengthof(this->decode_params); i++) SetDParam(i, this->decode_params[i]);
 
	return this->string;
 
}
 

	
 
struct dropdown_d {
 
	WindowClass parent_wnd_class;
 
	WindowNumber parent_wnd_num;
 
	byte parent_button;
 
	DropDownList *list;
 
	byte selected_index;
 
	byte click_delay;
 
	bool drag_mode;
 
};
 
assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(dropdown_d));
 

	
 
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)
 
{
 
	if (GetWidgetFromPos(w, _cursor.pos.x - w->left, _cursor.pos.y - w->top) < 0) return -1;
 

	
 
	int y = _cursor.pos.y - w->top - 2 + w->vscroll.pos * 10;
 
	if (y < 0) return -1;
 

	
 
	uint selected_row = y / 10;
 
	const DropDownList *list = WP(w, dropdown_d).list;
 

	
 
	if (selected_row >= list->size()) return -1;
 

	
 
	for (DropDownList::const_iterator it = list->begin(); it != list->end(); ++it, selected_row--) {
 
		if (selected_row == 0) {
 
			const DropDownListItem *item = *it;
 
			if (item->masked || item->String() == STR_NULL) return -1;
 
			return item->result;
 
		}
 
	}
 

	
 
	return -1;
 
}
 

	
 
static void DropDownMenuWndProc(Window *w, WindowEvent *e)
 
{
 
	switch (e->event) {
 
		case WE_PAINT: {
 
			DrawWindowWidgets(w);
 

	
 
			int x = 1;
 
			int y = 2 - w->vscroll.pos * 10;
 

	
 
			int sel    = WP(w, dropdown_d).selected_index;
 
			int width  = w->widget[0].right - 3;
 
			int height = w->widget[0].bottom - 3;
 

	
 
			DropDownList *list = WP(w, dropdown_d).list;
 

	
 
			for (DropDownList::const_iterator it = list->begin(); it != list->end(); ++it) {
 
				if (y >= 0 && y <= height) {
 
					const DropDownListItem *item = *it;
 
					if (item->String() != STR_NULL) {
 
						if (sel == item->result) GfxFillRect(x + 1, y, x + width, y + 9, 0);
 

	
 
						DrawStringTruncated(x + 2, y, item->String(), sel == item->result ? TC_WHITE : TC_BLACK, x + width);
 

	
 
						if (item->masked) {
 
							GfxFillRect(x, y, x + width, y + 9,
 
								(1 << 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;
 
			int 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) {
 
				int 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) {
 
				w2->RaiseWidget(WP(w, dropdown_d).parent_button);
 
				w2->InvalidateWidget(WP(w, dropdown_d).parent_button);
 
			}
 

	
 
			delete WP(w, dropdown_d).list;
 
		} break;
 
	}
 
}
 

	
 
void ShowDropDownList(Window *w, DropDownList *list, int selected, int button)
 
{
 
	bool is_dropdown_menu_shown = w->IsWidgetLowered(button);
 

	
 
	DeleteWindowById(WC_DROPDOWN_MENU, 0);
 

	
 
	if (is_dropdown_menu_shown) {
 
		delete list;
 
		return;
 
	}
 

	
 
	w->LowerWidget(button);
 
	w->InvalidateWidget(button);
 

	
 
	/* Our parent's button widget is used to determine where to place the drop
 
	 * down list window. */
 
	const Widget *wi = &w->widget[button];
 

	
 
	/* The preferred position is just below the dropdown calling widget */
 
	int top = w->top + wi->bottom + 2;
 
	int height = list->size() * 10 + 4;
 

	
 
	/* Check if the status bar is visible, as we don't want to draw over it */
 
	Window *w3 = FindWindowById(WC_STATUS_BAR, 0);
 
	int screen_bottom = w3 == NULL ? _screen.height : w3->top;
 

	
 
	bool scroll = false;
 

	
 
	/* Check if the dropdown will fully fit below the widget */
 
	if (top + height >= screen_bottom) {
 
		w3 = FindWindowById(WC_MAIN_TOOLBAR, 0);
 
		int 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;
 
		}
 
	}
 

	
 
	Window *dw = AllocateWindow(
 
		w->left + wi[-1].left + 1,
 
		top,
 
		wi->right - wi[-1].left + 1,
 
		height,
 
		DropDownMenuWndProc,
 
		WC_DROPDOWN_MENU,
 
		_dropdown_menu_widgets);
 

	
 
	dw->widget[0].color = wi->color;
 
	dw->widget[0].right = wi->right - wi[-1].left;
 
	dw->widget[0].bottom = height - 1;
 

	
 
	dw->SetWidgetHiddenState(1, !scroll);
 

	
 
	if (scroll) {
 
		/* We're scrolling, so enable the scroll bar and shrink the list by
 
		 * the scrollbar's width */
 
		dw->widget[1].color  = wi->color;
 
		dw->widget[1].right  = dw->widget[0].right;
 
		dw->widget[1].left   = dw->widget[1].right - 11;
 
		dw->widget[1].bottom = height - 1;
 
		dw->widget[0].right -= 12;
 

	
 
		dw->vscroll.cap   = (height - 4) / 10;
 
		dw->vscroll.count = list->size();
 
	}
 

	
 
	dw->desc_flags = WDF_DEF_WIDGET;
 
	dw->flags4 &= ~WF_WHITE_BORDER_MASK;
 

	
 
	WP(dw, dropdown_d).parent_wnd_class = w->window_class;
 
	WP(dw, dropdown_d).parent_wnd_num   = w->window_number;
 
	WP(dw, dropdown_d).parent_button    = button;
 
	WP(dw, dropdown_d).list             = list;
 
	WP(dw, dropdown_d).selected_index   = selected;
 
	WP(dw, dropdown_d).click_delay      = 0;
 
	WP(dw, dropdown_d).drag_mode        = true;
 
}
 

	
 
void ShowDropDownMenu(Window *w, const StringID *strings, int selected, int button, uint32 disabled_mask, uint32 hidden_mask)
 
{
 
	uint result = 0;
 
	DropDownList *list = new DropDownList();
 

	
 
	for (uint i = 0; strings[i] != INVALID_STRING_ID; i++) {
 
		if (!HasBit(hidden_mask, i)) {
 
			list->push_back(new DropDownListStringItem(strings[i], result, HasBit(disabled_mask, i)));
 
		}
 
		result++;
 
	}
 

	
 
	/* No entries in the list? */
 
	if (list->size() == 0) {
 
		delete list;
 
		return;
 
	}
 

	
 
	ShowDropDownList(w, list, selected, button);
 
}
 

	
 
void HideDropDownMenu(Window *pw)
 
{
 
	Window **wz;
 
	FOR_ALL_WINDOWS(wz) {
 
		if ((*wz)->window_class != WC_DROPDOWN_MENU) continue;
 

	
 
		if (pw->window_class == WP(*wz, dropdown_d).parent_wnd_class &&
 
				pw->window_number == WP(*wz, dropdown_d).parent_wnd_num) {
 
			DeleteWindow(*wz);
 
			break;
 
		}
 
	}
 
}
 

	
src/widgets/dropdown_func.h
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
#ifndef WIDGETS_DROPDOWN_FUNC_H
 
#define WIDGETS_DROPDOWN_FUNC_H
 

	
 
/* Show drop down menu containing a fixed list of strings */
 
void ShowDropDownMenu(Window *w, const StringID *strings, int selected, int button, uint32 disabled_mask, uint32 hidden_mask);
 

	
 
/* Hide drop down menu of a parent window */
 
void HideDropDownMenu(Window *pw);
 

	
 
#endif /* WIDGETS_DROPDOWN_FUNC_H */
src/widgets/dropdown_type.h
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
#ifndef WIDGETS_DROPDOWN_TYPE_H
 
#define WIDGETS_DROPDOWN_TYPE_H
 

	
 
#include "../window_type.h"
 
#include <list>
 

	
 
/**
 
 * Base list item class from which others are derived. If placed in a list it
 
 * will appear as a horizontal line in the menu.
 
 */
 
class DropDownListItem {
 
public:
 
	int result;  ///< Result code to return to window on selection
 
	bool masked; ///< Masked and unselectable item
 

	
 
	virtual StringID String() const;
 
};
 

	
 
/**
 
 * Common string list item.
 
 */
 
class DropDownListStringItem : public DropDownListItem {
 
public:
 
	StringID string; ///< String ID of item
 

	
 
	DropDownListStringItem(StringID string, uint result, bool masked)
 
	{
 
		this->string = string;
 
		this->result = result;
 
		this->masked = masked;
 
	}
 

	
 
	StringID String() const;
 
};
 

	
 
/**
 
 * String list item with parameters.
 
 */
 
class DropDownListParamStringItem : public DropDownListStringItem {
 
public:
 
	uint64 decode_params[10]; ///< Parameters of the string
 

	
 
	StringID String() const;
 
	void SetParam(uint index, uint64 value) { decode_params[index] = value; }
 
};
 

	
 
/**
 
 * A drop down list is a collection of drop down list items.
 
 */
 
typedef std::list<DropDownListItem *> DropDownList;
 

	
 
/**
 
 * Show a drop down list.
 
 * @param w        Parent window for the list.
 
 * @param list     Prepopulated DropDownList. Will be deleted when the list is
 
 *                 closed.
 
 * @param selected The initially selected list item.
 
 * @param button   The widget within the parent window that is used to determine
 
 *                 the list's location.
 
 */
 
void ShowDropDownList(Window *w, DropDownList *list, int selected, int button);
 

	
 
#endif /* WIDGETS_DROPDOWN_TYPE_H */
src/window_gui.h
Show inline comments
 
@@ -430,38 +430,24 @@ struct list_d {
 
	SortListFlags flags; ///< used to control sorting/resorting/etc.
 
	uint16 resort_timer; ///< resort list after a given amount of ticks if set
 
};
 
assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(list_d));
 

	
 
struct message_d {
 
	int msg;
 
	int wparam;
 
	int lparam;
 
};
 
assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(message_d));
 

	
 
struct dropdown_d {
 
	uint32 disabled_state;
 
	uint32 hidden_state;
 
	WindowClass parent_wnd_class;
 
	WindowNumber parent_wnd_num;
 
	byte parent_button;
 
	byte num_items;
 
	byte selected_index;
 
	const StringID *items;
 
	byte click_delay;
 
	bool drag_mode;
 
};
 
assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(dropdown_d));
 

	
 
struct vehiclelist_d {
 
	const Vehicle** sort_list;  // List of vehicles (sorted)
 
	Listing *_sorting;          // pointer to the appropiate subcategory of _sorting
 
	uint16 length_of_sort_list; // Keeps track of how many vehicle pointers sort list got space for
 
	VehicleType vehicle_type;   // The vehicle type that is sorted
 
	list_d l;                   // General list struct
 
};
 
assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(vehiclelist_d));
 

	
 
struct grouplist_d {
 
	const Group **sort_list;
 
	list_d l;                   // General list struct
 
@@ -583,25 +569,24 @@ void InvalidateWindowData(WindowClass cl
 
void RelocateAllWindows(int neww, int newh);
 

	
 
/* misc_gui.cpp */
 
void GuiShowTooltipsWithArgs(StringID str, uint paramcount, const uint64 params[]);
 
static inline void GuiShowTooltips(StringID str)
 
{
 
	GuiShowTooltipsWithArgs(str, 0, NULL);
 
}
 

	
 
/* widget.cpp */
 
int GetWidgetFromPos(const Window *w, int x, int y);
 
void DrawWindowWidgets(const Window *w);
 
void ShowDropDownMenu(Window *w, const StringID *strings, int selected, int button, uint32 disabled_mask, uint32 hidden_mask);
 

	
 

	
 
Window *GetCallbackWnd();
 
void DeleteNonVitalWindows();
 
void DeleteAllNonVitalWindows();
 
void HideVitalWindows();
 
void ShowVitalWindows();
 
Window **FindWindowZPosition(const Window *w);
 

	
 
/* window.cpp */
 
extern Window *_z_windows[];
 
extern Window **_last_z_window;
0 comments (0 inline, 0 general)