(svn r13108) -Codechange: make a Window subclass of the main toolbars sub menus.
authorrubidium
Thu, 15 May 2008 20:04:10 +0000
changeset 10564 9d79c5088048
parent 10563 76819f7c2dc2
child 10565 0889f005903b
(svn r13108) -Codechange: make a Window subclass of the main toolbars sub menus.
src/network/network_gui.cpp
src/toolbar_gui.cpp
src/window_gui.h
--- a/src/network/network_gui.cpp	Thu May 15 19:24:15 2008 +0000
+++ b/src/network/network_gui.cpp	Thu May 15 20:04:10 2008 +0000
@@ -1217,14 +1217,6 @@
 // Max 10 actions per client
 #define MAX_CLIENTLIST_ACTION 10
 
-// Some standard bullshit.. defines variables ;)
-static void ClientListWndProc(Window *w, WindowEvent *e);
-static void ClientListPopupWndProc(Window *w, WindowEvent *e);
-static byte _selected_clientlist_item = 255;
-static byte _selected_clientlist_y = 0;
-static char _clientlist_action[MAX_CLIENTLIST_ACTION][50];
-static ClientList_Action_Proc *_clientlist_proc[MAX_CLIENTLIST_ACTION];
-
 enum {
 	CLNWND_OFFSET = 16,
 	CLNWND_ROWSIZE = 10
@@ -1249,7 +1241,7 @@
 	WC_CLIENT_LIST, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
 	_client_list_widgets,
-	ClientListWndProc
+	NULL
 };
 
 // Finds the Xth client-info that is active
@@ -1321,267 +1313,271 @@
 
 
 
