scummvm/engines/m4/gui/gui_dialog.cpp
2023-12-24 01:53:38 +01:00

1599 lines
44 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 "m4/gui/gui_dialog.h"
#include "m4/gui/gui_event.h"
#include "m4/gui/gui_sys.h"
#include "m4/gui/gui_vmng.h"
#include "m4/gui/gui.h"
#include "m4/core/imath.h"
#include "m4/platform/keys.h"
#include "m4/graphics/gr_pal.h"
#include "m4/graphics/graphics.h"
#include "m4/graphics/krn_pal.h"
#include "m4/mem/mem.h"
#include "m4/mem/memman.h"
#include "m4/vars.h"
namespace M4 {
#define _GD(X) _G(dialog).X
#define STR_DIALOG "dialog box"
#define STR_TEXTSCRN "text screen"
static void DialogShow(void *s, void *r, void *b, int32 destX, int32 destY);
static bool Dialog_EventHandler(void *myDialog, int32 eventType, int32 parm1, int32 parm2, int32 parm3, bool *currScreen);
static bool TextScrn_EventHandler(void *theTextScrn, int32 eventType, int32 parm1, int32 parm2, int32 parm3, bool *currScreen);
void Dialog::destroy() {
DialogDestroy(this);
}
void Dialog::refresh() {
Dialog_Refresh(this);
}
void Dialog::resize(int32 newW, int32 newH) {
Dialog_Resize(this, newW, newH);
}
void Dialog::configure(int32 defaultTag, int32 returnTag, int32 cancelTag) {
Dialog_Configure(this, defaultTag, returnTag, cancelTag);
}
void Dialog::setDefault(int32 tag) {
Dialog_SetDefault(this, tag);
}
bool Dialog::setPressed(int32 tag) {
return Dialog_SetPressed(this, tag);
}
void Dialog::show() {
vmng_screen_show(this);
}
bool Dialog::addMessage(int32 x, int32 y, const char *prompt, int32 tag) {
return Dialog_Add_Message(this, x, y, prompt, tag);
}
bool Dialog::addPicture(int32 x, int32 y, Buffer *myBuff, int32 tag) {
return Dialog_Add_Picture(this, x, y, myBuff, tag);
}
bool Dialog::addButton(int32 x, int32 y, const char *prompt, M4CALLBACK cb, int32 tag) {
return Dialog_Add_Button(this, x, y, prompt, cb, tag);
}
bool Dialog::addRepeatButton(int32 x, int32 y, const char *prompt, M4CALLBACK cb, int32 tag) {
return Dialog_Add_RepeatButton(this, x, y, prompt, cb, tag);
}
bool Dialog::addList(int32 x1, int32 y1, int32 x2, int32 y2, M4CALLBACK cb, int32 tag) {
return Dialog_Add_List(this, x1, y1, x2, y2, cb, tag);
}
bool Dialog::addTextField(int32 x1, int32 y1, int32 x2, const char *defaultPrompt, M4CALLBACK cb, int32 tag, int32 fieldLength) {
return Dialog_Add_TextField(this, x1, y1, x2, defaultPrompt, cb, tag, fieldLength);
}
void Dialog::registerTextField() {
Dialog_RegisterTextField(this);
}
Item *Dialog::getItem(int32 tag) {
return Dialog_Get_Item(this, tag);
}
void Dialog::changeItemPrompt(const char *newPrompt, Item *myItem, int32 tag) {
Dialog_Change_Item_Prompt(this, newPrompt, myItem, tag);
}
bool Dialog::removeItem(Item *myItem, int32 tag) {
return Dialog_Remove_Item(this, myItem, tag);
}
void Dialog::refreshItem(Item *myItem, int32 tag) {
Dialog_Refresh_Item(this, myItem, tag);
}
bool gui_dialog_init() {
_GD(listboxSearchStr)[0] = '\0';
return true;
}
void gui_dialog_shutdown() {
}
void vmng_TextScrn_Destroy(TextScrn *myTextScrn) {
TextItem *myTextItems;
TextItem *tempTextItem;
tempTextItem = myTextItems = myTextScrn->myTextItems;
while (tempTextItem) {
myTextItems = myTextItems->next;
mem_free(tempTextItem->prompt);
mem_free((void *)tempTextItem);
tempTextItem = myTextItems;
}
delete myTextScrn->textScrnBuffer;
mem_free(myTextScrn);
}
Dialog *DialogCreateAbsolute(int32 x1, int32 y1, int32 x2, int32 y2, uint32 scrnFlags) {
Buffer *tempBuffer;
Dialog *dialog;
ButtonDrawRec bdr;
if ((dialog = (Dialog *)mem_alloc(sizeof(Dialog), STR_DIALOG)) == nullptr) {
return nullptr;
}
dialog->w = x2 - x1 + 1;
dialog->h = y2 - y1 + 1;
dialog->dlgBuffer = new GrBuff(x2 - x1 + 1, y2 - y1 + 1);
if (!dialog->dlgBuffer) {
return nullptr;
}
dialog->num_items = 0;
dialog->itemList = nullptr;
dialog->cancel_item = dialog->return_item = dialog->default_item = nullptr;
if (!vmng_screen_create(x1, y1, x2, y2, SCRN_DLG, scrnFlags, (void *)dialog,
(RefreshFunc)DialogShow, (EventHandler)Dialog_EventHandler)) return nullptr;
// Draw dialog box bounding rectangle
tempBuffer = dialog->dlgBuffer->get_buffer();
bdr.dialog = (void *)dialog;
bdr.scrBuf = tempBuffer;
bdr.fillMe = FILL_INTERIOR;
bdr.pressed = false; bdr.el_type = DIALOGBOX;
bdr.x1 = 0; bdr.y1 = 0; bdr.x2 = dialog->w - 1; bdr.y2 = dialog->h - 1;
drawGUIelement(&bdr, nullptr);
dialog->dlgBuffer->release();
return dialog;
}
Dialog *DialogCreate(M4Rect *r, uint32 scrnFlags) {
return DialogCreateAbsolute(r->x1, r->y1, r->x2, r->y2, scrnFlags);
}
void vmng_Dialog_Destroy(Dialog *d) {
Item *myItems;
Item *tempItem;
tempItem = myItems = d->itemList;
while (tempItem) {
myItems = myItems->next;
Item_destroy(tempItem);
tempItem = myItems;
}
delete d->dlgBuffer;
mem_free((void *)d);
}
void DialogDestroy(Dialog *d, M4Rect *r) {
ScreenContext *myScreen;
if (!d)
return;
if (r) {
if ((myScreen = vmng_screen_find((void *)d, nullptr)) != nullptr) {
r->x1 = myScreen->x1;
r->x2 = myScreen->x2;
r->y1 = myScreen->y1;
r->y2 = myScreen->y2;
}
}
vmng_screen_dispose((void *)d);
vmng_Dialog_Destroy(d);
}
bool GetDialogCoords(Dialog *d, M4Rect *r) {
ScreenContext *myScreen;
if ((!d) || (!r))
return false;
if ((myScreen = vmng_screen_find((void *)d, nullptr)) == nullptr)
return false;
r->x1 = myScreen->x1;
r->x2 = myScreen->x2;
r->y1 = myScreen->y1;
r->y2 = myScreen->y2;
return true;
}
bool Dialog_Add_Message(Dialog *d, int32 x, int32 y, const char *prompt, int32 tag) {
Item *myItem;
if ((myItem = ItemAdd(d->itemList, x, y, 0, 0, prompt, tag, MESSAGE, nullptr, 0)) == nullptr) {
return false;
}
if (!d->itemList)
d->itemList = myItem;
d->listBottom = myItem;
Dialog_Refresh_Item(d, myItem, myItem->tag);
return true;
}
bool Dialog_Add_Picture(Dialog *d, int32 x, int32 y, Buffer *myBuff, int32 tag) {
Item *myItem;
if ((myItem = ItemAdd(d->itemList, x, y,
myBuff->w, myBuff->h, (char *)myBuff->data, tag, PICTURE, nullptr, 0)) == nullptr) {
return false;
}
if (!d->itemList)
d->itemList = myItem;
d->listBottom = myItem;
Dialog_Refresh_Item(d, myItem, myItem->tag);
return true;
}
bool Dialog_Add_Button(Dialog *d, int32 x, int32 y, const char *prompt, M4CALLBACK cb, int32 tag) {
Item *myItem;
if ((myItem = ItemAdd(d->itemList, x, y, 0, 0, prompt, tag, BUTTON, cb, 0)) == nullptr) {
return false;
}
if (!d->itemList)
d->itemList = myItem;
d->listBottom = myItem;
Dialog_Refresh_Item(d, myItem, myItem->tag);
return true;
}
bool Dialog_Add_RepeatButton(Dialog *d, int32 x, int32 y, const char *prompt, M4CALLBACK cb, int32 tag) {
Item *myItem;
if ((myItem = ItemAdd(d->itemList, x, y, 0, 0, prompt, tag, REPEAT_BUTTON, cb, 0)) == nullptr) {
return false;
}
if (!d->itemList)
d->itemList = myItem;
d->listBottom = myItem;
Dialog_Refresh_Item(d, myItem, myItem->tag);
return true;
}
bool Dialog_Add_List(Dialog *d, int32 x1, int32 y1, int32 x2, int32 y2,
M4CALLBACK cb, int32 tag) {
Item *myItem;
if ((myItem = ItemAdd(d->itemList, x1, y1, x2 - x1 + 1, y2 - y1 + 1, nullptr, tag, LISTBOX, cb, 0)) == nullptr) {
return false;
}
if (!d->itemList)
d->itemList = myItem;
d->listBottom = myItem;
Dialog_Refresh_Item(d, myItem, myItem->tag);
return true;
}
bool Dialog_Add_TextField(Dialog *d, int32 x1, int32 y1, int32 x2,
const char *defaultPrompt, M4CALLBACK cb, int32 tag, int32 fieldLength) {
Item *myItem;
if ((myItem = ItemAdd(d->itemList, x1, y1, x2 - x1 + 1, 0, defaultPrompt, tag, TEXTFIELD, cb, fieldLength)) == nullptr) {
return false;
}
if (!d->itemList)
d->itemList = myItem;
d->listBottom = myItem;
Dialog_Refresh_Item(d, myItem, myItem->tag);
return true;
}
bool Dialog_Add_Key(Dialog *d, long myKey, HotkeyCB cb) {
return AddScreenHotkey((void *)d, myKey, cb);
}
bool Dialog_Remove_Key(Dialog *d, long myKey) {
return RemoveScreenHotkey((void *)d, myKey);
}
bool Dialog_Remove_Item(Dialog *d, Item *myItem, int32 tag) {
Buffer *tempBuffer;
ScreenContext *myScreen;
int32 status;
myScreen = vmng_screen_find((void *)d, &status);
if (!myScreen)
return false;
if (!myItem)
myItem = ItemFind(d->itemList, tag);
if (!myItem)
return false;
// NOTE: if the item removed is the default, cancel, or return item, problems could happen...
if (myItem->next)
myItem->next->prev = myItem->prev;
else
d->listBottom = myItem;
if (myItem->prev)
myItem->prev->next = myItem->next;
else
d->itemList = myItem->next;
gr_color_set(__LTGRAY);
tempBuffer = d->dlgBuffer->get_buffer();
gr_buffer_rect_fill(tempBuffer, myItem->x, myItem->y, myItem->w, myItem->h);
d->dlgBuffer->release();
if (status == SCRN_ACTIVE) {
RestoreScreens(myScreen->x1 + myItem->x, myScreen->y1 + myItem->y,
myScreen->x1 + myItem->x + myItem->w - 1,
myScreen->y1 + myItem->y + myItem->h - 1);
}
Item_destroy(myItem);
return true;
}
bool Dialog_ListItemExists(Dialog *d, Item *myItem, int32 tag, char *prompt, int32 listTag) {
if ((!myItem) && (!d))
return false;
if (!myItem)
myItem = ItemFind(d->itemList, tag);
if (!myItem)
return false;
return ListItemExists(myItem, prompt, listTag);
}
bool Dialog_Add_List_Item(Dialog *d, Item *myItem, char *prompt, int32 tag, int32 listTag, int32 addMode, bool refresh) {
ScreenContext *myScreen;
int32 status;
bool retValue;
myScreen = vmng_screen_find((void *)d, &status);
if (!myScreen)
return false;
if (!myItem)
myItem = ItemFind(d->itemList, tag);
retValue = ListItemAdd(myItem, prompt, listTag, addMode, nullptr);
if (retValue && refresh) {
Dialog_Refresh_Item(d, myItem, myItem->tag);
}
return true;
}
bool Dialog_Delete_List_Item(Dialog *d, Item *myItem, int32 tag, ListItem *myListItem, int32 listTag) {
ScreenContext *myScreen;
int32 status;
if ((myScreen = vmng_screen_find((void *)d, &status)) == nullptr)
return false;
if (!myItem) {
myItem = ItemFind(d->itemList, tag);
myListItem = nullptr;
}
if (ListItemDelete(myItem, myListItem, listTag)) {
Dialog_Refresh_Item(d, myItem, myItem->tag);
}
return true;
}
bool Dialog_Change_List_Item(Dialog *d, Item *myItem, int32 tag, ListItem *myListItem,
int32 listTag, char *newPrompt, int32 newListTag, int32 changeMode, bool refresh) {
ScreenContext *myScreen;
int32 status;
bool retValue;
myScreen = vmng_screen_find((void *)d, &status);
if (!myScreen)
return false;
if (!myItem) {
myItem = ItemFind(d->itemList, tag);
myListItem = nullptr;
}
retValue = ListItemChange(myItem, myListItem, listTag, newPrompt, newListTag, changeMode);
if (retValue && refresh) {
Dialog_Refresh_Item(d, myItem, myItem->tag);
}
return retValue;
}
void Dialog_Change_Item_Prompt(Dialog *d, const char *newPrompt, Item *myItem, int32 tag) {
Buffer *tempBuffer;
ScreenContext *myScreen;
int32 status, tempWidth, tempHeight, itemType;
if ((myScreen = vmng_screen_find((void *)d, &status)) == nullptr) {
return;
}
if (!myItem) {
myItem = ItemFind(d->itemList, tag);
}
if (myItem) {
tempWidth = myItem->w;
tempHeight = myItem->h;
if (Item_change_prompt(myItem, newPrompt)) {
tempWidth = imath_max(tempWidth, myItem->w);
tempHeight = imath_max(tempHeight, myItem->h);
gr_color_set(__LTGRAY);
tempBuffer = d->dlgBuffer->get_buffer();
gr_buffer_rect_fill(tempBuffer, myItem->x, myItem->y, tempWidth, tempHeight);
if (myItem == d->default_item) {
itemType = ITEM_DEFAULT;
} else if (myItem == d->return_item) {
itemType = ITEM_RETURN;
} else {
itemType = ITEM_NORMAL;
}
if (Item_show(myItem, (void *)d, tempBuffer, itemType)) {
if (status == SCRN_ACTIVE) {
RestoreScreens(myScreen->x1 + myItem->x, myScreen->y1 + myItem->y,
myScreen->x1 + myItem->x + tempWidth - 1,
myScreen->y1 + myItem->y + tempHeight - 1);
}
}
d->dlgBuffer->release();
}
}
}
bool Dialog_ListboxSearch(Dialog *d, Item *myItem, int32 tag, int32 searchMode, char *searchStr, int32 parm1) {
ScreenContext *myScreen;
int32 status;
bool returnValue;
myScreen = vmng_screen_find((void *)d, &status);
if (!myScreen)
return false;
if (!myItem)
myItem = ItemFind(d->itemList, tag);
if (!myItem || (myItem->type != LISTBOX))
return false;
returnValue = ListItemSearch(myItem, searchMode, searchStr, parm1);
Dialog_Refresh_Item(d, myItem, myItem->tag);
return returnValue;
}
Item *Dialog_Get_Item(Dialog *d, int32 tag) {
if (!d)
return nullptr;
return ItemFind(d->itemList, tag);
}
void Dialog_Refresh_Item(Dialog *d, Item *myItem, int32 tag) {
Buffer *tempBuffer;
ScreenContext *myScreen;
int32 status, itemType;
if (!d)
return;
if ((myScreen = vmng_screen_find((void *)d, &status)) == nullptr)
return;
if (!myItem)
myItem = ItemFind(d->itemList, tag);
if (!myItem)
return;
if (myItem == d->default_item)
itemType = ITEM_DEFAULT;
else if (myItem == d->return_item)
itemType = ITEM_RETURN;
else
itemType = ITEM_NORMAL;
tempBuffer = d->dlgBuffer->get_buffer();
if (Item_show(myItem, (void *)d, tempBuffer, itemType)) {
if (status == SCRN_ACTIVE) {
RestoreScreens(myScreen->x1 + myItem->x, myScreen->y1 + myItem->y,
myScreen->x1 + myItem->x + myItem->w - 1,
myScreen->y1 + myItem->y + myItem->h - 1);
}
}
d->dlgBuffer->release();
}
void Dialog_Refresh(Dialog *d) {
Buffer *tempBuffer;
ScreenContext *myScreen;
Item *i;
int32 status, itemType;
ButtonDrawRec bdr;
if (!d) return;
tempBuffer = d->dlgBuffer->get_buffer();
bdr.dialog = (void *)d;
bdr.scrBuf = tempBuffer; bdr.fillMe = FILL_INTERIOR;
bdr.pressed = false; bdr.el_type = DIALOGBOX;
bdr.x1 = 0; bdr.y1 = 0; bdr.x2 = d->w - 1; bdr.y2 = d->h - 1;
drawGUIelement(&bdr, nullptr);
for (i = d->itemList; i != nullptr; i = i->next) {
if (i == d->default_item) itemType = ITEM_DEFAULT;
else if (i == d->return_item) itemType = ITEM_RETURN;
else itemType = ITEM_NORMAL;
Item_show(i, (void *)d, tempBuffer, itemType);
}
d->dlgBuffer->release();
if ((myScreen = vmng_screen_find((void *)d, &status)) == nullptr)
return;
if (status == SCRN_ACTIVE) {
RestoreScreens(myScreen->x1, myScreen->y1, myScreen->x2, myScreen->y2);
}
}
void Dialog_Refresh_All(void) {
ScreenContext *myScreen;
myScreen = _G(frontScreen);
while (myScreen) {
if (myScreen->scrnType == SCRN_DLG) {
Dialog_Refresh((Dialog *)myScreen->scrnContent);
}
myScreen = myScreen->behind;
}
}
void Dialog_Resize(Dialog *d, int32 newW, int32 newH) {
if (!d) {
return;
}
if (newW <= 0) {
newW = d->w;
}
if (newH <= 0) {
newH = d->h;
}
delete d->dlgBuffer;
d->dlgBuffer = new GrBuff(newW, newH);
d->w = newW;
d->h = newH;
ResizeScreen(d, newW, newH);
Dialog_Refresh(d);
return;
}
static void DialogShow(void *s, void *r, void *b, int32 destX, int32 destY) {
ScreenContext *myScreen = (ScreenContext *)s;
RectList *myRectList = (RectList *)r;
Buffer *destBuffer = (Buffer *)b;
Buffer *tempBuffer;
Dialog *d;
RectList *myRect;
// Parameter verification
if (!myScreen)
return;
d = (Dialog *)(myScreen->scrnContent);
if (!d)
return;
// If no destBuffer, then draw directly to video
if (!destBuffer) {
myRect = myRectList;
while (myRect) {
d->dlgBuffer->refresh_video(myRect->x1, myRect->y1, myRect->x1 - myScreen->x1, myRect->y1 - myScreen->y1,
myRect->x2 - myScreen->x1, myRect->y2 - myScreen->y1);
myRect = myRect->next;
}
} else {
// Else draw to the dest buffer
tempBuffer = d->dlgBuffer->get_buffer();
myRect = myRectList;
while (myRect) {
gr_buffer_rect_copy_2(tempBuffer, destBuffer, myRect->x1 - myScreen->x1, myRect->y1 - myScreen->y1,
destX, destY, myRect->x2 - myRect->x1 + 1, myRect->y2 - myRect->y1 + 1);
myRect = myRect->next;
}
d->dlgBuffer->release();
}
}
void Dialog_Configure(Dialog *d, int32 defaultTag, int32 returnTag, int32 cancelTag) {
if (!d)
return;
d->return_item = ItemFind(d->itemList, returnTag);
d->cancel_item = ItemFind(d->itemList, cancelTag);
Dialog_SetDefault(d, defaultTag);
if (d->default_item) {
Dialog_Refresh_Item(d, d->default_item, d->default_item->tag);
}
}
void Dialog_SetDefault(Dialog *d, int32 tag) {
ScreenContext *myScreen;
Item *origItem, *newDefault;
int32 status;
myScreen = vmng_screen_find((void *)d, &status);
if (!myScreen)
return;
origItem = d->default_item;
newDefault = Item_set_default(d->itemList, d->default_item, tag);
if ((!newDefault) || ((newDefault->type != LISTBOX) && (newDefault->type != TEXTFIELD))) {
d->default_item = nullptr;
} else {
d->default_item = newDefault;
Item_set_pressed(nullptr, d->default_item, 0);
}
if (origItem && (origItem != d->default_item)) {
Item_set_unpressed(nullptr, origItem, 0);
Dialog_Refresh_Item(d, origItem, origItem->tag);
}
}
bool Dialog_SetPressed(Dialog *d, int32 tag) {
ScreenContext *myScreen;
Item *myItem;
int32 status;
myScreen = vmng_screen_find((void *)d, &status);
if (!myScreen)
return false;
myItem = Item_set_pressed(d->itemList, nullptr, tag);
if (myItem) {
Dialog_Refresh_Item(d, myItem, myItem->tag);
return true;
} else {
return false;
}
}
static bool Dialog_SetUnpressed(Dialog *d, int32 tag) {
ScreenContext *myScreen;
Item *myItem;
int32 status;
myScreen = vmng_screen_find((void *)d, &status);
if (!myScreen)
return false;
myItem = Item_set_unpressed(d->itemList, nullptr, tag);
if (myItem) {
Dialog_Refresh_Item(d, myItem, myItem->tag);
return true;
} else {
return false;
}
}
static bool Dialog_SetNextDefault(ScreenContext *myScreen, Dialog *d) {
int32 status;
Item *origItem;
if (!myScreen)
myScreen = vmng_screen_find((void *)d, &status);
else
status = SCRN_ACTIVE;
if (!myScreen)
return false;
origItem = d->default_item;
d->default_item = Item_set_next_default(d->default_item, d->itemList);
if (status == SCRN_ACTIVE) {
if (origItem && (origItem != d->default_item)) {
Dialog_Refresh_Item(d, origItem, origItem->tag);
}
if (d->default_item) {
Dialog_Refresh_Item(d, d->default_item, d->default_item->tag);
}
}
if (d->default_item)
return true;
else
return false;
}
static bool Dialog_SetPrevDefault(ScreenContext *myScreen, Dialog *d) {
int32 status;
Item *origItem;
if (!myScreen)
myScreen = vmng_screen_find((void *)d, &status);
else
status = SCRN_ACTIVE;
if (!myScreen)
return false;
origItem = d->default_item;
d->default_item = Item_set_prev_default(d->default_item, d->listBottom);
if (status == SCRN_ACTIVE) {
if (origItem && (origItem != d->default_item)) {
Dialog_Refresh_Item(d, origItem, origItem->tag);
}
if (d->default_item) {
Dialog_Refresh_Item(d, d->default_item, d->default_item->tag);
}
}
if (d->default_item)
return true;
else
return false;
}
void Dialog_GetNextListItem(Dialog *d) {
if ((!d->default_item) || (d->default_item->type != LISTBOX))
return;
if (GetNextListItem(d->default_item)) {
Dialog_Refresh_Item(d, d->default_item, d->default_item->tag);
}
}
static void Dialog_GetNextPageList(Dialog *d) {
if ((!d->default_item) || (d->default_item->type != LISTBOX))
return;
if (GetNextPageList(d->default_item)) {
Dialog_Refresh_Item(d, d->default_item, d->default_item->tag);
}
}
void Dialog_GetPrevListItem(Dialog *d) {
if ((!d->default_item) || (d->default_item->type != LISTBOX))
return;
if (GetPrevListItem(d->default_item)) {
Dialog_Refresh_Item(d, d->default_item, d->default_item->tag);
}
}
static void Dialog_GetPrevPageList(Dialog *d) {
if ((!d->default_item) || (d->default_item->type != LISTBOX))
return;
if (GetPrevPageList(d->default_item)) {
Dialog_Refresh_Item(d, d->default_item, d->default_item->tag);
}
}
ListItem *Dialog_GetCurrListItem(Dialog *d, Item *i, int32 tag) {
if ((!i) && (!d))
return nullptr;
if (!i)
i = ItemFind(d->itemList, tag);
if (!i)
return nullptr;
return i->currItem;
}
char *Dialog_GetCurrListItemPrompt(Dialog *d, Item *i, int32 tag) {
ListItem *myListItem;
if ((myListItem = Dialog_GetCurrListItem(d, i, tag)) == nullptr)
return nullptr;
return myListItem->prompt;
}
bool Dialog_GetCurrListItemTag(Dialog *d, Item *i, int32 tag, int32 *listTag) {
ListItem *myListItem;
if ((myListItem = Dialog_GetCurrListItem(d, i, tag)) == nullptr)
return false;
*listTag = myListItem->tag;
return true;
}
char *Dialog_GetListItemPrompt(Dialog *d, Item *i, int32 tag, int32 listTag) {
ListItem *myListItem;
if (!i)
i = ItemFind(d->itemList, tag);
if (!i)
return nullptr;
if ((myListItem = ListItemFind(i, LIST_BY_TAG, nullptr, listTag)) == nullptr)
return nullptr;
return myListItem->prompt;
}
void Dialog_EmptyListBox(Dialog *d, Item *i, int32 tag) {
int32 status;
if ((!i) && (!d))
return;
if (!i)
i = ItemFind(d->itemList, tag);
if (!i)
return;
Item_empty_list(i);
(void)vmng_screen_find((void *)d, &status);
Dialog_Refresh_Item(d, i, i->tag);
}
void Dialog_RegisterTextField(Dialog *d) {
Item *myItem = nullptr;
ScreenContext *myScreen;
int32 status;
myScreen = vmng_screen_find((void *)d, &status);
if ((!myScreen) || (status != SCRN_ACTIVE))
return;
if ((myItem = Item_CheckTextField()) == nullptr)
return;
if (myItem->callback) {
(myItem->callback)((void *)myItem, (void *)d);
myScreen = vmng_screen_find((void *)d, &status);
Dialog_Refresh_Item(d, myItem, myItem->tag);
}
}
static void SystemErrCallback(void *, void *) {
_GD(okButton) = true;
}
void Dialog_SystemError(char *s) {
Dialog *aDlog = DialogCreateAbsolute(0, 0, MAX_VIDEO_X, MAX_VIDEO_Y, SF_ALERT);
Dialog_Add_Message(aDlog, 20, 60, s, 2);
Dialog_Add_Button(aDlog, 50, 80, " OK ", SystemErrCallback, 100);
Dialog_Configure(aDlog, 0, 100, 0);
vmng_screen_show((void *)aDlog);
_GD(okButton) = false;
while (!_GD(okButton)) {
gui_system_event_handler();
}
DialogDestroy(aDlog, (M4Rect *)nullptr);
}
void Dialog_KeyMouseCollision(void) {
Item *textItem;
_GD(movingScreen) = false;
_GD(clickItem) = nullptr;
_GD(doubleClickItem) = nullptr;
_GD(listboxSearchStr)[0] = '\0';
if ((textItem = Item_CheckTextField()) != nullptr) {
if (textItem->callback) {
(textItem->callback)((void *)textItem, nullptr);
}
}
}
static bool Dialog_EventHandler(void *myDialog, int32 eventType, int32 parm1, int32 parm2, int32 parm3, bool *currScreen) {
ScreenContext *myScreen;
Dialog *d = (Dialog *)myDialog;
Item *myItem, *textItem;
int32 status;
bool handled;
bool clearClickItem;
static uint32 repeatTime;
int32 scrollable = 0;
uint32 tempTime;
static int32 movingX;
static int32 movingY;
char tempStr[2];
myScreen = vmng_screen_find(myDialog, &status);
if ((!myScreen) || (status != SCRN_ACTIVE))
return false;
if (eventType == EVENT_KEY) {
handled = false;
if (d->default_item) {
if (d->default_item->type == TEXTFIELD) {
_GD(listboxSearchStr)[0] = '\0';
if (parm1 == KEY_ESCAPE) {
if ((textItem = Item_RestoreTextField()) != nullptr) {
Dialog_Refresh_Item(d, textItem, textItem->tag);
}
} else if ((parm1 == KEY_RETURN) || (parm1 == KEY_TAB) || (parm1 == KEY_SHFTTAB)) {
if ((textItem = Item_CheckTextField()) != nullptr) {
if (textItem->callback) {
(textItem->callback)((void *)textItem, (void *)d);
myScreen = vmng_screen_find((void *)d, &status);
if ((!myScreen) || (status != SCRN_ACTIVE)) handled = true;
}
}
} else {
// will fall out to catch the "set next/prev default"
handled = Item_TextEdit(d->default_item, parm1);
Dialog_Refresh_Item(d, d->default_item, d->default_item->tag);
}
} else if (d->default_item->type == LISTBOX) {
handled = true;
switch (parm1) {
case KEY_RETURN:
_GD(listboxSearchStr)[0] = '\0';
if (d->default_item->callback) {
handled = true;
(d->default_item->callback)((void *)(d->default_item), (void *)d);
} else handled = false;
break;
case KEY_PAGE_UP:
_GD(listboxSearchStr)[0] = '\0';
if (Item_SetViewBottom(d->default_item)) {
Dialog_GetPrevPageList(d);
} else ViewCurrListItem(d->default_item);
break;
case KEY_PAGE_DOWN:
_GD(listboxSearchStr)[0] = '\0';
if (Item_SetViewBottom(d->default_item)) {
Dialog_GetNextPageList(d);
} else ViewCurrListItem(d->default_item);
break;
case KEY_UP:
_GD(listboxSearchStr)[0] = '\0';
if (Item_SetViewBottom(d->default_item)) {
Dialog_GetPrevListItem(d);
} else ViewCurrListItem(d->default_item);
break;
case KEY_DOWN:
_GD(listboxSearchStr)[0] = '\0';
if (Item_SetViewBottom(d->default_item)) {
Dialog_GetNextListItem(d);
} else ViewCurrListItem(d->default_item);
break;
case KEY_LEFT:
_GD(listboxSearchStr)[0] = '\0';
if (Item_SetViewBottom(d->default_item)) {
Dialog_GetPrevListItem(d);
} else ViewCurrListItem(d->default_item);
break;
case KEY_RIGHT:
_GD(listboxSearchStr)[0] = '\0';
if (Item_SetViewBottom(d->default_item)) {
Dialog_GetNextListItem(d);
} else ViewCurrListItem(d->default_item);
break;
default:
if ((parm1 >= 32) && (parm1 <= 127)) {
if (strlen(_GD(listboxSearchStr)) < 79) {
tempStr[0] = (char)parm1;
tempStr[1] = '\0';
Common::strcat_s(_GD(listboxSearchStr), 80, tempStr);
}
if (!ListItemSearch(d->default_item, LIST_ALPH, _GD(listboxSearchStr), 0)) {
_GD(listboxSearchStr)[0] = (char)parm1;
_GD(listboxSearchStr)[1] = '\0';
ListItemSearch(d->default_item, LIST_ALPH, _GD(listboxSearchStr), 0);
}
} else handled = false;
break;
}
if (handled) {
Dialog_Refresh_Item(d, d->default_item, d->default_item->tag);
}
}
}
if (!handled) {
_GD(listboxSearchStr)[0] = '\0';
switch (parm1) {
case KEY_ESCAPE:
if ((d->cancel_item) && (d->cancel_item->callback)) {
handled = true;
(d->cancel_item->callback)((void *)(d->cancel_item), (void *)d);
}
break;
case KEY_RETURN:
if ((d->return_item) && (d->return_item->callback)) {
handled = true;
(d->return_item->callback)((void *)(d->return_item), (void *)d);
}
break;
case KEY_TAB:
handled = Dialog_SetNextDefault(myScreen, d);
break;
case KEY_SHFTTAB:
handled = Dialog_SetPrevDefault(myScreen, d);
break;
}
}
return handled;
} else if (eventType == EVENT_MOUSE) {
if (parm1 != _ME_move) _GD(listboxSearchStr)[0] = '\0';
myItem = d->itemList;
while (myItem && (!((parm2 - myScreen->x1 >= myItem->x) &&
(parm2 - myScreen->x1 <= (myItem->x + myItem->w - 1)) &&
(parm3 - myScreen->y1 >= myItem->y) &&
(parm3 - myScreen->y1 <= (myItem->y + myItem->h - 1))))) {
myItem = myItem->next;
}
clearClickItem = false;
switch (parm1) {
case _ME_L_click:
if (currScreen) *currScreen = true;
repeatTime = timer_read_60();
if ((textItem = Item_CheckTextField()) != nullptr) {
if (textItem->callback) {
(textItem->callback)((void *)textItem, (void *)d);
myScreen = vmng_screen_find((void *)d, &status);
if ((!myScreen) || (status != SCRN_ACTIVE)) {
if (currScreen) *currScreen = false;
_GD(clickItem) = nullptr;
return true;
}
}
}
vmng_screen_show(myScreen->scrnContent);
if (myItem && (myItem->type != MESSAGE) && (myItem->type != PICTURE)) _GD(clickItem) = myItem;
else {
_GD(clickItem) = nullptr;
Dialog_SetDefault(d, 0);
}
if (_GD(clickItem)) {
if (_GD(clickItem)->type == LISTBOX) {
ClickOnListBox(_GD(clickItem), parm2 - myScreen->x1 - _GD(clickItem)->x, parm3 - myScreen->y1 - _GD(clickItem)->y, SCROLLABLE | PAGEABLE);
} else if (_GD(clickItem)->type == TEXTFIELD) {
SetTextBlockBegin(_GD(clickItem), parm2 - myScreen->x1 - _GD(clickItem)->x);
}
Dialog_SetDefault(d, _GD(clickItem)->tag);
Dialog_SetPressed(d, _GD(clickItem)->tag);
} else if (!(myScreen->scrnFlags & SF_IMMOVABLE)) {
_GD(movingScreen) = true;
movingX = parm2;
movingY = parm3;
}
break;
case _ME_L_hold:
case _ME_doubleclick_hold:
tempTime = timer_read_60();
if (_GD(clickItem)) {
if (_GD(clickItem)->type == LISTBOX) {
if (tempTime > (repeatTime + 2)) {
repeatTime = tempTime;
ClickOnListBox(_GD(clickItem), parm2 - myScreen->x1 - _GD(clickItem)->x, parm3 - myScreen->y1 - _GD(clickItem)->y, SCROLLABLE);
}
} else if (_GD(clickItem)->type == REPEAT_BUTTON) {
if (tempTime > (repeatTime + 2)) {
repeatTime = tempTime;
if (_GD(clickItem)->callback) {
(_GD(clickItem)->callback)((void *)_GD(clickItem), (void *)d);
myScreen = vmng_screen_find((void *)d, &status);
if ((!myScreen) || (status != SCRN_ACTIVE)) {
_GD(clickItem) = nullptr;
return true;
}
}
}
}
}
break;
case _ME_L_drag:
if (_GD(movingScreen)) {
MoveScreenDelta(myScreen, parm2 - movingX, parm3 - movingY);
movingX = parm2;
movingY = parm3;
} else if (_GD(clickItem)) {
if (_GD(clickItem)->type == LISTBOX) {
tempTime = timer_read_60();
if (tempTime > (repeatTime + 2)) {
scrollable = SCROLLABLE;
repeatTime = tempTime;
}
ClickOnListBox(_GD(clickItem), parm2 - myScreen->x1 - _GD(clickItem)->x,
parm3 - myScreen->y1 - _GD(clickItem)->y, scrollable);
} else if (_GD(clickItem)->type == TEXTFIELD) {
SetTextBlockEnd(_GD(clickItem), parm2 - myScreen->x1 - _GD(clickItem)->x);
} else if (_GD(clickItem) == myItem) {
Dialog_SetPressed(d, _GD(clickItem)->tag);
} else {
Dialog_SetUnpressed(d, _GD(clickItem)->tag);
}
}
break;
case _ME_doubleclick:
if (myItem == _GD(doubleClickItem)) {
_GD(clickItem) = _GD(doubleClickItem);
_GD(doubleClickItem) = nullptr;
}
if (_GD(clickItem) && (_GD(clickItem)->type == LISTBOX)) {
if (DoubleClickOnListBox(_GD(clickItem), parm2 - myScreen->x1 - _GD(clickItem)->x,
parm3 - myScreen->y1 - _GD(clickItem)->y)) {
if (_GD(clickItem)->callback) {
(_GD(clickItem)->callback)((void *)_GD(clickItem), (void *)d);
clearClickItem = true;
myScreen = vmng_screen_find((void *)d, &status);
if ((!myScreen) || (status != SCRN_ACTIVE)) {
if (currScreen) *currScreen = false;
_GD(clickItem) = nullptr;
return true;
}
}
} else {
ClickOnListBox(_GD(clickItem), parm2 - myScreen->x1 - _GD(clickItem)->x,
parm3 - myScreen->y1 - _GD(clickItem)->y, SCROLLABLE | PAGEABLE);
Dialog_SetDefault(d, _GD(clickItem)->tag);
Dialog_SetPressed(d, _GD(clickItem)->tag);
}
} else if (_GD(clickItem) && (_GD(clickItem)->type == TEXTFIELD)) {
SetTextBlockBegin(_GD(clickItem), 0);
SetTextBlockEnd(_GD(clickItem), 32767);
}
break;
case _ME_L_release:
if (currScreen) *currScreen = false;
if (_GD(movingScreen)) {
_GD(movingScreen) = false;
clearClickItem = true;
} else if (_GD(clickItem)) {
if (_GD(clickItem)->type == LISTBOX) {
ResetDefaultListBox(_GD(clickItem));
clearClickItem = true;
} else if (_GD(clickItem)->type != TEXTFIELD) {
Dialog_SetUnpressed(d, _GD(clickItem)->tag);
clearClickItem = true;
if ((myItem == _GD(clickItem)) && (myItem->callback)) {
(myItem->callback)((void *)myItem, (void *)d);
myScreen = vmng_screen_find((void *)d, &status);
if ((!myScreen) || (status != SCRN_ACTIVE)) {
_GD(clickItem) = nullptr;
return true;
}
}
} else clearClickItem = true;
}
break;
case _ME_doubleclick_release:
if (_GD(clickItem) && (_GD(clickItem)->type == LISTBOX)) {
ResetDefaultListBox(_GD(clickItem));
clearClickItem = true;
}
break;
}
if (_GD(clickItem)) {
if ((_GD(clickItem) = Dialog_Get_Item(d, _GD(clickItem)->tag)) != nullptr) {
Dialog_Refresh_Item(d, _GD(clickItem), _GD(clickItem)->tag);
}
}
if (clearClickItem) {
_GD(doubleClickItem) = _GD(clickItem);
_GD(clickItem) = nullptr;
}
return true;
}
return false;
}
// TEXTSCRN STUFF...
static void TextScrn_Show(void *s, void *r, void *b, int32 destX, int32 destY) {
ScreenContext *myScreen = (ScreenContext *)s;
TextScrn *myTextScrn;
TextItem *myItem;
matte *myRectList = (matte *)r;
Buffer *destBuffer = (Buffer *)b;
Buffer *myBuff;
GrBuff *myGrBuff;
ScreenContext *tempScreen;
matte *myMatte, tempMatte;
RectList *updateList, *updateRect;
RectList *newUpdateList;
Font *currFont;
// Parameter verification
if (!myScreen)
return;
myTextScrn = (TextScrn *)(myScreen->scrnContent);
if (!myTextScrn)
return;
myGrBuff = (GrBuff *)(myTextScrn->textScrnBuffer);
if (!myGrBuff)
return;
// If no destBuffer, then draw directly to video
if (!destBuffer) {
tempMatte.nextMatte = nullptr;
// Create an updateRectList to catch the black areas afterwards
updateList = vmng_CreateNewRect(myScreen->x1, myScreen->y1, myScreen->x2, myScreen->y2);
updateList->prev = nullptr;
updateList->next = nullptr;
// Now loop through all the screens behind myScreen
tempScreen = myScreen->behind;
while (tempScreen && updateList) {
// Duplicate the updateList
newUpdateList = vmng_DuplicateRectList(updateList);
// Loop through the updateList
updateRect = updateList;
while (updateRect) {
// See if it intersects
tempMatte.x1 = imath_max(updateRect->x1, tempScreen->x1);
tempMatte.y1 = imath_max(updateRect->y1, tempScreen->y1);
tempMatte.x2 = imath_min(updateRect->x2, tempScreen->x2);
tempMatte.y2 = imath_min(updateRect->y2, tempScreen->y2);
if (tempScreen->redraw && (tempMatte.x1 <= tempMatte.x2) && (tempMatte.y1 <= tempMatte.y2)) {
// Draw the intersected part of tempScreen onto myBuffer
myBuff = myGrBuff->get_buffer();
(tempScreen->redraw)(tempScreen, (void *)&tempMatte, myBuff, tempMatte.x1 - myScreen->x1, tempMatte.y1 - myScreen->y1);
myGrBuff->release();
// Remove that rectangle from the update list
vmng_RemoveRectFromRectList(&newUpdateList, tempMatte.x1, tempMatte.y1, tempMatte.x2, tempMatte.y2);
}
// Get the next updateRect
updateRect = updateRect->next;
}
// The newUpdateList now contains all the pieces not covered by tempScreen;
// Turf the update list, and replace it with the newupdateList
vmng_DisposeRectList(&updateList);
updateList = newUpdateList;
// Now get the next screen
tempScreen = tempScreen->behind;
}
// Now we've gone through all the screens, whatever is left in the updateList should be filled in with black
gr_color_set(__BLACK);
updateRect = updateList;
myBuff = myGrBuff->get_buffer();
while (updateRect) {
gr_buffer_rect_fill(myBuff, updateRect->x1 - myScreen->x1, updateRect->y1 - myScreen->y1,
updateRect->x2 - updateRect->x1 + 1, updateRect->y2 - updateRect->y1 + 1);
updateRect = updateRect->next;
}
myGrBuff->release();
// Now dispose of the updateList
vmng_DisposeRectList(&updateList);
// Now we darken (or lighten) the screen by the luminance percentage
myBuff = myGrBuff->get_buffer();
krn_ChangeBufferLuminance(myBuff, myTextScrn->luminance);
myGrBuff->release();
// Now myBuff should contain a copy of everything on the screen, except the actual contents of this transparent screen
// Now would be the time to draw the contents
currFont = gr_font_get();
gr_font_set(myTextScrn->myFont);
myItem = myTextScrn->myTextItems;
myBuff = myGrBuff->get_buffer();
while (myItem) {
if (myItem == myTextScrn->hiliteItem) {
// Gr_font_set_color(myTextScrn->hiliteColor);
font_set_colors(myTextScrn->hiliteColor_alt1, myTextScrn->hiliteColor_alt2, myTextScrn->hiliteColor);
} else {
// Gr_font_set_color(myTextScrn->textColor);
font_set_colors(myTextScrn->textColor_alt1, myTextScrn->textColor_alt2, myTextScrn->textColor);
}
gr_font_write(myBuff, myItem->prompt, myItem->x, myItem->y, 0, 0); // MattP no auto spacing
myItem = myItem->next;
}
myGrBuff->release();
gr_font_set(currFont);
// Now dump the matte list out to video
myMatte = myRectList;
while (myMatte) {
myGrBuff->refresh_video(myMatte->x1, myMatte->y1, myMatte->x1 - myScreen->x1, myMatte->y1 - myScreen->y1,
myMatte->x2 - myScreen->x1, myMatte->y2 - myScreen->y1);
//vmng_refresh_video(myMatte->x1, myMatte->y1, myMatte->x1 - myScreen->x1, myMatte->y1 - myScreen->y1,
// myMatte->x2 - myScreen->x1, myMatte->y2 - myScreen->y1, myBuff);
myMatte = myMatte->nextMatte;
}
} else {
// Else draw to the dest buffer
myMatte = myRectList;
myBuff = myGrBuff->get_buffer();
while (myMatte) {
gr_buffer_rect_copy_2(myBuff, destBuffer, myMatte->x1 - myScreen->x1, myMatte->y1 - myScreen->y1,
destX, destY, myMatte->x2 - myMatte->x1 + 1, myMatte->y2 - myMatte->y1 + 1);
myMatte = myMatte->nextMatte;
}
myGrBuff->release();
}
}
TextScrn *TextScrn_Create(int32 x1, int32 y1, int32 x2, int32 y2, int32 luminance, uint32 scrnFlags,
int32 textColor, int32 hiliteColor,
int32 textColorAlt1, int32 hiliteColorAlt1, int32 textColorAlt2, int32 hiliteColorAlt2) {
TextScrn *myTextScrn;
if ((myTextScrn = (TextScrn *)mem_alloc(sizeof(TextScrn), STR_TEXTSCRN)) == nullptr)
return nullptr;
myTextScrn->w = x2 - x1 + 1;
myTextScrn->h = y2 - y1 + 1;
myTextScrn->textColor = textColor;
myTextScrn->textColor_alt1 = textColorAlt1;
myTextScrn->textColor_alt2 = textColorAlt2;
myTextScrn->hiliteColor = hiliteColor;
myTextScrn->hiliteColor_alt1 = hiliteColorAlt1;
myTextScrn->hiliteColor_alt2 = hiliteColorAlt2;
myTextScrn->luminance = luminance;
myTextScrn->myFont = gr_font_get();
myTextScrn->myTextItems = nullptr;
myTextScrn->hiliteItem = nullptr;
myTextScrn->textScrnBuffer = new GrBuff(myTextScrn->w, myTextScrn->h);
if (!myTextScrn->textScrnBuffer) {
return nullptr;
}
if (!vmng_screen_create(x1, y1, x2, y2, SCRN_TEXT, scrnFlags | SF_TRANSPARENT, (void *)myTextScrn, (RefreshFunc)TextScrn_Show, TextScrn_EventHandler)) {
return nullptr;
}
return myTextScrn;
}
void TextScrn_Destroy(TextScrn *myTextScrn) {
if (!myTextScrn) return;
vmng_screen_dispose((void *)myTextScrn);
vmng_TextScrn_Destroy(myTextScrn);
_G(currScreen) = false;
}
void TextScrn_Activate(TextScrn *myTextScrn) {
vmng_screen_show((void *)myTextScrn);
}
bool TextScrn_Add_Key(TextScrn *myTextScrn, long myKey, HotkeyCB cb) {
return AddScreenHotkey((void *)myTextScrn, myKey, cb);
}
bool TextScrn_Add_TextItem(TextScrn *myTextScrn, int32 x, int32 y, int32 tag,
int32 justification, const char *prompt, M4CALLBACK callback) {
TextItem *myTextItem;
if (!myTextScrn) {
return false;
}
if ((myTextItem = (TextItem *)mem_alloc(sizeof(TextItem), "text item")) == nullptr)
return false;
myTextItem->w = gr_font_string_width(prompt, 0); // No auto spacing
myTextItem->h = gr_font_get_height() + 1;
myTextItem->y = y;
myTextItem->justification = justification;
switch (justification) {
case TS_JUST_LEFT:
myTextItem->x = 0;
break;
case TS_JUST_RIGHT:
myTextItem->x = myTextScrn->w - myTextItem->w - 1;
break;
case TS_CENTRE:
myTextItem->x = (myTextScrn->w - myTextItem->w) >> 1;
break;
case TS_GIVEN:
default:
myTextItem->x = x;
break;
}
myTextItem->tag = tag;
myTextItem->type = BUTTON;
myTextItem->prompt = mem_strdup(prompt);
myTextItem->callback = callback;
myTextItem->next = myTextScrn->myTextItems;
myTextScrn->myTextItems = myTextItem;
return true;
}
bool TextScrn_Add_Message(TextScrn *myTextScrn, int32 x, int32 y, int32 tag,
int32 justification, const char *prompt) {
TextItem *myTextItem;
if (!myTextScrn) {
return false;
}
if ((myTextItem = (TextItem *)mem_alloc(sizeof(TextItem), "textscrn msg")) == nullptr)
return false;
myTextItem->w = gr_font_string_width(prompt, 0); // No auto spacing
myTextItem->h = gr_font_get_height() + 1;
myTextItem->y = y;
myTextItem->justification = justification;
switch (justification) {
case TS_JUST_LEFT:
myTextItem->x = 0;
break;
case TS_JUST_RIGHT:
myTextItem->x = myTextScrn->w - myTextItem->w - 1;
break;
case TS_CENTRE:
myTextItem->x = (myTextScrn->w - myTextItem->w) >> 1;
break;
case TS_GIVEN:
default:
myTextItem->x = x;
break;
}
myTextItem->tag = tag;
myTextItem->type = MESSAGE;
myTextItem->prompt = mem_strdup(prompt);
myTextItem->next = myTextScrn->myTextItems;
myTextScrn->myTextItems = myTextItem;
return true;
}
void TextScrn_Delete_TextItem(TextScrn *myTextScrn, int32 tag) {
ScreenContext *myScreen;
int32 status, x, y, w, h;
TextItem *myTextItem, *tempTextItem;
if ((myScreen = vmng_screen_find((void *)myTextScrn, &status)) == nullptr)
return;
myTextItem = myTextScrn->myTextItems;
if (myTextItem->tag == tag) {
myTextScrn->myTextItems = myTextItem->next;
tempTextItem = myTextItem;
} else {
while (myTextItem->next && (myTextItem->next->tag != tag)) myTextItem = myTextItem->next;
if ((tempTextItem = myTextItem->next) == nullptr) return;
myTextItem->next = tempTextItem->next;
}
x = tempTextItem->x;
y = tempTextItem->y;
w = tempTextItem->w;
h = tempTextItem->h;
mem_free(tempTextItem->prompt);
mem_free((void *)tempTextItem);
if (status == SCRN_ACTIVE) {
RestoreScreens(myScreen->x1 + x, myScreen->y1 + y, myScreen->x1 + x + w - 1, myScreen->y1 + y + h - 1);
}
}
static bool TextScrn_EventHandler(void *theTextScrn, int32 eventType, int32 parm1, int32 parm2, int32 parm3, bool *currScreen) {
ScreenContext *myScreen;
TextScrn *myTextScrn = (TextScrn *)theTextScrn;
TextItem *myTextItem, *oldHiliteItem;
int32 status;
static int32 movingX;
static int32 movingY;
myScreen = vmng_screen_find(theTextScrn, &status);
if ((!myScreen) || (status != SCRN_ACTIVE))
return false;
if (!(eventType == EVENT_MOUSE))
return false;
myTextItem = myTextScrn->myTextItems;
while (myTextItem && (!((parm2 >= myScreen->x1) &&
(parm2 <= myScreen->x2) &&
(parm3 - myScreen->y1 >= myTextItem->y) &&
(parm3 - myScreen->y1 <= (myTextItem->y + myTextItem->h - 1))))) {
myTextItem = myTextItem->next;
}
if (myTextItem && (myTextItem->type == MESSAGE)) {
myTextItem = nullptr;
}
if (myTextItem != myTextScrn->hiliteItem) {
oldHiliteItem = myTextScrn->hiliteItem;
myTextScrn->hiliteItem = myTextItem;
if (oldHiliteItem) {
RestoreScreens(myScreen->x1 + oldHiliteItem->x, myScreen->y1 + oldHiliteItem->y,
myScreen->x1 + oldHiliteItem->x + oldHiliteItem->w - 1,
myScreen->y1 + oldHiliteItem->y + oldHiliteItem->h - 1);
}
if (myTextItem) {
RestoreScreens(myScreen->x1 + myTextItem->x, myScreen->y1 + myTextItem->y,
myScreen->x1 + myTextItem->x + myTextItem->w - 1,
myScreen->y1 + myTextItem->y + myTextItem->h - 1);
}
}
switch (parm1) {
case _ME_L_click:
if (currScreen) {
*currScreen = true;
}
if (!(myScreen->scrnFlags & SF_IMMOVABLE)) {
_GD(movingScreen) = true;
movingX = parm2;
movingY = parm3;
}
break;
case _ME_L_hold:
case _ME_doubleclick_hold:
break;
case _ME_L_drag:
if (_GD(movingScreen)) {
MoveScreenDelta(myScreen, parm2 - movingX, parm3 - movingY);
movingX = parm2;
movingY = parm3;
}
break;
case _ME_move:
if ((parm2 < myScreen->x1) || (parm2 > myScreen->x2) ||
(parm3 < myScreen->y1) || (parm3 > myScreen->y2)) {
if (currScreen) {
*currScreen = false;
}
return false;
}
break;
case _ME_doubleclick:
break;
case _ME_L_release:
if (currScreen) {
*currScreen = false;
}
_GD(movingScreen) = false;
if (myTextItem && myTextItem->callback) {
(myTextItem->callback)((void *)myTextItem, (void *)myTextScrn);
}
myScreen = vmng_screen_find(theTextScrn, &status);
break;
case _ME_doubleclick_release:
break;
}
if (myScreen && myTextScrn->hiliteItem && currScreen) {
*currScreen = true;
}
return true;
}
} // namespace M4