[Scummvm-git-logs] scummvm master -> ae8fc03e3a1800eef97bd1a45b282e107a4baf95

dreammaster noreply at scummvm.org
Thu Feb 13 06:44:07 UTC 2025


This automated email contains information about 3 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
d5313f37f9 M4: RIDDLE: Move msg methods to menuItemMsg
01da5fd1cf M4: RIDDLE: Move slider methods to slider classes
ae8fc03e3a M4: RIDDLE: Move text field methods to menuItemTextField


Commit: d5313f37f95210d0de729594626d0a0d679e33da
    https://github.com/scummvm/scummvm/commit/d5313f37f95210d0de729594626d0a0d679e33da
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2025-02-12T21:51:07-08:00

Commit Message:
M4: RIDDLE: Move msg methods to menuItemMsg

Changed paths:
    engines/m4/burger/gui/game_menu.cpp
    engines/m4/burger/gui/game_menu.h
    engines/m4/gui/gui_menu.cpp
    engines/m4/gui/gui_menu.h


diff --git a/engines/m4/burger/gui/game_menu.cpp b/engines/m4/burger/gui/game_menu.cpp
index a8455c4761f..2f2af9d904d 100644
--- a/engines/m4/burger/gui/game_menu.cpp
+++ b/engines/m4/burger/gui/game_menu.cpp
@@ -235,127 +235,6 @@ Sprite *menu_CreateThumbnail(int32 *spriteSize) {
 	return thumbNailSprite;
 }
 
-//-------------------------------    MESSAGE MENU ITEM    ---------------------------------//
-
-
-void menu_DrawMsg(menuItemMsg *myItem, guiMenu *myMenu, int32 x, int32 y, int32, int32) {
-	Buffer *myBuff = nullptr;
-	Buffer *backgroundBuff = nullptr;
-	Sprite *mySprite = nullptr;
-
-	// Verify params
-	if (!myItem || !myMenu) {
-		return;
-	}
-
-	// If the item is marked transparent, get the background buffer
-	if (myItem->transparent) {
-		if (!myItem->background) {
-			return;
-		}
-		backgroundBuff = myItem->background->get_buffer();
-		if (!backgroundBuff) {
-			return;
-		}
-	}
-
-	// Get the button info and select the sprite
-	//myMsg = (menuItemMsg *)myItem->itemInfo;
-	switch (myItem->tag) {
-	case SL_TAG_SAVE_LABEL:
-		mySprite = _GM(menuSprites)[Burger::GUI::SL_SAVE_LABEL];
-		break;
-	case SL_TAG_LOAD_LABEL:
-		mySprite = _GM(menuSprites)[Burger::GUI::SL_LOAD_LABEL];
-		break;
-	case SL_TAG_THUMBNAIL:
-		mySprite = _GM(saveLoadThumbNail);
-		break;
-	}
-
-	// Get the menu buffer and draw the sprite to it
-	myBuff = myMenu->menuBuffer->get_buffer();
-	if (!myBuff) {
-		return;
-	}
-
-	// If the item is tagged as transparent, we need to fill in it's background behind it
-	if (backgroundBuff) {
-		gr_buffer_rect_copy_2(backgroundBuff, myBuff, 0, 0, x, y, backgroundBuff->w, backgroundBuff->h);
-		myItem->background->release();
-	} else if (myItem->tag == SL_TAG_THUMBNAIL && mySprite->w == 160) {
-		// Hack for handling smaller ScummVM thumbnails
-		for (int yp = y; yp < (y + SL_THUMBNAIL_H); ++yp) {
-			byte *line = myBuff->data + myBuff->stride * yp + x;
-			Common::fill(line, line + SL_THUMBNAIL_W, 0);
-		}
-
-		x += 25;
-		y += 25;
-	}
-
-	// Draw the sprite in
-	gui_DrawSprite(mySprite, myBuff, x, y);
-
-	// Release the menu buffer
-	myMenu->menuBuffer->release();
-}
-
-
-menuItemMsg *menu_MsgAdd(guiMenu *myMenu, int32 tag, int32 x, int32 y, int32 w, int32 h, bool transparent) {
-	menuItemMsg *newItem;
-	ScreenContext *myScreen;
-	int32 status;
-
-	// Verify params
-	if (!myMenu) {
-		return nullptr;
-	}
-
-	// Allocate a new one
-	newItem = new menuItemMsg();
-
-	// Initialize the struct
-	newItem->next = myMenu->itemList;
-	newItem->prev = nullptr;
-	if (myMenu->itemList) {
-		myMenu->itemList->prev = newItem;
-	}
-	myMenu->itemList = newItem;
-
-	newItem->myMenu = myMenu;
-	newItem->tag = tag;
-	newItem->x1 = x;
-	newItem->y1 = y;
-	newItem->x2 = x + w - 1;
-	newItem->y2 = y + h - 1;
-	newItem->callback = nullptr;
-
-	if (!transparent) {
-		newItem->transparent = false;
-		newItem->background = nullptr;
-	} else {
-		newItem->transparent = true;
-		newItem->background = guiMenu::copyBackground(myMenu, x, y, w, h);
-	}
-
-	newItem->redraw = (DrawFunction)menu_DrawMsg;
-	newItem->destroy = (DestroyFunction)menuItem::destroyItem;
-	newItem->itemEventHandler = nullptr;
-
-	// Draw the message in now
-	(newItem->redraw)(newItem, myMenu, x, y, 0, 0);
-
-	// See if the screen is currently visible
-	myScreen = vmng_screen_find(myMenu, &status);
-	if (myScreen && (status == SCRN_ACTIVE)) {
-		RestoreScreens(myScreen->x1 + newItem->x1, myScreen->y1 + newItem->y1,
-			myScreen->x1 + newItem->x2, myScreen->y1 + newItem->y2);
-	}
-
-	return newItem;
-}
-
 //-------------------------------    HSLIDER MENU ITEM    ---------------------------------//
 
 enum {
@@ -2236,11 +2115,11 @@ void CreateSaveLoadMenu(RGB8 *myPalette, bool saveMenu) {
 	}
 
 	if (_GM(currMenuIsSave)) {
-		menu_MsgAdd(_GM(slMenu), SL_TAG_SAVE_LABEL, SL_SAVE_LABEL_X, SL_SAVE_LABEL_Y, SL_SAVE_LABEL_W, SL_SAVE_LABEL_H);
+		menuItemMsg::msgAdd(_GM(slMenu), SL_TAG_SAVE_LABEL, SL_SAVE_LABEL_X, SL_SAVE_LABEL_Y, SL_SAVE_LABEL_W, SL_SAVE_LABEL_H);
 		menuItemButton::buttonAdd(_GM(slMenu), SL_TAG_SAVE, SL_SAVE_X, SL_SAVE_Y, SL_SAVE_W, SL_SAVE_H,
 			(CALLBACK)cb_SaveLoad_Save, menuItemButton::BTN_TYPE_SL_SAVE, true);
 	} else {
-		menu_MsgAdd(_GM(slMenu), SL_TAG_LOAD_LABEL, SL_LOAD_LABEL_X, SL_LOAD_LABEL_Y, SL_LOAD_LABEL_W, SL_LOAD_LABEL_H);
+		menuItemMsg::msgAdd(_GM(slMenu), SL_TAG_LOAD_LABEL, SL_LOAD_LABEL_X, SL_LOAD_LABEL_Y, SL_LOAD_LABEL_W, SL_LOAD_LABEL_H);
 		menuItemButton::buttonAdd(_GM(slMenu), SL_TAG_LOAD, SL_LOAD_X, SL_LOAD_Y, SL_LOAD_W, SL_LOAD_H,
 			(CALLBACK)cb_SaveLoad_Load, menuItemButton::BTN_TYPE_SL_LOAD, true);
 	}
@@ -2281,7 +2160,7 @@ void CreateSaveLoadMenu(RGB8 *myPalette, bool saveMenu) {
 		_GM(saveLoadThumbNail) = _GM(menuSprites)[Burger::GUI::SL_EMPTY_THUMB];
 	}
 
-	menu_MsgAdd(_GM(slMenu), SL_TAG_THUMBNAIL, SL_THUMBNAIL_X, SL_THUMBNAIL_Y, SL_THUMBNAIL_W, SL_THUMBNAIL_H, false);
+	menuItemMsg::msgAdd(_GM(slMenu), SL_TAG_THUMBNAIL, SL_THUMBNAIL_X, SL_THUMBNAIL_Y, SL_THUMBNAIL_W, SL_THUMBNAIL_H, false);
 
 	if (_GM(currMenuIsSave)) {
 		//<return> - if a slot has been selected, saves the game
diff --git a/engines/m4/burger/gui/game_menu.h b/engines/m4/burger/gui/game_menu.h
index 7a8ae6df6f6..506dbe000eb 100644
--- a/engines/m4/burger/gui/game_menu.h
+++ b/engines/m4/burger/gui/game_menu.h
@@ -45,11 +45,6 @@ using M4::GUI::ItemHandlerFunction;
 
 // SPECIFIC ITEM FUNCTIONS
 
-// Messages
-extern menuItemMsg *menu_MsgAdd(guiMenu *myMenu, int32 tag, int32 x, int32 y, int32 w, int32 h, bool transparent = false);
-extern void menu_DisableMsg(menuItemMsg *myItem, int32 tag, guiMenu *myMenu);
-extern void menu_EnableMsg(menuItemMsg *myItem, int32 tag, guiMenu *myMenu);
-
 // Horizontal sliders
 menuItemHSlider *menu_HSliderAdd(guiMenu *myMenu, int32 tag, int32 x, int32 y, int32 w, int32 h,
 	int32 initPercent = 0, CALLBACK callback = nullptr, bool transparent = false);
@@ -98,16 +93,6 @@ enum game_menu_button_tags {
 #define SAVE_LOAD_MENU_W		344
 #define SAVE_LOAD_MENU_H		460
 
-enum save_load_menu_item_tags {
-	SL_TAG_SAVE = 100,
-	SL_TAG_SAVE_LABEL,
-	SL_TAG_LOAD,
-	SL_TAG_LOAD_LABEL,
-	SL_TAG_CANCEL,
-	SL_TAG_VSLIDER,
-	SL_TAG_THUMBNAIL
-};
-
 #define SL_SAVE_X			214
 #define SL_SAVE_Y			384
 #define SL_SAVE_W			 74
diff --git a/engines/m4/gui/gui_menu.cpp b/engines/m4/gui/gui_menu.cpp
index 7ae72e61400..3527e9e7d23 100644
--- a/engines/m4/gui/gui_menu.cpp
+++ b/engines/m4/gui/gui_menu.cpp
@@ -1132,5 +1132,125 @@ void menuItemButton::enableButton(menuItemButton *myItem, int32 tag, guiMenu *my
 	myItem->itemFlags = BTN_STATE_NORM;
 }
 
+
+//-----------------------------  MSG FUNCTIONS    ---------------------------------//
+
+menuItemMsg *menuItemMsg::msgAdd(guiMenu *myMenu, int32 tag, int32 x, int32 y, int32 w, int32 h, bool transparent) {
+	menuItemMsg *newItem;
+	ScreenContext *myScreen;
+	int32 status;
+
+	// Verify params
+	if (!myMenu) {
+		return nullptr;
+	}
+
+	// Allocate a new one
+	newItem = new menuItemMsg();
+
+	// Initialize the struct
+	newItem->next = myMenu->itemList;
+	newItem->prev = nullptr;
+	if (myMenu->itemList) {
+		myMenu->itemList->prev = newItem;
+	}
+	myMenu->itemList = newItem;
+
+	newItem->myMenu = myMenu;
+	newItem->tag = tag;
+	newItem->x1 = x;
+	newItem->y1 = y;
+	newItem->x2 = x + w - 1;
+	newItem->y2 = y + h - 1;
+	newItem->callback = nullptr;
+
+	if (!transparent) {
+		newItem->transparent = false;
+		newItem->background = nullptr;
+	} else {
+		newItem->transparent = true;
+		newItem->background = guiMenu::copyBackground(myMenu, x, y, w, h);
+	}
+
+	newItem->redraw = (DrawFunction)menuItemMsg::drawMsg;
+	newItem->destroy = (DestroyFunction)menuItem::destroyItem;
+	newItem->itemEventHandler = nullptr;
+
+	// Draw the message in now
+	(newItem->redraw)(newItem, myMenu, x, y, 0, 0);
+
+	// See if the screen is currently visible
+	myScreen = vmng_screen_find(myMenu, &status);
+	if (myScreen && (status == SCRN_ACTIVE)) {
+		RestoreScreens(myScreen->x1 + newItem->x1, myScreen->y1 + newItem->y1,
+			myScreen->x1 + newItem->x2, myScreen->y1 + newItem->y2);
+	}
+
+	return newItem;
+}
+
+void menuItemMsg::drawMsg(menuItemMsg *myItem, guiMenu *myMenu, int32 x, int32 y, int32, int32) {
+	Buffer *myBuff = nullptr;
+	Buffer *backgroundBuff = nullptr;
+	Sprite *mySprite = nullptr;
+
+	// Verify params
+	if (!myItem || !myMenu) {
+		return;
+	}
+
+	// If the item is marked transparent, get the background buffer
+	if (myItem->transparent) {
+		if (!myItem->background) {
+			return;
+		}
+		backgroundBuff = myItem->background->get_buffer();
+		if (!backgroundBuff) {
+			return;
+		}
+	}
+
+	// Get the button info and select the sprite
+	//myMsg = (menuItemMsg *)myItem->itemInfo;
+	switch (myItem->tag) {
+	case SL_TAG_SAVE_LABEL:
+		mySprite = _GM(menuSprites)[Burger::GUI::SL_SAVE_LABEL];
+		break;
+	case SL_TAG_LOAD_LABEL:
+		mySprite = _GM(menuSprites)[Burger::GUI::SL_LOAD_LABEL];
+		break;
+	case SL_TAG_THUMBNAIL:
+		mySprite = _GM(saveLoadThumbNail);
+		break;
+	}
+
+	// Get the menu buffer and draw the sprite to it
+	myBuff = myMenu->menuBuffer->get_buffer();
+	if (!myBuff) {
+		return;
+	}
+
+	// If the item is tagged as transparent, we need to fill in it's background behind it
+	if (backgroundBuff) {
+		gr_buffer_rect_copy_2(backgroundBuff, myBuff, 0, 0, x, y, backgroundBuff->w, backgroundBuff->h);
+		myItem->background->release();
+	} else if (myItem->tag == SL_TAG_THUMBNAIL && mySprite->w == 160) {
+		// Hack for handling smaller ScummVM thumbnails
+		for (int yp = y; yp < (y + SL_THUMBNAIL_H); ++yp) {
+			byte *line = myBuff->data + myBuff->stride * yp + x;
+			Common::fill(line, line + SL_THUMBNAIL_W, 0);
+		}
+
+		x += 25;
+		y += 25;
+	}
+
+	// Draw the sprite in
+	gui_DrawSprite(mySprite, myBuff, x, y);
+
+	// Release the menu buffer
+	myMenu->menuBuffer->release();
+}
+
 } // namespace GUI
 } // namespace M4
diff --git a/engines/m4/gui/gui_menu.h b/engines/m4/gui/gui_menu.h
index 9b938eefae8..571b7396fb7 100644
--- a/engines/m4/gui/gui_menu.h
+++ b/engines/m4/gui/gui_menu.h
@@ -98,6 +98,16 @@ enum options_menu_sprites {
 	OM_TOTAL_SPRITES
 };
 
+enum save_load_menu_item_tags {
+	SL_TAG_SAVE = 100,
+	SL_TAG_SAVE_LABEL,
+	SL_TAG_LOAD,
+	SL_TAG_LOAD_LABEL,
+	SL_TAG_CANCEL,
+	SL_TAG_VSLIDER,
+	SL_TAG_THUMBNAIL
+};
+
 } // namespace GUI
 } // namespace Burger
 
