mirror of
https://github.com/scummvm/scummvm.git
synced 2026-06-20 05:45:29 +00:00
3603 lines
94 KiB
C++
3603 lines
94 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "graphics/thumbnail.h"
|
|
#include "m4/burger/gui/game_menu.h"
|
|
#include "m4/burger/gui/interface.h"
|
|
#include "m4/adv_r/other.h"
|
|
#include "m4/adv_r/adv_background.h"
|
|
#include "m4/adv_r/adv_control.h"
|
|
#include "m4/adv_r/adv_player.h"
|
|
#include "m4/core/errors.h"
|
|
#include "m4/core/imath.h"
|
|
#include "m4/gui/gui_event.h"
|
|
#include "m4/gui/hotkeys.h"
|
|
#include "m4/graphics/gr_line.h"
|
|
#include "m4/graphics/gr_sprite.h"
|
|
#include "m4/graphics/krn_pal.h"
|
|
#include "m4/gui/gui_sys.h"
|
|
#include "m4/gui/gui_vmng.h"
|
|
#include "m4/mem/mem.h"
|
|
#include "m4/platform/keys.h"
|
|
#include "m4/burger/hotkeys.h"
|
|
#include "m4/burger/vars.h"
|
|
#include "m4/m4.h"
|
|
|
|
namespace M4 {
|
|
namespace Burger {
|
|
namespace GUI {
|
|
|
|
#define _GM(X) _G(menu).X
|
|
#define LockMouseSprite mouse_lock_sprite
|
|
#define UnlockMouseSprite mouse_unlock_sprite
|
|
|
|
static bool buttonClosesDialog;
|
|
|
|
void UpdateThumbNails(int32 firstSlot, guiMenu *myMenu);
|
|
|
|
Sprite *menu_CreateThumbnail(int32 *spriteSize) {
|
|
Sprite *thumbNailSprite;
|
|
GrBuff *thumbNail;
|
|
Buffer *scrnBuff, *intrBuff, *destBuff, RLE8Buff;
|
|
uint8 *srcPtr, *srcPtr2, *srcPtr3, *srcRowPtr, *destPtr;
|
|
ScreenContext *gameScreen;
|
|
int32 i, status;
|
|
int32 currRow, beginRow, endRow;
|
|
|
|
// Create a Sprite for the thumbNail
|
|
if ((thumbNailSprite = (Sprite *)mem_alloc(sizeof(Sprite), "sprite")) == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
thumbNail = new GrBuff((MAX_VIDEO_X + 1) / 3, (MAX_VIDEO_Y + 1) / 3);
|
|
if (!thumbNail) {
|
|
return nullptr;
|
|
}
|
|
|
|
destBuff = thumbNail->get_buffer();
|
|
if (!destBuff) {
|
|
return nullptr;
|
|
}
|
|
|
|
gameScreen = vmng_screen_find(_G(gameDrawBuff), &status);
|
|
if ((!gameScreen) || (status != SCRN_ACTIVE)) {
|
|
return nullptr;
|
|
}
|
|
|
|
scrnBuff = _G(gameDrawBuff)->get_buffer();
|
|
if (!scrnBuff) {
|
|
return nullptr;
|
|
}
|
|
|
|
// Grab the interface buffer
|
|
intrBuff = _G(gameInterfaceBuff)->get_buffer();
|
|
|
|
if (gameScreen->y1 > 0) {
|
|
// Paint the top of the thumbnail black
|
|
beginRow = gameScreen->y1;
|
|
memset(destBuff->data, 21, (beginRow / 3) * destBuff->stride);
|
|
srcRowPtr = (uint8 *)(scrnBuff->data + (-gameScreen->x1));
|
|
destPtr = (uint8 *)(destBuff->data + ((beginRow / 3) * destBuff->stride));
|
|
} else {
|
|
srcRowPtr = (uint8 *)(scrnBuff->data + ((-gameScreen->y1) * scrnBuff->stride) + (-gameScreen->x1));
|
|
beginRow = 0;
|
|
destPtr = destBuff->data;
|
|
}
|
|
endRow = imath_min(MAX_VIDEO_Y, gameScreen->y2);
|
|
|
|
for (currRow = beginRow; currRow <= endRow; currRow += 3) {
|
|
|
|
// Set the src pointers
|
|
srcPtr = srcRowPtr;
|
|
srcPtr2 = srcRowPtr + scrnBuff->stride;
|
|
srcPtr3 = srcRowPtr + (scrnBuff->stride << 1);
|
|
|
|
for (i = 0; i < (MAX_VIDEO_X + 1) / 3; i++) {
|
|
|
|
// Calculate the average - make sure not to extend past the end of the buffer
|
|
if (endRow - currRow < 1) {
|
|
*destPtr = (uint8)((uint32)((*srcPtr + *(srcPtr + 1) + *(srcPtr + 2)) / 3));
|
|
} else if (endRow - currRow < 2) {
|
|
*destPtr = (uint8)((uint32)((*srcPtr + *(srcPtr + 1) + *(srcPtr + 2) +
|
|
*srcPtr2 + *(srcPtr2 + 1) + *(srcPtr2 + 2)) / 6));
|
|
} else {
|
|
*destPtr = (uint8)((uint32)((*srcPtr + *(srcPtr + 1) + *(srcPtr + 2) +
|
|
*srcPtr2 + *(srcPtr2 + 1) + *(srcPtr2 + 2) +
|
|
*srcPtr3 + *(srcPtr3 + 1) + *(srcPtr3 + 2)) / 9));
|
|
}
|
|
|
|
if (*destPtr == 0) {
|
|
*destPtr = 21;
|
|
}
|
|
|
|
// Increment the pointers
|
|
srcPtr += 3;
|
|
srcPtr2 += 3;
|
|
srcPtr3 += 3;
|
|
destPtr++;
|
|
}
|
|
|
|
// Update the row pointer
|
|
srcRowPtr += scrnBuff->stride * 3;
|
|
}
|
|
|
|
// Reset the currRow
|
|
beginRow = currRow;
|
|
|
|
// Paint the interface section of the thumbnail
|
|
if (currRow < MAX_VIDEO_Y) {
|
|
// If the interface is visible, grab it
|
|
if (intrBuff) {
|
|
srcRowPtr = intrBuff->data;
|
|
endRow = imath_min(MAX_VIDEO_Y, beginRow + intrBuff->h - 1);
|
|
for (currRow = beginRow; currRow <= endRow; currRow += 3) {
|
|
// Set the src pointers
|
|
srcPtr = srcRowPtr;
|
|
srcPtr2 = srcRowPtr + intrBuff->stride;
|
|
srcPtr3 = srcRowPtr + (intrBuff->stride << 1);
|
|
|
|
for (i = 0; i < (MAX_VIDEO_X + 1) / 3; i++) {
|
|
// If the pix is outside of the inventory objects in the interface, set to black
|
|
// If ((srcPtr - srcRowPtr < 180) || (srcPtr - srcRowPtr > 575)) {
|
|
if (true) { // for now make everything in the interface black
|
|
*destPtr = 21;
|
|
}
|
|
|
|
// Else calculate the average - make sure not to extend past the end of the buffer
|
|
else {
|
|
if (endRow - currRow < 1) {
|
|
*destPtr = (uint8)((uint32)((*srcPtr + *(srcPtr + 1) + *(srcPtr + 2)) / 3));
|
|
} else if (endRow - currRow < 2) {
|
|
*destPtr = (uint8)((uint32)((*srcPtr + *(srcPtr + 1) + *(srcPtr + 2) +
|
|
*srcPtr2 + *(srcPtr2 + 1) + *(srcPtr2 + 2)) / 6));
|
|
} else {
|
|
*destPtr = (uint8)((uint32)((*srcPtr + *(srcPtr + 1) + *(srcPtr + 2) +
|
|
*srcPtr2 + *(srcPtr2 + 1) + *(srcPtr2 + 2) +
|
|
*srcPtr3 + *(srcPtr3 + 1) + *(srcPtr3 + 2)) / 9));
|
|
}
|
|
if (*destPtr == 0) {
|
|
*destPtr = 21;
|
|
}
|
|
}
|
|
|
|
// Increment the pointers
|
|
srcPtr += 3;
|
|
srcPtr2 += 3;
|
|
srcPtr3 += 3;
|
|
destPtr++;
|
|
}
|
|
|
|
// Update the row pointer
|
|
srcRowPtr += intrBuff->stride * 3;
|
|
}
|
|
} else {
|
|
// Else paint the bottom of the thumbnail black
|
|
destPtr = (uint8 *)(destBuff->data + ((currRow / 3) * destBuff->stride));
|
|
memset(destPtr, 21, (destBuff->h - (currRow / 3)) * destBuff->stride);
|
|
}
|
|
}
|
|
|
|
// Reset the currRow
|
|
beginRow = currRow;
|
|
|
|
if (currRow < MAX_VIDEO_Y) {
|
|
// Paint the bottom of the thumbnail black
|
|
destPtr = (uint8 *)(destBuff->data + ((currRow / 3) * destBuff->stride));
|
|
memset(destPtr, 21, (destBuff->h - (currRow / 3)) * destBuff->stride);
|
|
}
|
|
|
|
// Compress the thumbNail data into the RLE8Buff
|
|
if ((*spriteSize = (int32)gr_sprite_RLE8_encode(destBuff, &RLE8Buff)) <= 0) {
|
|
return nullptr;
|
|
}
|
|
|
|
// Fill in the Sprite structure
|
|
thumbNailSprite->w = destBuff->w;
|
|
thumbNailSprite->h = destBuff->h;
|
|
thumbNailSprite->encoding = RLE8;
|
|
thumbNailSprite->data = nullptr;
|
|
if ((thumbNailSprite->sourceHandle = NewHandle(*spriteSize, "thumbNail source")) == nullptr) {
|
|
return nullptr;
|
|
}
|
|
thumbNailSprite->sourceOffset = 0;
|
|
|
|
// Now copy the RLE8Buff into the thumbNail source handle
|
|
HLock(thumbNailSprite->sourceHandle);
|
|
thumbNailSprite->data = (uint8 *)(*(thumbNailSprite->sourceHandle));
|
|
memcpy(thumbNailSprite->data, RLE8Buff.data, *spriteSize);
|
|
HUnLock(thumbNailSprite->sourceHandle);
|
|
|
|
// Release all buffers
|
|
_G(gameDrawBuff)->release();
|
|
if (intrBuff) {
|
|
_G(gameInterfaceBuff)->release();
|
|
}
|
|
thumbNail->release();
|
|
|
|
// Free up both the thumbNail and the RLE8Buff
|
|
delete thumbNail;
|
|
mem_free((void *)RLE8Buff.data);
|
|
|
|
return thumbNailSprite;
|
|
}
|
|
|
|
|
|
bool menu_CursorInsideItem(menuItem *myItem, int32 cursorX, int32 cursorY) {
|
|
if ((cursorX >= myItem->x1) && (cursorX <= myItem->x2) && (cursorY >= myItem->y1) && (cursorY <= myItem->y2)) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
void gui_DrawSprite(Sprite *mySprite, Buffer *myBuff, int32 x, int32 y) {
|
|
DrawRequest spriteDrawReq;
|
|
Buffer drawSpriteBuff;
|
|
|
|
if ((!mySprite) || (!myBuff)) {
|
|
return;
|
|
}
|
|
|
|
if (mySprite->sourceHandle) {
|
|
HLock(mySprite->sourceHandle);
|
|
mySprite->data = (uint8 *)((intptr)*(mySprite->sourceHandle) + mySprite->sourceOffset);
|
|
|
|
drawSpriteBuff.w = mySprite->w;
|
|
drawSpriteBuff.stride = mySprite->w;
|
|
drawSpriteBuff.h = mySprite->h;
|
|
drawSpriteBuff.encoding = (mySprite->encoding) & (uint8)0x7f;
|
|
drawSpriteBuff.data = mySprite->data;
|
|
|
|
spriteDrawReq.Src = &drawSpriteBuff;
|
|
spriteDrawReq.Dest = myBuff;
|
|
spriteDrawReq.x = x;
|
|
spriteDrawReq.y = y;
|
|
spriteDrawReq.scaleX = 100;
|
|
spriteDrawReq.scaleY = 100;
|
|
spriteDrawReq.srcDepth = 0;
|
|
spriteDrawReq.depthCode = nullptr;
|
|
spriteDrawReq.Pal = nullptr;
|
|
spriteDrawReq.ICT = nullptr;
|
|
|
|
gr_sprite_draw(&spriteDrawReq);
|
|
|
|
// Unlock the handle
|
|
HUnLock(mySprite->sourceHandle);
|
|
}
|
|
}
|
|
|
|
|
|
void item_Destroy(void *theItem) {
|
|
menuItem *myItem = (menuItem *)theItem;
|
|
|
|
// Verify params
|
|
if (!myItem) {
|
|
return;
|
|
}
|
|
if (myItem->background) {
|
|
delete myItem->background;
|
|
}
|
|
|
|
if (myItem->itemInfo) {
|
|
mem_free((void *)myItem->itemInfo);
|
|
}
|
|
mem_free((void *)myItem);
|
|
}
|
|
|
|
|
|
//------------------------------- MESSAGE MENU ITEM ---------------------------------//
|
|
|
|
|
|
void menu_DrawMsg(void *theItem, void *theMenu, int32 x, int32 y, int32, int32) {
|
|
menuItem *myItem = (menuItem *)theItem;
|
|
guiMenu *myMenu = (guiMenu *)theMenu;
|
|
Buffer *myBuff = nullptr;
|
|
Buffer *backgroundBuff = nullptr;
|
|
Sprite *mySprite = nullptr;
|
|
|
|
// Verify params
|
|
if ((!myItem) || (!myItem->itemInfo) || (!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)[SL_SAVE_LABEL];
|
|
break;
|
|
case SL_TAG_LOAD_LABEL:
|
|
mySprite = _GM(menuSprites)[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();
|
|
}
|
|
|
|
|
|
menuItem *menu_MsgAdd(guiMenu *myMenu, int32 tag, int32 x, int32 y, int32 w, int32 h, bool transparent) {
|
|
menuItem *newItem;
|
|
menuItemMsg *msgInfo;
|
|
ScreenContext *myScreen;
|
|
int32 status;
|
|
|
|
// Verify params
|
|
if (!myMenu) {
|
|
return nullptr;
|
|
}
|
|
|
|
// Allocate a new one
|
|
if ((newItem = (menuItem *)mem_alloc(sizeof(menuItem), "gui menu item")) == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
// Initialize the struct
|
|
newItem->next = myMenu->itemList;
|
|
newItem->prev = nullptr;
|
|
if (myMenu->itemList) {
|
|
myMenu->itemList->prev = newItem;
|
|
}
|
|
myMenu->itemList = newItem;
|
|
|
|
newItem->myMenu = (void *)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 = menu_CopyBackground(myMenu, x, y, w, h);
|
|
}
|
|
|
|
if ((msgInfo = (menuItemMsg *)mem_alloc(sizeof(menuItemMsg), "menu item message")) == nullptr) {
|
|
return nullptr;
|
|
}
|
|
newItem->itemInfo = (void *)msgInfo;
|
|
|
|
newItem->redraw = menu_DrawMsg;
|
|
newItem->destroy = item_Destroy;
|
|
newItem->itemEventHandler = nullptr;
|
|
|
|
// Draw the message in now
|
|
(newItem->redraw)(newItem, (void *)myMenu, x, y, 0, 0);
|
|
|
|
// See if the screen is currently visible
|
|
myScreen = vmng_screen_find((void *)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;
|
|
}
|
|
|
|
|
|
|
|
//------------------------------- BUTTON MENU ITEM ----------------------------------//
|
|
|
|
enum button_states {
|
|
BTN_STATE_NORM = 0,
|
|
BTN_STATE_OVER = 1,
|
|
BTN_STATE_PRESS = 2,
|
|
BTN_STATE_GREY = 3
|
|
};
|
|
|
|
enum button_types {
|
|
BTN_TYPE_GM_GENERIC,
|
|
BTN_TYPE_SL_SAVE,
|
|
BTN_TYPE_SL_LOAD,
|
|
BTN_TYPE_SL_CANCEL,
|
|
BTN_TYPE_SL_TEXT,
|
|
BTN_TYPE_OM_DONE,
|
|
BTN_TYPE_OM_CANCEL,
|
|
|
|
BTN_TYPE_TOTAL_NUMBER
|
|
};
|
|
|
|
|
|
void menu_DrawButton(void *theItem, void *theMenu, int32 x, int32 y, int32, int32) {
|
|
menuItem *myItem = (menuItem *)theItem;
|
|
guiMenu *myMenu = (guiMenu *)theMenu;
|
|
menuItemButton *myButton = nullptr;
|
|
Buffer *myBuff = nullptr;
|
|
Buffer *backgroundBuff = nullptr;
|
|
Sprite *mySprite = nullptr;
|
|
char tempStr[32];
|
|
|
|
// Verify params
|
|
if ((!myItem) || (!myItem->itemInfo) || (!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
|
|
myButton = (menuItemButton *)myItem->itemInfo;
|
|
|
|
switch (myButton->buttonType) {
|
|
case BTN_TYPE_GM_GENERIC:
|
|
switch (myButton->itemFlags) {
|
|
case BTN_STATE_NORM:
|
|
mySprite = _GM(menuSprites)[GM_BUTTON_NORM];
|
|
break;
|
|
case BTN_STATE_OVER:
|
|
mySprite = _GM(menuSprites)[GM_BUTTON_OVER];
|
|
break;
|
|
case BTN_STATE_PRESS:
|
|
mySprite = _GM(menuSprites)[GM_BUTTON_PRESS];
|
|
break;
|
|
default:
|
|
case BTN_STATE_GREY:
|
|
mySprite = _GM(menuSprites)[GM_BUTTON_GREY];
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case BTN_TYPE_SL_SAVE:
|
|
switch (myButton->itemFlags) {
|
|
case BTN_STATE_NORM:
|
|
mySprite = _GM(menuSprites)[SL_SAVE_BTN_NORM];
|
|
break;
|
|
case BTN_STATE_OVER:
|
|
mySprite = _GM(menuSprites)[SL_SAVE_BTN_OVER];
|
|
break;
|
|
case BTN_STATE_PRESS:
|
|
mySprite = _GM(menuSprites)[SL_SAVE_BTN_PRESS];
|
|
break;
|
|
default:
|
|
case BTN_STATE_GREY:
|
|
mySprite = _GM(menuSprites)[SL_SAVE_BTN_GREY];
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case BTN_TYPE_SL_LOAD:
|
|
switch (myButton->itemFlags) {
|
|
case BTN_STATE_NORM:
|
|
mySprite = _GM(menuSprites)[SL_LOAD_BTN_NORM];
|
|
break;
|
|
case BTN_STATE_OVER:
|
|
mySprite = _GM(menuSprites)[SL_LOAD_BTN_OVER];
|
|
break;
|
|
case BTN_STATE_PRESS:
|
|
mySprite = _GM(menuSprites)[SL_LOAD_BTN_PRESS];
|
|
break;
|
|
default:
|
|
case BTN_STATE_GREY:
|
|
mySprite = _GM(menuSprites)[SL_LOAD_BTN_GREY];
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case BTN_TYPE_SL_TEXT:
|
|
switch (myButton->itemFlags) {
|
|
case BTN_STATE_OVER:
|
|
font_set_colors(TEXT_COLOR_OVER_SHADOW, TEXT_COLOR_OVER_FOREGROUND, TEXT_COLOR_OVER_HILITE);
|
|
// Gr_font_set_color(TEXT_COLOR_OVER);
|
|
mySprite = _GM(menuSprites)[SL_LINE_OVER];
|
|
break;
|
|
case BTN_STATE_PRESS:
|
|
font_set_colors(TEXT_COLOR_PRESS_SHADOW, TEXT_COLOR_PRESS_FOREGROUND, TEXT_COLOR_PRESS_HILITE);
|
|
// Gr_font_set_color(TEXT_COLOR_PRESS);
|
|
mySprite = _GM(menuSprites)[SL_LINE_PRESS];
|
|
break;
|
|
case BTN_STATE_GREY:
|
|
font_set_colors(TEXT_COLOR_GREY_SHADOW, TEXT_COLOR_GREY_FOREGROUND, TEXT_COLOR_GREY_HILITE);
|
|
// Gr_font_set_color(TEXT_COLOR_GREY);
|
|
mySprite = _GM(menuSprites)[SL_LINE_NORM];
|
|
break;
|
|
default:
|
|
case BTN_STATE_NORM:
|
|
font_set_colors(TEXT_COLOR_NORM_SHADOW, TEXT_COLOR_NORM_FOREGROUND, TEXT_COLOR_NORM_HILITE);
|
|
// Gr_font_set_color(TEXT_COLOR_NORM);
|
|
mySprite = _GM(menuSprites)[SL_LINE_NORM];
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case BTN_TYPE_SL_CANCEL:
|
|
switch (myButton->itemFlags) {
|
|
case BTN_STATE_NORM:
|
|
mySprite = _GM(menuSprites)[SL_CANCEL_BTN_NORM];
|
|
break;
|
|
case BTN_STATE_OVER:
|
|
mySprite = _GM(menuSprites)[SL_CANCEL_BTN_OVER];
|
|
break;
|
|
case BTN_STATE_PRESS:
|
|
mySprite = _GM(menuSprites)[SL_CANCEL_BTN_PRESS];
|
|
break;
|
|
default:
|
|
case BTN_STATE_GREY:
|
|
mySprite = _GM(menuSprites)[SL_CANCEL_BTN_NORM];
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case BTN_TYPE_OM_DONE:
|
|
switch (myButton->itemFlags) {
|
|
case BTN_STATE_NORM:
|
|
mySprite = _GM(menuSprites)[OM_DONE_BTN_NORM];
|
|
break;
|
|
case BTN_STATE_OVER:
|
|
mySprite = _GM(menuSprites)[OM_DONE_BTN_OVER];
|
|
break;
|
|
case BTN_STATE_PRESS:
|
|
mySprite = _GM(menuSprites)[OM_DONE_BTN_PRESS];
|
|
break;
|
|
default:
|
|
case BTN_STATE_GREY:
|
|
mySprite = _GM(menuSprites)[OM_DONE_BTN_GREY];
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case BTN_TYPE_OM_CANCEL:
|
|
switch (myButton->itemFlags) {
|
|
case BTN_STATE_NORM:
|
|
mySprite = _GM(menuSprites)[OM_CANCEL_BTN_NORM];
|
|
break;
|
|
case BTN_STATE_OVER:
|
|
mySprite = _GM(menuSprites)[OM_CANCEL_BTN_OVER];
|
|
break;
|
|
case BTN_STATE_PRESS:
|
|
mySprite = _GM(menuSprites)[OM_CANCEL_BTN_PRESS];
|
|
break;
|
|
default:
|
|
case BTN_STATE_GREY:
|
|
mySprite = _GM(menuSprites)[OM_CANCEL_BTN_NORM];
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// 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();
|
|
}
|
|
|
|
// Draw the button sprite in
|
|
gui_DrawSprite(mySprite, myBuff, x, y);
|
|
|
|
// If the button is a textbutton, write in the text
|
|
if ((myButton->buttonType == BTN_TYPE_SL_TEXT) && (myButton->prompt)) {
|
|
// Write in the special tag
|
|
Common::sprintf_s(tempStr, 32, "%02d", myItem->tag - 1000 + _GM(firstSlotIndex));
|
|
|
|
gr_font_set(_GM(menuFont));
|
|
gr_font_write(myBuff, tempStr, x + 4, y + 1, 0, -1);
|
|
gr_font_write(myBuff, myButton->prompt, x + 26, y + 1, 0, -1);
|
|
}
|
|
|
|
// Release the menu buffer
|
|
myMenu->menuBuffer->release();
|
|
}
|
|
|
|
|
|
bool button_Handler(void *theItem, int32 eventType, int32 event, int32 x, int32 y, void **currItem) {
|
|
menuItem *myItem = (menuItem *)theItem;
|
|
menuItemButton *myButton;
|
|
bool redrawItem, execCallback, handled;
|
|
ScreenContext *myScreen;
|
|
int32 status;
|
|
int32 currTag;
|
|
guiMenu *currMenu;
|
|
menuItem *tempItem;
|
|
|
|
// Verify params
|
|
if ((!myItem) || (!myItem->itemInfo)) {
|
|
return false;
|
|
}
|
|
myButton = (menuItemButton *)myItem->itemInfo;
|
|
|
|
if (!(eventType == EVENT_MOUSE)) {
|
|
return false;
|
|
}
|
|
|
|
if (myButton->itemFlags == BTN_STATE_GREY) {
|
|
return false;
|
|
}
|
|
|
|
redrawItem = false;
|
|
execCallback = false;
|
|
handled = true;
|
|
|
|
switch (event) {
|
|
case _ME_L_click:
|
|
case _ME_doubleclick:
|
|
if (menu_CursorInsideItem(myItem, x, y)) {
|
|
myButton->itemFlags = BTN_STATE_PRESS;
|
|
*currItem = theItem;
|
|
redrawItem = true;
|
|
} else {
|
|
*currItem = nullptr;
|
|
if (myButton->itemFlags != BTN_STATE_NORM) {
|
|
myButton->itemFlags = BTN_STATE_NORM;
|
|
redrawItem = true;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case _ME_L_drag:
|
|
case _ME_doubleclick_drag:
|
|
if (!*currItem) {
|
|
return true;
|
|
}
|
|
if (menu_CursorInsideItem(myItem, x, y)) {
|
|
if (myButton->itemFlags != BTN_STATE_PRESS) {
|
|
myButton->itemFlags = BTN_STATE_PRESS;
|
|
redrawItem = true;
|
|
}
|
|
} else {
|
|
if (myButton->itemFlags != BTN_STATE_OVER) {
|
|
myButton->itemFlags = BTN_STATE_OVER;
|
|
redrawItem = true;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case _ME_L_release:
|
|
case _ME_doubleclick_release:
|
|
if (menu_CursorInsideItem(myItem, x, y)) {
|
|
if (*currItem) {
|
|
execCallback = true;
|
|
} else {
|
|
*currItem = theItem;
|
|
}
|
|
myButton->itemFlags = BTN_STATE_OVER;
|
|
redrawItem = true;
|
|
} else {
|
|
*currItem = nullptr;
|
|
myButton->itemFlags = BTN_STATE_NORM;
|
|
redrawItem = true;
|
|
handled = false;
|
|
}
|
|
break;
|
|
|
|
case _ME_move:
|
|
if (menu_CursorInsideItem(myItem, x, y)) {
|
|
*currItem = theItem;
|
|
if (myButton->itemFlags != BTN_STATE_OVER) {
|
|
myButton->itemFlags = BTN_STATE_OVER;
|
|
redrawItem = true;
|
|
}
|
|
} else {
|
|
*currItem = nullptr;
|
|
if (myButton->itemFlags != BTN_STATE_NORM) {
|
|
myButton->itemFlags = BTN_STATE_NORM;
|
|
redrawItem = true;
|
|
handled = false;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case _ME_L_hold:
|
|
case _ME_doubleclick_hold:
|
|
break;
|
|
}
|
|
|
|
// See if we need to redraw the button
|
|
if (redrawItem) {
|
|
(myItem->redraw)((void *)myItem, (void *)myItem->myMenu, myItem->x1, myItem->y1, 0, 0);
|
|
myScreen = vmng_screen_find((void *)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) {
|
|
// digi_play(inv_click_snd, 2, 255, -1, inv_click_snd_room_lock);
|
|
currMenu = (guiMenu *)myItem->myMenu;
|
|
currTag = myItem->tag;
|
|
buttonClosesDialog = false;
|
|
|
|
(myItem->callback)((void *)myItem, (void *)myItem->myMenu);
|
|
|
|
status = 0;
|
|
myScreen = buttonClosesDialog ? nullptr : vmng_screen_find((void *)myItem->myMenu, &status);
|
|
|
|
if ((!myScreen) || (status != SCRN_ACTIVE)) {
|
|
*currItem = nullptr;
|
|
} else {
|
|
tempItem = menu_GetItem(currTag, currMenu);
|
|
if (!tempItem) {
|
|
*currItem = nullptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
return handled;
|
|
}
|
|
|
|
|
|
menuItem *menu_ButtonAdd(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) {
|
|
menuItem *newItem;
|
|
menuItemButton *buttonInfo;
|
|
ScreenContext *myScreen;
|
|
int32 status;
|
|
|
|
// Verify params
|
|
if (!myMenu) {
|
|
return nullptr;
|
|
}
|
|
|
|
// Allocate a new one
|
|
if ((newItem = (menuItem *)mem_alloc(sizeof(menuItem), "gui menu item")) == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
// Initialize the struct
|
|
newItem->next = myMenu->itemList;
|
|
newItem->prev = nullptr;
|
|
if (myMenu->itemList) {
|
|
myMenu->itemList->prev = newItem;
|
|
}
|
|
myMenu->itemList = newItem;
|
|
|
|
newItem->myMenu = (void *)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 = menu_CopyBackground(myMenu, x, y, w, h);
|
|
}
|
|
|
|
if ((buttonInfo = (menuItemButton *)mem_alloc(sizeof(menuItemButton), "menu item button")) == nullptr) {
|
|
return nullptr;
|
|
}
|
|
if (greyed) {
|
|
buttonInfo->itemFlags = BTN_STATE_GREY;
|
|
} else {
|
|
buttonInfo->itemFlags = BTN_STATE_NORM;
|
|
}
|
|
buttonInfo->buttonType = buttonType;
|
|
|
|
// Note: prompt is not duplicated, therefore, make sure the name is stored in non-volatile memory
|
|
buttonInfo->prompt = prompt;
|
|
buttonInfo->specialTag = tag - 1000;
|
|
|
|
newItem->itemInfo = (void *)buttonInfo;
|
|
|
|
newItem->redraw = menu_DrawButton;
|
|
newItem->destroy = item_Destroy;
|
|
newItem->itemEventHandler = i_handler;
|
|
|
|
// Draw the button in now
|
|
(newItem->redraw)(newItem, (void *)myMenu, x, y, 0, 0);
|
|
|
|
// See if the screen is currently visible
|
|
myScreen = vmng_screen_find((void *)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_DisableButton(menuItem *myItem, int32 tag, guiMenu *myMenu) {
|
|
menuItemButton *myButton;
|
|
|
|
// Verify params
|
|
if (!myMenu) {
|
|
return;
|
|
}
|
|
|
|
if (!myItem) {
|
|
myItem = menu_GetItem(tag, myMenu);
|
|
}
|
|
if ((!myItem) || (!myItem->itemInfo)) {
|
|
return;
|
|
}
|
|
|
|
myButton = (menuItemButton *)myItem->itemInfo;
|
|
myButton->itemFlags = BTN_STATE_GREY;
|
|
}
|
|
|
|
|
|
void menu_EnableButton(menuItem *myItem, int32 tag, guiMenu *myMenu) {
|
|
menuItemButton *myButton;
|
|
|
|
// Verify params
|
|
if (!myMenu) {
|
|
return;
|
|
}
|
|
|
|
if (!myItem) {
|
|
myItem = menu_GetItem(tag, myMenu);
|
|
}
|
|
if ((!myItem) || (!myItem->itemInfo)) {
|
|
return;
|
|
}
|
|
|
|
myButton = (menuItemButton *)myItem->itemInfo;
|
|
myButton->itemFlags = BTN_STATE_NORM;
|
|
}
|
|
|
|
|
|
//------------------------------- HSLIDER MENU ITEM ---------------------------------//
|
|
|
|
enum {
|
|
H_THUMB_NORM = 0,
|
|
H_THUMB_OVER = 1,
|
|
H_THUMB_PRESS = 2
|
|
};
|
|
|
|
|
|
void menu_DrawHSlider(void *theItem, void *theMenu, int32 x, int32 y, int32, int32) {
|
|
menuItem *myItem = (menuItem *)theItem;
|
|
guiMenu *myMenu = (guiMenu *)theMenu;
|
|
menuItemHSlider *mySlider = nullptr;
|
|
Buffer *myBuff = nullptr;
|
|
Buffer *backgroundBuff = nullptr;
|
|
Sprite *mySprite = nullptr;
|
|
|
|
// Verify params
|
|
if ((!myItem) || (!myItem->itemInfo) || (!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
|
|
mySlider = (menuItemHSlider *)myItem->itemInfo;
|
|
switch (mySlider->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 (mySlider->thumbX > 2) {
|
|
gr_color_set(SLIDER_BAR_COLOR);
|
|
gr_buffer_rect_fill(myBuff, myItem->x1 + 3, myItem->y1 + 9, mySlider->thumbX, mySlider->thumbH - 18);
|
|
}
|
|
|
|
// Draw in the thumb
|
|
gui_DrawSprite(mySprite, myBuff, myItem->x1 + mySlider->thumbX, myItem->y1);
|
|
|
|
// Release the menu buffer
|
|
myMenu->menuBuffer->release();
|
|
}
|
|
|
|
|
|
bool hslider_Handler(void *theItem, int32 eventType, int32 event, int32 x, int32 y, void **currItem) {
|
|
menuItem *myItem = (menuItem *)theItem;
|
|
menuItemHSlider *mySlider;
|
|
bool redrawItem, execCallback, handled;
|
|
ScreenContext *myScreen;
|
|
int32 status;
|
|
int32 deltaSlide;
|
|
static bool movingFlag;
|
|
static int32 movingX;
|
|
|
|
// Verify params
|
|
if ((!myItem) || (!myItem->itemInfo)) {
|
|
return false;
|
|
}
|
|
mySlider = (menuItemHSlider *)myItem->itemInfo;
|
|
|
|
if (!(eventType == EVENT_MOUSE)) {
|
|
return false;
|
|
}
|
|
|
|
redrawItem = false;
|
|
handled = true;
|
|
execCallback = false;
|
|
|
|
switch (event) {
|
|
case _ME_L_click:
|
|
case _ME_doubleclick:
|
|
if (menu_CursorInsideItem(myItem, x, y) && (x - myItem->x1 >= mySlider->thumbX) &&
|
|
(x - myItem->x1 <= mySlider->thumbX + mySlider->thumbW - 1)) {
|
|
// digi_play(inv_click_snd, 2, 255, -1, inv_click_snd_room_lock);
|
|
mySlider->itemFlags = H_THUMB_PRESS;
|
|
movingFlag = true;
|
|
movingX = x;
|
|
*currItem = theItem;
|
|
redrawItem = true;
|
|
} else {
|
|
*currItem = nullptr;
|
|
mySlider->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(mySlider->thumbX, movingX - x);
|
|
if (deltaSlide > 0) {
|
|
mySlider->thumbX -= deltaSlide;
|
|
redrawItem = true;
|
|
mySlider->percent = mySlider->thumbX * 100 / mySlider->maxThumbX;
|
|
execCallback = true;
|
|
}
|
|
} else if (x > movingX) {
|
|
deltaSlide = imath_min(mySlider->maxThumbX - mySlider->thumbX, x - movingX);
|
|
if (deltaSlide > 0) {
|
|
mySlider->thumbX += deltaSlide;
|
|
redrawItem = true;
|
|
mySlider->percent = mySlider->thumbX * 100 / mySlider->maxThumbX;
|
|
execCallback = true;
|
|
}
|
|
}
|
|
movingX = x;
|
|
if (movingX < (mySlider->thumbX + myItem->x1)) {
|
|
movingX = mySlider->thumbX + myItem->x1;
|
|
} else if (movingX > (mySlider->thumbX + mySlider->thumbW - 1 + myItem->x1)) {
|
|
movingX = mySlider->thumbX + mySlider->thumbW - 1 + myItem->x1;
|
|
}
|
|
} else {
|
|
*currItem = nullptr;
|
|
}
|
|
break;
|
|
|
|
case _ME_L_release:
|
|
case _ME_doubleclick_release:
|
|
if (!*currItem) {
|
|
return true;
|
|
}
|
|
movingFlag = false;
|
|
if (menu_CursorInsideItem(myItem, x, y) && (x - myItem->x1 >= mySlider->thumbX) &&
|
|
(x - myItem->x1 <= mySlider->thumbX + mySlider->thumbW - 1)) {
|
|
mySlider->itemFlags = H_THUMB_OVER;
|
|
*currItem = theItem;
|
|
} else {
|
|
mySlider->itemFlags = H_THUMB_NORM;
|
|
*currItem = nullptr;
|
|
}
|
|
redrawItem = true;
|
|
execCallback = true;
|
|
break;
|
|
|
|
case _ME_move:
|
|
if (menu_CursorInsideItem(myItem, x, y) && (x - myItem->x1 >= mySlider->thumbX) &&
|
|
(x - myItem->x1 <= mySlider->thumbX + mySlider->thumbW - 1)) {
|
|
if (mySlider->itemFlags != H_THUMB_OVER) {
|
|
mySlider->itemFlags = H_THUMB_OVER;
|
|
*currItem = theItem;
|
|
redrawItem = true;
|
|
}
|
|
} else {
|
|
if (mySlider->itemFlags != H_THUMB_NORM) {
|
|
mySlider->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)((void *)myItem, (void *)myItem->myMenu, myItem->x1, myItem->y1, 0, 0);
|
|
myScreen = vmng_screen_find((void *)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, (void *)myItem->myMenu);
|
|
myScreen = vmng_screen_find((void *)myItem->myMenu, &status);
|
|
if ((!myScreen) || (status != SCRN_ACTIVE)) {
|
|
*currItem = nullptr;
|
|
}
|
|
}
|
|
|
|
return handled;
|
|
}
|
|
|
|
|
|
menuItem *menu_HSliderAdd(guiMenu *myMenu, int32 tag, int32 x, int32 y, int32 w, int32 h,
|
|
int32 initPercent, CALLBACK callback, bool transparent) {
|
|
menuItem *newItem;
|
|
menuItemHSlider *sliderInfo;
|
|
ScreenContext *myScreen;
|
|
int32 status;
|
|
|
|
// Verify params
|
|
if (!myMenu) {
|
|
return nullptr;
|
|
}
|
|
|
|
// Allocate a new one
|
|
if ((newItem = (menuItem *)mem_alloc(sizeof(menuItem), "gui menu item")) == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
// Initialize the struct
|
|
newItem->next = myMenu->itemList;
|
|
newItem->prev = nullptr;
|
|
if (myMenu->itemList) {
|
|
myMenu->itemList->prev = newItem;
|
|
}
|
|
myMenu->itemList = newItem;
|
|
|
|
newItem->myMenu = (void *)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 = menu_CopyBackground(myMenu, x, y, w, h);
|
|
}
|
|
|
|
// Create a new slider
|
|
if ((sliderInfo = (menuItemHSlider *)mem_alloc(sizeof(menuItemHSlider), "menu item hslider")) == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
// Intialize the new slider
|
|
sliderInfo->itemFlags = H_THUMB_NORM;
|
|
sliderInfo->thumbW = _GM(menuSprites)[OM_SLIDER_BTN_NORM]->w;
|
|
sliderInfo->thumbH = _GM(menuSprites)[OM_SLIDER_BTN_NORM]->h;
|
|
sliderInfo->maxThumbX = w - _GM(menuSprites)[OM_SLIDER_BTN_NORM]->w;
|
|
|
|
if (initPercent < 0) {
|
|
initPercent = 0;
|
|
} else if (initPercent > 100) {
|
|
initPercent = 100;
|
|
}
|
|
|
|
// Calculate the initial thumbX
|
|
sliderInfo->percent = initPercent;
|
|
sliderInfo->thumbX = initPercent * sliderInfo->maxThumbX / 100;
|
|
|
|
newItem->itemInfo = (void *)sliderInfo;
|
|
|
|
newItem->redraw = menu_DrawHSlider;
|
|
newItem->destroy = item_Destroy;
|
|
newItem->itemEventHandler = hslider_Handler;
|
|
|
|
// Draw the slider in now
|
|
(newItem->redraw)(newItem, (void *)myMenu, x, y, 0, 0);
|
|
|
|
// See if the screen is currently visible
|
|
myScreen = vmng_screen_find((void *)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(void *theItem, void *theMenu, int32 x, int32 y, int32, int32) {
|
|
menuItem *myItem = (menuItem *)theItem;
|
|
guiMenu *myMenu = (guiMenu *)theMenu;
|
|
menuItemVSlider *myVSlider = nullptr;
|
|
Buffer *myBuff = nullptr;
|
|
Buffer *backgroundBuff = nullptr;
|
|
Sprite *upSprite = nullptr;
|
|
Sprite *thumbSprite = nullptr;
|
|
Sprite *downSprite = nullptr;
|
|
Sprite *vbarSprite = nullptr;
|
|
|
|
// Verify params
|
|
if ((!myItem) || (!myItem->itemInfo) || (!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;
|
|
}
|
|
}
|
|
|
|
myVSlider = (menuItemVSlider *)myItem->itemInfo;
|
|
|
|
// 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)[SL_SCROLL_BAR];
|
|
upSprite = _GM(menuSprites)[SL_UP_BTN_NORM];
|
|
thumbSprite = _GM(menuSprites)[SL_SLIDER_BTN_NORM];
|
|
downSprite = _GM(menuSprites)[SL_DOWN_BTN_NORM];
|
|
|
|
if ((myVSlider->itemFlags & VS_STATUS) == VS_GREY) {
|
|
upSprite = _GM(menuSprites)[SL_UP_BTN_GREY];
|
|
thumbSprite = nullptr;
|
|
downSprite = _GM(menuSprites)[SL_DOWN_BTN_GREY];
|
|
} else if ((myVSlider->itemFlags & VS_STATUS) == VS_OVER) {
|
|
if ((myVSlider->itemFlags & VS_COMPONENT) == VS_UP) {
|
|
upSprite = _GM(menuSprites)[SL_UP_BTN_OVER];
|
|
} else if ((myVSlider->itemFlags & VS_COMPONENT) == VS_THUMB) {
|
|
thumbSprite = _GM(menuSprites)[SL_SLIDER_BTN_OVER];
|
|
} else if ((myVSlider->itemFlags & VS_COMPONENT) == VS_DOWN) {
|
|
downSprite = _GM(menuSprites)[SL_DOWN_BTN_OVER];
|
|
}
|
|
} else if ((myVSlider->itemFlags & VS_STATUS) == VS_PRESS) {
|
|
if ((myVSlider->itemFlags & VS_COMPONENT) == VS_UP) {
|
|
upSprite = _GM(menuSprites)[SL_UP_BTN_PRESS];
|
|
} else if ((myVSlider->itemFlags & VS_COMPONENT) == VS_THUMB) {
|
|
thumbSprite = _GM(menuSprites)[SL_SLIDER_BTN_PRESS];
|
|
} else if ((myVSlider->itemFlags & VS_COMPONENT) == VS_DOWN) {
|
|
downSprite = _GM(menuSprites)[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 + myVSlider->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(void *theItem, int32 eventType, int32 event, int32 x, int32 y, void **currItem) {
|
|
menuItem *myItem = (menuItem *)theItem;
|
|
menuItemVSlider *myVSlider;
|
|
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) || (!myItem->itemInfo)) {
|
|
return false;
|
|
}
|
|
|
|
if (!(eventType == EVENT_MOUSE)) {
|
|
return false;
|
|
}
|
|
|
|
myVSlider = (menuItemVSlider *)myItem->itemInfo;
|
|
if ((myVSlider->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 (menu_CursorInsideItem(myItem, x, y)) {
|
|
// digi_play(inv_click_snd, 2, 255, -1, inv_click_snd_room_lock);
|
|
*currItem = theItem;
|
|
tempFlags = vslider_WhereIsCursor(myVSlider, y - myItem->y1);
|
|
if (tempFlags == VS_THUMB) {
|
|
movingFlag = true;
|
|
movingY = y;
|
|
}
|
|
if ((tempFlags == VS_PAGE_UP) || (tempFlags == VS_PAGE_DOWN)) {
|
|
myVSlider->itemFlags = tempFlags + VS_NORM;
|
|
} else {
|
|
myVSlider->itemFlags = tempFlags + VS_PRESS;
|
|
redrawItem = true;
|
|
}
|
|
execCallback = true;
|
|
} else {
|
|
*currItem = nullptr;
|
|
myVSlider->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(myVSlider->thumbY - myVSlider->minThumbY, movingY - y);
|
|
if (deltaSlide > 0) {
|
|
myVSlider->thumbY -= deltaSlide;
|
|
myVSlider->percent = ((myVSlider->thumbY - myVSlider->minThumbY) * 100) /
|
|
(myVSlider->maxThumbY - myVSlider->minThumbY);
|
|
redrawItem = true;
|
|
execCallback = true;
|
|
}
|
|
} else if (y > movingY) {
|
|
deltaSlide = imath_min(myVSlider->maxThumbY - myVSlider->thumbY, y - movingY);
|
|
if (deltaSlide > 0) {
|
|
myVSlider->thumbY += deltaSlide;
|
|
myVSlider->percent = ((myVSlider->thumbY - myVSlider->minThumbY) * 100) /
|
|
(myVSlider->maxThumbY - myVSlider->minThumbY);
|
|
redrawItem = true;
|
|
execCallback = true;
|
|
}
|
|
}
|
|
movingY = y;
|
|
if (movingY < (myVSlider->thumbY + myItem->y1)) {
|
|
movingY = myVSlider->thumbY + myItem->y1;
|
|
} else if (movingY > (myVSlider->thumbY + myVSlider->thumbH - 1 + myItem->y1)) {
|
|
movingY = myVSlider->thumbY + myVSlider->thumbH - 1 + myItem->y1;
|
|
}
|
|
} else {
|
|
if (menu_CursorInsideItem(myItem, x, y)) {
|
|
tempFlags = vslider_WhereIsCursor(myVSlider, y - myItem->y1);
|
|
if ((myVSlider->itemFlags & VS_COMPONENT) == tempFlags) {
|
|
if ((tempFlags != VS_PAGE_UP) && (tempFlags != VS_PAGE_DOWN) &&
|
|
((myVSlider->itemFlags & VS_STATUS) != VS_PRESS)) {
|
|
myVSlider->itemFlags = tempFlags + VS_PRESS;
|
|
redrawItem = true;
|
|
}
|
|
if (currTime - callbackTime > 6) {
|
|
execCallback = true;
|
|
}
|
|
} else {
|
|
if ((myVSlider->itemFlags & VS_STATUS) != VS_OVER) {
|
|
myVSlider->itemFlags = (myVSlider->itemFlags & VS_COMPONENT) + VS_OVER;
|
|
redrawItem = true;
|
|
}
|
|
}
|
|
execCallback = true;
|
|
} else {
|
|
if ((myVSlider->itemFlags & VS_STATUS) != VS_OVER) {
|
|
myVSlider->itemFlags = (myVSlider->itemFlags & VS_COMPONENT) + VS_OVER;
|
|
redrawItem = true;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case _ME_L_release:
|
|
case _ME_doubleclick_release:
|
|
movingFlag = false;
|
|
if (menu_CursorInsideItem(myItem, x, y)) {
|
|
tempFlags = vslider_WhereIsCursor(myVSlider, y - myItem->y1);
|
|
if ((tempFlags == VS_PAGE_UP) || (tempFlags == VS_PAGE_DOWN)) {
|
|
myVSlider->itemFlags = VS_NORM;
|
|
} else {
|
|
myVSlider->itemFlags = tempFlags + VS_OVER;
|
|
*currItem = theItem;
|
|
}
|
|
} else {
|
|
myVSlider->itemFlags = VS_NORM;
|
|
*currItem = nullptr;
|
|
}
|
|
redrawItem = true;
|
|
if (!_GM(currMenuIsSave)) {
|
|
UpdateThumbNails(_GM(firstSlotIndex), (guiMenu *)myItem->myMenu);
|
|
}
|
|
break;
|
|
|
|
case _ME_move:
|
|
if (menu_CursorInsideItem(myItem, x, y)) {
|
|
*currItem = theItem;
|
|
tempFlags = vslider_WhereIsCursor(myVSlider, y - myItem->y1);
|
|
if ((myVSlider->itemFlags & VS_COMPONENT) != tempFlags) {
|
|
if ((tempFlags == VS_PAGE_UP) || (tempFlags == VS_PAGE_DOWN)) {
|
|
myVSlider->itemFlags = VS_NORM;
|
|
} else {
|
|
myVSlider->itemFlags = tempFlags + VS_OVER;
|
|
}
|
|
redrawItem = true;
|
|
}
|
|
} else {
|
|
*currItem = nullptr;
|
|
if (myVSlider->itemFlags != VS_NORM) {
|
|
myVSlider->itemFlags = VS_NORM;
|
|
redrawItem = true;
|
|
handled = false;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case _ME_L_hold:
|
|
case _ME_doubleclick_hold:
|
|
if (!*currItem) {
|
|
return true;
|
|
}
|
|
if (menu_CursorInsideItem(myItem, x, y)) {
|
|
tempFlags = vslider_WhereIsCursor(myVSlider, y - myItem->y1);
|
|
if ((myVSlider->itemFlags & VS_COMPONENT) == tempFlags) {
|
|
if (currTime - callbackTime > 6) {
|
|
execCallback = true;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
// See if we need to redraw the vslider
|
|
if (redrawItem) {
|
|
(myItem->redraw)((void *)myItem, (void *)myItem->myMenu, myItem->x1, myItem->y1, 0, 0);
|
|
myScreen = vmng_screen_find((void *)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, (void *)myItem->myMenu);
|
|
myScreen = vmng_screen_find((void *)myItem->myMenu, &status);
|
|
if ((!myScreen) || (status != SCRN_ACTIVE)) {
|
|
*currItem = nullptr;
|
|
}
|
|
}
|
|
|
|
return handled;
|
|
}
|
|
|
|
|
|
menuItem *menu_VSliderAdd(guiMenu *myMenu, int32 tag, int32 x, int32 y, int32 w, int32 h,
|
|
int32 initPercent, CALLBACK callback, bool transparent) {
|
|
|
|
menuItem *newItem;
|
|
menuItemVSlider *vsliderInfo;
|
|
ScreenContext *myScreen;
|
|
int32 status;
|
|
|
|
// Verify params
|
|
if (!myMenu) {
|
|
return nullptr;
|
|
}
|
|
|
|
// Allocate a new one
|
|
if ((newItem = (menuItem *)mem_alloc(sizeof(menuItem), "gui menu item")) == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
// Initialize the struct
|
|
newItem->next = myMenu->itemList;
|
|
newItem->prev = nullptr;
|
|
if (myMenu->itemList) {
|
|
myMenu->itemList->prev = newItem;
|
|
}
|
|
myMenu->itemList = newItem;
|
|
|
|
newItem->myMenu = (void *)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 = menu_CopyBackground(myMenu, x, y, w, h);
|
|
}
|
|
|
|
if ((vsliderInfo = (menuItemVSlider *)mem_alloc(sizeof(menuItemVSlider), "menu item vslider")) == nullptr) {
|
|
return nullptr;
|
|
}
|
|
vsliderInfo->itemFlags = VS_NORM;
|
|
|
|
vsliderInfo->thumbW = _GM(menuSprites)[SL_SLIDER_BTN_NORM]->w;
|
|
vsliderInfo->thumbH = _GM(menuSprites)[SL_SLIDER_BTN_NORM]->h;
|
|
|
|
vsliderInfo->minThumbY = _GM(menuSprites)[SL_UP_BTN_NORM]->h + 1;
|
|
vsliderInfo->maxThumbY = _GM(menuSprites)[SL_UP_BTN_NORM]->h + _GM(menuSprites)[SL_SCROLL_BAR]->h
|
|
- _GM(menuSprites)[SL_SLIDER_BTN_NORM]->h - 1;
|
|
|
|
// Calculate the initial thumbY
|
|
vsliderInfo->percent = imath_max(imath_min(initPercent, 100), 0);
|
|
vsliderInfo->thumbY = vsliderInfo->minThumbY +
|
|
((vsliderInfo->percent * (vsliderInfo->maxThumbY - vsliderInfo->minThumbY)) / 100);
|
|
|
|
newItem->itemInfo = (void *)vsliderInfo;
|
|
|
|
newItem->redraw = menu_DrawVSlider;
|
|
newItem->destroy = item_Destroy;
|
|
newItem->itemEventHandler = vslider_Handler;
|
|
|
|
// Draw the vslider in now
|
|
(newItem->redraw)(newItem, (void *)myMenu, x, y, 0, 0);
|
|
|
|
// See if the screen is currently visible
|
|
myScreen = vmng_screen_find((void *)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(menuItem *myItem, int32 tag, guiMenu *myMenu) {
|
|
menuItemVSlider *mySlider;
|
|
|
|
// Verify params
|
|
if (!myMenu) {
|
|
return;
|
|
}
|
|
|
|
if (!myItem) {
|
|
myItem = menu_GetItem(tag, myMenu);
|
|
}
|
|
if ((!myItem) || (!myItem->itemInfo)) {
|
|
return;
|
|
}
|
|
|
|
mySlider = (menuItemVSlider *)myItem->itemInfo;
|
|
mySlider->itemFlags = VS_GREY;
|
|
}
|
|
|
|
|
|
void menu_EnableVSlider(menuItem *myItem, int32 tag, guiMenu *myMenu) {
|
|
menuItemVSlider *mySlider;
|
|
|
|
// Verify params
|
|
if (!myMenu) {
|
|
return;
|
|
}
|
|
|
|
if (!myItem) {
|
|
myItem = menu_GetItem(tag, myMenu);
|
|
}
|
|
if ((!myItem) || (!myItem->itemInfo)) {
|
|
return;
|
|
}
|
|
|
|
mySlider = (menuItemVSlider *)myItem->itemInfo;
|
|
mySlider->itemFlags = VS_NORM;
|
|
}
|
|
|
|
|
|
//----------------------------- TEXTFIELD MENU ITEM ---------------------------------//
|
|
|
|
enum {
|
|
TF_NORM = 0,
|
|
TF_OVER = 1,
|
|
TF_GREY = 2
|
|
};
|
|
|
|
void menu_DrawTextField(void *theItem, void *theMenu, int32 x, int32 y, int32, int32) {
|
|
menuItem *myItem = (menuItem *)theItem;
|
|
guiMenu *myMenu = (guiMenu *)theMenu;
|
|
menuItemTextField *myText = nullptr;
|
|
Buffer *myBuff = nullptr;
|
|
Buffer *backgroundBuff = nullptr;
|
|
Sprite *mySprite = nullptr;
|
|
char tempStr[64], tempChar;
|
|
int32 cursorX;
|
|
|
|
// Verify params
|
|
if ((!myItem) || (!myItem->itemInfo) || (!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
|
|
myText = (menuItemTextField *)myItem->itemInfo;
|
|
|
|
switch (myText->itemFlags) {
|
|
case TF_GREY:
|
|
mySprite = _GM(menuSprites)[SL_LINE_NORM];
|
|
break;
|
|
|
|
case TF_OVER:
|
|
mySprite = _GM(menuSprites)[SL_LINE_OVER];
|
|
break;
|
|
|
|
case TF_NORM:
|
|
default:
|
|
mySprite = _GM(menuSprites)[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(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(TEXT_COLOR_OVER_FOREGROUND);
|
|
gr_vline(myBuff, x + cursorX + 26, y + 1, y + 12);
|
|
}
|
|
}
|
|
|
|
// Release the menu buffer
|
|
myMenu->menuBuffer->release();
|
|
}
|
|
|
|
|
|
bool textfield_Handler(void *theItem, int32 eventType, int32 event, int32 x, int32 y, void **currItem) {
|
|
menuItem *myItem = (menuItem *)theItem;
|
|
menuItemTextField *myText;
|
|
bool redrawItem, execCallback, handled;
|
|
ScreenContext *myScreen;
|
|
int32 status, temp;
|
|
char tempStr[80], *tempPtr;
|
|
|
|
// Verify params
|
|
if ((!myItem) || (!myItem->itemInfo)) {
|
|
return false;
|
|
}
|
|
myText = (menuItemTextField *)myItem->itemInfo;
|
|
|
|
if (myText->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 (menu_CursorInsideItem(myItem, x, y)) {
|
|
*currItem = theItem;
|
|
}
|
|
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 (menu_CursorInsideItem(myItem, x, y)) {
|
|
if (myText->itemFlags == TF_OVER) {
|
|
temp = strlen(myText->prompt);
|
|
if (temp > 0) {
|
|
Common::strcpy_s(tempStr, myText->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);
|
|
}
|
|
myText->cursor = &myText->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) && (myText->itemFlags == TF_OVER)) {
|
|
switch (event) {
|
|
case KEY_RETURN:
|
|
_GM(deleteSaveDesc) = false;
|
|
execCallback = true;
|
|
break;
|
|
|
|
case KEY_HOME:
|
|
_GM(deleteSaveDesc) = false;
|
|
myText->cursor = &myText->prompt[0];
|
|
redrawItem = true;
|
|
break;
|
|
|
|
case KEY_END:
|
|
_GM(deleteSaveDesc) = false;
|
|
myText->cursor = myText->promptEnd;
|
|
redrawItem = true;
|
|
break;
|
|
|
|
case KEY_LEFT:
|
|
_GM(deleteSaveDesc) = false;
|
|
if (myText->cursor > &myText->prompt[0]) {
|
|
myText->cursor--;
|
|
redrawItem = true;
|
|
}
|
|
break;
|
|
|
|
case KEY_RIGHT:
|
|
_GM(deleteSaveDesc) = false;
|
|
if (myText->cursor < myText->promptEnd) {
|
|
myText->cursor++;
|
|
redrawItem = true;
|
|
}
|
|
break;
|
|
|
|
case KEY_DELETE:
|
|
if (_GM(deleteSaveDesc)) {
|
|
myText->prompt[0] = '\0';
|
|
myText->promptEnd = &myText->prompt[0];
|
|
myText->cursor = myText->promptEnd;
|
|
redrawItem = true;
|
|
} else if (myText->cursor < myText->promptEnd) {
|
|
Common::strcpy_s(tempStr, (char *)(myText->cursor + 1));
|
|
Common::strcpy_s(myText->cursor, 80, tempStr);
|
|
myText->promptEnd--;
|
|
redrawItem = true;
|
|
}
|
|
break;
|
|
|
|
case KEY_BACKSP:
|
|
_GM(deleteSaveDesc) = false;
|
|
if (myText->cursor > &myText->prompt[0]) {
|
|
Common::strcpy_s(tempStr, myText->cursor);
|
|
myText->promptEnd--;
|
|
myText->cursor--;
|
|
Common::strcpy_s(myText->cursor, 80, tempStr);
|
|
redrawItem = true;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
_GM(deleteSaveDesc) = false;
|
|
gr_font_set(_GM(menuFont));
|
|
temp = gr_font_string_width(&myText->prompt[0], -1);
|
|
if ((strlen(&myText->prompt[0]) < 79) && (temp < myText->pixWidth - 12) && (event >= 32) && (event <= 127)) {
|
|
if (myText->cursor < myText->promptEnd) {
|
|
Common::strcpy_s(tempStr, (char *)myText->cursor);
|
|
Common::sprintf_s(myText->cursor, 80, "%c%s", (char)event, tempStr);
|
|
} else {
|
|
*myText->cursor = (char)event;
|
|
*(myText->cursor + 1) = '\0';
|
|
}
|
|
myText->cursor++;
|
|
myText->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)((void *)myItem, (void *)myItem->myMenu, myItem->x1, myItem->y1, 0, 0);
|
|
myScreen = vmng_screen_find((void *)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, (void *)myItem->myMenu);
|
|
myScreen = vmng_screen_find((void *)myItem->myMenu, &status);
|
|
|
|
if ((!myScreen) || (status != SCRN_ACTIVE)) {
|
|
*currItem = nullptr;
|
|
}
|
|
}
|
|
|
|
return handled;
|
|
}
|
|
|
|
|
|
menuItem *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) {
|
|
menuItem *newItem;
|
|
menuItemTextField *textInfo;
|
|
ScreenContext *myScreen;
|
|
int32 status;
|
|
|
|
// Verify params
|
|
if (!myMenu) {
|
|
return nullptr;
|
|
}
|
|
|
|
// Allocate a new one
|
|
if ((newItem = (menuItem *)mem_alloc(sizeof(menuItem), "gui menu item")) == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
// Initialize the struct
|
|
newItem->next = myMenu->itemList;
|
|
newItem->prev = nullptr;
|
|
if (myMenu->itemList) {
|
|
myMenu->itemList->prev = newItem;
|
|
}
|
|
myMenu->itemList = newItem;
|
|
|
|
newItem->myMenu = (void *)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 = menu_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->itemInfo = (void *)textInfo;
|
|
|
|
newItem->redraw = menu_DrawTextField;
|
|
newItem->destroy = item_Destroy;
|
|
newItem->itemEventHandler = textfield_Handler;
|
|
|
|
// Draw the vslider in now
|
|
(newItem->redraw)(newItem, (void *)myMenu, x, y, 0, 0);
|
|
|
|
// See if the screen is currently visible
|
|
myScreen = vmng_screen_find((void *)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 FUNCTIONS ---------------------------------//
|
|
|
|
void DestroyGameMenu();
|
|
|
|
bool menu_LoadSprites(const char *series, int32 numSprites) {
|
|
int32 i;
|
|
|
|
// Load in the game menu series
|
|
if (LoadSpriteSeries(series, &_GM(menuSeriesHandle), &_GM(menuSeriesOffset),
|
|
&_GM(menuSeriesPalOffset), _GM(menuPalette)) <= 0) {
|
|
return false;
|
|
}
|
|
_GM(menuSeriesResource) = mem_strdup(series);
|
|
|
|
// Update the palette for the menu
|
|
gr_pal_set_range(_GM(menuPalette), 59, 197); // Rid
|
|
|
|
_GM(spriteCount) = numSprites;
|
|
|
|
// Create the _GM(menuSprites) array
|
|
if ((_GM(menuSprites) = (Sprite **)mem_alloc(sizeof(Sprite *) * _GM(spriteCount), "sprites array")) == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
// Create the menu sprites
|
|
for (i = 0; i < _GM(spriteCount); i++) {
|
|
if ((_GM(menuSprites)[i] = CreateSprite(_GM(menuSeriesHandle), _GM(menuSeriesOffset), i, nullptr, nullptr)) == nullptr) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void menu_UnloadSprites(void) {
|
|
int32 i;
|
|
|
|
if (!_GM(menuSeriesResource)) {
|
|
return;
|
|
}
|
|
|
|
// Unload the sprites from memory
|
|
rtoss(_GM(menuSeriesResource));
|
|
mem_free(_GM(menuSeriesResource));
|
|
_GM(menuSeriesResource) = nullptr;
|
|
_GM(menuSeriesHandle) = nullptr;
|
|
_GM(menuSeriesOffset) = -1;
|
|
_GM(menuSeriesPalOffset) = -1;
|
|
|
|
// Turf the sprites
|
|
for (i = 0; i < _GM(spriteCount); i++) {
|
|
mem_free((void *)_GM(menuSprites)[i]);
|
|
}
|
|
|
|
// Turf the sprites array
|
|
mem_free((void *)_GM(menuSprites));
|
|
_GM(menuSprites) = nullptr;
|
|
_GM(spriteCount) = 0;
|
|
}
|
|
|
|
|
|
bool menu_Initialize(RGB8 *myPalette) {
|
|
int32 i, memAvail;
|
|
|
|
// This procedure is called before *any* menu is created - the following global var is used
|
|
// By the menu_eventhandler() to trap events - it must be cleared.
|
|
_GM(menuCurrItem) = nullptr;
|
|
|
|
if (_G(menuSystemInitialized)) {
|
|
return true;
|
|
}
|
|
|
|
// Set this now to prevent re-entry into the menu system
|
|
_G(menuSystemInitialized) = true;
|
|
|
|
// Pause the game
|
|
game_pause(true);
|
|
|
|
// Hide the telegram window
|
|
// Hide_telegram_dialog(); // Ripley shit again!
|
|
|
|
// Hide the interface
|
|
if (INTERFACE_VISIBLE) {
|
|
_GM(interfaceWasVisible) = true;
|
|
interface_hide();
|
|
} else {
|
|
_GM(interfaceWasVisible) = false;
|
|
}
|
|
|
|
_GM(menuPalette) = myPalette;
|
|
krn_fade_to_grey(_GM(menuPalette), 5, 1);
|
|
|
|
_GM(dumpedCodes) = false;
|
|
_GM(dumpedBackground) = false;
|
|
|
|
// Make sure we have enough memory
|
|
PurgeMem();
|
|
CompactMem();
|
|
memAvail = mem_avail();
|
|
|
|
// Dump the screen codes if necessary
|
|
if (memAvail < MEMORY_NEEDED) {
|
|
adv_GetCodeMemory();
|
|
_GM(dumpedCodes) = true;
|
|
memAvail = mem_avail();
|
|
}
|
|
|
|
// Dump the background if necessary
|
|
if (memAvail < MEMORY_NEEDED) {
|
|
adv_GetBackgroundMemory();
|
|
_GM(dumpedBackground) = true;
|
|
memAvail = mem_avail();
|
|
}
|
|
|
|
// If we still don't have enough memory, we are hosed
|
|
if (memAvail < MEMORY_NEEDED) {
|
|
return false;
|
|
}
|
|
|
|
// Load in the font
|
|
_GM(menuFont) = gr_font_load("FONTMENU.FNT");
|
|
|
|
// Alloc space for the save/load tables
|
|
if ((_GM(slotTitles) = (char **)mem_alloc(sizeof(char *) * MAX_SLOTS, "slot desc array")) == nullptr) {
|
|
return false;
|
|
}
|
|
for (i = 0; i < MAX_SLOTS; i++) {
|
|
if ((_GM(slotTitles)[i] = (char *)mem_alloc(80, "slot title")) == nullptr) {
|
|
return false;
|
|
}
|
|
}
|
|
if ((_GM(slotInUse) = (bool *)mem_alloc(sizeof(bool) * MAX_SLOTS, "slotUnUse array")) == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
// Allocate space for the thumnail sprites
|
|
if ((_GM(thumbNails) = (Sprite **)mem_alloc(sizeof(Sprite *) * MAX_SLOTS, "thumbNail array")) == nullptr) {
|
|
return false;
|
|
}
|
|
for (i = 0; i < MAX_SLOTS; i++) {
|
|
if ((_GM(thumbNails)[i] = (Sprite *)mem_alloc(sizeof(Sprite), "thumbNail")) == nullptr) {
|
|
return false;
|
|
}
|
|
_GM(thumbNails)[i]->sourceHandle = nullptr;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void menu_Shutdown(bool fadeToColor) {
|
|
int32 i;
|
|
|
|
// Verify that we need to shutdown
|
|
if (!_G(menuSystemInitialized)) {
|
|
return;
|
|
}
|
|
|
|
_GM(menuCurrItem) = nullptr;
|
|
|
|
// Turf the font
|
|
gr_font_dealloc(_GM(menuFont));
|
|
_GM(menuFont) = nullptr;
|
|
|
|
// Turf the slot arrays
|
|
for (i = 0; i < MAX_SLOTS; i++) {
|
|
if (_GM(slotTitles)[i]) {
|
|
mem_free((void *)_GM(slotTitles)[i]);
|
|
}
|
|
}
|
|
mem_free((void *)_GM(slotTitles));
|
|
mem_free((void *)_GM(slotInUse));
|
|
|
|
// Turf the thumbnail sprites
|
|
for (i = 0; i < MAX_SLOTS; i++) {
|
|
if (_GM(thumbNails)[i]) {
|
|
mem_free((void *)_GM(thumbNails)[i]);
|
|
}
|
|
}
|
|
mem_free((void *)_GM(thumbNails));
|
|
|
|
// Restore the background and codes if necessary
|
|
PurgeMem();
|
|
CompactMem();
|
|
if (_GM(dumpedBackground)) {
|
|
if (!adv_restoreBackground()) {
|
|
error_show(FL, 0, "unable to restore background");
|
|
}
|
|
}
|
|
if (_GM(dumpedCodes)) {
|
|
if (!adv_restoreCodes()) {
|
|
error_show(FL, 0, "unable to restore screen codes");
|
|
}
|
|
}
|
|
|
|
// Fade the screen - up to color if the game resumes, down to black if a new game was loaded
|
|
if (fadeToColor) {
|
|
krn_fade_from_grey(_GM(menuPalette), 5, 1, TO_COLOR);
|
|
} else {
|
|
krn_fade_from_grey(_GM(menuPalette), 5, 1, TO_BLACK);
|
|
}
|
|
|
|
// See if the interface needs to be restored
|
|
if (_GM(interfaceWasVisible)) {
|
|
interface_show();
|
|
}
|
|
|
|
// Allow the mouse to change from a clock
|
|
UnlockMouseSprite();
|
|
|
|
// Unpause the game
|
|
game_pause(false);
|
|
|
|
// Menu is now uninitialized
|
|
_G(menuSystemInitialized) = false;
|
|
}
|
|
|
|
|
|
bool menu_EventHandler(void *theMenu, int32 eventType, int32 parm1, int32 parm2, int32 parm3, bool *currScreen);
|
|
|
|
|
|
GrBuff *menu_CopyBackground(guiMenu *myMenu, int32 x, int32 y, int32 w, int32 h) {
|
|
GrBuff *copyOfBackground;
|
|
Buffer *srcBuff, *destBuff;
|
|
|
|
// Verify params
|
|
if ((!myMenu) || (!myMenu->menuBuffer)) {
|
|
return nullptr;
|
|
}
|
|
|
|
// Create a new grbuff struct
|
|
copyOfBackground = new GrBuff(w, h);
|
|
if (!copyOfBackground) {
|
|
return nullptr;
|
|
}
|
|
|
|
// Get the source and destination buffers
|
|
srcBuff = myMenu->menuBuffer->get_buffer();
|
|
destBuff = copyOfBackground->get_buffer();
|
|
if ((!srcBuff) || (!destBuff)) {
|
|
delete copyOfBackground;
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
// Copy the rect
|
|
gr_buffer_rect_copy_2(srcBuff, destBuff, x, y, 0, 0, w, h);
|
|
|
|
// Now release the buffers
|
|
myMenu->menuBuffer->release();
|
|
copyOfBackground->release();
|
|
|
|
return copyOfBackground;
|
|
}
|
|
|
|
|
|
void menu_Show(void *s, void *r, void *b, int32 destX, int32 destY) {
|
|
ScreenContext *myScreen = (ScreenContext *)s;
|
|
RectList *myRectList = (RectList *)r;
|
|
Buffer *destBuffer = (Buffer *)b;
|
|
guiMenu *myMenu;
|
|
GrBuff *myMenuBuffer;
|
|
Buffer *myBuffer;
|
|
RectList *myRect;
|
|
|
|
// Parameter verification
|
|
if (!myScreen) {
|
|
return;
|
|
}
|
|
myMenu = (guiMenu *)(myScreen->scrnContent);
|
|
if (!myMenu) {
|
|
return;
|
|
}
|
|
myMenuBuffer = myMenu->menuBuffer;
|
|
if (!myMenuBuffer) {
|
|
return;
|
|
}
|
|
myBuffer = myMenuBuffer->get_buffer();
|
|
if (!myBuffer) {
|
|
return;
|
|
}
|
|
|
|
// If no destBuffer, then draw directly to video
|
|
if (!destBuffer) {
|
|
myRect = myRectList;
|
|
while (myRect) {
|
|
vmng_refresh_video(myRect->x1, myRect->y1, myRect->x1 - myScreen->x1, myRect->y1 - myScreen->y1,
|
|
myRect->x2 - myScreen->x1, myRect->y2 - myScreen->y1, myBuffer);
|
|
myRect = myRect->next;
|
|
}
|
|
}
|
|
|
|
// Else draw to the dest buffer
|
|
else {
|
|
myRect = myRectList;
|
|
while (myRect) {
|
|
gr_buffer_rect_copy_2(myBuffer, destBuffer, myRect->x1 - myScreen->x1, myRect->y1 - myScreen->y1,
|
|
destX, destY, myRect->x2 - myRect->x1 + 1, myRect->y2 - myRect->y1 + 1);
|
|
myRect = myRect->next;
|
|
}
|
|
}
|
|
|
|
// Release myBuffer
|
|
myMenuBuffer->release();
|
|
}
|
|
|
|
|
|
guiMenu *menu_Create(Sprite *backgroundSprite, int32 x1, int32 y1, int32 scrnFlags) {
|
|
guiMenu *newMenu;
|
|
Buffer *tempBuff, drawSpriteBuff;
|
|
DrawRequest spriteDrawReq;
|
|
|
|
// Verify params
|
|
if (!backgroundSprite) {
|
|
return nullptr;
|
|
}
|
|
|
|
if ((newMenu = (guiMenu *)mem_alloc(sizeof(guiMenu), "gui menu")) == nullptr) {
|
|
return nullptr;
|
|
}
|
|
newMenu->menuBuffer = new GrBuff(backgroundSprite->w, backgroundSprite->h);
|
|
newMenu->itemList = nullptr;
|
|
newMenu->cb_return = nullptr;
|
|
newMenu->cb_esc = nullptr;
|
|
newMenu->menuEventHandler = menu_EventHandler;
|
|
|
|
// Draw the background in to the menuBuffer
|
|
tempBuff = newMenu->menuBuffer->get_buffer();
|
|
|
|
// Copy background into menu-buffer because it is not rectangular (matte ink effect)
|
|
Buffer *matte = _G(gameDrawBuff)->get_buffer(); // get a pointer to the game background buffer
|
|
if (tempBuff->h > (_G(gameDrawBuff)->h - y1)) { // if temp buffer is going to hang off the bottom of the game buffer
|
|
gr_buffer_rect_copy_2(matte, tempBuff, x1, y1, 0, 0, tempBuff->w, _G(gameDrawBuff)->h - y1); // copy the differnce
|
|
} else {
|
|
gr_buffer_rect_copy_2(matte, tempBuff, x1, y1, 0, 0, tempBuff->w, tempBuff->h); // copy all of it
|
|
}
|
|
_G(gameDrawBuff)->release(); // Release the buffer so it can be moved if nesessary
|
|
|
|
// draw the sprite
|
|
if (backgroundSprite->sourceHandle) {
|
|
HLock(backgroundSprite->sourceHandle);
|
|
backgroundSprite->data = (uint8 *)((intptr)*(backgroundSprite->sourceHandle) + backgroundSprite->sourceOffset);
|
|
|
|
drawSpriteBuff.w = backgroundSprite->w;
|
|
drawSpriteBuff.stride = backgroundSprite->w;
|
|
drawSpriteBuff.h = backgroundSprite->h;
|
|
drawSpriteBuff.encoding = (backgroundSprite->encoding) & (uint8)0x7f;
|
|
drawSpriteBuff.data = backgroundSprite->data;
|
|
|
|
spriteDrawReq.Src = &drawSpriteBuff;
|
|
spriteDrawReq.Dest = tempBuff;
|
|
spriteDrawReq.x = 0;
|
|
spriteDrawReq.y = 0;
|
|
spriteDrawReq.scaleX = 100;
|
|
spriteDrawReq.scaleY = 100;
|
|
spriteDrawReq.srcDepth = 0;
|
|
spriteDrawReq.depthCode = nullptr;
|
|
spriteDrawReq.Pal = nullptr;
|
|
spriteDrawReq.ICT = nullptr;
|
|
|
|
gr_sprite_draw(&spriteDrawReq);
|
|
|
|
// Unlock the handle
|
|
HUnLock(backgroundSprite->sourceHandle);
|
|
}
|
|
// Release the tempBuffer
|
|
newMenu->menuBuffer->release();
|
|
|
|
if (!vmng_screen_create(x1, y1, x1 + backgroundSprite->w - 1, y1 + backgroundSprite->h - 1, 69, scrnFlags, (void *)newMenu,
|
|
(RefreshFunc)menu_Show, menu_EventHandler)) {
|
|
return nullptr;
|
|
}
|
|
|
|
return newMenu;
|
|
}
|
|
|
|
|
|
void menu_Destroy(guiMenu *myMenu) {
|
|
menuItem *myItem;
|
|
|
|
// Verify params
|
|
if (!myMenu) {
|
|
return;
|
|
}
|
|
|
|
// Destroy the items
|
|
myItem = myMenu->itemList;
|
|
while (myItem) {
|
|
myMenu->itemList = myItem->next;
|
|
(myItem->destroy)((void *)myItem);
|
|
myItem = myMenu->itemList;
|
|
}
|
|
|
|
// Destroy the buffer
|
|
delete myMenu->menuBuffer;
|
|
|
|
// Destroy the menu
|
|
mem_free((void *)myMenu);
|
|
}
|
|
|
|
void menu_Configure(guiMenu *myMenu, CALLBACK cb_return, CALLBACK cb_esc) {
|
|
if (!myMenu) {
|
|
return;
|
|
}
|
|
myMenu->cb_return = cb_return;
|
|
myMenu->cb_esc = cb_esc;
|
|
}
|
|
|
|
bool menu_EventHandler(void *theMenu, int32 eventType, int32 parm1, int32 parm2, int32 parm3, bool *currScreen) {
|
|
ScreenContext *myScreen;
|
|
guiMenu *myMenu = (guiMenu *)theMenu;
|
|
menuItem *myItem;
|
|
int32 status, menuX, menuY;
|
|
bool handled;
|
|
static int32 movingX;
|
|
static int32 movingY;
|
|
static bool movingScreen = false;
|
|
|
|
// Initialize the vars
|
|
handled = false;
|
|
if (currScreen)
|
|
*currScreen = false;
|
|
|
|
// Make sure the screen exists and is active
|
|
myScreen = vmng_screen_find(theMenu, &status);
|
|
if ((!myScreen) || (status != SCRN_ACTIVE)) {
|
|
return false;
|
|
}
|
|
|
|
// If the escape key was pressed, it takes priority over items handling the event
|
|
if ((eventType == EVENT_KEY) && (parm1 == KEY_ESCAPE)) {
|
|
if (myMenu->cb_esc) {
|
|
_GM(menuCurrItem) = nullptr;
|
|
(myMenu->cb_esc)(nullptr, theMenu);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// If the return key was pressed, it takes priority over items handling the event
|
|
if ((eventType == EVENT_KEY) && (parm1 == KEY_RETURN)) {
|
|
if (myMenu->cb_return) {
|
|
_GM(menuCurrItem) = nullptr;
|
|
(myMenu->cb_return)(nullptr, theMenu);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Convert the global coordinates to coords relative to the menu
|
|
menuX = parm2 - myScreen->x1;
|
|
menuY = parm3 - myScreen->y1;
|
|
|
|
// If we are currently handling the events for an item, continue until that item releases control
|
|
if (_GM(menuCurrItem)) {
|
|
handled = (_GM(menuCurrItem)->itemEventHandler)(_GM(menuCurrItem), eventType, parm1, menuX, menuY, (void **)&_GM(menuCurrItem));
|
|
if (_GM(menuCurrItem)) {
|
|
*currScreen = true;
|
|
}
|
|
if (handled) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// See what kind of event we have
|
|
if (eventType == EVENT_MOUSE) {
|
|
// Scroll through the list of items until we find one that the cursor is on top of
|
|
myItem = myMenu->itemList;
|
|
while (myItem && (!((menuX >= myItem->x1) && (menuX <= myItem->x2) &&
|
|
(menuY >= myItem->y1) && (menuY <= myItem->y2)))) {
|
|
myItem = myItem->next;
|
|
}
|
|
|
|
// If an item is found, then if it has an event handler, handle the event and return true
|
|
if (myItem) {
|
|
if (myItem->itemEventHandler) {
|
|
(myItem->itemEventHandler)(myItem, eventType, parm1, menuX, menuY, (void **)&_GM(menuCurrItem));
|
|
if (_GM(menuCurrItem)) {
|
|
*currScreen = true;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
else if (eventType == EVENT_KEY) {
|
|
// Else the event is a key event - loop through - see if anyone grabs it
|
|
myItem = myMenu->itemList;
|
|
while (myItem && (!handled)) {
|
|
if (myItem->itemEventHandler) {
|
|
handled = (myItem->itemEventHandler)(myItem, eventType, parm1, -1, -1, nullptr);
|
|
}
|
|
myItem = myItem->next;
|
|
}
|
|
return handled;
|
|
}
|
|
|
|
//otherwise the event is not handled by any of the menu items. Let the menu screen itself handle the event
|
|
|
|
switch (parm1) {
|
|
case _ME_L_click:
|
|
case _ME_doubleclick:
|
|
if (!(myScreen->scrnFlags & SF_IMMOVABLE)) {
|
|
*currScreen = true;
|
|
movingScreen = true;
|
|
movingX = parm2;
|
|
movingY = parm3;
|
|
}
|
|
break;
|
|
|
|
case _ME_L_drag:
|
|
case _ME_doubleclick_drag:
|
|
if (movingScreen) {
|
|
MoveScreenDelta(myScreen, parm2 - movingX, parm3 - movingY);
|
|
movingX = parm2;
|
|
movingY = parm3;
|
|
}
|
|
break;
|
|
|
|
case _ME_L_release:
|
|
case _ME_doubleclick_release:
|
|
*currScreen = false;
|
|
movingScreen = false;
|
|
break;
|
|
|
|
case _ME_move:
|
|
case _ME_L_hold:
|
|
case _ME_doubleclick_hold:
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
menuItem *menu_GetItem(int32 tag, guiMenu *myMenu) {
|
|
menuItem *myItem;
|
|
|
|
// Verify params
|
|
if (!myMenu) {
|
|
return nullptr;
|
|
}
|
|
|
|
myItem = myMenu->itemList;
|
|
while (myItem && (myItem->tag != tag)) {
|
|
myItem = myItem->next;
|
|
}
|
|
|
|
return myItem;
|
|
}
|
|
|
|
|
|
void menu_ItemDelete(menuItem *myItem, int32 tag, guiMenu *myMenu) {
|
|
|
|
Buffer *myBuff, *backgroundBuff;
|
|
|
|
// Verify params
|
|
if (!myMenu) {
|
|
return;
|
|
}
|
|
|
|
if (!myItem) {
|
|
myItem = menu_GetItem(tag, myMenu);
|
|
}
|
|
if (!myItem) {
|
|
return;
|
|
}
|
|
|
|
// Remove myItem from the item list
|
|
if (myItem->next) {
|
|
myItem->next->prev = myItem->prev;
|
|
}
|
|
if (myItem->prev) {
|
|
myItem->prev->next = myItem->next;
|
|
} else {
|
|
myMenu->itemList = myItem->next;
|
|
}
|
|
|
|
// If the item is marked transparent, we can remove it from the menu
|
|
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;
|
|
}
|
|
|
|
// Copy the clean piece of the background to the menu buffer
|
|
gr_buffer_rect_copy_2(backgroundBuff, myBuff, 0, 0, myItem->x1, myItem->y1, backgroundBuff->w, backgroundBuff->h);
|
|
|
|
// Release both buffers
|
|
myMenu->menuBuffer->release();
|
|
myItem->background->release();
|
|
}
|
|
|
|
// Destroy the item;
|
|
if (myItem->destroy) {
|
|
myItem->destroy((void *)myItem);
|
|
}
|
|
}
|
|
|
|
void menu_ItemRefresh(menuItem *myItem, int32 tag, guiMenu *myMenu) {
|
|
ScreenContext *myScreen;
|
|
int32 status;
|
|
|
|
// Verify params
|
|
if (!myMenu) {
|
|
return;
|
|
}
|
|
|
|
if (!myItem) {
|
|
myItem = menu_GetItem(tag, myMenu);
|
|
}
|
|
if (!myItem) {
|
|
return;
|
|
}
|
|
|
|
// Draw myItem
|
|
(myItem->redraw)(myItem, (void *)myItem->myMenu, myItem->x1, myItem->y1, 0, 0);
|
|
|
|
// Update the video
|
|
myScreen = vmng_screen_find((void *)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);
|
|
}
|
|
}
|
|
|
|
//------------------------------------- GAME MENU -------------------------------------//
|
|
|
|
void cb_Game_Quit(void *, void *) {
|
|
// Destroy the game menu
|
|
DestroyGameMenu();
|
|
|
|
// Shutdown the menu system
|
|
menu_Shutdown(false);
|
|
|
|
// Set the global that will cause the entire game to exit to dos
|
|
_G(kernel).going = false;
|
|
}
|
|
|
|
void cb_Game_Resume(void *, void *) {
|
|
// Destroy the game menu
|
|
DestroyGameMenu();
|
|
|
|
// Shutdown the menu system
|
|
menu_Shutdown(true);
|
|
}
|
|
|
|
void cb_Game_Save(void *, void *) {
|
|
// Destroy the game menu
|
|
DestroyGameMenu();
|
|
menu_Shutdown(true);
|
|
buttonClosesDialog = true;
|
|
|
|
// Create the save game menu
|
|
g_engine->showSaveScreen();
|
|
}
|
|
|
|
void cb_Game_Load(void *, void *) {
|
|
// Destroy the game menu
|
|
DestroyGameMenu();
|
|
menu_Shutdown(true);
|
|
buttonClosesDialog = true;
|
|
|
|
// Create the save game menu
|
|
g_engine->showLoadScreen(M4Engine::kLoadFromGameDialog);
|
|
}
|
|
|
|
void cb_Game_Main(void *, void *) {
|
|
// Destroy the game menu
|
|
DestroyGameMenu();
|
|
|
|
if (!_GM(gameMenuFromMain)) {
|
|
// Save the game so we can resume from here if possible
|
|
if (_GM(interfaceWasVisible) && player_commands_allowed()) {
|
|
other_save_game_for_resurrection();
|
|
}
|
|
|
|
// Make sure the interface does not reappear
|
|
_GM(interfaceWasVisible) = false;
|
|
|
|
// Shutdown the menu system
|
|
menu_Shutdown(false);
|
|
} else {
|
|
menu_Shutdown(true);
|
|
}
|
|
|
|
// Go to the main menu
|
|
_G(game).setRoom(_G(executing) == WHOLE_GAME ? 903 : 901);
|
|
}
|
|
|
|
void cb_Game_Options(void *, void *) {
|
|
// Destroy the game menu
|
|
DestroyGameMenu();
|
|
buttonClosesDialog = true;
|
|
|
|
// Create the options menu
|
|
CreateOptionsMenu(nullptr);
|
|
}
|
|
|
|
void DestroyGameMenu(void) {
|
|
if (!_GM(gameMenu)) {
|
|
return;
|
|
}
|
|
|
|
// Remove the screen from the gui
|
|
vmng_screen_dispose(_GM(gameMenu));
|
|
|
|
// Destroy the menu resources
|
|
menu_Destroy(_GM(gameMenu));
|
|
|
|
// Unload the menu sprites
|
|
menu_UnloadSprites();
|
|
}
|
|
|
|
void CreateGameMenuMain(RGB8 *myPalette) {
|
|
if (!_G(menuSystemInitialized)) {
|
|
menu_Initialize(myPalette);
|
|
}
|
|
|
|
// Keep the memory tidy
|
|
PurgeMem();
|
|
CompactMem();
|
|
|
|
// Load in the game menu sprites
|
|
if (!menu_LoadSprites("gamemenu", GM_TOTAL_SPRITES)) {
|
|
return;
|
|
}
|
|
|
|
_GM(gameMenu) = menu_Create(_GM(menuSprites)[GM_DIALOG_BOX], GAME_MENU_X, GAME_MENU_Y, MENU_DEPTH | SF_GET_ALL | SF_BLOCK_ALL | SF_IMMOVABLE);
|
|
if (!_GM(gameMenu)) {
|
|
return;
|
|
}
|
|
|
|
menu_ButtonAdd(_GM(gameMenu), GM_TAG_MAIN, GM_MAIN_X, GM_MAIN_Y, GM_MAIN_W, GM_MAIN_H, cb_Game_Main);
|
|
menu_ButtonAdd(_GM(gameMenu), GM_TAG_OPTIONS, GM_OPTIONS_X, GM_OPTIONS_Y, GM_OPTIONS_W, GM_OPTIONS_H, cb_Game_Options);
|
|
menu_ButtonAdd(_GM(gameMenu), GM_TAG_RESUME, GM_RESUME_X, GM_RESUME_Y, GM_RESUME_W, GM_RESUME_H, cb_Game_Resume);
|
|
menu_ButtonAdd(_GM(gameMenu), GM_TAG_QUIT, GM_QUIT_X, GM_QUIT_Y, GM_QUIT_W, GM_QUIT_H, cb_Game_Quit);
|
|
|
|
if (!_GM(gameMenuFromMain)) {
|
|
menu_ButtonAdd(_GM(gameMenu), GM_TAG_SAVE, GM_SAVE_X, GM_SAVE_Y, GM_SAVE_W, GM_SAVE_H, cb_Game_Save);
|
|
} else {
|
|
menu_ButtonAdd(_GM(gameMenu), GM_TAG_SAVE, GM_SAVE_X, GM_SAVE_Y, GM_SAVE_W, GM_SAVE_H, cb_Game_Save, BTN_TYPE_GM_GENERIC, true);
|
|
}
|
|
|
|
// See if there are any games to load
|
|
if (g_engine->savesExist()) {
|
|
menu_ButtonAdd(_GM(gameMenu), GM_TAG_LOAD, GM_LOAD_X, GM_LOAD_Y, GM_LOAD_W, GM_LOAD_H, cb_Game_Load);
|
|
} else {
|
|
menu_ButtonAdd(_GM(gameMenu), GM_TAG_LOAD, GM_LOAD_X, GM_LOAD_Y, GM_LOAD_W, GM_LOAD_H, cb_Game_Load, BTN_TYPE_GM_GENERIC, true);
|
|
}
|
|
|
|
// Configure the game so pressing <esc> will cause the menu to disappear and the game to resume
|
|
menu_Configure(_GM(gameMenu), cb_Game_Resume, cb_Game_Resume);
|
|
|
|
vmng_screen_show((void *)_GM(gameMenu));
|
|
LockMouseSprite(0);
|
|
}
|
|
|
|
|
|
//---------------------------------- OPTIONS MENU -------------------------------------//
|
|
|
|
void DestroyOptionsMenu();
|
|
|
|
|
|
void cb_Options_Game_Cancel(void *, void *) {
|
|
// Reset values of items to what they were when options menu came up
|
|
digi_set_overall_volume(_GM(remember_digi_volume));
|
|
_G(flags)[digestability] = _GM(remember_digestability);
|
|
|
|
// Destroy the options menu
|
|
DestroyOptionsMenu();
|
|
buttonClosesDialog = true;
|
|
|
|
// Create the options menu
|
|
CreateGameMenuMain(nullptr);
|
|
}
|
|
|
|
void cb_Options_Game_Done(void *, void *) {
|
|
// Destroy the options menu
|
|
DestroyOptionsMenu();
|
|
buttonClosesDialog = true;
|
|
|
|
// Create the options menu
|
|
CreateGameMenuMain(nullptr);
|
|
}
|
|
|
|
void cb_Options_Digi(void *theItem, void *theMenu) {
|
|
menuItem *myItem = (menuItem *)theItem;
|
|
guiMenu *myMenu = (guiMenu *)theMenu;
|
|
menuItemHSlider *mySlider;
|
|
|
|
mySlider = (menuItemHSlider *)myItem->itemInfo;
|
|
// Set the digi volume
|
|
digi_set_overall_volume(mySlider->percent);
|
|
term_message("digi volume: %d", mySlider->percent);
|
|
|
|
// This scroller control has been moved, so make sure that the DONE button is not greyed out
|
|
menu_EnableButton(nullptr, OM_TAG_DONE, myMenu);
|
|
menu_ItemRefresh(nullptr, OM_TAG_DONE, myMenu);
|
|
|
|
}
|
|
|
|
void cb_Options_Digestability(void *theItem, void *theMenu) {
|
|
menuItem *myItem = (menuItem *)theItem;
|
|
guiMenu *myMenu = (guiMenu *)theMenu;
|
|
menuItemHSlider *mySlider;
|
|
|
|
mySlider = (menuItemHSlider *)myItem->itemInfo;
|
|
// Set the midi volume
|
|
term_message("digestability: %d", mySlider->percent);
|
|
_G(flags)[digestability] = mySlider->percent;
|
|
|
|
// This scroller control has been moved, so make sure that the DONE button is not greyed out
|
|
menu_EnableButton(nullptr, OM_TAG_DONE, myMenu);
|
|
menu_ItemRefresh(nullptr, OM_TAG_DONE, myMenu);
|
|
}
|
|
|
|
void DestroyOptionsMenu(void) {
|
|
|
|
if (!_GM(opMenu)) {
|
|
return;
|
|
}
|
|
|
|
// Remove the screen from the gui
|
|
vmng_screen_dispose(_GM(opMenu));
|
|
|
|
// Destroy the menu resources
|
|
menu_Destroy(_GM(opMenu));
|
|
|
|
// Unload the menu sprites
|
|
menu_UnloadSprites();
|
|
}
|
|
|
|
|
|
void CreateOptionsMenu(RGB8 *myPalette) {
|
|
if (!_G(menuSystemInitialized)) {
|
|
menu_Initialize(myPalette);
|
|
}
|
|
|
|
// Keep the memory tidy
|
|
PurgeMem();
|
|
CompactMem();
|
|
|
|
// Load in the game menu sprites
|
|
if (!menu_LoadSprites("opmenu", OM_TOTAL_SPRITES)) {
|
|
return;
|
|
}
|
|
|
|
_GM(opMenu) = menu_Create(_GM(menuSprites)[OM_DIALOG_BOX], OPTIONS_MENU_X, OPTIONS_MENU_Y, MENU_DEPTH | SF_GET_ALL | SF_BLOCK_ALL | SF_IMMOVABLE);
|
|
if (!_GM(opMenu)) {
|
|
return;
|
|
}
|
|
|
|
menu_ButtonAdd(_GM(opMenu), OM_TAG_CANCEL, OM_CANCEL_X, OM_CANCEL_Y, OM_CANCEL_W, OM_CANCEL_H, cb_Options_Game_Cancel, BTN_TYPE_OM_CANCEL);
|
|
menu_ButtonAdd(_GM(opMenu), OM_TAG_DONE, OM_DONE_X, OM_DONE_Y, OM_DONE_W, OM_DONE_H, cb_Options_Game_Done, 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(), cb_Options_Digi, true);
|
|
menu_HSliderAdd(_GM(opMenu), OM_TAG_DIGESTABILITY, OM_DIGESTABILITY_X, OM_DIGESTABILITY_Y,
|
|
OM_DIGESTABILITY_W, OM_DIGESTABILITY_H, _G(flags)[digestability], cb_Options_Digestability, true);
|
|
|
|
// Remember the values of the items in case the user cancels
|
|
_GM(remember_digi_volume) = digi_get_overall_volume();
|
|
_GM(remember_digestability) = _G(flags)[digestability];
|
|
|
|
// Configure the game so pressing <esc> will cause the menu to disappear and the gamemenu to reappear
|
|
menu_Configure(_GM(opMenu), cb_Options_Game_Done, cb_Options_Game_Cancel);
|
|
|
|
vmng_screen_show((void *)_GM(opMenu));
|
|
LockMouseSprite(0);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------//
|
|
//-------------------------------- ERR MENU --------------------------------------//
|
|
//------------------------------------------------------------------------------------//
|
|
|
|
void DestroyErrMenu(void);
|
|
|
|
void cb_Err_Done(void *, void *) {
|
|
// Destroy the game menu
|
|
DestroyErrMenu();
|
|
|
|
// Shutdown the menu system
|
|
menu_Shutdown(true);
|
|
}
|
|
|
|
|
|
void DestroyErrMenu(void) {
|
|
if (!_GM(errMenu)) {
|
|
return;
|
|
}
|
|
|
|
// Remove the screen from the gui
|
|
vmng_screen_dispose(_GM(errMenu));
|
|
|
|
// Destroy the menu resources
|
|
menu_Destroy(_GM(errMenu));
|
|
|
|
// Unload the menu sprites
|
|
menu_UnloadSprites();
|
|
}
|
|
|
|
|
|
void CreateErrMenu(RGB8 *myPalette) {
|
|
Buffer *myBuff;
|
|
|
|
if (!_G(menuSystemInitialized)) {
|
|
menu_Initialize(myPalette);
|
|
}
|
|
|
|
// Keep the memory tidy
|
|
PurgeMem();
|
|
CompactMem();
|
|
|
|
// Load in the game menu sprites
|
|
if (!menu_LoadSprites("errmenu", 5)) {
|
|
return;
|
|
}
|
|
|
|
_GM(errMenu) = menu_Create(_GM(menuSprites)[EM_DIALOG_BOX], ERROR_MENU_X, ERROR_MENU_Y, MENU_DEPTH | SF_GET_ALL | SF_BLOCK_ALL | SF_IMMOVABLE);
|
|
if (!_GM(errMenu)) {
|
|
return;
|
|
}
|
|
|
|
// Get the menu buffer
|
|
myBuff = _GM(errMenu)->menuBuffer->get_buffer();
|
|
if (!myBuff) {
|
|
return;
|
|
}
|
|
|
|
//write the err message
|
|
gr_font_set_color(TEXT_COLOR_NORM_FOREGROUND);
|
|
gr_font_write(myBuff, "Save game failed!", 48, 8, 0, -1);
|
|
|
|
gr_font_write(myBuff, "A disk error has", 48, 23, 0, -1);
|
|
gr_font_write(myBuff, "occurred.", 48, 33, 0, -1);
|
|
|
|
gr_font_write(myBuff, "Please ensure you", 48, 48, 0, -1);
|
|
gr_font_write(myBuff, "have write access", 48, 58, 0, -1);
|
|
gr_font_write(myBuff, "and sufficient", 48, 68, 0, -1);
|
|
gr_font_write(myBuff, "disk space (40k).", 48, 78, 0, -1);
|
|
|
|
_GM(errMenu)->menuBuffer->release();
|
|
|
|
// Add the done button
|
|
menu_ButtonAdd(_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
|
|
menu_Configure(_GM(errMenu), cb_Err_Done, cb_Err_Done);
|
|
|
|
vmng_screen_show((void *)_GM(errMenu));
|
|
LockMouseSprite(0);
|
|
}
|
|
|
|
|
|
//-------------------------------- SAVE / LOAD MENU -----------------------------------//
|
|
|
|
void DestroySaveLoadMenu(bool saveMenu);
|
|
void cb_SaveLoad_Slot(void *theItem, void *theMenu);
|
|
bool load_Handler(void *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;
|
|
menu_DisableButton(nullptr, 1001 + i - firstSlot, myMenu);
|
|
menu_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;
|
|
menu_DisableButton(nullptr, 1001 + i - firstSlot, myMenu);
|
|
menu_ItemRefresh(nullptr, 1001 + i - firstSlot, myMenu);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set the var
|
|
_GM(thumbIndex) = firstSlot;
|
|
}
|
|
|
|
|
|
void SetFirstSlot(int32 firstSlot, guiMenu *myMenu) {
|
|
menuItem *tempItem;
|
|
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++) {
|
|
tempItem = menu_GetItem(i + 1001, myMenu);
|
|
myButton = (menuItemButton *)tempItem->itemInfo;
|
|
myButton->prompt = _GM(slotTitles)[firstSlot + i];
|
|
if (_GM(currMenuIsSave) || _GM(slotInUse)[firstSlot + i]) {
|
|
myButton->itemFlags = BTN_STATE_NORM;
|
|
} else {
|
|
myButton->itemFlags = BTN_STATE_GREY;
|
|
}
|
|
myButton->specialTag = firstSlot + i + 1;
|
|
menu_ItemRefresh(tempItem, i + 1001, myMenu);
|
|
}
|
|
}
|
|
|
|
|
|
void cb_SaveLoad_VSlider(void *theItem, void *theMenu) {
|
|
guiMenu *myMenu = (guiMenu *)theMenu;
|
|
menuItem *myItem = (menuItem *)theItem;
|
|
menuItemVSlider *mySlider;
|
|
bool redraw;
|
|
|
|
if ((!myMenu) || (!myItem) || (!myItem->itemInfo)) {
|
|
return;
|
|
}
|
|
|
|
// Get my slider
|
|
mySlider = (menuItemVSlider *)myItem->itemInfo;
|
|
|
|
if ((mySlider->itemFlags & VS_COMPONENT) != VS_THUMB) {
|
|
|
|
redraw = false;
|
|
switch (mySlider->itemFlags & VS_COMPONENT) {
|
|
|
|
case VS_UP:
|
|
if (_GM(firstSlotIndex) > 0) {
|
|
_GM(firstSlotIndex)--;
|
|
redraw = true;
|
|
}
|
|
break;
|
|
|
|
case VS_PAGE_UP:
|
|
if (_GM(firstSlotIndex) > 0) {
|
|
_GM(firstSlotIndex) = imath_max(_GM(firstSlotIndex) - 10, 0);
|
|
redraw = true;
|
|
}
|
|
break;
|
|
|
|
case VS_PAGE_DOWN:
|
|
if (_GM(firstSlotIndex) < 89) {
|
|
_GM(firstSlotIndex) = imath_min(_GM(firstSlotIndex) + 10, 89);
|
|
redraw = true;
|
|
}
|
|
break;
|
|
|
|
case VS_DOWN:
|
|
if (_GM(firstSlotIndex) < 89) {
|
|
_GM(firstSlotIndex)++;
|
|
redraw = true;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// See if we were able to set a new first slot index
|
|
if (redraw) {
|
|
SetFirstSlot(_GM(firstSlotIndex), myMenu);
|
|
|
|
// Calculate the new percent
|
|
mySlider->percent = (_GM(firstSlotIndex) * 100) / 89;
|
|
|
|
// Calculate the new thumbY
|
|
mySlider->thumbY = mySlider->minThumbY +
|
|
((mySlider->percent * (mySlider->maxThumbY - mySlider->minThumbY)) / 100);
|
|
|
|
// Redraw the slider
|
|
menu_ItemRefresh(myItem, -1, myMenu);
|
|
}
|
|
}
|
|
|
|
// Else the callback came from the thumb - set the _GM(firstSlotIndex) based on the slider percent
|
|
else {
|
|
_GM(firstSlotIndex) = (mySlider->percent * 89) / 100;
|
|
SetFirstSlot(_GM(firstSlotIndex), myMenu);
|
|
}
|
|
}
|
|
|
|
|
|
void cb_SaveLoad_Save(void *, void *theMenu) {
|
|
guiMenu *myMenu = (guiMenu *)theMenu;
|
|
menuItem *myTextItem;
|
|
menuItemTextField *myText;
|
|
bool saveGameFailed;
|
|
|
|
// If (slotSelected < 0) this callback is being executed by pressing return prematurely
|
|
if (_GM(slotSelected) < 0) {
|
|
return;
|
|
}
|
|
|
|
// First make the textfield NORM
|
|
myTextItem = menu_GetItem(2000, myMenu);
|
|
if ((!myTextItem) || (!myTextItem->itemInfo)) {
|
|
return;
|
|
}
|
|
myText = (menuItemTextField *)myTextItem->itemInfo;
|
|
myText->itemFlags = TF_NORM;
|
|
|
|
// Set the vars
|
|
_GM(slotInUse)[_GM(slotSelected) - 1] = true;
|
|
Common::strcpy_s(_GM(slotTitles)[_GM(slotSelected) - 1], 80, myText->prompt);
|
|
|
|
// Save the game
|
|
saveGameFailed = !g_engine->saveGameFromMenu(_GM(slotSelected),
|
|
myText->prompt, _GM(_thumbnail));
|
|
|
|
// If the save game failed, bring up the err menu
|
|
if (saveGameFailed) {
|
|
// Kill the save menu
|
|
DestroySaveLoadMenu(true);
|
|
|
|
// Create the err menu
|
|
CreateErrMenu(nullptr);
|
|
|
|
// Abort this procedure
|
|
return;
|
|
}
|
|
|
|
// Kill the save menu
|
|
DestroySaveLoadMenu(true);
|
|
|
|
// Shutdown the menu system
|
|
menu_Shutdown(true);
|
|
}
|
|
|
|
|
|
void cb_SaveLoad_Load(void *, void *theMenu) {
|
|
KernelTriggerType oldMode;
|
|
|
|
// If (slotSelected < 0) this callback is being executed by pressing return prematurely
|
|
if (_GM(slotSelected) < 0) {
|
|
return;
|
|
}
|
|
|
|
// Kill the menu
|
|
DestroySaveLoadMenu(false);
|
|
|
|
// Shutdown the menu system
|
|
menu_Shutdown(false);
|
|
|
|
// See if we need to reset the ESC, F2, and F3 hotkeys
|
|
if (_GM(gameMenuFromMain)) {
|
|
AddSystemHotkey(KEY_ESCAPE, Burger::Hotkeys::escape_key_pressed);
|
|
AddSystemHotkey(KEY_F2, M4::Hotkeys::saveGame);
|
|
AddSystemHotkey(KEY_F3, M4::Hotkeys::loadGame);
|
|
}
|
|
|
|
// Start the restore process
|
|
_G(kernel).restore_slot = _GM(slotSelected);
|
|
oldMode = _G(kernel).trigger_mode;
|
|
|
|
_G(kernel).trigger_mode = KT_DAEMON;
|
|
kernel_trigger_dispatch_now(TRIG_RESTORE_GAME);
|
|
_G(kernel).trigger_mode = oldMode;
|
|
}
|
|
|
|
|
|
void cb_SaveLoad_Cancel(void *, void *theMenu) {
|
|
guiMenu *myMenu = (guiMenu *)theMenu;
|
|
menuItem *myItem;
|
|
int32 i, x, y, w, h;
|
|
|
|
// If a slot has been selected, cancel will re-enable all slots
|
|
if (_GM(slotSelected) >= 0) {
|
|
// Enable the prev buttons
|
|
for (i = 1001; i <= 1010; i++) {
|
|
if (_GM(currMenuIsSave) || _GM(slotInUse)[i - 1001 + _GM(firstSlotIndex)]) {
|
|
menu_EnableButton(nullptr, i, myMenu);
|
|
menu_ItemRefresh(nullptr, i, myMenu);
|
|
}
|
|
}
|
|
|
|
// Find the textfield and use it's coords to place the button
|
|
myItem = menu_GetItem(2000, myMenu);
|
|
x = myItem->x1;
|
|
y = myItem->y1;
|
|
w = myItem->x2 - myItem->x1 + 1;
|
|
h = myItem->y2 - myItem->y1 + 1;
|
|
|
|
// Delete the textfield
|
|
menu_ItemDelete(myItem, 2000, myMenu);
|
|
|
|
// Add the button back in
|
|
if (_GM(currMenuIsSave)) {
|
|
menu_ButtonAdd(myMenu, 1000 + _GM(slotSelected) - _GM(firstSlotIndex), x, y, w, h,
|
|
cb_SaveLoad_Slot, BTN_TYPE_SL_TEXT, false, true, _GM(slotTitles)[_GM(slotSelected) - 1], button_Handler);
|
|
} else {
|
|
menu_ButtonAdd(myMenu, 1000 + _GM(slotSelected) - _GM(firstSlotIndex), x, y, w, h,
|
|
cb_SaveLoad_Slot, BTN_TYPE_SL_TEXT, false, true, _GM(slotTitles)[_GM(slotSelected) - 1], load_Handler);
|
|
|
|
// Remove the thumbnail
|
|
if (_GM(saveLoadThumbNail)) {
|
|
_GM(saveLoadThumbNail) = _GM(menuSprites)[SL_EMPTY_THUMB];
|
|
menu_ItemRefresh(nullptr, SL_TAG_THUMBNAIL, myMenu);
|
|
}
|
|
}
|
|
SetFirstSlot(_GM(firstSlotIndex), myMenu);
|
|
|
|
// Enable the slider
|
|
menu_EnableVSlider(nullptr, SL_TAG_VSLIDER, myMenu);
|
|
menu_ItemRefresh(nullptr, SL_TAG_VSLIDER, myMenu);
|
|
|
|
// Disable the save/load button
|
|
if (_GM(currMenuIsSave)) {
|
|
menu_DisableButton(nullptr, SL_TAG_SAVE, myMenu);
|
|
menu_ItemRefresh(nullptr, SL_TAG_SAVE, myMenu);
|
|
} else {
|
|
menu_DisableButton(nullptr, SL_TAG_LOAD, myMenu);
|
|
menu_ItemRefresh(nullptr, SL_TAG_LOAD, myMenu);
|
|
}
|
|
|
|
// Reset the slot selected var
|
|
_GM(slotSelected) = -1;
|
|
|
|
} else {
|
|
// Otherwise, back to the game menu
|
|
|
|
// Destroy the menu
|
|
DestroySaveLoadMenu(_GM(currMenuIsSave));
|
|
|
|
if (_GM(saveLoadFromHotkey)) {
|
|
// Shutdown the menu system
|
|
menu_Shutdown(true);
|
|
} else {
|
|
// Create the game menu
|
|
CreateGameMenuMain(nullptr);
|
|
}
|
|
}
|
|
|
|
buttonClosesDialog = true;
|
|
}
|
|
|
|
|
|
void cb_SaveLoad_Slot(void *theItem, void *theMenu) {
|
|
guiMenu *myMenu = (guiMenu *)theMenu;
|
|
menuItem *myItem = (menuItem *)theItem;
|
|
menuItemButton *myButton;
|
|
int32 i, x, y, w, h;
|
|
char prompt[80];
|
|
int32 specialTag;
|
|
|
|
// Verify params
|
|
if ((!myMenu) || (!myItem) || (!myItem->itemInfo)) {
|
|
return;
|
|
}
|
|
|
|
// Get the button
|
|
myButton = (menuItemButton *)myItem->itemInfo;
|
|
Common::strcpy_s(prompt, 80, myButton->prompt);
|
|
specialTag = myButton->specialTag;
|
|
|
|
// Set the globals
|
|
_GM(slotSelected) = myButton->specialTag;
|
|
_GM(deleteSaveDesc) = true;
|
|
|
|
// Disable all other buttons
|
|
for (i = 1001; i <= 1010; i++) {
|
|
if (i != myItem->tag) {
|
|
menu_DisableButton(nullptr, i, myMenu);
|
|
menu_ItemRefresh(nullptr, i, myMenu);
|
|
}
|
|
}
|
|
|
|
// Get the slot coords, and delete it
|
|
x = myItem->x1;
|
|
y = myItem->y1;
|
|
w = myItem->x2 - myItem->x1 + 1;
|
|
h = myItem->y2 - myItem->y1 + 1;
|
|
menu_ItemDelete(myItem, -1, 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,
|
|
nullptr, specialTag, cb_SaveLoad_Save, true);
|
|
} else {
|
|
menu_TextFieldAdd(myMenu, 2000, x, y, w, h, TF_OVER,
|
|
prompt, specialTag, cb_SaveLoad_Save, true);
|
|
}
|
|
} else {
|
|
menu_TextFieldAdd(myMenu, 2000, x, y, w, h, TF_NORM,
|
|
prompt, specialTag, cb_SaveLoad_Load, true);
|
|
}
|
|
|
|
// Disable the slider
|
|
menu_DisableVSlider(nullptr, SL_TAG_VSLIDER, myMenu);
|
|
menu_ItemRefresh(nullptr, SL_TAG_VSLIDER, myMenu);
|
|
|
|
// Enable the save/load button
|
|
if (_GM(currMenuIsSave)) {
|
|
menu_EnableButton(nullptr, SL_TAG_SAVE, myMenu);
|
|
menu_ItemRefresh(nullptr, SL_TAG_SAVE, myMenu);
|
|
} else {
|
|
menu_EnableButton(nullptr, SL_TAG_LOAD, myMenu);
|
|
menu_ItemRefresh(nullptr, SL_TAG_LOAD, myMenu);
|
|
}
|
|
}
|
|
|
|
void InitializeSlotTables(void) {
|
|
const SaveStateList saves = g_engine->listSaves();
|
|
|
|
// First reset all the slots to empty
|
|
for (int i = 0; i < MAX_SLOTS; ++i) {
|
|
Common::strcpy_s(_GM(slotTitles)[i], 80, "<empty>");
|
|
_GM(slotInUse)[i] = false;
|
|
}
|
|
|
|
for (const auto &save : saves) {
|
|
if (save.getSaveSlot() != 0) {
|
|
Common::String desc = save.getDescription();
|
|
Common::strcpy_s(_GM(slotTitles)[save.getSaveSlot() - 1], 80, desc.c_str());
|
|
_GM(slotInUse)[save.getSaveSlot() - 1] = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool load_Handler(void *theItem, int32 eventType, int32 event, int32 x, int32 y, void **currItem) {
|
|
menuItem *myItem = (menuItem *)theItem;
|
|
menuItemButton *myButton;
|
|
bool handled;
|
|
|
|
// Handle the event just like any other button
|
|
handled = button_Handler(theItem, eventType, event, x, y, currItem);
|
|
|
|
// If we've selected a slot, we want the thumbNail to remain on the menu permanently
|
|
if (_GM(slotSelected) >= 0) {
|
|
return handled;
|
|
}
|
|
|
|
// But if the event moved the mouse, we want to display the correct thumbNail;
|
|
if ((eventType == EVENT_MOUSE) && ((event == _ME_move) || (event == _ME_L_drag) || (event == _ME_L_release) ||
|
|
(event == _ME_doubleclick_drag) || (event == _ME_doubleclick_release))) {
|
|
|
|
// Get the button
|
|
if ((!myItem) || (!myItem->itemInfo)) {
|
|
return handled;
|
|
}
|
|
myButton = (menuItemButton *)myItem->itemInfo;
|
|
|
|
// This determines that we are over the button
|
|
if ((myButton->itemFlags == BTN_STATE_OVER) || (myButton->itemFlags == BTN_STATE_PRESS)) {
|
|
// See if the current _GM(saveLoadThumbNail) is pointing to the correct sprite
|
|
if (_GM(saveLoadThumbNail) != _GM(thumbNails)[myButton->specialTag - 1]) {
|
|
_GM(saveLoadThumbNail) = _GM(thumbNails)[myButton->specialTag - 1];
|
|
menu_ItemRefresh(nullptr, SL_TAG_THUMBNAIL, (guiMenu *)myItem->myMenu);
|
|
}
|
|
}
|
|
|
|
// Else we must determine whether the thumbnail needs to be replaced with the empty thumbnail.
|
|
else {
|
|
|
|
// If the mouse has moved outside of the entire range of all 10 buttons,
|
|
//or it is over a button which is not hilited it is to be removed.
|
|
if (menu_CursorInsideItem(myItem, x, y)
|
|
|| (x < SL_SCROLL_FIELD_X)
|
|
|| (x > SL_SCROLL_FIELD_X + SL_SCROLL_FIELD_W)
|
|
|| (y < SL_SCROLL_FIELD_Y)
|
|
|| (y > SL_SCROLL_FIELD_Y + SL_SCROLL_FIELD_H)) {
|
|
|
|
// Remove the thumbnail
|
|
if (_GM(saveLoadThumbNail)) {
|
|
_GM(saveLoadThumbNail) = _GM(menuSprites)[SL_EMPTY_THUMB];
|
|
menu_ItemRefresh(nullptr, SL_TAG_THUMBNAIL, (guiMenu *)myItem->myMenu);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return handled;
|
|
}
|
|
|
|
|
|
void DestroySaveLoadMenu(bool saveMenu) {
|
|
int32 i;
|
|
|
|
if (!_GM(slMenu)) {
|
|
return;
|
|
}
|
|
|
|
// Determine whether the screen was the SAVE or the LOAD menu
|
|
if (saveMenu) {
|
|
|
|
// If SAVE, there should be a thumbnail to unload
|
|
if (_GM(saveLoadThumbNail)) {
|
|
DisposeHandle(_GM(saveLoadThumbNail)->sourceHandle);
|
|
mem_free(_GM(saveLoadThumbNail));
|
|
_GM(saveLoadThumbNail) = nullptr;
|
|
}
|
|
} else {
|
|
// Else there may be up to 10 somewhere in the list to be unloaded
|
|
for (i = 0; i < MAX_SLOTS; i++) {
|
|
UnloadThumbNail(i);
|
|
}
|
|
_GM(saveLoadThumbNail) = nullptr;
|
|
}
|
|
|
|
// Destroy the screen
|
|
vmng_screen_dispose(_GM(slMenu));
|
|
menu_Destroy(_GM(slMenu));
|
|
|
|
// Unload the save/load menu sprites
|
|
menu_UnloadSprites();
|
|
}
|
|
|
|
|
|
void CreateSaveLoadMenu(RGB8 *myPalette, bool saveMenu) {
|
|
ItemHandlerFunction i_handler;
|
|
bool buttonGreyed;
|
|
|
|
if (!_G(menuSystemInitialized)) {
|
|
menu_Initialize(myPalette);
|
|
}
|
|
|
|
// Keep the memory tidy
|
|
PurgeMem();
|
|
CompactMem();
|
|
|
|
// Load in the game menu sprites
|
|
if (!menu_LoadSprites("slmenu", SL_TOTAL_SPRITES)) {
|
|
return;
|
|
}
|
|
|
|
// Initialize some global vars
|
|
_GM(firstSlotIndex) = 0;
|
|
_GM(slotSelected) = -1;
|
|
_GM(saveLoadThumbNail) = nullptr;
|
|
_GM(thumbIndex) = 100;
|
|
_GM(currMenuIsSave) = saveMenu;
|
|
|
|
_GM(slMenu) = menu_Create(_GM(menuSprites)[SL_DIALOG_BOX], SAVE_LOAD_MENU_X, SAVE_LOAD_MENU_Y,
|
|
MENU_DEPTH | SF_GET_ALL | SF_BLOCK_ALL | SF_IMMOVABLE);
|
|
if (!_GM(slMenu)) {
|
|
return;
|
|
}
|
|
|
|
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);
|
|
menu_ButtonAdd(_GM(slMenu), SL_TAG_SAVE, SL_SAVE_X, SL_SAVE_Y, SL_SAVE_W, SL_SAVE_H,
|
|
cb_SaveLoad_Save, 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);
|
|
menu_ButtonAdd(_GM(slMenu), SL_TAG_LOAD, SL_LOAD_X, SL_LOAD_Y, SL_LOAD_W, SL_LOAD_H,
|
|
cb_SaveLoad_Load, BTN_TYPE_SL_LOAD, true);
|
|
}
|
|
|
|
menu_ButtonAdd(_GM(slMenu), SL_TAG_CANCEL, SL_CANCEL_X, SL_CANCEL_Y, SL_CANCEL_W, SL_CANCEL_H,
|
|
cb_SaveLoad_Cancel, BTN_TYPE_SL_CANCEL);
|
|
|
|
menu_VSliderAdd(_GM(slMenu), SL_TAG_VSLIDER, SL_SLIDER_X, SL_SLIDER_Y, SL_SLIDER_W, SL_SLIDER_H,
|
|
0, cb_SaveLoad_VSlider);
|
|
|
|
InitializeSlotTables();
|
|
|
|
if (_GM(currMenuIsSave)) {
|
|
buttonGreyed = false;
|
|
i_handler = button_Handler;
|
|
} else {
|
|
buttonGreyed = true;
|
|
i_handler = load_Handler;
|
|
}
|
|
|
|
for (int32 i = 0; i < MAX_SLOTS_SHOWN; i++) {
|
|
menu_ButtonAdd(_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,
|
|
cb_SaveLoad_Slot, BTN_TYPE_SL_TEXT,
|
|
buttonGreyed && (!_GM(slotInUse)[i]), true, _GM(slotTitles)[i], i_handler);
|
|
}
|
|
|
|
if (_GM(currMenuIsSave)) {
|
|
// Create thumbnails. One in the original game format for displaying,
|
|
// and the other in the ScummVM format for actually using in the save files
|
|
_GM(saveLoadThumbNail) = menu_CreateThumbnail(&_GM(sizeofThumbData));
|
|
_GM(_thumbnail).free();
|
|
Graphics::createThumbnail(_GM(_thumbnail));
|
|
|
|
} else {
|
|
UpdateThumbNails(0, _GM(slMenu));
|
|
_GM(saveLoadThumbNail) = _GM(menuSprites)[SL_EMPTY_THUMB];
|
|
}
|
|
|
|
menu_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
|
|
//<esc> - cancels and returns to the game menu
|
|
menu_Configure(_GM(slMenu), cb_SaveLoad_Save, cb_SaveLoad_Cancel);
|
|
} else {
|
|
//<return> - if a slot has been selected, loads the selected game
|
|
//<esc> - cancels and returns to the game menu
|
|
menu_Configure(_GM(slMenu), cb_SaveLoad_Load, cb_SaveLoad_Cancel);
|
|
}
|
|
|
|
vmng_screen_show((void *)_GM(slMenu));
|
|
LockMouseSprite(0);
|
|
}
|
|
|
|
void CreateGameMenu(RGB8 *myPalette) {
|
|
if ((!player_commands_allowed()) || (!INTERFACE_VISIBLE) ||
|
|
_G(pal_fade_in_progress) || _G(menuSystemInitialized)) {
|
|
return;
|
|
}
|
|
|
|
_GM(gameMenuFromMain) = false;
|
|
CreateGameMenuMain(myPalette);
|
|
}
|
|
|
|
void CreateGameMenuFromMain(RGB8 *myPalette) {
|
|
if (_G(pal_fade_in_progress) || _G(menuSystemInitialized)) {
|
|
return;
|
|
}
|
|
|
|
_GM(gameMenuFromMain) = true;
|
|
CreateGameMenuMain(myPalette);
|
|
}
|
|
|
|
void CreateSaveMenu(RGB8 *myPalette) {
|
|
_GM(saveLoadFromHotkey) = false;
|
|
CreateSaveLoadMenu(myPalette, true);
|
|
}
|
|
|
|
void CreateF2SaveMenu(RGB8 *myPalette) {
|
|
if ((!player_commands_allowed()) || (!INTERFACE_VISIBLE) ||
|
|
_G(pal_fade_in_progress) || _G(menuSystemInitialized)) {
|
|
return;
|
|
}
|
|
|
|
_GM(saveLoadFromHotkey) = true;
|
|
_GM(gameMenuFromMain) = false;
|
|
CreateSaveLoadMenu(myPalette, true);
|
|
}
|
|
|
|
void CreateLoadMenu(RGB8 *myPalette) {
|
|
_GM(saveLoadFromHotkey) = false;
|
|
CreateSaveLoadMenu(myPalette, false);
|
|
}
|
|
|
|
void CreateF3LoadMenu(RGB8 *myPalette) {
|
|
if ((!player_commands_allowed()) || (!INTERFACE_VISIBLE) ||
|
|
_G(pal_fade_in_progress) || _G(menuSystemInitialized)) {
|
|
return;
|
|
}
|
|
|
|
_GM(saveLoadFromHotkey) = true;
|
|
_GM(gameMenuFromMain) = false;
|
|
CreateSaveLoadMenu(myPalette, false);
|
|
}
|
|
|
|
void CreateLoadMenuFromMain(RGB8 *myPalette) {
|
|
if (_G(pal_fade_in_progress) || _G(menuSystemInitialized)) {
|
|
return;
|
|
}
|
|
|
|
_GM(saveLoadFromHotkey) = true;
|
|
_GM(gameMenuFromMain) = true;
|
|
CreateSaveLoadMenu(myPalette, false);
|
|
}
|
|
|
|
} // namespace GUI
|
|
} // namespace Burger
|
|
} // namespace M4
|