r664 - trunk/game

spike at icculus.org spike at icculus.org
Tue Mar 7 21:30:28 EST 2006


Author: spike
Date: 2006-03-07 21:30:28 -0500 (Tue, 07 Mar 2006)
New Revision: 664

Modified:
   trunk/game/m_menucore.c
   trunk/game/m_menucore.h
Log:
Added editable(edit) items and List-Of-Values(combo) menu item types. Added test/demo items to the main menu.

Modified: trunk/game/m_menucore.c
===================================================================
--- trunk/game/m_menucore.c	2006-03-08 02:19:29 UTC (rev 663)
+++ trunk/game/m_menucore.c	2006-03-08 02:30:28 UTC (rev 664)
@@ -115,6 +115,10 @@
 		if (thisi->parent->selecteditem == item)
 			thisi->parent->selecteditem = NULL;
 	Menu_RemoveFromParent(item);
+
+	if (Menu.grabs == item)
+		Menu.grabs = NULL;	//hrm.
+
 	Mem_Free(&item);
 }
 Menu_Item *Menu_CreateGenericItem(Menu_SubMenu *parent, int x, int y, int bytes)
@@ -153,18 +157,23 @@
 	R_SetTexture(R.resource_font);
 	R_DrawString(thisi->text, 0, thisi->super.pos[0] + inh->addpos[0], thisi->super.pos[1] + inh->addpos[1], 8, 8, Console_DefaultColorTable, Console_DefaultColorTableSize, thisi->super.parent->selecteditem == &thisi->super);
 }
+void Menu_Text_DefaultUse (struct Menu_TextItem *item)
+{
+	Shell_ExecuteScript("console", item->command);
+}
 Nbool Menu_Text_KeyPress (void *item, UNUSED NUint mod, NUint sym, UNUSED NUint character, Nbool downevent)
 {
 	Menu_TextItem *thisi = item;
 	if (sym == SDLK_RETURN || sym == MOUSE1)
 	{
 		if (downevent)
-			Shell_ExecuteScript("console", thisi->command);
+			if (thisi->UseTextItem)
+				thisi->UseTextItem(thisi);
 		return true;
 	}
 	return false;
 }
-Menu_TextItem *Menu_CreateTextItem(Menu_SubMenu *parent, int x, int y, char *text, char *command)
+Menu_TextItem *Menu_CreateTextItem(Menu_SubMenu *parent, int x, int y, char *text, void *command, void (*UseTextItem) (struct Menu_TextItem *item))
 {
 	Menu_TextItem *it;
 	it = (Menu_TextItem*)Menu_CreateGenericItem(parent, x, y, sizeof(Menu_TextItem));
@@ -181,17 +190,276 @@
 	it->text = text;
 	it->command = command;
 
+	if (UseTextItem == NULL && command)
+		UseTextItem = Menu_Text_DefaultUse;
+
+	it->UseTextItem = UseTextItem;
+
 	return it;
 }
 
 
 
 