-/**
- * An action is clicked! What do we do?
- */
-static void HandleClientListPopupClick(byte index, byte clientno)
-{
-	/* A click on the Popup of the ClientList.. handle the command */
-	if (index < MAX_CLIENTLIST_ACTION && _clientlist_proc[index] != NULL) {
-		_clientlist_proc[index](clientno);
-	}
-}
+struct NetworkClientListPopupWindow : Window {
+	int sel_index;
+	int client_no;
+	char action[MAX_CLIENTLIST_ACTION][50];
+	ClientList_Action_Proc *proc[MAX_CLIENTLIST_ACTION];
 
-/**
- * Finds the amount of clients and set the height correct
- */
-static bool CheckClientListHeight(Window *w)
-{
-	int num = 0;
-	const NetworkClientInfo *ci;
+	NetworkClientListPopupWindow(int x, int y, const Widget *widgets, int client_no) :
+			Window(x, y, 150, 100, NULL, WC_TOOLBAR_MENU, widgets),
+			sel_index(0), client_no(client_no)
+	{
+		/*
+		 * Fill the actions this client has.
+		 * Watch is, max 50 chars long!
+		 */
 
-	/* Should be replaced with a loop through all clients */
-	FOR_ALL_ACTIVE_CLIENT_INFOS(ci) {
-		num++;
+		const NetworkClientInfo *ci = NetworkFindClientInfo(client_no);
+
+		int i = 0;
+		if (_network_own_client_index != ci->client_index) {
+			GetString(this->action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT, lastof(this->action[i]));
+			this->proc[i++] = &ClientList_SpeakToClient;
+		}
+
+		if (IsValidPlayer(ci->client_playas) || ci->client_playas == PLAYER_SPECTATOR) {
+			GetString(this->action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY, lastof(this->action[i]));
+			this->proc[i++] = &ClientList_SpeakToCompany;
+		}
+		GetString(this->action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL, lastof(this->action[i]));
+		this->proc[i++] = &ClientList_SpeakToAll;
+
+		if (_network_own_client_index != ci->client_index) {
+			/* We are no spectator and the player we want to give money to is no spectator and money gifts are allowed */
+			if (IsValidPlayer(_network_playas) && IsValidPlayer(ci->client_playas) && _patches.give_money) {
+				GetString(this->action[i], STR_NETWORK_CLIENTLIST_GIVE_MONEY, lastof(this->action[i]));
+				this->proc[i++] = &ClientList_GiveMoney;
+			}
+		}
+
+		/* A server can kick clients (but not himself) */
+		if (_network_server && _network_own_client_index != ci->client_index) {
+			GetString(this->action[i], STR_NETWORK_CLIENTLIST_KICK, lastof(this->action[i]));
+			this->proc[i++] = &ClientList_Kick;
+
+			sprintf(this->action[i],"Ban"); // XXX GetString?
+			this->proc[i++] = &ClientList_Ban;
+		}
+
+		if (i == 0) {
+			GetString(this->action[i], STR_NETWORK_CLIENTLIST_NONE, lastof(this->action[i]));
+			this->proc[i++] = &ClientList_None;
+		}
+
+		/* Calculate the height */
+		int h = ClientListPopupHeight();
+
+		/* Allocate the popup */
+		this->widget[0].bottom = this->widget[0].top + h;
+		this->widget[0].right = this->widget[0].left + 150;
+
+		this->flags4 &= ~WF_WHITE_BORDER_MASK;
+
+		this->FindWindowPlacementAndResize(150, h + 1);
 	}
 
-	num *= CLNWND_ROWSIZE;
-
-	/* If height is changed */
-	if (w->height != CLNWND_OFFSET + num + 1) {
-		// XXX - magic unfortunately; (num + 2) has to be one bigger than heigh (num + 1)
-		w->SetDirty();
-		w->widget[3].bottom = w->widget[3].top + num + 2;
-		w->height = CLNWND_OFFSET + num + 1;
-		w->SetDirty();
-		return false;
-	}
-	return true;
-}
-
-/**
- * Finds the amount of actions in the popup and set the height correct
- */
-static uint ClientListPopupHeight()
-{
-	int num = 0;
-
-	// Find the amount of actions
-	for (int i = 0; i < MAX_CLIENTLIST_ACTION; i++) {
-		if (_clientlist_action[i][0] == '\0') continue;
-		if (_clientlist_proc[i] == NULL) continue;
-		num++;
+	/**
+	 * An action is clicked! What do we do?
+	 */
+	void HandleClientListPopupClick(byte index)
+	{
+		/* A click on the Popup of the ClientList.. handle the command */
+		if (index < MAX_CLIENTLIST_ACTION && this->proc[index] != NULL) {
+			this->proc[index](this->client_no);
+		}
 	}
 
-	num *= CLNWND_ROWSIZE;
+	/**
+	 * Finds the amount of actions in the popup and set the height correct
+	 */
+	uint ClientListPopupHeight()
+	{
+		int num = 0;
 
-	return num + 1;
-}
+		// Find the amount of actions
+		for (int i = 0; i < MAX_CLIENTLIST_ACTION; i++) {
+			if (this->action[i][0] == '\0') continue;
+			if (this->proc[i] == NULL) continue;
+			num++;
+		}
+
+		num *= CLNWND_ROWSIZE;
+
+		return num + 1;
+	}
+
+
+	virtual void OnPaint()
+	{
+		DrawWindowWidgets(this);
+
+		/* Draw the actions */
+		int sel = this->sel_index;
+		int y = 1;
+		for (int i = 0; i < MAX_CLIENTLIST_ACTION; i++, y += CLNWND_ROWSIZE) {
+			if (this->action[i][0] == '\0') continue;
+			if (this->proc[i] == NULL) continue;
+
+			TextColour colour;
+			if (sel-- == 0) { // Selected item, highlight it
+				GfxFillRect(1, y, 150 - 2, y + CLNWND_ROWSIZE - 1, 0);
+				colour = TC_WHITE;
+			} else {
+				colour = TC_BLACK;
+			}
+
+			DoDrawString(this->action[i], 4, y, colour);
+		}
+	}
+
+	virtual void OnMouseLoop()
+	{
+		/* We selected an action */
+		int index = (_cursor.pos.y - this->top) / CLNWND_ROWSIZE;
+
+		if (_left_button_down) {
+			if (index == -1 || index == this->sel_index) return;
+
+			this->sel_index = index;
+			this->SetDirty();
+		} else {
+			if (index >= 0 && _cursor.pos.y >= this->top) {
+				HandleClientListPopupClick(index);
+			}
+
+			DeleteWindowById(WC_TOOLBAR_MENU, 0);
+		}
+	}
+};
 
 /**
  * Show the popup (action list)
  */
-static Window *PopupClientList(Window *w, int client_no, int x, int y)
+static void PopupClientList(int client_no, int x, int y)
 {
-	int i;
-	const NetworkClientInfo *ci;
 	DeleteWindowById(WC_TOOLBAR_MENU, 0);
 
-	/* Clean the current actions */
-	for (i = 0; i < MAX_CLIENTLIST_ACTION; i++) {
-		_clientlist_action[i][0] = '\0';
-		_clientlist_proc[i] = NULL;
-	}
-
-	/*
-	 * Fill the actions this client has.
-	 * Watch is, max 50 chars long!
-	 */
-
-	ci = NetworkFindClientInfo(client_no);
-	if (ci == NULL) return NULL;
-
-	i = 0;
-	if (_network_own_client_index != ci->client_index) {
-		GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT, lastof(_clientlist_action[i]));
-		_clientlist_proc[i++] = &ClientList_SpeakToClient;
-	}
-
-	if (IsValidPlayer(ci->client_playas) || ci->client_playas == PLAYER_SPECTATOR) {
-		GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY, lastof(_clientlist_action[i]));
-		_clientlist_proc[i++] = &ClientList_SpeakToCompany;
-	}
-	GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL, lastof(_clientlist_action[i]));
-	_clientlist_proc[i++] = &ClientList_SpeakToAll;
-
-	if (_network_own_client_index != ci->client_index) {
-		/* We are no spectator and the player we want to give money to is no spectator and money gifts are allowed */
-		if (IsValidPlayer(_network_playas) && IsValidPlayer(ci->client_playas) && _patches.give_money) {
-			GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_GIVE_MONEY, lastof(_clientlist_action[i]));
-			_clientlist_proc[i++] = &ClientList_GiveMoney;
-		}
-	}
-
-	/* A server can kick clients (but not himself) */
-	if (_network_server && _network_own_client_index != ci->client_index) {
-		GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_KICK, lastof(_clientlist_action[i]));
-		_clientlist_proc[i++] = &ClientList_Kick;
-
-		sprintf(_clientlist_action[i],"Ban"); // XXX GetString?
-		_clientlist_proc[i++] = &ClientList_Ban;
-	}
-
-	if (i == 0) {
-		GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_NONE, lastof(_clientlist_action[i]));
-		_clientlist_proc[i++] = &ClientList_None;
-	}
-
-	/* Calculate the height */
-	int h = ClientListPopupHeight();
+	if (NetworkFindClientInfo(client_no) == NULL) return;
 