@@ -173,7 +183,15 @@ struct menuItem {
 
 
 struct menuItemMsg : public menuItem {
+private:
+	static void drawMsg(menuItemMsg *myItem, guiMenu *myMenu, int32 x, int32 y, int32, int32);
+
+public:
 	int32 itemFlags = 0;
+
+	static menuItemMsg *msgAdd(guiMenu *myMenu, int32 tag, int32 x, int32 y, int32 w, int32 h, bool transparent = false);
+	static void disableMsg(menuItemMsg *myItem, int32 tag, guiMenu *myMenu);
+	static void enableMsg(menuItemMsg *myItem, int32 tag, guiMenu *myMenu);
 };
 
 struct menuItemButton : public menuItem {


Commit: 01da5fd1cffc2ce0a440681975ced14d3d778d69
    https://github.com/scummvm/scummvm/commit/01da5fd1cffc2ce0a440681975ced14d3d778d69
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2025-02-12T22:32:47-08:00

Commit Message:
M4: RIDDLE: Move slider methods to slider classes

Changed paths:
    engines/m4/burger/gui/game_menu.cpp
    engines/m4/burger/gui/game_menu.h
    engines/m4/gui/gui_menu.cpp
    engines/m4/gui/gui_menu.h
    engines/m4/riddle/gui/game_menu.cpp


diff --git a/engines/m4/burger/gui/game_menu.cpp b/engines/m4/burger/gui/game_menu.cpp
index 2f2af9d904d..97c198d86f8 100644
--- a/engines/m4/burger/gui/game_menu.cpp
+++ b/engines/m4/burger/gui/game_menu.cpp
@@ -45,10 +45,6 @@ namespace M4 {
 namespace Burger {
 namespace GUI {
 
-static bool buttonClosesDialog;
-
-void UpdateThumbNails(int32 firstSlot, guiMenu *myMenu);
-
 Sprite *menu_CreateThumbnail(int32 *spriteSize) {
 	Sprite *thumbNailSprite;
 	GrBuff *thumbNail;
@@ -235,678 +231,6 @@ Sprite *menu_CreateThumbnail(int32 *spriteSize) {
 	return thumbNailSprite;
 }
 
-//-------------------------------    HSLIDER MENU ITEM    ---------------------------------//
-
-enum {
-	H_THUMB_NORM = 0,
-	H_THUMB_OVER = 1,
-	H_THUMB_PRESS = 2
-};
-
-
-void menu_DrawHSlider(menuItemHSlider *myItem, guiMenu *myMenu, int32 x, int32 y, int32, int32) {
-	Buffer *myBuff = nullptr;
-	Buffer *backgroundBuff = nullptr;
-	Sprite *mySprite = nullptr;
-
-	// Verify params
-	if (!myItem || !myMenu)
-		return;
-
-	// If the item is marked transparent, get the background buffer
-	if (myItem->transparent) {
-		if (!myItem->background) {
-			return;
-		}
-		backgroundBuff = myItem->background->get_buffer();
-		if (!backgroundBuff) {
-			return;
-		}
-	}
-
-	// Get the menu buffer and draw the sprite to it
-	myBuff = myMenu->menuBuffer->get_buffer();
-	if (!myBuff) {
-		return;
-	}
-
-	// If the item is tagged as transparent, we need to fill in it's background behind it
-	if (backgroundBuff) {
-		gr_buffer_rect_copy_2(backgroundBuff, myBuff, 0, 0, x, y, backgroundBuff->w, backgroundBuff->h);
-		myItem->background->release();
-	}
-
-	// Get the slider info and select the thumb sprite
-	switch (myItem->itemFlags) {
-	case H_THUMB_OVER:
-		mySprite = _GM(menuSprites)[OM_SLIDER_BTN_OVER];
-		break;
-	case H_THUMB_PRESS:
-		mySprite = _GM(menuSprites)[OM_SLIDER_BTN_PRESS];
-		break;
-	default:
-	case H_THUMB_NORM:
-		mySprite = _GM(menuSprites)[OM_SLIDER_BTN_NORM];
-		break;
-	}
-
-	// Fill in everything left of the thumb with a hilite color
-	if (myItem->thumbX > 2) {
-		gr_color_set(menuItem::SLIDER_BAR_COLOR);
-		gr_buffer_rect_fill(myBuff, myItem->x1 + 3, myItem->y1 + 9, myItem->thumbX, myItem->thumbH - 18);
-	}
-
-	// Draw in the thumb
-	gui_DrawSprite(mySprite, myBuff, myItem->x1 + myItem->thumbX, myItem->y1);
-
-	// Release the menu buffer
-	myMenu->menuBuffer->release();
-}
-
-
-bool hslider_Handler(menuItemHSlider *myItem, int32 eventType, int32 event, int32 x, int32 y, void **currItem) {
-	bool redrawItem, execCallback, handled;
-	ScreenContext *myScreen;
-	int32 status;
-	int32 deltaSlide;
-	static bool movingFlag;
-	static int32 movingX;
-
-	// Verify params
-	if (!myItem)
-		return false;
-
-	if (!(eventType == EVENT_MOUSE)) {
-		return false;
-	}
-
-	redrawItem = false;
-	handled = true;
-	execCallback = false;
-
-	switch (event) {
-	case _ME_L_click:
-	case _ME_doubleclick:
-		if (menuItem::cursorInsideItem(myItem, x, y) && (x - myItem->x1 >= myItem->thumbX) &&
-				(x - myItem->x1 <= myItem->thumbX + myItem->thumbW - 1)) {
-			myItem->itemFlags = H_THUMB_PRESS;
-			movingFlag = true;
-			movingX = x;
-			*currItem = myItem;
-			redrawItem = true;
-		} else {
-			*currItem = nullptr;
-			myItem->itemFlags = 0;
-			redrawItem = true;
-		}
-		break;
-
-	case _ME_L_drag:
-	case _ME_doubleclick_drag:
-		if (!*currItem) {
-			return true;
-		}
-		if (movingFlag) {
-			if (x < movingX) {
-				deltaSlide = imath_min(myItem->thumbX, movingX - x);
-				if (deltaSlide > 0) {
-					myItem->thumbX -= deltaSlide;
-					redrawItem = true;
-					myItem->percent = myItem->thumbX * 100 / myItem->maxThumbX;
-					execCallback = true;
-				}
-			} else if (x > movingX) {
-				deltaSlide = imath_min(myItem->maxThumbX - myItem->thumbX, x - movingX);
-				if (deltaSlide > 0) {
-					myItem->thumbX += deltaSlide;
-					redrawItem = true;
-					myItem->percent = myItem->thumbX * 100 / myItem->maxThumbX;
-					execCallback = true;
-				}
-			}
-			movingX = x;
-			if (movingX < (myItem->thumbX + myItem->x1)) {
-				movingX = myItem->thumbX + myItem->x1;
-			} else if (movingX > (myItem->thumbX + myItem->thumbW - 1 + myItem->x1)) {
-				movingX = myItem->thumbX + myItem->thumbW - 1 + myItem->x1;
-			}
-		} else {
-			*currItem = nullptr;
-		}
-		break;
-
-	case _ME_L_release:
-	case _ME_doubleclick_release:
-		if (!*currItem) {
-			return true;
-		}
-		movingFlag = false;
-		if (menuItem::cursorInsideItem(myItem, x, y) && (x - myItem->x1 >= myItem->thumbX) &&
-			(x - myItem->x1 <= myItem->thumbX + myItem->thumbW - 1)) {
-			myItem->itemFlags = H_THUMB_OVER;
-			*currItem = myItem;
-		} else {
-			myItem->itemFlags = H_THUMB_NORM;
-			*currItem = nullptr;
-		}
-		redrawItem = true;
-		execCallback = true;
-		break;
-
-	case _ME_move:
-		if (menuItem::cursorInsideItem(myItem, x, y) && (x - myItem->x1 >= myItem->thumbX) &&
-			(x - myItem->x1 <= myItem->thumbX + myItem->thumbW - 1)) {
-			if (myItem->itemFlags != H_THUMB_OVER) {
-				myItem->itemFlags = H_THUMB_OVER;
-				*currItem = myItem;
-				redrawItem = true;
-			}
-		} else {
-			if (myItem->itemFlags != H_THUMB_NORM) {
-				myItem->itemFlags = H_THUMB_NORM;
-				*currItem = nullptr;
-				redrawItem = true;
-				handled = false;
-			}
-		}
-		break;
-
-	case _ME_L_hold:
-	case _ME_doubleclick_hold:
-		break;
-	}
-
-	// See if we need to redraw the hslider
-	if (redrawItem) {
-		(myItem->redraw)(myItem, myItem->myMenu, myItem->x1, myItem->y1, 0, 0);
-		myScreen = vmng_screen_find(myItem->myMenu, &status);
-		if (myScreen && (status == SCRN_ACTIVE)) {
-			RestoreScreens(myScreen->x1 + myItem->x1, myScreen->y1 + myItem->y1,
-				myScreen->x1 + myItem->x2, myScreen->y1 + myItem->y2);
-		}
-	}
-
-	// See if we need to call the callback function
-	if (execCallback && myItem->callback) {
-		(myItem->callback)((void *)myItem, myItem->myMenu);
-		myScreen = vmng_screen_find(myItem->myMenu, &status);
-		if ((!myScreen) || (status != SCRN_ACTIVE)) {
-			*currItem = nullptr;
-		}
-	}
-
-	return handled;
-}
-
-
-menuItemHSlider *menu_HSliderAdd(guiMenu *myMenu, int32 tag, int32 x, int32 y, int32 w, int32 h,
-	int32 initPercent, CALLBACK callback, bool transparent) {
-	menuItemHSlider *newItem;
-	ScreenContext *myScreen;
-	int32 status;
-
-	// Verify params
-	if (!myMenu) {
-		return nullptr;
-	}
-
-	// Allocate a new one
-	newItem = new menuItemHSlider();
-
-	// Initialize the struct
-	newItem->next = myMenu->itemList;
-	newItem->prev = nullptr;
-	if (myMenu->itemList) {
-		myMenu->itemList->prev = newItem;
-	}
-	myMenu->itemList = newItem;
-
-	newItem->myMenu = myMenu;
-	newItem->tag = tag;
-	newItem->x1 = x;
-	newItem->y1 = y;
-	newItem->x2 = x + w - 1;
-	newItem->y2 = y + h - 1;
-	newItem->callback = callback;
-
-	if (!transparent) {
-		newItem->transparent = false;
-		newItem->background = nullptr;
-	} else {
-		newItem->transparent = true;
-		newItem->background = guiMenu::copyBackground(myMenu, x, y, w, h);
-	}
-
-	// Intialize the new slider
-	newItem->itemFlags = H_THUMB_NORM;
-	newItem->thumbW = _GM(menuSprites)[OM_SLIDER_BTN_NORM]->w;
-	newItem->thumbH = _GM(menuSprites)[OM_SLIDER_BTN_NORM]->h;
-	newItem->maxThumbX = w - _GM(menuSprites)[OM_SLIDER_BTN_NORM]->w;
-
-	if (initPercent < 0) {
-		initPercent = 0;
-	} else if (initPercent > 100) {
-		initPercent = 100;
-	}
-
-	// Calculate the initial thumbX
-	newItem->percent = initPercent;
-	newItem->thumbX = initPercent * newItem->maxThumbX / 100;
-
-	newItem->redraw = (DrawFunction)menu_DrawHSlider;
-	newItem->destroy = (DestroyFunction)menuItem::destroyItem;
-	newItem->itemEventHandler = (ItemHandlerFunction)hslider_Handler;
-
-	// Draw the slider in now
-	(newItem->redraw)(newItem, myMenu, x, y, 0, 0);
-
-	// See if the screen is currently visible
-	myScreen = vmng_screen_find(myMenu, &status);
-	if (myScreen && (status == SCRN_ACTIVE)) {
-		RestoreScreens(myScreen->x1 + newItem->x1, myScreen->y1 + newItem->y1,
-			myScreen->x1 + newItem->x2, myScreen->y1 + newItem->y2);
-	}
-
-	return newItem;
-}
-
-
-//-------------------------------    VSLIDER MENU ITEM    ---------------------------------//
-
-enum {
-	VS_NORM = 0x0000,
-	VS_OVER = 0x0001,
-	VS_PRESS = 0x0002,
-	VS_GREY = 0x0003,
-	VS_STATUS = 0x000f,
-	VS_UP = 0x0010,
-	VS_PAGE_UP = 0x0020,
-	VS_THUMB = 0x0030,
-	VS_PAGE_DOWN = 0x0040,
-	VS_DOWN = 0x0050,
-	VS_COMPONENT = 0x00f0
-};
-
-
-void menu_DrawVSlider(menuItemVSlider *myItem, guiMenu *myMenu, int32 x, int32 y, int32, int32) {
-	Buffer *myBuff = nullptr;
-	Buffer *backgroundBuff = nullptr;
-	Sprite *upSprite = nullptr;
-	Sprite *thumbSprite = nullptr;
-	Sprite *downSprite = nullptr;
-	Sprite *vbarSprite = nullptr;
-
-	// Verify params
-	if (!myItem || !myMenu)
-		return;
-
-	// If the item is marked transparent, get the background buffer
-	if (myItem->transparent) {
-		if (!myItem->background) {
-			return;
-		}
-		backgroundBuff = myItem->background->get_buffer();
-		if (!backgroundBuff) {
-			return;
-		}
-	}
-
-	// Get the menu buffer
-	myBuff = myMenu->menuBuffer->get_buffer();
-	if (!myBuff) {
-		return;
-	}
-
-	// If the item is tagged as transparent, we need to fill in it's background behind it
-	if (backgroundBuff) {
-		gr_buffer_rect_copy_2(backgroundBuff, myBuff, 0, 0, x, y, backgroundBuff->w, backgroundBuff->h);
-		myItem->background->release();
-	}
-
-	// Set the different sprite components
-	vbarSprite = _GM(menuSprites)[Burger::GUI::SL_SCROLL_BAR];
-	upSprite = _GM(menuSprites)[Burger::GUI::SL_UP_BTN_NORM];
-	thumbSprite = _GM(menuSprites)[Burger::GUI::SL_SLIDER_BTN_NORM];
-	downSprite = _GM(menuSprites)[Burger::GUI::SL_DOWN_BTN_NORM];
-
-	if ((myItem->itemFlags & VS_STATUS) == VS_GREY) {
-		upSprite = _GM(menuSprites)[Burger::GUI::SL_UP_BTN_GREY];
-		thumbSprite = nullptr;
-		downSprite = _GM(menuSprites)[Burger::GUI::SL_DOWN_BTN_GREY];
-	} else if ((myItem->itemFlags & VS_STATUS) == VS_OVER) {
-		if ((myItem->itemFlags & VS_COMPONENT) == VS_UP) {
-			upSprite = _GM(menuSprites)[Burger::GUI::SL_UP_BTN_OVER];
-		} else if ((myItem->itemFlags & VS_COMPONENT) == VS_THUMB) {
-			thumbSprite = _GM(menuSprites)[Burger::GUI::SL_SLIDER_BTN_OVER];
-		} else if ((myItem->itemFlags & VS_COMPONENT) == VS_DOWN) {
-			downSprite = _GM(menuSprites)[Burger::GUI::SL_DOWN_BTN_OVER];
-		}
-	} else if ((myItem->itemFlags & VS_STATUS) == VS_PRESS) {
-		if ((myItem->itemFlags & VS_COMPONENT) == VS_UP) {
-			upSprite = _GM(menuSprites)[Burger::GUI::SL_UP_BTN_PRESS];
-		} else if ((myItem->itemFlags & VS_COMPONENT) == VS_THUMB) {
-			thumbSprite = _GM(menuSprites)[Burger::GUI::SL_SLIDER_BTN_PRESS];
-		} else if ((myItem->itemFlags & VS_COMPONENT) == VS_DOWN) {
-			downSprite = _GM(menuSprites)[Burger::GUI::SL_DOWN_BTN_PRESS];
-		}
-	}
-
-	// Draw the sprite comonents
-	gui_DrawSprite(vbarSprite, myBuff, x, y + upSprite->h);
-	gui_DrawSprite(upSprite, myBuff, x, y);
-	gui_DrawSprite(thumbSprite, myBuff, x, y + myItem->thumbY);
-	gui_DrawSprite(downSprite, myBuff, x, y + upSprite->h + vbarSprite->h);
-
-	// Release the menu buffer
-	myMenu->menuBuffer->release();
-}
-
-int32 vslider_WhereIsCursor(menuItemVSlider *myVSlider, int32 y) {
-	if (y < myVSlider->minThumbY) {
-		return VS_UP;
-	} else if (y < myVSlider->thumbY) {
-		return VS_PAGE_UP;
-	} else if (y < myVSlider->thumbY + myVSlider->thumbH) {
-		return VS_THUMB;
-	} else if (y < myVSlider->maxThumbY + myVSlider->thumbH) {
-		return VS_PAGE_DOWN;
-	} else {
-		return VS_DOWN;
-	}
-}
-
-bool vslider_Handler(menuItemVSlider *myItem, int32 eventType, int32 event, int32 x, int32 y, void **currItem) {
-	bool redrawItem, execCallback, handled;
-	int32 tempFlags;
-	ScreenContext *myScreen;
-	int32 status;
-	int32 deltaSlide;
-	int32 currTime;
-	static bool movingFlag;
-	static int32 movingY;
-	static int32 callbackTime;
-
-	// Verify params
-	if (!myItem)
-		return false;
-
-	if (!(eventType == EVENT_MOUSE))
-		return false;
-
-	if ((myItem->itemFlags & VS_STATUS) == VS_GREY) {
-		*currItem = nullptr;
-		return false;
-	}
-
-	currTime = timer_read_60();
-	redrawItem = false;
-	handled = true;
-	execCallback = false;
-
-	switch (event) {
-	case _ME_L_click:
-	case _ME_doubleclick:
-		if (menuItem::cursorInsideItem(myItem, x, y)) {
-			//				  digi_play(inv_click_snd, 2, 255, -1, inv_click_snd_room_lock);
-			*currItem = myItem;
-			tempFlags = vslider_WhereIsCursor(myItem, y - myItem->y1);
-			if (tempFlags == VS_THUMB) {
-				movingFlag = true;
-				movingY = y;
-			}
-			if ((tempFlags == VS_PAGE_UP) || (tempFlags == VS_PAGE_DOWN)) {
-				myItem->itemFlags = tempFlags + VS_NORM;
-			} else {
-				myItem->itemFlags = tempFlags + VS_PRESS;
-				redrawItem = true;
-			}
-			execCallback = true;
-		} else {
-			*currItem = nullptr;
-			myItem->itemFlags = VS_NORM;
-			redrawItem = true;
-		}
-		break;
-
-	case _ME_L_drag:
-	case _ME_doubleclick_drag:
-		if (!*currItem) {
-			return true;
-		}
-		if (movingFlag) {
-			if (y < movingY) {
-				deltaSlide = imath_min(myItem->thumbY - myItem->minThumbY, movingY - y);
-				if (deltaSlide > 0) {
-					myItem->thumbY -= deltaSlide;
-					myItem->percent = ((myItem->thumbY - myItem->minThumbY) * 100) /
-						(myItem->maxThumbY - myItem->minThumbY);
-					redrawItem = true;
-					execCallback = true;
-				}
-			} else if (y > movingY) {
-				deltaSlide = imath_min(myItem->maxThumbY - myItem->thumbY, y - movingY);
-				if (deltaSlide > 0) {
-					myItem->thumbY += deltaSlide;
-					myItem->percent = ((myItem->thumbY - myItem->minThumbY) * 100) /
-						(myItem->maxThumbY - myItem->minThumbY);
-					redrawItem = true;
-					execCallback = true;
-				}
-			}
-			movingY = y;
-			if (movingY < (myItem->thumbY + myItem->y1)) {
-				movingY = myItem->thumbY + myItem->y1;
-			} else if (movingY > (myItem->thumbY + myItem->thumbH - 1 + myItem->y1)) {
-				movingY = myItem->thumbY + myItem->thumbH - 1 + myItem->y1;
-			}
-		} else {
-			if (menuItem::cursorInsideItem(myItem, x, y)) {
-				tempFlags = vslider_WhereIsCursor(myItem, y - myItem->y1);
-				if ((myItem->itemFlags & VS_COMPONENT) == tempFlags) {
-					if ((tempFlags != VS_PAGE_UP) && (tempFlags != VS_PAGE_DOWN) &&
-						((myItem->itemFlags & VS_STATUS) != VS_PRESS)) {
-						myItem->itemFlags = tempFlags + VS_PRESS;
-						redrawItem = true;
-					}
-					if (currTime - callbackTime > 6) {
-						execCallback = true;
-					}
-				} else {
-					if ((myItem->itemFlags & VS_STATUS) != VS_OVER) {
-						myItem->itemFlags = (myItem->itemFlags & VS_COMPONENT) + VS_OVER;
-						redrawItem = true;
-					}
-				}
-				execCallback = true;
-			} else {
-				if ((myItem->itemFlags & VS_STATUS) != VS_OVER) {
-					myItem->itemFlags = (myItem->itemFlags & VS_COMPONENT) + VS_OVER;
-					redrawItem = true;
-				}
-			}
-		}
-		break;
-
-	case _ME_L_release:
-	case _ME_doubleclick_release:
-		movingFlag = false;
-		if (menuItem::cursorInsideItem(myItem, x, y)) {
-			tempFlags = vslider_WhereIsCursor(myItem, y - myItem->y1);
-			if ((tempFlags == VS_PAGE_UP) || (tempFlags == VS_PAGE_DOWN)) {
-				myItem->itemFlags = VS_NORM;
-			} else {
-				myItem->itemFlags = tempFlags + VS_OVER;
-				*currItem = myItem;
-			}
-		} else {
-			myItem->itemFlags = VS_NORM;
-			*currItem = nullptr;
-		}
-		redrawItem = true;
-		if (!_GM(currMenuIsSave)) {
-			UpdateThumbNails(_GM(firstSlotIndex), (guiMenu *)myItem->myMenu);
-		}
-		break;
-
-	case _ME_move:
-		if (menuItem::cursorInsideItem(myItem, x, y)) {
-			*currItem = myItem;
-			tempFlags = vslider_WhereIsCursor(myItem, y - myItem->y1);
-			if ((myItem->itemFlags & VS_COMPONENT) != tempFlags) {
-				if ((tempFlags == VS_PAGE_UP) || (tempFlags == VS_PAGE_DOWN)) {
-					myItem->itemFlags = VS_NORM;
-				} else {
-					myItem->itemFlags = tempFlags + VS_OVER;
-				}
-				redrawItem = true;
-			}
-		} else {
-			*currItem = nullptr;
-			if (myItem->itemFlags != VS_NORM) {
-				myItem->itemFlags = VS_NORM;
-				redrawItem = true;
-				handled = false;
-			}
-		}
-		break;
-
-	case _ME_L_hold:
-	case _ME_doubleclick_hold:
-		if (!*currItem) {
-			return true;
-		}
-		if (menuItem::cursorInsideItem(myItem, x, y)) {
-			tempFlags = vslider_WhereIsCursor(myItem, y - myItem->y1);
-			if ((myItem->itemFlags & VS_COMPONENT) == tempFlags) {
-				if (currTime - callbackTime > 6) {
-					execCallback = true;
-				}
-			}
-		}
-		break;
-	}
-
-	// See if we need to redraw the vslider
-	if (redrawItem) {
-		(myItem->redraw)(myItem, myItem->myMenu, myItem->x1, myItem->y1, 0, 0);
-		myScreen = vmng_screen_find(myItem->myMenu, &status);
-		if (myScreen && (status == SCRN_ACTIVE)) {
-			RestoreScreens(myScreen->x1 + myItem->x1, myScreen->y1 + myItem->y1,
-				myScreen->x1 + myItem->x2, myScreen->y1 + myItem->y2);
-		}
-	}
-
-	// See if we need to call the callback function
-	if (execCallback && myItem->callback) {
-		callbackTime = currTime;
-		(myItem->callback)((void *)myItem, myItem->myMenu);
-		myScreen = vmng_screen_find(myItem->myMenu, &status);
-		if ((!myScreen) || (status != SCRN_ACTIVE)) {
-			*currItem = nullptr;
-		}
-	}
-
-	return handled;
-}
-
-
-menuItemVSlider *menu_VSliderAdd(guiMenu *myMenu, int32 tag, int32 x, int32 y, int32 w, int32 h,
-		int32 initPercent, CALLBACK callback, bool transparent) {
-	menuItemVSlider *newItem;
-	ScreenContext *myScreen;
-	int32 status;
-
-	// Verify params
-	if (!myMenu)
-		return nullptr;
-
-	// Allocate a new one
-	newItem = new menuItemVSlider();
-
-	// Initialize the struct
-	newItem->next = myMenu->itemList;
-	newItem->prev = nullptr;
-	if (myMenu->itemList) {
-		myMenu->itemList->prev = newItem;
-	}
-	myMenu->itemList = newItem;
-
-	newItem->myMenu = myMenu;
-	newItem->tag = tag;
-	newItem->x1 = x;
-	newItem->y1 = y;
-	newItem->x2 = x + w - 1;
-	newItem->y2 = y + h - 1;
-	newItem->callback = callback;
-
-	if (!transparent) {
-		newItem->transparent = false;
-		newItem->background = nullptr;
-	} else {
-		newItem->transparent = true;
-		newItem->background = guiMenu::copyBackground(myMenu, x, y, w, h);
-	}
-
-	newItem->itemFlags = VS_NORM;
-
-	newItem->thumbW = _GM(menuSprites)[Burger::GUI::SL_SLIDER_BTN_NORM]->w;
-	newItem->thumbH = _GM(menuSprites)[Burger::GUI::SL_SLIDER_BTN_NORM]->h;
-
-	newItem->minThumbY = _GM(menuSprites)[Burger::GUI::SL_UP_BTN_NORM]->h + 1;
-	newItem->maxThumbY = _GM(menuSprites)[Burger::GUI::SL_UP_BTN_NORM]->h + _GM(menuSprites)[Burger::GUI::SL_SCROLL_BAR]->h
-		- _GM(menuSprites)[Burger::GUI::SL_SLIDER_BTN_NORM]->h - 1;
-
-	// Calculate the initial thumbY
-	newItem->percent = imath_max(imath_min(initPercent, 100), 0);
-	newItem->thumbY = newItem->minThumbY +
-		((newItem->percent * (newItem->maxThumbY - newItem->minThumbY)) / 100);
-
-	newItem->redraw = (DrawFunction)menu_DrawVSlider;
-	newItem->destroy = (DestroyFunction)menuItem::destroyItem;
-	newItem->itemEventHandler = (ItemHandlerFunction)vslider_Handler;
-
-	// Draw the vslider in now
-	(newItem->redraw)(newItem, myMenu, x, y, 0, 0);
-
-	// See if the screen is currently visible
-	myScreen = vmng_screen_find(myMenu, &status);
-	if (myScreen && (status == SCRN_ACTIVE)) {
-		RestoreScreens(myScreen->x1 + newItem->x1, myScreen->y1 + newItem->y1,
-			myScreen->x1 + newItem->x2, myScreen->y1 + newItem->y2);
-	}
-
-	return newItem;
-}
-
-
-void menu_DisableVSlider(menuItemVSlider *myItem, int32 tag, guiMenu *myMenu) {
-	// Verify params
-	if (!myMenu)
-		return;
-
-	if (!myItem)
-		myItem = (menuItemVSlider *)guiMenu::getItem(tag, myMenu);
-	if (!myItem)
-		return;
-
-	myItem->itemFlags = VS_GREY;
-}
-
-
-void menu_EnableVSlider(menuItemVSlider *myItem, int32 tag, guiMenu *myMenu) {
-	// Verify params
-	if (!myMenu)
-		return;
-
-	if (!myItem)
-		myItem = (menuItemVSlider *)guiMenu::getItem(tag, myMenu);
-	if (!myItem)
-		return;
-
-	myItem->itemFlags = VS_NORM;
-}
-
-
 //-----------------------------    TEXTFIELD MENU ITEM    ---------------------------------//
 
 enum {
@@ -1306,7 +630,7 @@ void cb_Game_Save(void *, void *) {
 	// Destroy the game menu
 	DestroyGameMenu();
 	guiMenu::shutdown(true);
-	buttonClosesDialog = true;
+	_GM(buttonClosesDialog) = true;
 
 	// Create the save game menu
 	g_engine->showSaveScreen();
@@ -1316,7 +640,7 @@ void cb_Game_Load(void *, void *) {
 	// Destroy the game menu
 	DestroyGameMenu();
 	guiMenu::shutdown(true);
-	buttonClosesDialog = true;
+	_GM(buttonClosesDialog) = true;
 
 	// Create the save game menu
 	g_engine->showLoadScreen(M4Engine::kLoadFromGameDialog);
@@ -1348,7 +672,7 @@ void cb_Game_Main(void *, void *) {
 void cb_Game_Options(void *, void *) {
 	// Destroy the game menu
 	DestroyGameMenu();
-	buttonClosesDialog = true;
+	_GM(buttonClosesDialog) = true;
 
 	// Create the options menu
 	CreateOptionsMenu(nullptr);
@@ -1388,22 +712,22 @@ void CreateGameMenuMain(RGB8 *myPalette) {
 		return;
 	}
 
-	menuItemButton::buttonAdd(_GM(gameMenu), GM_TAG_MAIN, GM_MAIN_X, GM_MAIN_Y, GM_MAIN_W, GM_MAIN_H, cb_Game_Main);
-	menuItemButton::buttonAdd(_GM(gameMenu), GM_TAG_OPTIONS, GM_OPTIONS_X, GM_OPTIONS_Y, GM_OPTIONS_W, GM_OPTIONS_H, cb_Game_Options);
-	menuItemButton::buttonAdd(_GM(gameMenu), GM_TAG_RESUME, GM_RESUME_X, GM_RESUME_Y, GM_RESUME_W, GM_RESUME_H, cb_Game_Resume);
-	menuItemButton::buttonAdd(_GM(gameMenu), GM_TAG_QUIT, GM_QUIT_X, GM_QUIT_Y, GM_QUIT_W, GM_QUIT_H, cb_Game_Quit);
+	menuItemButton::add(_GM(gameMenu), GM_TAG_MAIN, GM_MAIN_X, GM_MAIN_Y, GM_MAIN_W, GM_MAIN_H, cb_Game_Main);
+	menuItemButton::add(_GM(gameMenu), GM_TAG_OPTIONS, GM_OPTIONS_X, GM_OPTIONS_Y, GM_OPTIONS_W, GM_OPTIONS_H, cb_Game_Options);
+	menuItemButton::add(_GM(gameMenu), GM_TAG_RESUME, GM_RESUME_X, GM_RESUME_Y, GM_RESUME_W, GM_RESUME_H, cb_Game_Resume);
+	menuItemButton::add(_GM(gameMenu), GM_TAG_QUIT, GM_QUIT_X, GM_QUIT_Y, GM_QUIT_W, GM_QUIT_H, cb_Game_Quit);
 
 	if (!_GM(gameMenuFromMain)) {
-		menuItemButton::buttonAdd(_GM(gameMenu), GM_TAG_SAVE, GM_SAVE_X, GM_SAVE_Y, GM_SAVE_W, GM_SAVE_H, cb_Game_Save);
+		menuItemButton::add(_GM(gameMenu), GM_TAG_SAVE, GM_SAVE_X, GM_SAVE_Y, GM_SAVE_W, GM_SAVE_H, cb_Game_Save);
 	} else {
-		menuItemButton::buttonAdd(_GM(gameMenu), GM_TAG_SAVE, GM_SAVE_X, GM_SAVE_Y, GM_SAVE_W, GM_SAVE_H, cb_Game_Save, menuItemButton::BTN_TYPE_GM_GENERIC, true);
+		menuItemButton::add(_GM(gameMenu), GM_TAG_SAVE, GM_SAVE_X, GM_SAVE_Y, GM_SAVE_W, GM_SAVE_H, cb_Game_Save, menuItemButton::BTN_TYPE_GM_GENERIC, true);
 	}
 
 	// See if there are any games to load
 	if (g_engine->savesExist()) {
-		menuItemButton::buttonAdd(_GM(gameMenu), GM_TAG_LOAD, GM_LOAD_X, GM_LOAD_Y, GM_LOAD_W, GM_LOAD_H, cb_Game_Load);
+		menuItemButton::add(_GM(gameMenu), GM_TAG_LOAD, GM_LOAD_X, GM_LOAD_Y, GM_LOAD_W, GM_LOAD_H, cb_Game_Load);
 	} else {
-		menuItemButton::buttonAdd(_GM(gameMenu), GM_TAG_LOAD, GM_LOAD_X, GM_LOAD_Y, GM_LOAD_W, GM_LOAD_H, cb_Game_Load, menuItemButton::BTN_TYPE_GM_GENERIC, true);
+		menuItemButton::add(_GM(gameMenu), GM_TAG_LOAD, GM_LOAD_X, GM_LOAD_Y, GM_LOAD_W, GM_LOAD_H, cb_Game_Load, menuItemButton::BTN_TYPE_GM_GENERIC, true);
 	}
 
 	// Configure the game so pressing <esc> will cause the menu to disappear and the game to resume
@@ -1426,7 +750,7 @@ void cb_Options_Game_Cancel(void *, void *) {
 
 	// Destroy the options menu
 	DestroyOptionsMenu();
-	buttonClosesDialog = true;
+	_GM(buttonClosesDialog) = true;
 
 	// Create the options menu
 	CreateGameMenuMain(nullptr);
@@ -1435,7 +759,7 @@ void cb_Options_Game_Cancel(void *, void *) {
 void cb_Options_Game_Done(void *, void *) {
 	// Destroy the options menu
 	DestroyOptionsMenu();
-	buttonClosesDialog = true;
+	_GM(buttonClosesDialog) = true;
 
 	// Create the options menu
 	CreateGameMenuMain(nullptr);
@@ -1495,11 +819,11 @@ void CreateOptionsMenu(RGB8 *myPalette) {
 		return;
 	}
 
-	menuItemButton::buttonAdd(_GM(opMenu), OM_TAG_CANCEL, OM_CANCEL_X, OM_CANCEL_Y, OM_CANCEL_W, OM_CANCEL_H, cb_Options_Game_Cancel, menuItemButton::BTN_TYPE_OM_CANCEL);
-	menuItemButton::buttonAdd(_GM(opMenu), OM_TAG_DONE, OM_DONE_X, OM_DONE_Y, OM_DONE_W, OM_DONE_H, cb_Options_Game_Done, menuItemButton::BTN_TYPE_OM_DONE, true);
-	menu_HSliderAdd(_GM(opMenu), OM_TAG_DIGI, OM_DIGI_X, OM_DIGI_Y, OM_DIGI_W, OM_DIGI_H, digi_get_overall_volume(),
+	menuItemButton::add(_GM(opMenu), OM_TAG_CANCEL, OM_CANCEL_X, OM_CANCEL_Y, OM_CANCEL_W, OM_CANCEL_H, cb_Options_Game_Cancel, menuItemButton::BTN_TYPE_OM_CANCEL);
+	menuItemButton::add(_GM(opMenu), OM_TAG_DONE, OM_DONE_X, OM_DONE_Y, OM_DONE_W, OM_DONE_H, cb_Options_Game_Done, menuItemButton::BTN_TYPE_OM_DONE, true);
+	menuItemHSlider::add(_GM(opMenu), OM_TAG_DIGI, OM_DIGI_X, OM_DIGI_Y, OM_DIGI_W, OM_DIGI_H, digi_get_overall_volume(),
 		(CALLBACK)cb_Options_Digi, true);
-	menu_HSliderAdd(_GM(opMenu), OM_TAG_DIGESTABILITY, OM_DIGESTABILITY_X, OM_DIGESTABILITY_Y,
+	menuItemHSlider::add(_GM(opMenu), OM_TAG_DIGESTABILITY, OM_DIGESTABILITY_X, OM_DIGESTABILITY_Y,
 		OM_DIGESTABILITY_W, OM_DIGESTABILITY_H, _G(flags)[digestability],
 		(CALLBACK)cb_Options_Digestability, true);
 
@@ -1587,7 +911,7 @@ void CreateErrMenu(RGB8 *myPalette) {
 	_GM(errMenu)->menuBuffer->release();
 
 	// Add the done button
-	menuItemButton::buttonAdd(_GM(errMenu), EM_TAG_RETURN, EM_RETURN_X, EM_RETURN_Y, EM_RETURN_W, EM_RETURN_H, cb_Err_Done);
+	menuItemButton::add(_GM(errMenu), EM_TAG_RETURN, EM_RETURN_X, EM_RETURN_Y, EM_RETURN_W, EM_RETURN_H, cb_Err_Done);
 
 	// Configure the game so pressing <esc> will cause the menu to disappear and the gamemenu to reappear
 	guiMenu::configure(_GM(errMenu), cb_Err_Done, cb_Err_Done);
@@ -1603,142 +927,37 @@ void DestroySaveLoadMenu(bool saveMenu);
 void cb_SaveLoad_Slot(menuItemButton *theItem, guiMenu *myMenu);
 bool load_Handler(menuItemButton *theItem, int32 eventType, int32 event, int32 x, int32 y, void **currItem);
 
-
-bool LoadThumbNail(int32 slotNum) {
-	Sprite *&thumbNailSprite = _GM(thumbNails)[slotNum];
-	return g_engine->loadSaveThumbnail(slotNum + 1, thumbNailSprite);
-}
-
-
-void UnloadThumbNail(int32 slotNum) {
-	if (_GM(thumbNails)[slotNum]->sourceHandle) {
-		HUnLock(_GM(thumbNails)[slotNum]->sourceHandle);
-		DisposeHandle(_GM(thumbNails)[slotNum]->sourceHandle);
-		_GM(thumbNails)[slotNum]->sourceHandle = nullptr;
-	}
-}
-
-
-void UpdateThumbNails(int32 firstSlot, guiMenu *myMenu) {
-	int32 i, startIndex, endIndex;
-
-	// Make sure there is something to update
-	if (firstSlot == _GM(thumbIndex)) {
-		return;
-	}
-
-	// Ensure firstSlot is in a valid range
-	firstSlot = imath_max(imath_min(firstSlot, 89), 0);
-
-	if (firstSlot > _GM(thumbIndex)) {
-		// Dump Out all thumbnails in slots which don't overlap
-		startIndex = _GM(thumbIndex);
-		endIndex = imath_min(_GM(thumbIndex) + 9, firstSlot - 1);
-		for (i = startIndex; i <= endIndex; i++) {
-			UnloadThumbNail(i);
-		}
-
-		// Load in all thumbnails missing thumbnails
-		startIndex = imath_max(_GM(thumbIndex) + 10, firstSlot);
-		endIndex = imath_min(firstSlot + 9, 98);
-		for (i = startIndex; i <= endIndex; i++) {
-			if (_GM(slotInUse)[i]) {
-				if (!LoadThumbNail(i)) {
-					_GM(slotInUse)[i] = false;
-					menuItemButton::disableButton(nullptr, 1001 + i - firstSlot, myMenu);
-					guiMenu::itemRefresh(nullptr, 1001 + i - firstSlot, myMenu);
-				}
-			}
-		}
-	} else {
-		// Else firstSlot < _GM(thumbIndex)
-		// Dump Out all thumbnails in slots which don't overlap
-		startIndex = imath_max(firstSlot + 10, _GM(thumbIndex));
-		endIndex = imath_min(_GM(thumbIndex) + 9, 98);
-		for (i = startIndex; i <= endIndex; i++) {
-			UnloadThumbNail(i);
-		}
-
-		// Load in all thumbnails missing thumbnails
-		startIndex = firstSlot;
-		endIndex = imath_min(firstSlot + 9, _GM(thumbIndex) - 1);
-		for (i = startIndex; i <= endIndex; i++) {
-			if (_GM(slotInUse)[i]) {
-				if (!LoadThumbNail(i)) {
-					_GM(slotInUse)[i] = false;
-					menuItemButton::disableButton(nullptr, 1001 + i - firstSlot, myMenu);
-					guiMenu::itemRefresh(nullptr, 1001 + i - firstSlot, myMenu);
-				}
-			}
-		}
-	}
-
-	// Set the var
-	_GM(thumbIndex) = firstSlot;
-}
-
-
-void SetFirstSlot(int32 firstSlot, guiMenu *myMenu) {
-	menuItemButton *myButton;
-	int32 i;
-
-	if (!myMenu) {
-		return;
-	}
-
-	// Ensure firstSlot is in a valid range
-	firstSlot = imath_max(imath_min(firstSlot, 89), 0);
-
-	// Change the prompt and special tag of each of the slot buttons
-	for (i = 0; i < MAX_SLOTS_SHOWN; i++) {
-		myButton = (menuItemButton *)guiMenu::getItem(i + 1001, myMenu);
-
-		myButton->prompt = _GM(slotTitles)[firstSlot + i];
-		if (_GM(currMenuIsSave) || _GM(slotInUse)[firstSlot + i]) {
-			myButton->itemFlags = menuItemButton::BTN_STATE_NORM;
-		} else {
-			myButton->itemFlags = menuItemButton::BTN_STATE_GREY;
-		}
-
-		myButton->specialTag = firstSlot + i + 1;
-		guiMenu::itemRefresh(myButton, i + 1001, myMenu);
-	}
-}
-
-
 void cb_SaveLoad_VSlider(menuItemVSlider *myItem, guiMenu *myMenu) {
 	bool redraw;
 
 	if (!myMenu || !myItem)
 		return;
 
-	if ((myItem->itemFlags & VS_COMPONENT) != VS_THUMB) {
-
+	if ((myItem->itemFlags & menuItemVSlider::VS_COMPONENT) != menuItemVSlider::VS_THUMB) {
 		redraw = (DrawFunction)false;
-		switch (myItem->itemFlags & VS_COMPONENT) {
-
-		case VS_UP:
+		switch (myItem->itemFlags & menuItemVSlider::VS_COMPONENT) {
+		case menuItemVSlider::VS_UP:
 			if (_GM(firstSlotIndex) > 0) {
 				_GM(firstSlotIndex)--;
 				redraw = (DrawFunction)true;
 			}
 			break;
 
-		case VS_PAGE_UP:
+		case menuItemVSlider::VS_PAGE_UP:
 			if (_GM(firstSlotIndex) > 0) {
 				_GM(firstSlotIndex) = imath_max(_GM(firstSlotIndex) - 10, 0);
 				redraw = (DrawFunction)true;
 			}
 			break;
 
-		case VS_PAGE_DOWN:
+		case menuItemVSlider::VS_PAGE_DOWN:
 			if (_GM(firstSlotIndex) < 89) {
 				_GM(firstSlotIndex) = imath_min(_GM(firstSlotIndex) + 10, 89);
 				redraw = (DrawFunction)true;
 			}
 			break;
 
-		case VS_DOWN:
+		case menuItemVSlider::VS_DOWN:
 			if (_GM(firstSlotIndex) < 89) {
 				_GM(firstSlotIndex)++;
 				redraw = (DrawFunction)true;
@@ -1871,10 +1090,10 @@ void cb_SaveLoad_Cancel(menuItemButton *, guiMenu *myMenu) {
 
 		// Add the button back in
 		if (_GM(currMenuIsSave)) {
-			menuItemButton::buttonAdd(myMenu, 1000 + _GM(slotSelected) - _GM(firstSlotIndex), x, y, w, h,
+			menuItemButton::add(myMenu, 1000 + _GM(slotSelected) - _GM(firstSlotIndex), x, y, w, h,
 				(CALLBACK)cb_SaveLoad_Slot, menuItemButton::BTN_TYPE_SL_TEXT, false, true, _GM(slotTitles)[_GM(slotSelected) - 1]);
 		} else {
-			menuItemButton::buttonAdd(myMenu, 1000 + _GM(slotSelected) - _GM(firstSlotIndex), x, y, w, h,
+			menuItemButton::add(myMenu, 1000 + _GM(slotSelected) - _GM(firstSlotIndex), x, y, w, h,
 				(CALLBACK)cb_SaveLoad_Slot, menuItemButton::BTN_TYPE_SL_TEXT, false, true, _GM(slotTitles)[_GM(slotSelected) - 1],
 				(ItemHandlerFunction)load_Handler);
 
@@ -1887,7 +1106,7 @@ void cb_SaveLoad_Cancel(menuItemButton *, guiMenu *myMenu) {
 		SetFirstSlot(_GM(firstSlotIndex), myMenu);
 
 		// Enable the slider
-		menu_EnableVSlider(nullptr, SL_TAG_VSLIDER, myMenu);
+		menuItemVSlider::enableVSlider(nullptr, SL_TAG_VSLIDER, myMenu);
 		guiMenu::itemRefresh(nullptr, SL_TAG_VSLIDER, myMenu);
 
 		// Disable the save/load button
@@ -1917,7 +1136,7 @@ void cb_SaveLoad_Cancel(menuItemButton *, guiMenu *myMenu) {
 		}
 	}
 
-	buttonClosesDialog = true;
+	_GM(buttonClosesDialog) = true;
 }
 
 
@@ -1968,7 +1187,7 @@ void cb_SaveLoad_Slot(menuItemButton *myButton, guiMenu *myMenu) {
 	}
 
 	// Disable the slider
-	menu_DisableVSlider(nullptr, SL_TAG_VSLIDER, myMenu);
+	menuItemVSlider::disableVSlider(nullptr, SL_TAG_VSLIDER, myMenu);
 	guiMenu::itemRefresh(nullptr, SL_TAG_VSLIDER, myMenu);
 
 	// Enable the save/load button
@@ -2116,18 +1335,18 @@ void CreateSaveLoadMenu(RGB8 *myPalette, bool saveMenu) {
 
 	if (_GM(currMenuIsSave)) {
 		menuItemMsg::msgAdd(_GM(slMenu), SL_TAG_SAVE_LABEL, SL_SAVE_LABEL_X, SL_SAVE_LABEL_Y, SL_SAVE_LABEL_W, SL_SAVE_LABEL_H);
-		menuItemButton::buttonAdd(_GM(slMenu), SL_TAG_SAVE, SL_SAVE_X, SL_SAVE_Y, SL_SAVE_W, SL_SAVE_H,
+		menuItemButton::add(_GM(slMenu), SL_TAG_SAVE, SL_SAVE_X, SL_SAVE_Y, SL_SAVE_W, SL_SAVE_H,
 			(CALLBACK)cb_SaveLoad_Save, menuItemButton::BTN_TYPE_SL_SAVE, true);
 	} else {
 		menuItemMsg::msgAdd(_GM(slMenu), SL_TAG_LOAD_LABEL, SL_LOAD_LABEL_X, SL_LOAD_LABEL_Y, SL_LOAD_LABEL_W, SL_LOAD_LABEL_H);
-		menuItemButton::buttonAdd(_GM(slMenu), SL_TAG_LOAD, SL_LOAD_X, SL_LOAD_Y, SL_LOAD_W, SL_LOAD_H,
+		menuItemButton::add(_GM(slMenu), SL_TAG_LOAD, SL_LOAD_X, SL_LOAD_Y, SL_LOAD_W, SL_LOAD_H,
 			(CALLBACK)cb_SaveLoad_Load, menuItemButton::BTN_TYPE_SL_LOAD, true);
 	}
 
-	menuItemButton::buttonAdd(_GM(slMenu), SL_TAG_CANCEL, SL_CANCEL_X, SL_CANCEL_Y, SL_CANCEL_W, SL_CANCEL_H,
+	menuItemButton::add(_GM(slMenu), SL_TAG_CANCEL, SL_CANCEL_X, SL_CANCEL_Y, SL_CANCEL_W, SL_CANCEL_H,
 		(CALLBACK)cb_SaveLoad_Cancel, menuItemButton::BTN_TYPE_SL_CANCEL);
 
-	menu_VSliderAdd(_GM(slMenu), SL_TAG_VSLIDER, SL_SLIDER_X, SL_SLIDER_Y, SL_SLIDER_W, SL_SLIDER_H,
+	menuItemVSlider::add(_GM(slMenu), SL_TAG_VSLIDER, SL_SLIDER_X, SL_SLIDER_Y, SL_SLIDER_W, SL_SLIDER_H,
 		0, (CALLBACK)cb_SaveLoad_VSlider);
 
 	InitializeSlotTables();
@@ -2141,7 +1360,7 @@ void CreateSaveLoadMenu(RGB8 *myPalette, bool saveMenu) {
 	}
 
 	for (int32 i = 0; i < MAX_SLOTS_SHOWN; i++) {
-		menuItemButton::buttonAdd(_GM(slMenu), 1001 + i,
+		menuItemButton::add(_GM(slMenu), 1001 + i,
 			SL_SCROLL_FIELD_X, SL_SCROLL_FIELD_Y + i * SL_SCROLL_LINE_H,
 			SL_SCROLL_LINE_W, SL_SCROLL_LINE_H,
 			(CALLBACK)cb_SaveLoad_Slot, menuItemButton::BTN_TYPE_SL_TEXT,
diff --git a/engines/m4/burger/gui/game_menu.h b/engines/m4/burger/gui/game_menu.h
index 506dbe000eb..6a17d82060b 100644
--- a/engines/m4/burger/gui/game_menu.h
+++ b/engines/m4/burger/gui/game_menu.h
@@ -43,18 +43,6 @@ using M4::GUI::Sprite;
 using M4::GUI::CALLBACK;
 using M4::GUI::ItemHandlerFunction;
 
-// SPECIFIC ITEM FUNCTIONS
-
-// Horizontal sliders
-menuItemHSlider *menu_HSliderAdd(guiMenu *myMenu, int32 tag, int32 x, int32 y, int32 w, int32 h,
-	int32 initPercent = 0, CALLBACK callback = nullptr, bool transparent = false);
-
-// Vertical sliders
-menuItemVSlider *menu_VSliderAdd(guiMenu *myMenu, int32 tag, int32 x, int32 y, int32 w, int32 h,
-	int32 initPercent = 0, CALLBACK callback = nullptr, bool transparent = false);
-void menu_DisableVSlider(menuItemVSlider *myItem, int32 tag, guiMenu *myMenu);
-void menu_EnableVSlider(menuItemVSlider *myItem, int32 tag, guiMenu *myMenu);
-
 // Textfields
 menuItemTextField *menu_TextFieldAdd(guiMenu *myMenu, int32 tag, int32 x, int32 y, int32 w, int32 h, int32 initFlags,
 	const char *prompt = nullptr, int32 specialtag = 0, CALLBACK callback = nullptr, bool transparent = false);
@@ -143,8 +131,6 @@ enum game_menu_button_tags {
 
 #define SL_THUMBNAIL_X			 66
 #define SL_THUMBNAIL_Y			 28
-#define SL_THUMBNAIL_W			215
-#define SL_THUMBNAIL_H		   162
 
 /**
  * Options menu defines
diff --git a/engines/m4/gui/gui_menu.cpp b/engines/m4/gui/gui_menu.cpp
index 3527e9e7d23..3268e477b8c 100644
--- a/engines/m4/gui/gui_menu.cpp
+++ b/engines/m4/gui/gui_menu.cpp
@@ -78,6 +78,106 @@ void gui_DrawSprite(Sprite *mySprite, Buffer *myBuff, int32 x, int32 y) {
 	}
 }
 
+bool LoadThumbNail(int32 slotNum) {
+	Sprite *&thumbNailSprite = _GM(thumbNails)[slotNum];
+	return g_engine->loadSaveThumbnail(slotNum + 1, thumbNailSprite);
+}
+
+void UnloadThumbNail(int32 slotNum) {
+	if (_GM(thumbNails)[slotNum]->sourceHandle) {
+		HUnLock(_GM(thumbNails)[slotNum]->sourceHandle);
+		DisposeHandle(_GM(thumbNails)[slotNum]->sourceHandle);
+		_GM(thumbNails)[slotNum]->sourceHandle = nullptr;
+	}
+}
+
+void UpdateThumbNails(int32 firstSlot, guiMenu *myMenu) {
+	int32 i, startIndex, endIndex;
+
+	// Make sure there is something to update
+	if (firstSlot == _GM(thumbIndex)) {
+		return;
+	}
+
+	// Ensure firstSlot is in a valid range
+	firstSlot = imath_max(imath_min(firstSlot, 89), 0);
+
+	if (firstSlot > _GM(thumbIndex)) {
+		// Dump Out all thumbnails in slots which don't overlap
+		startIndex = _GM(thumbIndex);
+		endIndex = imath_min(_GM(thumbIndex) + 9, firstSlot - 1);
+		for (i = startIndex; i <= endIndex; i++) {
+			UnloadThumbNail(i);
+		}
+
+		// Load in all thumbnails missing thumbnails
+		startIndex = imath_max(_GM(thumbIndex) + 10, firstSlot);
+		endIndex = imath_min(firstSlot + 9, 98);
+		for (i = startIndex; i <= endIndex; i++) {
+			if (_GM(slotInUse)[i]) {
+				if (!LoadThumbNail(i)) {
+					_GM(slotInUse)[i] = false;
+					menuItemButton::disableButton(nullptr, 1001 + i - firstSlot, myMenu);
+					guiMenu::itemRefresh(nullptr, 1001 + i - firstSlot, myMenu);
+				}
+			}
+		}
+	} else {
+		// Else firstSlot < _GM(thumbIndex)
+		// Dump Out all thumbnails in slots which don't overlap
+		startIndex = imath_max(firstSlot + 10, _GM(thumbIndex));
+		endIndex = imath_min(_GM(thumbIndex) + 9, 98);
+		for (i = startIndex; i <= endIndex; i++) {
+			UnloadThumbNail(i);
+		}
+
+		// Load in all thumbnails missing thumbnails
+		startIndex = firstSlot;
+		endIndex = imath_min(firstSlot + 9, _GM(thumbIndex) - 1);
+		for (i = startIndex; i <= endIndex; i++) {
+			if (_GM(slotInUse)[i]) {
+				if (!LoadThumbNail(i)) {
+					_GM(slotInUse)[i] = false;
+					menuItemButton::disableButton(nullptr, 1001 + i - firstSlot, myMenu);
+					guiMenu::itemRefresh(nullptr, 1001 + i - firstSlot, myMenu);
+				}
+			}
+		}
+	}
+
+	// Set the var
+	_GM(thumbIndex) = firstSlot;
+}
+
+void SetFirstSlot(int32 firstSlot, guiMenu *myMenu) {
+	menuItemButton *myButton;
+	int32 i;
+
+	if (!myMenu) {
+		return;
+	}
+
+	// Ensure firstSlot is in a valid range
+	firstSlot = imath_max(imath_min(firstSlot, 89), 0);
+
+	// Change the prompt and special tag of each of the slot buttons
+	for (i = 0; i < MAX_SLOTS_SHOWN; i++) {
+		myButton = (menuItemButton *)guiMenu::getItem(i + 1001, myMenu);
+
+		myButton->prompt = _GM(slotTitles)[firstSlot + i];
+		if (_GM(currMenuIsSave) || _GM(slotInUse)[firstSlot + i]) {
+			myButton->itemFlags = menuItemButton::BTN_STATE_NORM;
+		} else {
+			myButton->itemFlags = menuItemButton::BTN_STATE_GREY;
+		}
+
+		myButton->specialTag = firstSlot + i + 1;
+		guiMenu::itemRefresh(myButton, i + 1001, myMenu);
+	}
+}
+
+//-----------------------------  MENU DIALOG FUNCTIONS    ---------------------------------//
+
 bool guiMenu::initialize(RGB8 *myPalette) {
 	int32 i, memAvail;
 
@@ -1040,7 +1140,7 @@ bool menuItemButton::handler(menuItemButton *myItem, int32 eventType, int32 even
 	return handled;
 }
 
-menuItemButton *menuItemButton::buttonAdd(guiMenu *myMenu, int32 tag, int32 x, int32 y, int32 w, int32 h, CALLBACK callback, int32 buttonType,
+menuItemButton *menuItemButton::add(guiMenu *myMenu, int32 tag, int32 x, int32 y, int32 w, int32 h, CALLBACK callback, int32 buttonType,
 	bool greyed, bool transparent, const char *prompt, ItemHandlerFunction i_handler) {
 	menuItemButton *newItem;
 	ScreenContext *myScreen;
@@ -1210,16 +1310,15 @@ void menuItemMsg::drawMsg(menuItemMsg *myItem, guiMenu *myMenu, int32 x, int32 y
 		}
 	}
 
-	// Get the button info and select the sprite
-	//myMsg = (menuItemMsg *)myItem->itemInfo;
+	// Select the sprite
 	switch (myItem->tag) {
-	case SL_TAG_SAVE_LABEL:
+	case Burger::GUI::SL_TAG_SAVE_LABEL:
 		mySprite = _GM(menuSprites)[Burger::GUI::SL_SAVE_LABEL];
 		break;
-	case SL_TAG_LOAD_LABEL:
+	case Burger::GUI::SL_TAG_LOAD_LABEL:
 		mySprite = _GM(menuSprites)[Burger::GUI::SL_LOAD_LABEL];
 		break;
-	case SL_TAG_THUMBNAIL:
+	case Burger::GUI::SL_TAG_THUMBNAIL:
 		mySprite = _GM(saveLoadThumbNail);
 		break;
 	}
@@ -1234,11 +1333,11 @@ void menuItemMsg::drawMsg(menuItemMsg *myItem, guiMenu *myMenu, int32 x, int32 y
 	if (backgroundBuff) {
 		gr_buffer_rect_copy_2(backgroundBuff, myBuff, 0, 0, x, y, backgroundBuff->w, backgroundBuff->h);
 		myItem->background->release();
-	} else if (myItem->tag == SL_TAG_THUMBNAIL && mySprite->w == 160) {
+	} else if (myItem->tag == Burger::GUI::SL_TAG_THUMBNAIL && mySprite->w == 160) {
 		// Hack for handling smaller ScummVM thumbnails
-		for (int yp = y; yp < (y + SL_THUMBNAIL_H); ++yp) {
+		for (int yp = y; yp < (y + Burger::GUI::SL_THUMBNAIL_H); ++yp) {
 			byte *line = myBuff->data + myBuff->stride * yp + x;
-			Common::fill(line, line + SL_THUMBNAIL_W, 0);
+			Common::fill(line, line + Burger::GUI::SL_THUMBNAIL_W, 0);
 		}
 
 		x += 25;
@@ -1252,5 +1351,653 @@ void menuItemMsg::drawMsg(menuItemMsg *myItem, guiMenu *myMenu, int32 x, int32 y
 	myMenu->menuBuffer->release();
 }
 
+
+//-------------------------------    HSLIDER MENU ITEM    ---------------------------------//
+
+void menuItemHSlider::drawHSlider(menuItemHSlider *myItem, guiMenu *myMenu, int32 x, int32 y, int32, int32) {
+	Buffer *myBuff = nullptr;
+	Buffer *backgroundBuff = nullptr;
+	Sprite *mySprite = nullptr;
+
+	// Verify params
+	if (!myItem || !myMenu)
+		return;
+
+	// If the item is marked transparent, get the background buffer
+	if (myItem->transparent) {
+		if (!myItem->background) {
+			return;
+		}
+		backgroundBuff = myItem->background->get_buffer();
+		if (!backgroundBuff) {
+			return;
+		}
+	}
+
+	// Get the menu buffer and draw the sprite to it
+	myBuff = myMenu->menuBuffer->get_buffer();
+	if (!myBuff) {
+		return;
+	}
+
+	// If the item is tagged as transparent, we need to fill in it's background behind it
+	if (backgroundBuff) {
+		gr_buffer_rect_copy_2(backgroundBuff, myBuff, 0, 0, x, y, backgroundBuff->w, backgroundBuff->h);
+		myItem->background->release();
+	}
+
+	// Get the slider info and select the thumb sprite
+	switch (myItem->itemFlags) {
+	case H_THUMB_OVER:
+		mySprite = _GM(menuSprites)[Burger::GUI::OM_SLIDER_BTN_OVER];
+		break;
+	case H_THUMB_PRESS:
+		mySprite = _GM(menuSprites)[Burger::GUI::OM_SLIDER_BTN_PRESS];
+		break;
+	default:
+	case H_THUMB_NORM:
+		mySprite = _GM(menuSprites)[Burger::GUI::OM_SLIDER_BTN_NORM];
+		break;
+	}
+
+	// Fill in everything left of the thumb with a hilite color
+	if (myItem->thumbX > 2) {
+		gr_color_set(menuItem::SLIDER_BAR_COLOR);
+		gr_buffer_rect_fill(myBuff, myItem->x1 + 3, myItem->y1 + 9, myItem->thumbX, myItem->thumbH - 18);
+	}
+
+	// Draw in the thumb
+	gui_DrawSprite(mySprite, myBuff, myItem->x1 + myItem->thumbX, myItem->y1);
+
+	// Release the menu buffer
+	myMenu->menuBuffer->release();
+}
+
+bool menuItemHSlider::handler(menuItemHSlider *myItem, int32 eventType, int32 event, int32 x, int32 y, void **currItem) {
+	bool redrawItem, execCallback, handled;
+	ScreenContext *myScreen;
+	int32 status;
+	int32 deltaSlide;
+	static bool movingFlag;
+	static int32 movingX;
+
+	// Verify params
+	if (!myItem)
+		return false;
+
+	if (!(eventType == EVENT_MOUSE)) {
+		return false;
+	}
+
+	redrawItem = false;
+	handled = true;
+	execCallback = false;
+
+	switch (event) {
+	case _ME_L_click:
+	case _ME_doubleclick:
+		if (menuItem::cursorInsideItem(myItem, x, y) && (x - myItem->x1 >= myItem->thumbX) &&
+			(x - myItem->x1 <= myItem->thumbX + myItem->thumbW - 1)) {
+			myItem->itemFlags = H_THUMB_PRESS;
+			movingFlag = true;
+			movingX = x;
+			*currItem = myItem;
+			redrawItem = true;
+		} else {
+			*currItem = nullptr;
+			myItem->itemFlags = 0;
+			redrawItem = true;
+		}
+		break;
+
+	case _ME_L_drag:
+	case _ME_doubleclick_drag:
+		if (!*currItem) {
+			return true;
+		}
+		if (movingFlag) {
+			if (x < movingX) {
+				deltaSlide = imath_min(myItem->thumbX, movingX - x);
+				if (deltaSlide > 0) {
+					myItem->thumbX -= deltaSlide;
+					redrawItem = true;
+					myItem->percent = myItem->thumbX * 100 / myItem->maxThumbX;
+					execCallback = true;
+				}
+			} else if (x > movingX) {
+				deltaSlide = imath_min(myItem->maxThumbX - myItem->thumbX, x - movingX);
+				if (deltaSlide > 0) {
+					myItem->thumbX += deltaSlide;
+					redrawItem = true;
+					myItem->percent = myItem->thumbX * 100 / myItem->maxThumbX;
+					execCallback = true;
+				}
+			}
+			movingX = x;
+			if (movingX < (myItem->thumbX + myItem->x1)) {
+				movingX = myItem->thumbX + myItem->x1;
+			} else if (movingX > (myItem->thumbX + myItem->thumbW - 1 + myItem->x1)) {
+				movingX = myItem->thumbX + myItem->thumbW - 1 + myItem->x1;
+			}
+		} else {
+			*currItem = nullptr;
+		}
+		break;
+
+	case _ME_L_release:
+	case _ME_doubleclick_release:
+		if (!*currItem) {
+			return true;
+		}
+		movingFlag = false;
+		if (menuItem::cursorInsideItem(myItem, x, y) && (x - myItem->x1 >= myItem->thumbX) &&
+			(x - myItem->x1 <= myItem->thumbX + myItem->thumbW - 1)) {
+			myItem->itemFlags = H_THUMB_OVER;
+			*currItem = myItem;
+		} else {
+			myItem->itemFlags = H_THUMB_NORM;
+			*currItem = nullptr;
+		}
+		redrawItem = true;
+		execCallback = true;
+		break;
+
+	case _ME_move:
+		if (menuItem::cursorInsideItem(myItem, x, y) && (x - myItem->x1 >= myItem->thumbX) &&
+			(x - myItem->x1 <= myItem->thumbX + myItem->thumbW - 1)) {
+			if (myItem->itemFlags != H_THUMB_OVER) {
+				myItem->itemFlags = H_THUMB_OVER;
+				*currItem = myItem;
+				redrawItem = true;
+			}
+		} else {
+			if (myItem->itemFlags != H_THUMB_NORM) {
+				myItem->itemFlags = H_THUMB_NORM;
+				*currItem = nullptr;
+				redrawItem = true;
+				handled = false;
+			}
+		}
+		break;
+
+	case _ME_L_hold:
+	case _ME_doubleclick_hold:
+		break;
+	}
+
+	// See if we need to redraw the hslider
+	if (redrawItem) {
+		(myItem->redraw)(myItem, myItem->myMenu, myItem->x1, myItem->y1, 0, 0);
+		myScreen = vmng_screen_find(myItem->myMenu, &status);
+		if (myScreen && (status == SCRN_ACTIVE)) {
+			RestoreScreens(myScreen->x1 + myItem->x1, myScreen->y1 + myItem->y1,
+				myScreen->x1 + myItem->x2, myScreen->y1 + myItem->y2);
+		}
+	}
+
+	// See if we need to call the callback function
+	if (execCallback && myItem->callback) {
+		(myItem->callback)((void *)myItem, myItem->myMenu);
+		myScreen = vmng_screen_find(myItem->myMenu, &status);
+		if ((!myScreen) || (status != SCRN_ACTIVE)) {
+			*currItem = nullptr;
+		}
+	}
+
+	return handled;
+}
+
+menuItemHSlider *menuItemHSlider::add(guiMenu *myMenu, int32 tag, int32 x, int32 y, int32 w, int32 h,
+	int32 initPercent, CALLBACK callback, bool transparent) {
+	menuItemHSlider *newItem;
+	ScreenContext *myScreen;
+	int32 status;
+
+	// Verify params
+	if (!myMenu) {
+		return nullptr;
+	}
+
+	// Allocate a new one
+	newItem = new menuItemHSlider();
+
+	// Initialize the struct
+	newItem->next = myMenu->itemList;
+	newItem->prev = nullptr;
+	if (myMenu->itemList) {
+		myMenu->itemList->prev = newItem;
+	}
+	myMenu->itemList = newItem;
+
+	newItem->myMenu = myMenu;
+	newItem->tag = tag;
+	newItem->x1 = x;
+	newItem->y1 = y;
+	newItem->x2 = x + w - 1;
+	newItem->y2 = y + h - 1;
+	newItem->callback = callback;
+
+	if (!transparent) {
+		newItem->transparent = false;
+		newItem->background = nullptr;
+	} else {
+		newItem->transparent = true;
+		newItem->background = guiMenu::copyBackground(myMenu, x, y, w, h);
+	}
+
+	// Intialize the new slider
+	newItem->itemFlags = H_THUMB_NORM;
+	newItem->thumbW = _GM(menuSprites)[Burger::GUI::OM_SLIDER_BTN_NORM]->w;
+	newItem->thumbH = _GM(menuSprites)[Burger::GUI::OM_SLIDER_BTN_NORM]->h;
+	newItem->maxThumbX = w - _GM(menuSprites)[Burger::GUI::OM_SLIDER_BTN_NORM]->w;
+
+	if (initPercent < 0) {
+		initPercent = 0;
+	} else if (initPercent > 100) {
+		initPercent = 100;
+	}
+
+	// Calculate the initial thumbX
+	newItem->percent = initPercent;
+	newItem->thumbX = initPercent * newItem->maxThumbX / 100;
+
+	newItem->redraw = (DrawFunction)menuItemHSlider::drawHSlider;
+	newItem->destroy = (DestroyFunction)menuItem::destroyItem;
+	newItem->itemEventHandler = (ItemHandlerFunction)menuItemHSlider::handler;
+
+	// Draw the slider in now
+	(newItem->redraw)(newItem, myMenu, x, y, 0, 0);
+
+	// See if the screen is currently visible
+	myScreen = vmng_screen_find(myMenu, &status);
+	if (myScreen && (status == SCRN_ACTIVE)) {
+		RestoreScreens(myScreen->x1 + newItem->x1, myScreen->y1 + newItem->y1,
+			myScreen->x1 + newItem->x2, myScreen->y1 + newItem->y2);
+	}
+
+	return newItem;
+}
+
+
+//-------------------------------    VSLIDER MENU ITEM    ---------------------------------//
+
+void menuItemVSlider::drawVSlider(menuItemVSlider *myItem, guiMenu *myMenu, int32 x, int32 y, int32, int32) {
+	Buffer *myBuff = nullptr;
+	Buffer *backgroundBuff = nullptr;
+	Sprite *upSprite = nullptr;
+	Sprite *thumbSprite = nullptr;
+	Sprite *downSprite = nullptr;
+	Sprite *vbarSprite = nullptr;
+
+	// Verify params
+	if (!myItem || !myMenu)
+		return;
+
+	// If the item is marked transparent, get the background buffer
+	if (myItem->transparent) {
+		if (!myItem->background) {
+			return;
+		}
+		backgroundBuff = myItem->background->get_buffer();
+		if (!backgroundBuff) {
+			return;
+		}
+	}
+
+	// Get the menu buffer
+	myBuff = myMenu->menuBuffer->get_buffer();
+	if (!myBuff) {
+		return;
+	}
+
+	// If the item is tagged as transparent, we need to fill in it's background behind it
+	if (backgroundBuff) {
+		gr_buffer_rect_copy_2(backgroundBuff, myBuff, 0, 0, x, y, backgroundBuff->w, backgroundBuff->h);
+		myItem->background->release();
+	}
+
+	// Set the different sprite components
+	vbarSprite = _GM(menuSprites)[Burger::GUI::SL_SCROLL_BAR];
+	upSprite = _GM(menuSprites)[Burger::GUI::SL_UP_BTN_NORM];
+	thumbSprite = _GM(menuSprites)[Burger::GUI::SL_SLIDER_BTN_NORM];
+	downSprite = _GM(menuSprites)[Burger::GUI::SL_DOWN_BTN_NORM];
+
+	if ((myItem->itemFlags & VS_STATUS) == VS_GREY) {
+		upSprite = _GM(menuSprites)[Burger::GUI::SL_UP_BTN_GREY];
+		thumbSprite = nullptr;
+		downSprite = _GM(menuSprites)[Burger::GUI::SL_DOWN_BTN_GREY];
+	} else if ((myItem->itemFlags & VS_STATUS) == VS_OVER) {
+		if ((myItem->itemFlags & VS_COMPONENT) == VS_UP) {
+			upSprite = _GM(menuSprites)[Burger::GUI::SL_UP_BTN_OVER];
+		} else if ((myItem->itemFlags & VS_COMPONENT) == VS_THUMB) {
+			thumbSprite = _GM(menuSprites)[Burger::GUI::SL_SLIDER_BTN_OVER];
+		} else if ((myItem->itemFlags & VS_COMPONENT) == VS_DOWN) {
+			downSprite = _GM(menuSprites)[Burger::GUI::SL_DOWN_BTN_OVER];
+		}
+	} else if ((myItem->itemFlags & VS_STATUS) == VS_PRESS) {
+		if ((myItem->itemFlags & VS_COMPONENT) == VS_UP) {
+			upSprite = _GM(menuSprites)[Burger::GUI::SL_UP_BTN_PRESS];
+		} else if ((myItem->itemFlags & VS_COMPONENT) == VS_THUMB) {
+			thumbSprite = _GM(menuSprites)[Burger::GUI::SL_SLIDER_BTN_PRESS];
+		} else if ((myItem->itemFlags & VS_COMPONENT) == VS_DOWN) {
+			downSprite = _GM(menuSprites)[Burger::GUI::SL_DOWN_BTN_PRESS];
+		}
+	}
+
+	// Draw the sprite comonents
+	gui_DrawSprite(vbarSprite, myBuff, x, y + upSprite->h);
+	gui_DrawSprite(upSprite, myBuff, x, y);
+	gui_DrawSprite(thumbSprite, myBuff, x, y + myItem->thumbY);
+	gui_DrawSprite(downSprite, myBuff, x, y + upSprite->h + vbarSprite->h);
+
+	// Release the menu buffer
+	myMenu->menuBuffer->release();
+}
+
+int32 menuItemVSlider::whereIsCursor(menuItemVSlider *myVSlider, int32 y) {
+	if (y < myVSlider->minThumbY) {
+		return VS_UP;
+	} else if (y < myVSlider->thumbY) {
+		return VS_PAGE_UP;
+	} else if (y < myVSlider->thumbY + myVSlider->thumbH) {
+		return VS_THUMB;
+	} else if (y < myVSlider->maxThumbY + myVSlider->thumbH) {
+		return VS_PAGE_DOWN;
+	} else {
+		return VS_DOWN;
+	}
+}
+
+bool menuItemVSlider::handler(menuItemVSlider *myItem, int32 eventType, int32 event, int32 x, int32 y, void **currItem) {
+	bool redrawItem, execCallback, handled;
+	int32 tempFlags;
+	ScreenContext *myScreen;
+	int32 status;
+	int32 deltaSlide;
+	int32 currTime;
+	static bool movingFlag;
+	static int32 movingY;
+	static int32 callbackTime;
+
+	// Verify params
+	if (!myItem)
+		return false;
+
+	if (!(eventType == EVENT_MOUSE))
+		return false;
+
+	if ((myItem->itemFlags & VS_STATUS) == VS_GREY) {
+		*currItem = nullptr;
+		return false;
+	}
+
+	currTime = timer_read_60();
+	redrawItem = false;
+	handled = true;
+	execCallback = false;
+
+	switch (event) {
+	case _ME_L_click:
+	case _ME_doubleclick:
+		if (menuItem::cursorInsideItem(myItem, x, y)) {
+			//				  digi_play(inv_click_snd, 2, 255, -1, inv_click_snd_room_lock);
+			*currItem = myItem;
+			tempFlags = menuItemVSlider::whereIsCursor(myItem, y - myItem->y1);
+			if (tempFlags == VS_THUMB) {
+				movingFlag = true;
+				movingY = y;
+			}
+			if ((tempFlags == VS_PAGE_UP) || (tempFlags == VS_PAGE_DOWN)) {
+				myItem->itemFlags = tempFlags + VS_NORM;
+			} else {
+				myItem->itemFlags = tempFlags + VS_PRESS;
+				redrawItem = true;
+			}
+			execCallback = true;
+		} else {
+			*currItem = nullptr;
+			myItem->itemFlags = VS_NORM;
+			redrawItem = true;
+		}
+		break;
+
+	case _ME_L_drag:
+	case _ME_doubleclick_drag:
+		if (!*currItem) {
+			return true;
+		}
+		if (movingFlag) {
+			if (y < movingY) {
+				deltaSlide = imath_min(myItem->thumbY - myItem->minThumbY, movingY - y);
+				if (deltaSlide > 0) {
+					myItem->thumbY -= deltaSlide;
+					myItem->percent = ((myItem->thumbY - myItem->minThumbY) * 100) /
+						(myItem->maxThumbY - myItem->minThumbY);
+					redrawItem = true;
+					execCallback = true;
+				}
+			} else if (y > movingY) {
+				deltaSlide = imath_min(myItem->maxThumbY - myItem->thumbY, y - movingY);
+				if (deltaSlide > 0) {
+					myItem->thumbY += deltaSlide;
+					myItem->percent = ((myItem->thumbY - myItem->minThumbY) * 100) /
+						(myItem->maxThumbY - myItem->minThumbY);
+					redrawItem = true;
+					execCallback = true;
+				}
+			}
+			movingY = y;
+			if (movingY < (myItem->thumbY + myItem->y1)) {
+				movingY = myItem->thumbY + myItem->y1;
+			} else if (movingY > (myItem->thumbY + myItem->thumbH - 1 + myItem->y1)) {
+				movingY = myItem->thumbY + myItem->thumbH - 1 + myItem->y1;
+			}
+		} else {
+			if (menuItem::cursorInsideItem(myItem, x, y)) {
+				tempFlags = menuItemVSlider::whereIsCursor(myItem, y - myItem->y1);
+				if ((myItem->itemFlags & VS_COMPONENT) == tempFlags) {
+					if ((tempFlags != VS_PAGE_UP) && (tempFlags != VS_PAGE_DOWN) &&
+						((myItem->itemFlags & VS_STATUS) != VS_PRESS)) {
+						myItem->itemFlags = tempFlags + VS_PRESS;
+						redrawItem = true;
+					}
+					if (currTime - callbackTime > 6) {
+						execCallback = true;
+					}
+				} else {
+					if ((myItem->itemFlags & VS_STATUS) != VS_OVER) {
+						myItem->itemFlags = (myItem->itemFlags & VS_COMPONENT) + VS_OVER;
+						redrawItem = true;
+					}
+				}
+				execCallback = true;
+			} else {
+				if ((myItem->itemFlags & VS_STATUS) != VS_OVER) {
+					myItem->itemFlags = (myItem->itemFlags & VS_COMPONENT) + VS_OVER;
+					redrawItem = true;
+				}
+			}
+		}
+		break;
+
+	case _ME_L_release:
+	case _ME_doubleclick_release:
+		movingFlag = false;
+		if (menuItem::cursorInsideItem(myItem, x, y)) {
+			tempFlags = menuItemVSlider::whereIsCursor(myItem, y - myItem->y1);
+			if ((tempFlags == VS_PAGE_UP) || (tempFlags == VS_PAGE_DOWN)) {
+				myItem->itemFlags = VS_NORM;
+			} else {
+				myItem->itemFlags = tempFlags + VS_OVER;
+				*currItem = myItem;
+			}
+		} else {
+			myItem->itemFlags = VS_NORM;
+			*currItem = nullptr;
+		}
+		redrawItem = true;
+		if (!_GM(currMenuIsSave)) {
+			UpdateThumbNails(_GM(firstSlotIndex), (guiMenu *)myItem->myMenu);
+		}
+		break;
+
+	case _ME_move:
+		if (menuItem::cursorInsideItem(myItem, x, y)) {
+			*currItem = myItem;
+			tempFlags = menuItemVSlider::whereIsCursor(myItem, y - myItem->y1);
+			if ((myItem->itemFlags & VS_COMPONENT) != tempFlags) {
+				if ((tempFlags == VS_PAGE_UP) || (tempFlags == VS_PAGE_DOWN)) {
+					myItem->itemFlags = VS_NORM;
+				} else {
+					myItem->itemFlags = tempFlags + VS_OVER;
+				}
+				redrawItem = true;
+			}
+		} else {
+			*currItem = nullptr;
+			if (myItem->itemFlags != VS_NORM) {
+				myItem->itemFlags = VS_NORM;
+				redrawItem = true;
+				handled = false;
+			}
+		}
+		break;
+
+	case _ME_L_hold:
+	case _ME_doubleclick_hold:
+		if (!*currItem) {
+			return true;
+		}
+		if (menuItem::cursorInsideItem(myItem, x, y)) {
+			tempFlags = menuItemVSlider::whereIsCursor(myItem, y - myItem->y1);
+			if ((myItem->itemFlags & VS_COMPONENT) == tempFlags) {
+				if (currTime - callbackTime > 6) {
+					execCallback = true;
+				}
+			}
+		}
+		break;
+	}
+
+	// See if we need to redraw the vslider
+	if (redrawItem) {
+		(myItem->redraw)(myItem, myItem->myMenu, myItem->x1, myItem->y1, 0, 0);
+		myScreen = vmng_screen_find(myItem->myMenu, &status);
+		if (myScreen && (status == SCRN_ACTIVE)) {
+			RestoreScreens(myScreen->x1 + myItem->x1, myScreen->y1 + myItem->y1,
+				myScreen->x1 + myItem->x2, myScreen->y1 + myItem->y2);
+		}
+	}
+
+	// See if we need to call the callback function
+	if (execCallback && myItem->callback) {
+		callbackTime = currTime;
+		(myItem->callback)((void *)myItem, myItem->myMenu);
+		myScreen = vmng_screen_find(myItem->myMenu, &status);
+		if ((!myScreen) || (status != SCRN_ACTIVE)) {
+			*currItem = nullptr;
+		}
+	}
+
+	return handled;
+}
+
+
+menuItemVSlider *menuItemVSlider::add(guiMenu *myMenu, int32 tag, int32 x, int32 y, int32 w, int32 h,
+	int32 initPercent, CALLBACK callback, bool transparent) {
+	menuItemVSlider *newItem;
+	ScreenContext *myScreen;
+	int32 status;
+
+	// Verify params
+	if (!myMenu)
+		return nullptr;
+
+	// Allocate a new one
+	newItem = new menuItemVSlider();
+
+	// Initialize the struct
+	newItem->next = myMenu->itemList;
+	newItem->prev = nullptr;
+	if (myMenu->itemList) {
+		myMenu->itemList->prev = newItem;
+	}
+	myMenu->itemList = newItem;
+
+	newItem->myMenu = myMenu;
+	newItem->tag = tag;
+	newItem->x1 = x;
+	newItem->y1 = y;
+	newItem->x2 = x + w - 1;
+	newItem->y2 = y + h - 1;
+	newItem->callback = callback;
+
+	if (!transparent) {
+		newItem->transparent = false;
+		newItem->background = nullptr;
+	} else {
+		newItem->transparent = true;
+		newItem->background = guiMenu::copyBackground(myMenu, x, y, w, h);
+	}
+
+	newItem->itemFlags = menuItemVSlider::VS_NORM;
+
+	newItem->thumbW = _GM(menuSprites)[Burger::GUI::SL_SLIDER_BTN_NORM]->w;
+	newItem->thumbH = _GM(menuSprites)[Burger::GUI::SL_SLIDER_BTN_NORM]->h;
+
+	newItem->minThumbY = _GM(menuSprites)[Burger::GUI::SL_UP_BTN_NORM]->h + 1;
+	newItem->maxThumbY = _GM(menuSprites)[Burger::GUI::SL_UP_BTN_NORM]->h + _GM(menuSprites)[Burger::GUI::SL_SCROLL_BAR]->h
+		- _GM(menuSprites)[Burger::GUI::SL_SLIDER_BTN_NORM]->h - 1;
+
+	// Calculate the initial thumbY
+	newItem->percent = imath_max(imath_min(initPercent, 100), 0);
+	newItem->thumbY = newItem->minThumbY +
+		((newItem->percent * (newItem->maxThumbY - newItem->minThumbY)) / 100);
+
+	newItem->redraw = (DrawFunction)menuItemVSlider::drawVSlider;
+	newItem->destroy = (DestroyFunction)menuItem::destroyItem;
+	newItem->itemEventHandler = (ItemHandlerFunction)menuItemVSlider::handler;
+
+	// Draw the vslider in now
+	(newItem->redraw)(newItem, myMenu, x, y, 0, 0);
+
+	// See if the screen is currently visible
+	myScreen = vmng_screen_find(myMenu, &status);
+	if (myScreen && (status == SCRN_ACTIVE)) {
+		RestoreScreens(myScreen->x1 + newItem->x1, myScreen->y1 + newItem->y1,
+			myScreen->x1 + newItem->x2, myScreen->y1 + newItem->y2);
+	}
+
+	return newItem;
+}
+
+void menuItemVSlider::disableVSlider(menuItemVSlider *myItem, int32 tag, guiMenu *myMenu) {
+	// Verify params
+	if (!myMenu)
+		return;
+
+	if (!myItem)
+		myItem = (menuItemVSlider *)guiMenu::getItem(tag, myMenu);
+	if (!myItem)
+		return;
+
+	myItem->itemFlags = menuItemVSlider::VS_GREY;
+}
+
+void menuItemVSlider::enableVSlider(menuItemVSlider *myItem, int32 tag, guiMenu *myMenu) {
+	// Verify params
+	if (!myMenu)
+		return;
+
+	if (!myItem)
+		myItem = (menuItemVSlider *)guiMenu::getItem(tag, myMenu);
+	if (!myItem)
+		return;
+
+	myItem->itemFlags = menuItemVSlider::VS_NORM;
+}
+
+
+
 } // namespace GUI
 } // namespace M4
diff --git a/engines/m4/gui/gui_menu.h b/engines/m4/gui/gui_menu.h
index 571b7396fb7..48eefee03c7 100644
--- a/engines/m4/gui/gui_menu.h
+++ b/engines/m4/gui/gui_menu.h
@@ -108,6 +108,9 @@ enum save_load_menu_item_tags {
 	SL_TAG_THUMBNAIL
 };
 
+constexpr int SL_THUMBNAIL_W = 215;
+constexpr int SL_THUMBNAIL_H = 162;
+
 } // namespace GUI
 } // namespace Burger
 
@@ -181,7 +184,6 @@ struct menuItem {
 	static bool cursorInsideItem(menuItem *myItem, int32 cursorX, int32 cursorY);
 };
 
-
 struct menuItemMsg : public menuItem {
 private:
 	static void drawMsg(menuItemMsg *myItem, guiMenu *myMenu, int32 x, int32 y, int32, int32);
@@ -225,7 +227,7 @@ public:
 	menuItem *assocItem = nullptr;
 	int32 specialTag = 0;
 
-	static menuItemButton *buttonAdd(guiMenu *myMenu, int32 tag, int32 x, int32 y, int32 w, int32 h, CALLBACK callback = nullptr,
+	static menuItemButton *add(guiMenu *myMenu, int32 tag, int32 x, int32 y, int32 w, int32 h, CALLBACK callback = nullptr,
 		int32 buttonType = 0, bool ghosted = false, bool transparent = false,
 		const char *prompt = nullptr, ItemHandlerFunction i_handler = (ItemHandlerFunction)handler);
 	static void disableButton(menuItemButton *myItem, int32 tag, guiMenu *myMenu);
@@ -235,21 +237,61 @@ public:
 };
 
 struct menuItemHSlider : public menuItem {
+private:
+	static void drawHSlider(menuItemHSlider *myItem, guiMenu *myMenu, int32 x, int32 y, int32, int32);
+	static bool handler(menuItemHSlider *myItem, int32 eventType, int32 event, int32 x, int32 y, void **currItem);
+
+public:
 	int32 itemFlags = 0;
 
 	int32 thumbW = 0, thumbH = 0;
 	int32 thumbX = 0, maxThumbX = 0;
 
 	int32 percent = 0;
+
+	enum {
+		H_THUMB_NORM = 0,
+		H_THUMB_OVER = 1,
+		H_THUMB_PRESS = 2
+	};
+
+	static menuItemHSlider *add(guiMenu *myMenu, int32 tag,
+		int32 x, int32 y, int32 w, int32 h, int32 initPercent = 0,
+		CALLBACK callback = nullptr, bool transparent = false);
 };
 
 struct menuItemVSlider : public menuItem {
+private:
+	static int32 whereIsCursor(menuItemVSlider *myVSlider, int32 y);
+
+public:
 	int32 itemFlags = 0;
 
 	int32 thumbW = 0, thumbH = 0;
 	int32 thumbY = 0, minThumbY = 0, maxThumbY = 0;
 
 	int32 percent = 0;
+
+	enum {
+		VS_NORM = 0x0000,
+		VS_OVER = 0x0001,
+		VS_PRESS = 0x0002,
+		VS_GREY = 0x0003,
+		VS_STATUS = 0x000f,
+		VS_UP = 0x0010,
+		VS_PAGE_UP = 0x0020,
+		VS_THUMB = 0x0030,
+		VS_PAGE_DOWN = 0x0040,
+		VS_DOWN = 0x0050,
+		VS_COMPONENT = 0x00f0
+	};
+
+	static menuItemVSlider *add(guiMenu *myMenu, int32 tag, int32 x, int32 y, int32 w, int32 h,
+		int32 initPercent = 0, CALLBACK callback = nullptr, bool transparent = false);
+	static void disableVSlider(menuItemVSlider *myItem, int32 tag, guiMenu *myMenu);
+	static void enableVSlider(menuItemVSlider *myItem, int32 tag, guiMenu *myMenu);
+	static void drawVSlider(menuItemVSlider *myItem, guiMenu *myMenu, int32 x, int32 y, int32, int32);
+	static bool handler(menuItemVSlider *myItem, int32 eventType, int32 event, int32 x, int32 y, void **currItem);
 };
 
 struct menuItemTextField : public menuItem {
@@ -345,6 +387,10 @@ struct MenuGlobals {
 };
 
 extern void gui_DrawSprite(Sprite *mySprite, Buffer *myBuff, int32 x, int32 y);
+extern bool LoadThumbNail(int32 slotNum);
+extern void UnloadThumbNail(int32 slotNum);
+extern void UpdateThumbNails(int32 firstSlot, guiMenu *myMenu);
+extern void SetFirstSlot(int32 firstSlot, guiMenu *myMenu);
 
 //======================================
 //
diff --git a/engines/m4/riddle/gui/game_menu.cpp b/engines/m4/riddle/gui/game_menu.cpp
index 338dd927afe..847c4cf9f85 100644
--- a/engines/m4/riddle/gui/game_menu.cpp
+++ b/engines/m4/riddle/gui/game_menu.cpp
@@ -104,24 +104,24 @@ void GameMenu::show(RGB8 *myPalette) {
 		GAME_MENU_X, GAME_MENU_Y, MENU_DEPTH | SF_GET_ALL | SF_BLOCK_ALL | SF_IMMOVABLE);
 	assert(_GM(gameMenu));
 
-	menuItemButton::buttonAdd(_GM(gameMenu), GM_TAG_QUIT,
+	menuItemButton::add(_GM(gameMenu), GM_TAG_QUIT,
 		GM_QUIT_X, GM_QUIT_Y, GM_QUIT_W, GM_QUIT_H, cbQuitGame);
-	menuItemButton::buttonAdd(_GM(gameMenu), GM_TAG_MAIN,
+	menuItemButton::add(_GM(gameMenu), GM_TAG_MAIN,
 		GM_MAIN_X, GM_MAIN_Y, GM_MAIN_W, GM_MAIN_H, cbMainMenu);
-	menuItemButton::buttonAdd(_GM(gameMenu), GM_TAG_OPTIONS, GM_OPTIONS_X, GM_OPTIONS_Y, GM_OPTIONS_W, GM_OPTIONS_H, cbOptions);
-	menuItemButton::buttonAdd(_GM(gameMenu), GM_TAG_RESUME, GM_RESUME_X, GM_RESUME_Y, GM_RESUME_W, GM_RESUME_H, cbResume);
+	menuItemButton::add(_GM(gameMenu), GM_TAG_OPTIONS, GM_OPTIONS_X, GM_OPTIONS_Y, GM_OPTIONS_W, GM_OPTIONS_H, cbOptions);
+	menuItemButton::add(_GM(gameMenu), GM_TAG_RESUME, GM_RESUME_X, GM_RESUME_Y, GM_RESUME_W, GM_RESUME_H, cbResume);
 
 	if (!_GM(gameMenuFromMain)) {
-		menuItemButton::buttonAdd(_GM(gameMenu), GM_TAG_SAVE, GM_SAVE_X, GM_SAVE_Y, GM_SAVE_W, GM_SAVE_H, cbSave);
+		menuItemButton::add(_GM(gameMenu), GM_TAG_SAVE, GM_SAVE_X, GM_SAVE_Y, GM_SAVE_W, GM_SAVE_H, cbSave);
 	} else {
-		menuItemButton::buttonAdd(_GM(gameMenu), GM_TAG_SAVE, GM_SAVE_X, GM_SAVE_Y, GM_SAVE_W, GM_SAVE_H, cbSave, menuItemButton::BTN_TYPE_GM_GENERIC, true);
+		menuItemButton::add(_GM(gameMenu), GM_TAG_SAVE, GM_SAVE_X, GM_SAVE_Y, GM_SAVE_W, GM_SAVE_H, cbSave, menuItemButton::BTN_TYPE_GM_GENERIC, true);
 	}
 
 	// See if there are any games to load
 	if (g_engine->savesExist()) {
-		menuItemButton::buttonAdd(_GM(gameMenu), GM_TAG_LOAD, GM_LOAD_X, GM_LOAD_Y, GM_LOAD_W, GM_LOAD_H, cbLoad);
+		menuItemButton::add(_GM(gameMenu), GM_TAG_LOAD, GM_LOAD_X, GM_LOAD_Y, GM_LOAD_W, GM_LOAD_H, cbLoad);
 	} else {
-		menuItemButton::buttonAdd(_GM(gameMenu), GM_TAG_LOAD, GM_LOAD_X, GM_LOAD_Y, GM_LOAD_W, GM_LOAD_H, cbLoad, menuItemButton::BTN_TYPE_GM_GENERIC, true);
+		menuItemButton::add(_GM(gameMenu), GM_TAG_LOAD, GM_LOAD_X, GM_LOAD_Y, GM_LOAD_W, GM_LOAD_H, cbLoad, menuItemButton::BTN_TYPE_GM_GENERIC, true);
 	}
 
 	// Configure the game so pressing <esc> will cause the menu to disappear and the game to resume


Commit: ae8fc03e3a1800eef97bd1a45b282e107a4baf95
    https://github.com/scummvm/scummvm/commit/ae8fc03e3a1800eef97bd1a45b282e107a4baf95
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2025-02-12T22:43:58-08:00

Commit Message:
M4: RIDDLE: Move text field methods to menuItemTextField

Changed paths:
    engines/m4/burger/gui/game_menu.cpp
    engines/m4/burger/gui/game_menu.h
    engines/m4/gui/gui_menu.cpp
    engines/m4/gui/gui_menu.h


diff --git a/engines/m4/burger/gui/game_menu.cpp b/engines/m4/burger/gui/game_menu.cpp
index 97c198d86f8..40cb8b82b00 100644
--- a/engines/m4/burger/gui/game_menu.cpp
+++ b/engines/m4/burger/gui/game_menu.cpp
@@ -231,342 +231,6 @@ Sprite *menu_CreateThumbnail(int32 *spriteSize) {
 	return thumbNailSprite;
 }
 
-//-----------------------------    TEXTFIELD MENU ITEM    ---------------------------------//
-
-enum {
-	TF_NORM = 0,
-	TF_OVER = 1,
-	TF_GREY = 2
-};
-
-void menu_DrawTextField(menuItemTextField *myItem, guiMenu *myMenu, int32 x, int32 y, int32, int32) {
-	menuItemTextField *myText = nullptr;
-	Buffer *myBuff = nullptr;
-	Buffer *backgroundBuff = nullptr;
-	Sprite *mySprite = nullptr;
-	char tempStr[64], tempChar;
-	int32 cursorX;
-
-	// Verify params
-	if (!myItem || !myMenu)
-		return;
-
-	// If the item is marked transparent, get the background buffer
-	if (myItem->transparent) {
-		if (!myItem->background) {
-			return;
-		}
-		backgroundBuff = myItem->background->get_buffer();
-		if (!backgroundBuff) {
-			return;
-		}
-	}
-
-	// Select the sprite
-	switch (myText->itemFlags) {
-	case TF_GREY:
-		mySprite = _GM(menuSprites)[Burger::GUI::SL_LINE_NORM];
-		break;
-
-	case TF_OVER:
-		mySprite = _GM(menuSprites)[Burger::GUI::SL_LINE_OVER];
-		break;
-
-	case TF_NORM:
-	default:
-		mySprite = _GM(menuSprites)[Burger::GUI::SL_LINE_OVER];
-		break;
-	}
-
-	// Get the menu buffer and draw the sprite to it
-	myBuff = myMenu->menuBuffer->get_buffer();
-	if (!myBuff) {
-		return;
-	}
-
-	// If the item is tagged as transparent, we need to fill in it's background behind it
-	if (backgroundBuff) {
-		gr_buffer_rect_copy_2(backgroundBuff, myBuff, 0, 0, x, y, backgroundBuff->w, backgroundBuff->h);
-		myItem->background->release();
-	}
-
-	// Draw the item sprite in
-	gui_DrawSprite(mySprite, myBuff, x, y);
-
-	//write in the special tag
-	gr_font_set_color(menuItem::TEXT_COLOR_NORM_FOREGROUND);
-	Common::sprintf_s(tempStr, 64, "%02d", myText->specialTag);
-	gr_font_set(_GM(menuFont));
-	gr_font_write(myBuff, tempStr, x + 4, y + 1, 0, -1);
-
-	//write in the text
-	gr_font_write(myBuff, &myText->prompt[0], x + 26, y + 1, 0, -1);
-
-	if (myText->itemFlags == TF_OVER) {
-		// Draw in the cursor
-		if (myText->cursor) {
-			tempChar = *myText->cursor;
-			*myText->cursor = '\0';
-			cursorX = gr_font_string_width(&myText->prompt[0], -1);
-			*myText->cursor = tempChar;
-
-			gr_color_set(menuItem::TEXT_COLOR_OVER_FOREGROUND);
-			gr_vline(myBuff, x + cursorX + 26, y + 1, y + 12);
-		}
-	}
-
-	// Release the menu buffer
-	myMenu->menuBuffer->release();
-}
-
-
-bool textfield_Handler(menuItemTextField *myItem, int32 eventType, int32 event, int32 x, int32 y, void **currItem) {
-	bool redrawItem, execCallback, handled;
-	ScreenContext *myScreen;
-	int32 status, temp;
-	char tempStr[80], *tempPtr;
-
-	// Verify params
-	if (!myItem)
-		return false;
-
-	if (myItem->itemFlags == TF_GREY) {
-		return false;
-	}
-
-	redrawItem = false;
-	execCallback = false;
-	handled = true;
-
-	if (eventType == EVENT_MOUSE) {
-		switch (event) {
-		case _ME_L_click:
-		case _ME_doubleclick:
-			_GM(deleteSaveDesc) = false;
-			if (menuItem::cursorInsideItem(myItem, x, y)) {
-				*currItem = myItem;
-			}
-			break;
-
-		case _ME_L_drag:
-		case _ME_doubleclick_drag:
-			break;
-
-		case _ME_L_release:
-		case _ME_doubleclick_release:
-			if (!*currItem) {
-				return true;
-			}
-			*currItem = nullptr;
-			if (menuItem::cursorInsideItem(myItem, x, y)) {
-				if (myItem->itemFlags == TF_OVER) {
-					temp = strlen(myItem->prompt);
-					if (temp > 0) {
-						Common::strcpy_s(tempStr, myItem->prompt);
-						tempPtr = &tempStr[temp];
-						gr_font_set(_GM(menuFont));
-						temp = gr_font_string_width(tempStr, -1);
-						while ((tempPtr != &tempStr[0]) && (temp > x - myItem->x1 - 26)) {
-							*--tempPtr = '\0';
-							temp = gr_font_string_width(tempStr, -1);
-						}
-						myItem->cursor = &myItem->prompt[tempPtr - &tempStr[0]];
-						redrawItem = true;
-					}
-				} else if (event == _ME_doubleclick_release) {
-					execCallback = true;
-				}
-			}
-			break;
-
-		case _ME_move:
-		case _ME_L_hold:
-		case _ME_doubleclick_hold:
-			break;
-		}
-	} else if ((eventType == EVENT_KEY) && (myItem->itemFlags == TF_OVER)) {
-		switch (event) {
-		case KEY_RETURN:
-			_GM(deleteSaveDesc) = false;
-			execCallback = true;
-			break;
-
-		case KEY_HOME:
-			_GM(deleteSaveDesc) = false;
-			myItem->cursor = &myItem->prompt[0];
-			redrawItem = true;
-			break;
-
-		case KEY_END:
-			_GM(deleteSaveDesc) = false;
-			myItem->cursor = myItem->promptEnd;
-			redrawItem = true;
-			break;
-
-		case KEY_LEFT:
-			_GM(deleteSaveDesc) = false;
-			if (myItem->cursor > &myItem->prompt[0]) {
-				myItem->cursor--;
-				redrawItem = true;
-			}
-			break;
-
-		case KEY_RIGHT:
-			_GM(deleteSaveDesc) = false;
-			if (myItem->cursor < myItem->promptEnd) {
-				myItem->cursor++;
-				redrawItem = true;
-			}
-			break;
-
-		case KEY_DELETE:
-			if (_GM(deleteSaveDesc)) {
-				myItem->prompt[0] = '\0';
-				myItem->promptEnd = &myItem->prompt[0];
-				myItem->cursor = myItem->promptEnd;
-				redrawItem = true;
-			} else if (myItem->cursor < myItem->promptEnd) {
-				Common::strcpy_s(tempStr, (char *)(myItem->cursor + 1));
-				Common::strcpy_s(myItem->cursor, 80, tempStr);
-				myItem->promptEnd--;
-				redrawItem = true;
-			}
-			break;
-
-		case KEY_BACKSP:
-			_GM(deleteSaveDesc) = false;
-			if (myItem->cursor > &myItem->prompt[0]) {
-				Common::strcpy_s(tempStr, myItem->cursor);
-				myItem->promptEnd--;
-				myItem->cursor--;
-				Common::strcpy_s(myItem->cursor, 80, tempStr);
-				redrawItem = true;
-			}
-			break;
-
-		default:
-			_GM(deleteSaveDesc) = false;
-			gr_font_set(_GM(menuFont));
-			temp = gr_font_string_width(&myItem->prompt[0], -1);
-			if ((strlen(&myItem->prompt[0]) < 79) && (temp < myItem->pixWidth - 12) && (event >= 32) && (event <= 127)) {
-				if (myItem->cursor < myItem->promptEnd) {
-					Common::strcpy_s(tempStr, (char *)myItem->cursor);
-					Common::sprintf_s(myItem->cursor, 80, "%c%s", (char)event, tempStr);
-				} else {
-					*myItem->cursor = (char)event;
-					*(myItem->cursor + 1) = '\0';
-				}
-				myItem->cursor++;
-				myItem->promptEnd++;
-
-				redrawItem = true;
-			}
-			break;
-		}
-	} else if ((eventType == EVENT_KEY) && (event == KEY_RETURN)) {
-		// The only events a NORM textfield can respond to are doubleclick_release and <return> keypress
-		execCallback = true;
-	} else {
-		// Otherwise the event will not be handled
-		return false;
-	}
-
-	// See if we need to redraw the button
-	if (redrawItem) {
-		(myItem->redraw)(myItem, myItem->myMenu, myItem->x1, myItem->y1, 0, 0);
-		myScreen = vmng_screen_find(myItem->myMenu, &status);
-		if (myScreen && (status == SCRN_ACTIVE)) {
-			RestoreScreens(myScreen->x1 + myItem->x1, myScreen->y1 + myItem->y1,
-				myScreen->x1 + myItem->x2, myScreen->y1 + myItem->y2);
-		}
-	}
-
-	// See if we need to call the callback function
-	if (execCallback && myItem->callback) {
-		(myItem->callback)((void *)myItem, myItem->myMenu);
-		myScreen = vmng_screen_find(myItem->myMenu, &status);
-
-		if ((!myScreen) || (status != SCRN_ACTIVE)) {
-			*currItem = nullptr;
-		}
-	}
-
-	return handled;
-}
-
-
-menuItemTextField *menu_TextFieldAdd(guiMenu *myMenu, int32 tag, int32 x, int32 y, int32 w, int32 h, int32 initFlags,
-		const char *prompt, int32 specialTag, CALLBACK callback, bool transparent) {
-	menuItemTextField *newItem;
-	menuItemTextField *textInfo;
-	ScreenContext *myScreen;
-	int32 status;
-
-	// Verify params
-	if (!myMenu)
-		return nullptr;
-
-	// Allocate a new one
-	newItem = new menuItemTextField();
-
-	// Initialize the struct
-	newItem->next = myMenu->itemList;
-	newItem->prev = nullptr;
-	if (myMenu->itemList) {
-		myMenu->itemList->prev = newItem;
-	}
-	myMenu->itemList = newItem;
-
-	newItem->myMenu = myMenu;
-	newItem->tag = tag;
-	newItem->x1 = x;
-	newItem->y1 = y;
-	newItem->x2 = x + w - 1;
-	newItem->y2 = y + h - 1;
-	newItem->callback = callback;
-
-	if (!transparent) {
-		newItem->transparent = false;
-		newItem->background = nullptr;
-	} else {
-		newItem->transparent = true;
-		newItem->background = guiMenu::copyBackground(myMenu, x, y, w, h);
-	}
-
-	if ((textInfo = (menuItemTextField *)mem_alloc(sizeof(menuItemTextField), "menu item textfield")) == nullptr) {
-		return nullptr;
-	}
-	textInfo->itemFlags = initFlags;
-
-	textInfo->specialTag = specialTag;
-	textInfo->pixWidth = w - 27;
-	if (prompt) {
-		Common::strcpy_s(&textInfo->prompt[0], 80, prompt);
-		textInfo->promptEnd = &textInfo->prompt[strlen(prompt)];
-	} else {
-		textInfo->prompt[0] = '\0';
-		textInfo->promptEnd = &textInfo->prompt[0];
-	}
-	textInfo->cursor = textInfo->promptEnd;
-
-	newItem->redraw = (DrawFunction)menu_DrawTextField;
-	newItem->destroy = (DestroyFunction)menuItem::destroyItem;
-	newItem->itemEventHandler = (ItemHandlerFunction)textfield_Handler;
-
-	// Draw the vslider in now
-	(newItem->redraw)(newItem, myMenu, x, y, 0, 0);
-
-	// See if the screen is currently visible
-	myScreen = vmng_screen_find(myMenu, &status);
-	if (myScreen && (status == SCRN_ACTIVE)) {
-		RestoreScreens(myScreen->x1 + newItem->x1, myScreen->y1 + newItem->y1,
-			myScreen->x1 + newItem->x2, myScreen->y1 + newItem->y2);
-	}
-
-	return newItem;
-}
-
-
 //-------------------------------------   GAME MENU   -------------------------------------//
 
 
@@ -1003,7 +667,7 @@ void cb_SaveLoad_Save(void *, guiMenu *myMenu) {
 	if (myText)
 		return;
 
-	myText->itemFlags = TF_NORM;
+	myText->itemFlags = menuItemTextField::TF_NORM;
 
 	// Set the vars
 	_GM(slotInUse)[_GM(slotSelected) - 1] = true;
@@ -1175,14 +839,14 @@ void cb_SaveLoad_Slot(menuItemButton *myButton, guiMenu *myMenu) {
 	if (_GM(currMenuIsSave)) {
 		// Replace the current button with a textfield
 		if (!strcmp(prompt, "<empty>")) {
-			menu_TextFieldAdd(myMenu, 2000, x, y, w, h, TF_OVER,
+			menuItemTextField::add(myMenu, 2000, x, y, w, h, menuItemTextField::TF_OVER,
 				nullptr, specialTag, (CALLBACK)cb_SaveLoad_Save, true);
 		} else {
-			menu_TextFieldAdd(myMenu, 2000, x, y, w, h, TF_OVER,
+			menuItemTextField::add(myMenu, 2000, x, y, w, h, menuItemTextField::TF_OVER,
 				prompt, specialTag, (CALLBACK)cb_SaveLoad_Save, true);
 		}
 	} else {
-		menu_TextFieldAdd(myMenu, 2000, x, y, w, h, TF_NORM,
+		menuItemTextField::add(myMenu, 2000, x, y, w, h, menuItemTextField::TF_NORM,
 			prompt, specialTag, (CALLBACK)cb_SaveLoad_Load, true);
 	}
 
diff --git a/engines/m4/burger/gui/game_menu.h b/engines/m4/burger/gui/game_menu.h
index 6a17d82060b..47f1c55cf31 100644
--- a/engines/m4/burger/gui/game_menu.h
+++ b/engines/m4/burger/gui/game_menu.h
@@ -43,10 +43,6 @@ using M4::GUI::Sprite;
 using M4::GUI::CALLBACK;
 using M4::GUI::ItemHandlerFunction;
 
-// Textfields
-menuItemTextField *menu_TextFieldAdd(guiMenu *myMenu, int32 tag, int32 x, int32 y, int32 w, int32 h, int32 initFlags,
-	const char *prompt = nullptr, int32 specialtag = 0, CALLBACK callback = nullptr, bool transparent = false);
-
 //GAME MENU FUNCTIONS
 extern void CreateGameMenu(RGB8 *myPalette);
 extern void CreateOptionsMenu(RGB8 *myPalette);
diff --git a/engines/m4/gui/gui_menu.cpp b/engines/m4/gui/gui_menu.cpp
index 3268e477b8c..c8df5004594 100644
--- a/engines/m4/gui/gui_menu.cpp
+++ b/engines/m4/gui/gui_menu.cpp
@@ -1998,6 +1998,332 @@ void menuItemVSlider::enableVSlider(menuItemVSlider *myItem, int32 tag, guiMenu
 }
 
 
+//-----------------------------    TEXTFIELD MENU ITEM    ---------------------------------//
+
+void menuItemTextField::drawTextField(menuItemTextField *myItem, guiMenu *myMenu, int32 x, int32 y, int32, int32) {
+	menuItemTextField *myText = nullptr;
+	Buffer *myBuff = nullptr;
+	Buffer *backgroundBuff = nullptr;
+	Sprite *mySprite = nullptr;
+	char tempStr[64], tempChar;
+	int32 cursorX;
+
+	// Verify params
+	if (!myItem || !myMenu)
+		return;
+
+	// If the item is marked transparent, get the background buffer
+	if (myItem->transparent) {
+		if (!myItem->background) {
+			return;
+		}
+		backgroundBuff = myItem->background->get_buffer();
+		if (!backgroundBuff) {
+			return;
+		}
+	}
+
+	// Select the sprite
+	switch (myText->itemFlags) {
+	case TF_GREY:
+		mySprite = _GM(menuSprites)[Burger::GUI::SL_LINE_NORM];
+		break;
+
+	case TF_OVER:
+		mySprite = _GM(menuSprites)[Burger::GUI::SL_LINE_OVER];
+		break;
+
+	case TF_NORM:
+	default:
+		mySprite = _GM(menuSprites)[Burger::GUI::SL_LINE_OVER];
+		break;
+	}
+
+	// Get the menu buffer and draw the sprite to it
+	myBuff = myMenu->menuBuffer->get_buffer();
+	if (!myBuff) {
+		return;
+	}
+
+	// If the item is tagged as transparent, we need to fill in it's background behind it
+	if (backgroundBuff) {
+		gr_buffer_rect_copy_2(backgroundBuff, myBuff, 0, 0, x, y, backgroundBuff->w, backgroundBuff->h);
+		myItem->background->release();
+	}
+
+	// Draw the item sprite in
+	gui_DrawSprite(mySprite, myBuff, x, y);
+
+	//write in the special tag
+	gr_font_set_color(menuItem::TEXT_COLOR_NORM_FOREGROUND);
+	Common::sprintf_s(tempStr, 64, "%02d", myText->specialTag);
+	gr_font_set(_GM(menuFont));
+	gr_font_write(myBuff, tempStr, x + 4, y + 1, 0, -1);
+
+	//write in the text
+	gr_font_write(myBuff, &myText->prompt[0], x + 26, y + 1, 0, -1);
+
+	if (myText->itemFlags == TF_OVER) {
+		// Draw in the cursor
+		if (myText->cursor) {
+			tempChar = *myText->cursor;
+			*myText->cursor = '\0';
+			cursorX = gr_font_string_width(&myText->prompt[0], -1);
+			*myText->cursor = tempChar;
+
+			gr_color_set(menuItem::TEXT_COLOR_OVER_FOREGROUND);
+			gr_vline(myBuff, x + cursorX + 26, y + 1, y + 12);
+		}
+	}
+
+	// Release the menu buffer
+	myMenu->menuBuffer->release();
+}
+
+bool menuItemTextField::handler(menuItemTextField *myItem, int32 eventType, int32 event, int32 x, int32 y, void **currItem) {
+	bool redrawItem, execCallback, handled;
+	ScreenContext *myScreen;
+	int32 status, temp;
+	char tempStr[80], *tempPtr;
+
+	// Verify params
+	if (!myItem)
+		return false;
+
+	if (myItem->itemFlags == TF_GREY) {
+		return false;
+	}
+
+	redrawItem = false;
+	execCallback = false;
+	handled = true;
+
+	if (eventType == EVENT_MOUSE) {
+		switch (event) {
+		case _ME_L_click:
+		case _ME_doubleclick:
+			_GM(deleteSaveDesc) = false;
+			if (menuItem::cursorInsideItem(myItem, x, y)) {
+				*currItem = myItem;
+			}
+			break;
+
+		case _ME_L_drag:
+		case _ME_doubleclick_drag:
+			break;
+
+		case _ME_L_release:
+		case _ME_doubleclick_release:
+			if (!*currItem) {
+				return true;
+			}
+			*currItem = nullptr;
+			if (menuItem::cursorInsideItem(myItem, x, y)) {
+				if (myItem->itemFlags == TF_OVER) {
+					temp = strlen(myItem->prompt);
+					if (temp > 0) {
+						Common::strcpy_s(tempStr, myItem->prompt);
+						tempPtr = &tempStr[temp];
+						gr_font_set(_GM(menuFont));
+						temp = gr_font_string_width(tempStr, -1);
+						while ((tempPtr != &tempStr[0]) && (temp > x - myItem->x1 - 26)) {
+							*--tempPtr = '\0';
+							temp = gr_font_string_width(tempStr, -1);
+						}
+						myItem->cursor = &myItem->prompt[tempPtr - &tempStr[0]];
+						redrawItem = true;
+					}
+				} else if (event == _ME_doubleclick_release) {
+					execCallback = true;
+				}
+			}
+			break;
+
+		case _ME_move:
+		case _ME_L_hold:
+		case _ME_doubleclick_hold:
+			break;
+		}
+	} else if ((eventType == EVENT_KEY) && (myItem->itemFlags == TF_OVER)) {
+		switch (event) {
+		case KEY_RETURN:
+			_GM(deleteSaveDesc) = false;
+			execCallback = true;
+			break;
+
+		case KEY_HOME:
+			_GM(deleteSaveDesc) = false;
+			myItem->cursor = &myItem->prompt[0];
+			redrawItem = true;
+			break;
+
+		case KEY_END:
+			_GM(deleteSaveDesc) = false;
+			myItem->cursor = myItem->promptEnd;
+			redrawItem = true;
+			break;
+
+		case KEY_LEFT:
+			_GM(deleteSaveDesc) = false;
+			if (myItem->cursor > &myItem->prompt[0]) {
+				myItem->cursor--;
+				redrawItem = true;
+			}
+			break;
+
+		case KEY_RIGHT:
+			_GM(deleteSaveDesc) = false;
+			if (myItem->cursor < myItem->promptEnd) {
+				myItem->cursor++;
+				redrawItem = true;
+			}
+			break;
+
+		case KEY_DELETE:
+			if (_GM(deleteSaveDesc)) {
+				myItem->prompt[0] = '\0';
+				myItem->promptEnd = &myItem->prompt[0];
+				myItem->cursor = myItem->promptEnd;
+				redrawItem = true;
+			} else if (myItem->cursor < myItem->promptEnd) {
+				Common::strcpy_s(tempStr, (char *)(myItem->cursor + 1));
+				Common::strcpy_s(myItem->cursor, 80, tempStr);
+				myItem->promptEnd--;
+				redrawItem = true;
+			}
+			break;
+
+		case KEY_BACKSP:
+			_GM(deleteSaveDesc) = false;
+			if (myItem->cursor > &myItem->prompt[0]) {
+				Common::strcpy_s(tempStr, myItem->cursor);
+				myItem->promptEnd--;
+				myItem->cursor--;
+				Common::strcpy_s(myItem->cursor, 80, tempStr);
+				redrawItem = true;
+			}
+			break;
+
+		default:
+			_GM(deleteSaveDesc) = false;
+			gr_font_set(_GM(menuFont));
+			temp = gr_font_string_width(&myItem->prompt[0], -1);
+			if ((strlen(&myItem->prompt[0]) < 79) && (temp < myItem->pixWidth - 12) && (event >= 32) && (event <= 127)) {
+				if (myItem->cursor < myItem->promptEnd) {
+					Common::strcpy_s(tempStr, (char *)myItem->cursor);
+					Common::sprintf_s(myItem->cursor, 80, "%c%s", (char)event, tempStr);
+				} else {
+					*myItem->cursor = (char)event;
+					*(myItem->cursor + 1) = '\0';
+				}
+				myItem->cursor++;
+				myItem->promptEnd++;
+
+				redrawItem = true;
+			}
+			break;
+		}
+	} else if ((eventType == EVENT_KEY) && (event == KEY_RETURN)) {
+		// The only events a NORM textfield can respond to are doubleclick_release and <return> keypress
+		execCallback = true;
+	} else {
+		// Otherwise the event will not be handled
+		return false;
+	}
+
+	// See if we need to redraw the button
+	if (redrawItem) {
+		(myItem->redraw)(myItem, myItem->myMenu, myItem->x1, myItem->y1, 0, 0);
+		myScreen = vmng_screen_find(myItem->myMenu, &status);
+		if (myScreen && (status == SCRN_ACTIVE)) {
+			RestoreScreens(myScreen->x1 + myItem->x1, myScreen->y1 + myItem->y1,
+				myScreen->x1 + myItem->x2, myScreen->y1 + myItem->y2);
+		}
+	}
+
+	// See if we need to call the callback function
+	if (execCallback && myItem->callback) {
+		(myItem->callback)((void *)myItem, myItem->myMenu);
+		myScreen = vmng_screen_find(myItem->myMenu, &status);
+
+		if ((!myScreen) || (status != SCRN_ACTIVE)) {
+			*currItem = nullptr;
+		}
+	}
+
+	return handled;
+}
+
+menuItemTextField *menuItemTextField::add(guiMenu *myMenu, int32 tag, int32 x, int32 y, int32 w, int32 h, int32 initFlags,
+	const char *prompt, int32 specialTag, CALLBACK callback, bool transparent) {
+	menuItemTextField *newItem;
+	menuItemTextField *textInfo;
+	ScreenContext *myScreen;
+	int32 status;
+
+	// Verify params
+	if (!myMenu)
+		return nullptr;
+
+	// Allocate a new one
+	newItem = new menuItemTextField();
+
+	// Initialize the struct
+	newItem->next = myMenu->itemList;
+	newItem->prev = nullptr;
+	if (myMenu->itemList) {
+		myMenu->itemList->prev = newItem;
+	}
+	myMenu->itemList = newItem;
+
+	newItem->myMenu = myMenu;
+	newItem->tag = tag;
+	newItem->x1 = x;
+	newItem->y1 = y;
+	newItem->x2 = x + w - 1;
+	newItem->y2 = y + h - 1;
+	newItem->callback = callback;
+
+	if (!transparent) {
+		newItem->transparent = false;
+		newItem->background = nullptr;
+	} else {
+		newItem->transparent = true;
+		newItem->background = guiMenu::copyBackground(myMenu, x, y, w, h);
+	}
+
+	if ((textInfo = (menuItemTextField *)mem_alloc(sizeof(menuItemTextField), "menu item textfield")) == nullptr) {
+		return nullptr;
+	}
+	textInfo->itemFlags = initFlags;
+
+	textInfo->specialTag = specialTag;
+	textInfo->pixWidth = w - 27;
+	if (prompt) {
+		Common::strcpy_s(&textInfo->prompt[0], 80, prompt);
+		textInfo->promptEnd = &textInfo->prompt[strlen(prompt)];
+	} else {
+		textInfo->prompt[0] = '\0';
+		textInfo->promptEnd = &textInfo->prompt[0];
+	}
+	textInfo->cursor = textInfo->promptEnd;
+
+	newItem->redraw = (DrawFunction)menuItemTextField::drawTextField;
+	newItem->destroy = (DestroyFunction)menuItem::destroyItem;
+	newItem->itemEventHandler = (ItemHandlerFunction)menuItemTextField::handler;
+
+	// Draw the vslider in now
+	(newItem->redraw)(newItem, myMenu, x, y, 0, 0);
+
+	// See if the screen is currently visible
+	myScreen = vmng_screen_find(myMenu, &status);
+	if (myScreen && (status == SCRN_ACTIVE)) {
+		RestoreScreens(myScreen->x1 + newItem->x1, myScreen->y1 + newItem->y1,
+			myScreen->x1 + newItem->x2, myScreen->y1 + newItem->y2);
+	}
+
+	return newItem;
+}
 
 } // namespace GUI
 } // namespace M4
diff --git a/engines/m4/gui/gui_menu.h b/engines/m4/gui/gui_menu.h
index 48eefee03c7..89a24b61d70 100644
--- a/engines/m4/gui/gui_menu.h
+++ b/engines/m4/gui/gui_menu.h
@@ -304,6 +304,17 @@ struct menuItemTextField : public menuItem {
 	char *promptEnd = nullptr;
 
 	char *cursor = nullptr;
+
+	enum {
+		TF_NORM = 0,
+		TF_OVER = 1,
+		TF_GREY = 2
+	};
+
+	static menuItemTextField *add(guiMenu *myMenu, int32 tag, int32 x, int32 y, int32 w, int32 h, int32 initFlags,
+		const char *prompt = nullptr, int32 specialtag = 0, CALLBACK callback = nullptr, bool transparent = false);
+	static bool handler(menuItemTextField *myItem, int32 eventType, int32 event, int32 x, int32 y, void **currItem);
+	static void drawTextField(menuItemTextField *myItem, guiMenu *myMenu, int32 x, int32 y, int32, int32);
 };
 
 struct guiMenu {




More information about the Scummvm-git-logs mailing list