+//text-edit fields
+//fixme: only work with grabs?
+void Menu_DrawEditItem(void *item, Menu_Inheritance *inh)
+{
+	Menu_EditItem *thisi = item;
+	R_SetBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+	R_SetTexture(R.resource_font);
+	R_DrawString(thisi->text, 0, thisi->super.pos[0] + inh->addpos[0], thisi->super.pos[1] + inh->addpos[1], 8, 8, Console_DefaultColorTable, Console_DefaultColorTableSize, thisi->super.parent->selecteditem == &thisi->super);
+	if (thisi->super.parent->selecteditem == &thisi->super)
+		R_DrawString("_", 0, thisi->super.pos[0] + inh->addpos[0] + thisi->cursorpos*8, thisi->super.pos[1] + inh->addpos[1], 8, 8, Console_DefaultColorTable, Console_DefaultColorTableSize, 0);
+}
+Nbool Menu_Edit_KeyPress (void *item, UNUSED NUint mod, NUint sym, NUint character, Nbool downevent)
+{
+	Menu_EditItem *thisi = item;
+	if (sym == SDLK_RETURN || sym == MOUSE1)
+	{
+//		if (downevent)
+//			Shell_ExecuteScript("console", thisi->command);
+		return true;
+	}
+	if (sym == SDLK_BACKSPACE)
+	{
+		if (!downevent)
+			return true;
+		if (!thisi->cursorpos)
+		{
+			if (*thisi->text)
+				thisi->cursorpos = 1;
+			else
+				return true;
+		}
 
+		memmove(thisi->text+thisi->cursorpos-1, thisi->text+thisi->cursorpos, strlen(thisi->text+thisi->cursorpos)+1);
+		thisi->cursorpos--;
+		return true;
+	}
+	if (sym == SDLK_HOME)
+	{
+		thisi->cursorpos = 0;
+		return true;
+	}
+	if (sym == SDLK_END)
+	{
+		thisi->cursorpos = strlen(thisi->text);
+		return true;
+	}
+	if (sym == SDLK_LEFT)
+	{
+		thisi->cursorpos -= downevent;
+		if (thisi->cursorpos < 0)
+			thisi->cursorpos = 0;
+		return true;
+	}
+	if (sym == SDLK_RIGHT)
+	{
+		thisi->cursorpos += downevent;
+		if (thisi->cursorpos > strlen(thisi->text))
+			thisi->cursorpos = strlen(thisi->text);
+		return true;
+	}
 
+	if (character && character != SDLK_TAB)
+	{
+		char *newt;
+		if (!downevent)
+			return true;
 
+		if (thisi->maxchars && thisi->maxchars <= strlen(thisi->text))
+			return true;	//already reached the max
 
+		newt = Mem_Alloc(Menu.menu_zone, strlen(thisi->text)+2);
+		memcpy(newt, thisi->text, thisi->cursorpos);
+		memcpy(newt+thisi->cursorpos+1, thisi->text+thisi->cursorpos, strlen(thisi->text+thisi->cursorpos)+1);
+		newt[thisi->cursorpos] = character;
 
+		Mem_Free(&thisi->text);
+		thisi->text = newt;
+
+		thisi->cursorpos++;
+		return true;
+	}
+	return false;
+}
+Menu_EditItem *Menu_CreateEditItem(Menu_SubMenu *parent, int x, int y, char *text)
+{
+	Menu_EditItem *it;
+	it = (Menu_EditItem*)Menu_CreateGenericItem(parent, x, y, sizeof(Menu_EditItem));
+
+	it->super.DrawMenu = Menu_DrawEditItem;
+	it->super.MouseMove = Menu_Generic_MouseMoveSelectable;
+	it->super.KeyEvent = Menu_Edit_KeyPress;
+	it->super.size[0] = 8*strlen(text);
+	it->super.size[1] = 8;
+
+	//FIXME: No delete to free the text
+	it->text = Mem_Alloc(Menu.menu_zone, strlen(text)+1);
+	strcpy(it->text, text);
+	it->cursorpos = strlen(text);
+//	it->command = command;
+
+	return it;
+}
+
+
+
+
+
+
+
+
+
+
+//combos
+void Menu_DrawComboItem(void *item, Menu_Inheritance *inh)
+{
+	Menu_ComboItem *thisi = item;
+	R_SetBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+	R_SetTexture(R.resource_font);
+	R_DrawString(thisi->text, 0, thisi->super.pos[0] + inh->addpos[0], thisi->super.pos[1] + inh->addpos[1], 8, 8, Console_DefaultColorTable, Console_DefaultColorTableSize, thisi->super.parent->selecteditem == &thisi->super);
+
+	R_DrawString("V", 0, thisi->super.pos[0] + thisi->super.size[0]-8 + inh->addpos[0], thisi->super.pos[1] + inh->addpos[1], 8, 8, Console_DefaultColorTable, Console_DefaultColorTableSize, thisi->super.parent->selecteditem == &thisi->super);
+}
+
+void Menu_Combo_SetText(Menu_ComboItem *thisi, char *text)//it's just easier. not sure weather this should be public or not.
+{
+	Menu_ComboOption *option;
+	char *oldtext;
+	oldtext = thisi->text;
+	thisi->text = Mem_Alloc(Menu.menu_zone, strlen(text)+1);
+	strcpy(thisi->text, text);
+
+	thisi->selected = NULL;
+	for (option = thisi->options; option; option = option->next)
+	{
+		if (!strcmp(option->text, text))
+		{
+			thisi->selected = option;
+			break;
+		}
+	}
+
+	Mem_Free(&oldtext);
+}
+
+void Menu_ComboSlider (struct Menu_SliderItem *slider)
+{
+	Menu_SubMenu *thisi = slider->data;
+	thisi->subwindow.pos[1] = -slider->value;
+}
+void Menu_UseOption (Menu_TextItem *it)
+{
+	Menu_ComboItem *thisi = (void*)it->command;
+	Menu_Combo_SetText(thisi, it->text);
+
+	//seeing as this happens from a key event, and the text control will return true, we can safly kill the popup
+	thisi->popup->super.Destroy(thisi->popup);
+}
+
+
+Nbool Menu_Combo_KeyPress (void *item, UNUSED NUint mod, UNUSED NUint sym, UNUSED NUint character, UNUSED Nbool downevent)
+{
+	int i;
+	Menu_TextItem *txt;
+	Menu_ComboItem *thisi = item;
+	Menu_ComboOption *option;
+	Menu_SubMenu *interior;
+	int pixels;
+	if (sym == SDLK_RETURN || sym == MOUSE1)
+	{
+		thisi->popup = Menu_CreateMenu(&Menu.rootmenu);
+		Menu_BringToFront(thisi->popup);
+		interior = Menu_CreateMenu(thisi->popup);
+		interior->allowclose = false;
+		Menu.grabs = &thisi->popup->super;
+		option = thisi->options;
+		for (i = 0; option; i+=8, option = option->next)
+		{
+			txt = Menu_CreateTextItem(interior, 0, i, option->text, thisi, Menu_UseOption);
+			txt->super.size[0] = thisi->super.size[0] - 8;
+		}
+		pixels = i-64;
+		if (pixels < 0)
+			pixels = 0;
+		Menu_CreateVSliderItem(thisi->popup, thisi->super.size[0] - 8, 0, 8, ((i>64)?64:i), 0, pixels, 0, Menu_ComboSlider, NULL, interior);
+
+		thisi->popup->super.pos[0] = Input.mouse[0];
+		thisi->popup->super.pos[1] = Input.mouse[1];
+
+		thisi->popup->subwindow.pos[0] = thisi->popup->super.pos[0];
+		thisi->popup->subwindow.pos[1] = thisi->popup->super.pos[1];
+		Menu_FinishMenu(interior);
+		interior->super.size[1] = ((i>64)?64:i);
+		Menu_FinishMenu(thisi->popup);
+		return true;
+	}
+	return false;
+}
+
+void Menu_Combo_Destroy(void *item)
+{
+	Menu_ComboItem *combo = item;
+	if (combo->popup)
+		combo->popup->super.Destroy(combo->popup);
+	Menu_Generic_Destroy(item);
+}
+
+Menu_ComboItem *Menu_CreateComboItem(Menu_SubMenu *parent, int x, int y, int w, char *defalt, char *list)
+{
+	char *pipe;
+	int chars;
+	int ident;
+	Menu_ComboOption *option;
+	//list is pipe-sperated
+	Menu_ComboItem *it;
+	it = (Menu_ComboItem*)Menu_CreateGenericItem(parent, x, y, sizeof(Menu_ComboItem));
+
+	it->super.DrawMenu = Menu_DrawComboItem;
+	it->super.MouseMove = Menu_Generic_MouseMoveSelectable;
+	it->super.KeyEvent = Menu_Combo_KeyPress;
+	it->super.Destroy = Menu_Combo_Destroy;
+	it->super.size[0] = w;
+	it->super.size[1] = 8;
+
+	//FIXME: no delete to free the text
+	it->text = Mem_Alloc(Menu.menu_zone, strlen(defalt)+1);
+	strcpy(it->text, defalt);
+
+	if (*list)
+	{
+		ident = 0;
+		for (pipe = list; ; pipe++)
+		{
+			if (*pipe == '|' || *pipe == '\0')
+			{
+				chars = pipe - list;
+
+				option = Mem_Alloc(Menu.menu_zone, sizeof(Menu_ComboOption) + chars+1);
+				option->text = (char*)(option+1);
+				option->ident = ident++;
+				strncpy(option->text, list, chars);
+				option->text[chars] = '\0';
+				option->next = it->options;
+				it->options = option;
+
+				if (*pipe == '\0')
+					break;
+				pipe++;
+				list = pipe;
+			}
+		}
+	}
+
+	return it;
+}
+
+
+
+
+
 //picture items
 void Menu_Picture_Draw(void *item, Menu_Inheritance *inh)
 {
@@ -427,7 +695,7 @@
 	int j;
 	int wmin, wmax;
 
-	if (Menu.grabs == &thisi->super)
+	if (Menu.grabs == &thisi->super && thisi->dragable)
 	{
 		thisi->subwindow.pos[0] += Input.mouse[0] - thisi->dragmousepos[0];
 		thisi->subwindow.pos[1] += Input.mouse[1] - thisi->dragmousepos[1];
@@ -478,7 +746,7 @@
 void Menu_DrawSubMenu(void *item, Menu_Inheritance *inh)
 {
 	Menu_SubMenu *thisi = item;
-	Menu_Item *subitem;
+	Menu_Item *subitem, *next;
 	Menu_Inheritance ninh;
 	int wmin, wmax;
 	int j;
@@ -507,8 +775,11 @@
 
 	R_SetScissor(ninh.window.pos[0], ninh.window.pos[1], ninh.window.size[0], ninh.window.size[1]);
 
-	for (subitem = thisi->subitems; subitem; subitem = subitem->next)
+	for (subitem = thisi->subitems; subitem; subitem = next)
+	{
+		next = subitem->next;//this funkyness is so that we can unlink and kill things in the draw function (if the need arises).
 		subitem->DrawMenu(subitem, &ninh);
+	}
 
 	R_SetScissor(inh->window.pos[0], inh->window.pos[1], inh->window.size[0], inh->window.size[1]);
 }
@@ -637,41 +908,52 @@
 void Menu_ArrangeSubItems(Menu_SubMenu *menu, Nbool horizontal, int pad, Menu_ArrangeStyle arrange)
 {
 	Menu_Item *sitem;
-	int side;
+	int axis, otheraxis;
 	int val = 0;
 	int maxval=0;
 
+	//axis is usually the 'vertical' axis, where each field is spaced with padding
+	//otheraxis is the axis on which we align stuff (rather than just space it)
+
 	if (horizontal)
-		side = 0;
+		axis = 0;
 	else
-		side = 1;
+		axis = 1;
 
+	otheraxis = !axis;
+
 	for (sitem = menu->subitems; sitem; sitem = sitem->next)
 	{
-		sitem->pos[side] = maxval;
-		maxval += sitem->size[side] + pad;
+		sitem->pos[axis] = maxval;
+		maxval += sitem->size[axis] + pad;
 	}
 
 	val = maxval;
 	for (sitem = menu->subitems; sitem; sitem = sitem->next)
 	{
-		val -= sitem->size[side] + pad;
-		sitem->pos[side] = val;
+		val -= sitem->size[axis] + pad;
+		sitem->pos[axis] = val;
 
 		switch(arrange)
 		{
+		case MENU_ARRANGESTYLE_LEAVEALONE:
+			break;
+
 		case MENU_ARRANGESTYLE_LEFT:
-			sitem->pos[side^1] = 0;
+			sitem->pos[otheraxis] = 0;
 			break;
+
 		case MENU_ARRANGESTYLE_CENTER:
-			sitem->pos[side^1] = (menu->subwindow.size[side^1] - sitem->size[side^1])/2;
+			sitem->pos[otheraxis] = (menu->subwindow.size[otheraxis] - sitem->size[otheraxis])/2;
 			break;
+
 		case MENU_ARRANGESTYLE_RIGHT:
-			sitem->pos[side^1] = (menu->subwindow.size[side^1] - sitem->size[side^1]);
+			sitem->pos[otheraxis] = (menu->subwindow.size[otheraxis] - sitem->size[otheraxis]);
 			break;
+
 		case MENU_ARRANGESTYLE_RESIZE:
-			sitem->pos[side^1] = 0;
-			sitem->size[side^1] = menu->subwindow.size[side^1];
+			sitem->pos[otheraxis] = 0;
+			sitem->size[otheraxis] = menu->subwindow.size[otheraxis];
 			break;
 		}
 	}
@@ -708,6 +990,19 @@
 
 
 
+
+
+
+
+
+
+
+
+
+
+
+
+
 float sliderscale = 8;
 float imagesize = 512;
 float windowsize = 128;
@@ -782,17 +1077,20 @@
 	Menu_SubMenu *menu = Menu_CreateMenu(&Menu.rootmenu);
 	menu->dragable = true;
 
-	Menu_CreateTextItem(menu, 0, 0, "Main menu", NULL);
+	Menu_CreateTextItem(menu, 0, 0, "Main menu", NULL, NULL);
 
-	Menu_CreateTextItem(menu, 0, 16, "Hello World", "echo Hello World\n");
-	Menu_CreateTextItem(menu, 0, 24, "Start up test map", "map test\n");
-	Menu_CreateTextItem(menu, 0, 32, "Go to the west!", "map west\n");
-	Menu_CreateTextItem(menu, 0, 40, "quit", "menu_quit\n");
+	Menu_CreateTextItem(menu, 0, 16, "Hello World", "echo Hello World\n", NULL);
+	Menu_CreateTextItem(menu, 0, 24, "Start up test map", "map test\n", NULL);
+	Menu_CreateTextItem(menu, 0, 32, "Go to the west!", "map west\n", NULL);
+	Menu_CreateTextItem(menu, 0, 40, "quit", "menu_quit\n", NULL);
 
-	Menu_CreateTextItem(menu, 0, 56, "Close menu", "menu_close\n");
+	Menu_CreateTextItem(menu, 0, 56, "Close menu", "menu_close\n", NULL);
 
-	Menu_CreateTextItem(menu, 0, 56+16, "test menu", "menu_test\n");
+	Menu_CreateTextItem(menu, 0, 56+16, "test menu", "menu_test\n", NULL);
 
+	Menu_CreateEditItem(menu, 0, 56, "EditItem");
+	Menu_CreateComboItem(menu, 0, 56, 21*8, "ComboItem", "Option 1|Option 2|Option 3|Fuzzy Little Bunnies|Big Rocket Launcher|Children|Lightning Gun|Newborn Chicks|Grenade Launcher|Rodents|Nukes");
+
 	Menu_FinishMenu(menu);
 	Menu_ArrangeSubItems(menu, false, 0, MENU_ARRANGESTYLE_CENTER);
 	Menu_FinishMenu(menu);
@@ -833,10 +1131,10 @@
 	Menu_SubMenu *menu = Menu_CreateMenu(&Menu.rootmenu);
 	menu->dragable = true;
 
-	Menu_CreateTextItem(menu, 0, 0, "Really Quit?", NULL);
+	Menu_CreateTextItem(menu, 0, 0, "Really Quit?", NULL, NULL);
 
-	Menu_CreateTextItem(menu, 0, 16, "Yes, and wipe my harddrive too.", "quit\n");
-	Menu_CreateTextItem(menu, 0, 24, "No. I want to keep playing this awesome game", "menu_close\n");
+	Menu_CreateTextItem(menu, 0, 16, "Yes, and wipe my harddrive too.", "quit\n", NULL);
+	Menu_CreateTextItem(menu, 0, 24, "No. I want to keep playing this awesome game", "menu_close\n", NULL);
 
 	Menu_FinishMenu(menu);
 

Modified: trunk/game/m_menucore.h
===================================================================
--- trunk/game/m_menucore.h	2006-03-08 02:19:29 UTC (rev 663)
+++ trunk/game/m_menucore.h	2006-03-08 02:30:28 UTC (rev 664)
@@ -54,17 +54,55 @@
 {
 	Menu_Item super;
 
-	char *text;
-	char *command;	//it's handy
+	char *text;	//what to display (warning: it's a pointer, isn't freed, and isn't copied)
+	void *command;	//command is a misnomer, it should be used as a cookie for the text item
+
+	void (*UseTextItem) (struct Menu_TextItem *item);	//called when the user uses this item
 }
 Menu_TextItem;
 
+typedef struct Menu_EditItem
+{
+	Menu_Item super;
+
+	char *text;	//what it currently says
+	int cursorpos; //where the cursor is, set between 0 and strlen(text)
+	int scrollpos; //fixme
+	int maxchars;  //0 for unlimited
+}
+Menu_EditItem;
+
+typedef struct Menu_ComboOption
+{
+	char *text;	//the text of the item
+	int ident;	//if you wish to assosiate an int key with the item.
+	struct Menu_ComboOption *next;
+}
+Menu_ComboOption;
+
+typedef struct Menu_ComboItem
+{
+	Menu_Item super;
+
+	Nbool editable;	//user may type into the control
+	struct Menu_ComboOption *options;	//a list of the current options
+	struct Menu_ComboOption *selected;	//set 
+
+	char *text;
+	int cursorpos;
+	int scrollpos;
+	int maxchars;
+
+	struct Menu_SubMenu *popup;
+}
+Menu_ComboItem;
+
 typedef struct Menu_PictureItem
 {
 	Menu_Item super;
 
 	char *imagename;
-	char *command;	//it's handy
+	char *command;	//console command when clicked
 }
 Menu_PictureItem;
 
@@ -75,22 +113,23 @@
 	void *data;	//for custom stuff
 	float value;//set and used in the slider code
 
-	float minv;
-	float maxv;
+	float minv;//min value
+	float maxv;//max (can be inverted)
 
-	float scale;
+	float scale;//size of slider, in pixels.
 
 	//notification function
 	void (*SliderChanged) (struct Menu_SliderItem *slider);	//the user just changed the slider->value
 	void (*SliderUpdate) (struct Menu_SliderItem *slider);		//about to draw the slider's value, where you should feel free to update the value from external sources
 
 	//internal
-	Nbool mousepressed;
+	Nbool mousepressed; //adjust the slider with the mouse
 }
 Menu_SliderItem;
 
 typedef enum Menu_ArrangeStyle
 {
+	MENU_ARRANGESTYLE_LEAVEALONE,
 	MENU_ARRANGESTYLE_LEFT,
 	MENU_ARRANGESTYLE_CENTER,
 	MENU_ARRANGESTYLE_RIGHT,
@@ -114,4 +153,13 @@
 Nbool Menu_IsVisible(void);
 Nbool Menu_KeyEvent(NUint mod, NUint sym, UNUSED NUint character, Nbool downevent);
 
+
+Menu_SubMenu *Menu_CreateMenu(Menu_SubMenu *parent);
+Menu_SliderItem *Menu_CreateVSliderItem(Menu_SubMenu *parent, int x, int y, int w, int h, float minv, float maxv, float defaultv, void (*ChangeNotification)(Menu_SliderItem*), void (*UpdateSlider)(Menu_SliderItem*), void *data);//vertical scrolling bar
+Menu_SliderItem *Menu_CreateHSliderItem(Menu_SubMenu *parent, int x, int y, int w, int h, float minv, float maxv, float defaultv, void (*ChangeNotification)(Menu_SliderItem*), void (*UpdateSlider)(Menu_SliderItem*), void *data);//horizontal scrolling bar
+Menu_TextItem *Menu_CreateTextItem(Menu_SubMenu *parent, int x, int y, char *text, void *command, void (*UseTextItem) (struct Menu_TextItem *item)); //if usetextitem == null, interpret as a console command. if not null, command can be used as a magic cookie. If both null, item is non-selectable.
+Menu_EditItem *Menu_CreateEditItem(Menu_SubMenu *parent, int x, int y, char *text); //an item for editing text (fixme: needs callbacks and stuff)
+Menu_ComboItem *Menu_CreateComboItem(Menu_SubMenu *parent, int x, int y, int w, char *defalt, char *list);//a list of multiple choices.
+Menu_PictureItem *Menu_CreatePictureItem(Menu_SubMenu *parent, int x, int y, int w, int h, char *imagename, char *command); //just a simple picture. clicking it can give a console command (fixme: make like text)
+
 #endif




More information about the neither-commits mailing list