-	/* Allocate the popup */
-	w = new Window(x, y, 150, h + 1, ClientListPopupWndProc, WC_TOOLBAR_MENU, _client_list_popup_widgets);
-	w->widget[0].bottom = w->widget[0].top + h;
-	w->widget[0].right = w->widget[0].left + 150;
-
-	w->flags4 &= ~WF_WHITE_BORDER_MASK;
-	WP(w, menu_d).item_count = 0;
-	// Save our client
-	WP(w, menu_d).main_button = client_no;
-	WP(w, menu_d).sel_index = 0;
-
-	return w;
-}
-
-/** Main handle for the client popup list
- * uses menu_d WP macro */
-static void ClientListPopupWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT: {
-			DrawWindowWidgets(w);
-
-			/* Draw the actions */
-			int sel = WP(w, menu_d).sel_index;
-			int y = 1;
-			for (int i = 0; i < MAX_CLIENTLIST_ACTION; i++, y += CLNWND_ROWSIZE) {
-				if (_clientlist_action[i][0] == '\0') continue;
-				if (_clientlist_proc[i] == NULL) continue;
-
-				TextColour colour;
-				if (sel-- == 0) { // Selected item, highlight it
-					GfxFillRect(1, y, 150 - 2, y + CLNWND_ROWSIZE - 1, 0);
-					colour = TC_WHITE;
-				} else {
-					colour = TC_BLACK;
-				}
-
-				DoDrawString(_clientlist_action[i], 4, y, colour);
-			}
-		} break;
-
-		case WE_MOUSELOOP: {
-			/* We selected an action */
-			int index = (_cursor.pos.y - w->top) / CLNWND_ROWSIZE;
-
-			if (_left_button_down) {
-				if (index == -1 || index == WP(w, menu_d).sel_index) return;
-
-				WP(w, menu_d).sel_index = index;
-				w->SetDirty();
-			} else {
-				if (index >= 0 && _cursor.pos.y >= w->top) {
-					HandleClientListPopupClick(index, WP(w, menu_d).main_button);
-				}
-
-				DeleteWindowById(WC_TOOLBAR_MENU, 0);
-			}
-		} break;
-	}
+	new NetworkClientListPopupWindow(x, y, _client_list_popup_widgets, client_no);
 }
 
 /**
  * Main handle for clientlist
  */
-static void ClientListWndProc(Window *w, WindowEvent *e)
+struct NetworkClientListWindow : Window
 {
-	switch (e->event) {
-		case WE_PAINT: {
-			NetworkClientInfo *ci;
-			int i = 0;
-
-			/* Check if we need to reset the height */
-			if (!CheckClientListHeight(w)) break;
-
-			DrawWindowWidgets(w);
-
-			int y = CLNWND_OFFSET;
-
-			FOR_ALL_ACTIVE_CLIENT_INFOS(ci) {
-				TextColour colour;
-				if (_selected_clientlist_item == i++) { // Selected item, highlight it
-					GfxFillRect(1, y, 248, y + CLNWND_ROWSIZE - 1, 0);
-					colour = TC_WHITE;
-				} else {
-					colour = TC_BLACK;
-				}
-
-				if (ci->client_index == NETWORK_SERVER_INDEX) {
-					DrawString(4, y, STR_NETWORK_SERVER, colour);
-				} else {
-					DrawString(4, y, STR_NETWORK_CLIENT, colour);
-				}
+	byte selected_item;
+	byte selected_y;
 
-				/* Filter out spectators */
-				if (IsValidPlayer(ci->client_playas)) DrawPlayerIcon(ci->client_playas, 64, y + 1);
-
-				DoDrawString(ci->client_name, 81, y, colour);
-
-				y += CLNWND_ROWSIZE;
-			}
-		} break;
-
-		case WE_CLICK:
-			/* Show the popup with option */
-			if (_selected_clientlist_item != 255) {
-				PopupClientList(w, _selected_clientlist_item, e->we.click.pt.x + w->left, e->we.click.pt.y + w->top);
-			}
-			break;
+	NetworkClientListWindow(const WindowDesc *desc, WindowNumber window_number) :
+			Window(desc, window_number),
+			selected_item(0),
+			selected_y(255)
+	{
+		this->FindWindowPlacementAndResize(desc);
+	}
 
-		case WE_MOUSEOVER:
-			/* -1 means we left the current window */
-			if (e->we.mouseover.pt.y == -1) {
-				_selected_clientlist_y = 0;
-				_selected_clientlist_item = 255;
-				w->SetDirty();
-				break;
-			}
-			/* It did not change.. no update! */
-			if (e->we.mouseover.pt.y == _selected_clientlist_y) break;
+	/**
+	 * Finds the amount of clients and set the height correct
+	 */
+	bool CheckClientListHeight()
+	{
+		int num = 0;
+		const NetworkClientInfo *ci;
 
-			/* Find the new selected item (if any) */
-			_selected_clientlist_y = e->we.mouseover.pt.y;
-			if (e->we.mouseover.pt.y > CLNWND_OFFSET) {
-				_selected_clientlist_item = (e->we.mouseover.pt.y - CLNWND_OFFSET) / CLNWND_ROWSIZE;
+		/* Should be replaced with a loop through all clients */
+		FOR_ALL_ACTIVE_CLIENT_INFOS(ci) {
+			num++;
+		}
+
+		num *= CLNWND_ROWSIZE;
+
+		/* If height is changed */
+		if (this->height != CLNWND_OFFSET + num + 1) {
+			// XXX - magic unfortunately; (num + 2) has to be one bigger than heigh (num + 1)
+			this->SetDirty();
+			this->widget[3].bottom = this->widget[3].top + num + 2;
+			this->height = CLNWND_OFFSET + num + 1;
+			this->SetDirty();
+			return false;
+		}
+		return true;
+	}
+
+	virtual void OnPaint()
+	{
+		NetworkClientInfo *ci;
+		int i = 0;
+
+		/* Check if we need to reset the height */
+		if (!this->CheckClientListHeight()) return;
+
+		DrawWindowWidgets(this);
+
+		int y = CLNWND_OFFSET;
+
+		FOR_ALL_ACTIVE_CLIENT_INFOS(ci) {
+			TextColour colour;
+			if (this->selected_item == i++) { // Selected item, highlight it
+				GfxFillRect(1, y, 248, y + CLNWND_ROWSIZE - 1, 0);
+				colour = TC_WHITE;
 			} else {
-				_selected_clientlist_item = 255;
+				colour = TC_BLACK;
 			}
 
-			/* Repaint */
-			w->SetDirty();
-			break;
+			if (ci->client_index == NETWORK_SERVER_INDEX) {
+				DrawString(4, y, STR_NETWORK_SERVER, colour);
+			} else {
+				DrawString(4, y, STR_NETWORK_CLIENT, colour);
+			}
 
-		case WE_DESTROY: case WE_CREATE:
-			/* When created or destroyed, data is reset */
-			_selected_clientlist_item = 255;
-			_selected_clientlist_y = 0;
-			break;
+			/* Filter out spectators */
+			if (IsValidPlayer(ci->client_playas)) DrawPlayerIcon(ci->client_playas, 64, y + 1);
+
+			DoDrawString(ci->client_name, 81, y, colour);
+
+			y += CLNWND_ROWSIZE;
+		}
 	}
-}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		/* Show the popup with option */
+		if (this->selected_item != 255) {
+			PopupClientList(this->selected_item, pt.x + this->left, pt.y + this->top);
+		}
+	}
+
+	virtual void OnMouseOver(Point pt, int widget)
+	{
+		/* -1 means we left the current window */
+		if (pt.y == -1) {
+			this->selected_y = 0;
+			this->selected_item = 255;
+			this->SetDirty();
+			return;
+		}
+		/* It did not change.. no update! */
+		if (pt.y == this->selected_y) return;
+
+		/* Find the new selected item (if any) */
+		this->selected_y = pt.y;
+		if (pt.y > CLNWND_OFFSET) {
+			this->selected_item = (pt.y - CLNWND_OFFSET) / CLNWND_ROWSIZE;
+		} else {
+			this->selected_item = 255;
+		}
+
+		/* Repaint */
+		this->SetDirty();
+	}
+};
 
 void ShowClientList()
 {
-	AllocateWindowDescFront<Window>(&_client_list_desc, 0);
+	AllocateWindowDescFront<NetworkClientListWindow>(&_client_list_desc, 0);
 }
 
 
--- a/src/toolbar_gui.cpp	Thu May 15 19:24:15 2008 +0000
+++ b/src/toolbar_gui.cpp	Thu May 15 20:04:10 2008 +0000
@@ -78,13 +78,13 @@
 }
 
 /**
- * In a window with menu_d custom extension, retrieve the menu item number from a position
+ * Retrieve the menu item number from a position
  * @param w Window holding the menu items
  * @param x X coordinate of the position
  * @param y Y coordinate of the position
  * @return Index number of the menu item, or \c -1 if no valid selection under position
  */
-static int GetMenuItemIndex(const Window *w)
+static int GetMenuItemIndex(const Window *w, int item_count, int disabled_items)
 {
 	int x = _cursor.pos.x;
 	int y = _cursor.pos.y;
@@ -92,8 +92,8 @@
 	if ((x -= w->left) >= 0 && x < w->width && (y -= w->top + 1) >= 0) {
 		y /= 10;
 
-		if (y < WP(w, const menu_d).item_count &&
-				!HasBit(WP(w, const menu_d).disabled_items, y)) {
+		if (y < item_count &&
+				!HasBit(disabled_items, y)) {
 			return y;
 		}
 	}
@@ -1113,71 +1113,77 @@
 	MenuClickHelp,        /* 26 */
 };
 
-static void MenuWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_CREATE:
-			w->widget[0].right = w->width - 1;
-			break;
-
-		case WE_PAINT: {
-			byte count = WP(w, menu_d).item_count;
-			byte sel = WP(w, menu_d).sel_index;
-			uint16 chk = WP(w, menu_d).checked_items;
-			StringID string = WP(w, menu_d).string_id;
-			byte dis = WP(w, menu_d).disabled_items;
-
-			DrawWindowWidgets(w);
+struct ToolbarMenuWindow : Window {
+	int item_count;
+	int sel_index;
+	int main_button;
+	int action_id;
+	int checked_items;
+	int disabled_items;
+	StringID base_string;
 
-			int x = 1;
-			int y = 1;
-
-			for (; count != 0; count--, string++, sel--) {
-				TextColour color = HasBit(dis, 0) ? TC_GREY : (sel == 0) ? TC_WHITE : TC_BLACK;
-				if (sel == 0) GfxFillRect(x, y, x + w->width - 3, y + 9, 0);
-
-				if (HasBit(chk, 0)) DrawString(x + 2, y, STR_CHECKMARK, color);
-				DrawString(x + 2, y, string, color);
+	ToolbarMenuWindow(int x, int y, int width, int height, const Widget *widgets, int item_count,
+										int sel_index, int parent_button, StringID base_string, int checked_items,
+										int disabled_mask) :
+			Window(x, y, width, height, NULL, WC_TOOLBAR_MENU, widgets),
+			item_count(item_count), sel_index(sel_index), main_button(GB(parent_button, 0, 8)),
+			action_id((GB(parent_button, 8, 8) != 0) ? GB(parent_button, 8, 8) : parent_button),
+			checked_items(checked_items), disabled_items(disabled_items), base_string(base_string)
+	{
+		this->widget[0].bottom = item_count * 10 + 1;
+		this->widget[0].right = this->width - 1;
+		this->flags4 &= ~WF_WHITE_BORDER_MASK;
 
-				y += 10;
-				chk >>= 1;
-				dis >>= 1;
-			}
-		} break;
+		this->FindWindowPlacementAndResize(width, height);
+	}
 
-		case WE_DESTROY: {
-				Window *v = FindWindowById(WC_MAIN_TOOLBAR, 0);
-				v->RaiseWidget(WP(w, menu_d).main_button);
-				v->SetDirty();
-				return;
+	~ToolbarMenuWindow()
+	{
+		Window *w = FindWindowById(WC_MAIN_TOOLBAR, 0);
+		w->RaiseWidget(this->main_button);
+		w->SetDirty();
+	}
+
+	virtual void OnPaint()
+	{
+		DrawWindowWidgets(this);
+
+		for (int i = 0, x = 1, y = 1; i != this->item_count; i++, y += 10) {
+			TextColour color = HasBit(this->disabled_items, i) ? TC_GREY : (this->sel_index == i) ? TC_WHITE : TC_BLACK;
+			if (this->sel_index == i) GfxFillRect(x, y, x + this->width - 3, y + 9, 0);
+
+			if (HasBit(this->checked_items, i)) DrawString(x + 2, y, STR_CHECKMARK, color);
+			DrawString(x + 2, y, this->base_string + i, color);
+		}
+	}
+
+	virtual void OnMouseLoop()
+	{
+		int index = GetMenuItemIndex(this, this->item_count, this->disabled_items);
+
+		if (_left_button_down) {
+			if (index == -1 || index == this->sel_index) return;
+
+			this->sel_index = index;
+			this->SetDirty();
+		} else {
+			if (index < 0) {
+				Window *w = FindWindowById(WC_MAIN_TOOLBAR,0);
+				if (GetWidgetFromPos(w, _cursor.pos.x - w->left, _cursor.pos.y - w->top) == this->main_button) {
+					index = this->sel_index;
+				}
 			}
 
-		case WE_MOUSELOOP: {
-			int index = GetMenuItemIndex(w);
-
-			if (_left_button_down) {
-				if (index == -1 || index == WP(w, menu_d).sel_index) return;
+			int action_id = this->action_id;
+			delete this;
 
-				WP(w, menu_d).sel_index = index;
-				w->SetDirty();
-			} else {
-				if (index < 0) {
-					Window *w2 = FindWindowById(WC_MAIN_TOOLBAR,0);
-					if (GetWidgetFromPos(w2, _cursor.pos.x - w2->left, _cursor.pos.y - w2->top) == WP(w, menu_d).main_button)
-						index = WP(w, menu_d).sel_index;
-				}
-
-				int action_id = WP(w, menu_d).action_id;
-				delete w;
-
-				if (index >= 0) {
-					assert((uint)index <= lengthof(_menu_clicked_procs));
-					_menu_clicked_procs[action_id](index);
-				}
+			if (index >= 0) {
+				assert((uint)index <= lengthof(_menu_clicked_procs));
+				_menu_clicked_procs[action_id](index);
 			}
-		} break;
+		}
 	}
-}
+};
 
 /* Dynamic widget length determined by toolbar-string length.
  * See PopupMainToolbMenu en MenuWndProc */
@@ -1248,17 +1254,7 @@
 
 	Point pos = GetToolbarDropdownPos(parent_button, width, height);
 
-	Window *w = new Window(pos.x, pos.y, width, height, MenuWndProc, WC_TOOLBAR_MENU, _menu_widgets);
-	w->widget[0].bottom = item_count * 10 + 1;
-	w->flags4 &= ~WF_WHITE_BORDER_MASK;
-
-	WP(w, menu_d).item_count = item_count;
-	WP(w, menu_d).sel_index = sel_index;
-	WP(w, menu_d).main_button = GB(parent_button, 0, 8);
-	WP(w, menu_d).action_id = (GB(parent_button, 8, 8) != 0) ? GB(parent_button, 8, 8) : parent_button;
-	WP(w, menu_d).string_id = base_string;
-	WP(w, menu_d).checked_items = checked_items;
-	WP(w, menu_d).disabled_items = disabled_mask;
+	new ToolbarMenuWindow(pos.x, pos.y, width, height, _menu_widgets, item_count, sel_index, parent_button, base_string, checked_items, disabled_mask);
 
 	SndPlayFx(SND_15_BEEP);
 }
@@ -1276,119 +1272,141 @@
 	return -1;
 }
 
-static void UpdatePlayerMenuHeight(Window *w)
-{
-	byte num = ActivePlayerCount();
-
-	/* Increase one to fit in PlayerList in the menu when in network */
-	if (_networking && WP(w, menu_d).main_button == 9) num++;
+struct ToolbarPlayerMenuWindow : Window {
+	int item_count;
+	int sel_index;
+	int main_button;
+	int action_id;
+	int gray_items;
 
-	if (WP(w, menu_d).item_count != num) {
-		WP(w, menu_d).item_count = num;
-		w->SetDirty();
-		num = num * 10 + 2;
-		w->height = num;
-		w->widget[0].bottom = w->widget[0].top + num - 1;
-		w->top = GetToolbarDropdownPos(0, w->width, w->height).y;
+	ToolbarPlayerMenuWindow(int x, int y, int width, int height, const Widget *widgets, int main_button, int gray) :
+			Window(x, y, width, height, NULL, WC_TOOLBAR_MENU, widgets),
+			item_count(0), main_button(main_button), action_id(main_button), gray_items(gray)
+	{
+		this->flags4 &= ~WF_WHITE_BORDER_MASK;
+		this->sel_index = (_local_player != PLAYER_SPECTATOR) ? _local_player : GetPlayerIndexFromMenu(0);
+		if (_networking && main_button == 9) {
+			if (_local_player != PLAYER_SPECTATOR) {
+				this->sel_index++;
+			} else {
+				/* Select client list by default for spectators */
+				this->sel_index = 0;
+			}
+		}
+	}
+
+	~ToolbarPlayerMenuWindow()
+	{
+		Window *w = FindWindowById(WC_MAIN_TOOLBAR, 0);
+		w->RaiseWidget(this->main_button);
 		w->SetDirty();
 	}
-}
 
-static void PlayerMenuWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT: {
-			UpdatePlayerMenuHeight(w);
-			DrawWindowWidgets(w);
+	void UpdatePlayerMenuHeight()
+	{
+		byte num = ActivePlayerCount();
 
-			int x = 1;
-			int y = 1;
-			int sel = WP(w, menu_d).sel_index;
-			int chk = WP(w, menu_d).checked_items; // let this mean gray items.
+		/* Increase one to fit in PlayerList in the menu when in network */
+		if (_networking && this->main_button == 9) num++;
 
-			/* 9 = playerlist */
-			if (_networking && WP(w, menu_d).main_button == 9) {
-				if (sel == 0) {
+		if (this->item_count != num) {
+			this->item_count = num;
+			this->SetDirty();
+			num = num * 10 + 2;
+			this->height = num;
+			this->widget[0].bottom = this->widget[0].top + num - 1;
+			this->top = GetToolbarDropdownPos(0, this->width, this->height).y;
+			this->SetDirty();
+		}
+	}
+
+	virtual void OnPaint()
+	{
+		this->UpdatePlayerMenuHeight();
+		DrawWindowWidgets(this);
+
+		int x = 1;
+		int y = 1;
+		int sel = this->sel_index;
+		int gray = this->gray_items;
+
+		/* 9 = playerlist */
+		if (_networking && this->main_button == 9) {
+			if (sel == 0) {
+				GfxFillRect(x, y, x + 238, y + 9, 0);
+			}
+			DrawString(x + 19, y, STR_NETWORK_CLIENT_LIST, TC_FROMSTRING);
+			y += 10;
+			sel--;
+		}
+
+		const Player *p;
+		FOR_ALL_PLAYERS(p) {
+			if (p->is_active) {
+				if (p->index == sel) {
 					GfxFillRect(x, y, x + 238, y + 9, 0);
 				}
-				DrawString(x + 19, y, STR_NETWORK_CLIENT_LIST, TC_FROMSTRING);
+
+				DrawPlayerIcon(p->index, x + 2, y + 1);
+
+				SetDParam(0, p->index);
+				SetDParam(1, p->index);
+
+				TextColour color = (p->index == sel) ? TC_WHITE : TC_BLACK;
+				if (gray & 1) color = TC_GREY;
+				DrawString(x + 19, y, STR_7021, color);
+
 				y += 10;
-				sel--;
+			}
+			gray >>= 1;
+		}
+	}
+
+	virtual void OnMouseLoop()
+	{
+		int index = GetMenuItemIndex(this, this->item_count, 0);
+
+		if (_left_button_down) {
+			this->UpdatePlayerMenuHeight();
+			/* We have a new entry at the top of the list of menu 9 when networking
+				* so keep that in count */
+			if (_networking && this->main_button == 9) {
+				if (index > 0) index = GetPlayerIndexFromMenu(index - 1) + 1;
+			} else {
+				index = GetPlayerIndexFromMenu(index);
 			}
 
-			const Player *p;
-			FOR_ALL_PLAYERS(p) {
-				if (p->is_active) {
-					if (p->index == sel) {
-						GfxFillRect(x, y, x + 238, y + 9, 0);
-					}
-
-					DrawPlayerIcon(p->index, x + 2, y + 1);
-
-					SetDParam(0, p->index);
-					SetDParam(1, p->index);
-
-					TextColour color = (p->index == sel) ? TC_WHITE : TC_BLACK;
-					if (chk & 1) color = TC_GREY;
-					DrawString(x + 19, y, STR_7021, color);
-
-					y += 10;
-				}
-				chk >>= 1;
-			}
-		 } break;
-
-		case WE_DESTROY: {
-			Window *v = FindWindowById(WC_MAIN_TOOLBAR, 0);
-			v->RaiseWidget(WP(w, menu_d).main_button);
-			v->SetDirty();
-			return;
-		}
-
-		case WE_MOUSELOOP: {
-			int index = GetMenuItemIndex(w);
+			if (index == -1 || index == this->sel_index) return;
 
-			if (_left_button_down) {
-				UpdatePlayerMenuHeight(w);
-				/* We have a new entry at the top of the list of menu 9 when networking
-				 * so keep that in count */
-				if (_networking && WP(w, menu_d).main_button == 9) {
-					if (index > 0) index = GetPlayerIndexFromMenu(index - 1) + 1;
-				} else {
-					index = GetPlayerIndexFromMenu(index);
-				}
-
-				if (index == -1 || index == WP(w, menu_d).sel_index) return;
-
-				WP(w, menu_d).sel_index = index;
-				w->SetDirty();
-			} else {
-				int action_id = WP(w, menu_d).action_id;
+			this->sel_index = index;
+			this->SetDirty();
+		} else {
+			int action_id = this->action_id;
 
-				/* We have a new entry at the top of the list of menu 9 when networking
-				 * so keep that in count */
-				if (_networking && WP(w, menu_d).main_button == 9) {
-					if (index > 0) index = GetPlayerIndexFromMenu(index - 1) + 1;
-				} else {
-					index = GetPlayerIndexFromMenu(index);
-				}
+			/* We have a new entry at the top of the list of menu 9 when networking
+				* so keep that in count */
+			if (_networking && this->main_button == 9) {
+				if (index > 0) index = GetPlayerIndexFromMenu(index - 1) + 1;
+			} else {
+				index = GetPlayerIndexFromMenu(index);
+			}
 
-				if (index < 0) {
-					Window *w2 = FindWindowById(WC_MAIN_TOOLBAR,0);
-					if (GetWidgetFromPos(w2, _cursor.pos.x - w2->left, _cursor.pos.y - w2->top) == WP(w, menu_d).main_button)
-						index = WP(w, menu_d).sel_index;
-				}
-
-				delete w;
-
-				if (index >= 0) {
-					assert(index >= 0 && index < 30);
-					_menu_clicked_procs[action_id](index);
+			if (index < 0) {
+				Window *w = FindWindowById(WC_MAIN_TOOLBAR,0);
+				if (GetWidgetFromPos(w, _cursor.pos.x - w->left, _cursor.pos.y - w->top) == this->main_button) {
+					index = this->sel_index;
 				}
 			}
-		} break;
+
+			delete this;
+
+			if (index >= 0) {
+				assert(index >= 0 && index < 30);
+				_menu_clicked_procs[action_id](index);
+			}
+		}
 	}
-}
+};
 
 static const Widget _player_menu_widgets[] = {
 {    WWT_PANEL, RESIZE_NONE, 14, 0, 240, 0, 81, 0x0, STR_NULL},
@@ -1402,22 +1420,7 @@
 
 	DeleteWindowById(WC_TOOLBAR_MENU, 0);
 	Point pos = GetToolbarDropdownPos(main_button, 241, 82);
-	Window *w = new Window(pos.x, pos.y, 241, 82, PlayerMenuWndProc, WC_TOOLBAR_MENU, _player_menu_widgets);
-	w->flags4 &= ~WF_WHITE_BORDER_MASK;
-	WP(w, menu_d).item_count = 0;
-	WP(w, menu_d).sel_index = (_local_player != PLAYER_SPECTATOR) ? _local_player : GetPlayerIndexFromMenu(0);
-	if (_networking && main_button == 9) {
-		if (_local_player != PLAYER_SPECTATOR) {
-			WP(w, menu_d).sel_index++;
-		} else {
-			/* Select client list by default for spectators */
-			WP(w, menu_d).sel_index = 0;
-		}
-	}
-	WP(w, menu_d).action_id = main_button;
-	WP(w, menu_d).main_button = main_button;
-	WP(w, menu_d).checked_items = gray;
-	WP(w, menu_d).disabled_items = 0;
+	new ToolbarPlayerMenuWindow(pos.x, pos.y, 241, 82, _player_menu_widgets, main_button, gray);
 
 	SndPlayFx(SND_15_BEEP);
 }
--- a/src/window_gui.h	Thu May 15 19:24:15 2008 +0000
+++ b/src/window_gui.h	Thu May 15 20:04:10 2008 +0000
@@ -515,17 +515,6 @@
 	/*** End of the event handling ***/
 };
 
-struct menu_d {
-	byte item_count;      ///< follow_vehicle
-	byte sel_index;       ///< scrollpos_x
-	byte main_button;     ///< scrollpos_y
-	byte action_id;
-	StringID string_id;   ///< unk30
-	uint16 checked_items; ///< unk32
-	byte disabled_items;
-};
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(menu_d));
-
 struct def_d {
 	int16 data_1, data_2, data_3;
 };