From c04c93857f9ce337ea54e32cee54a1b64cda339e Mon Sep 17 00:00:00 2001 From: Wanne Date: Tue, 23 Aug 2011 06:42:39 +0000 Subject: [PATCH] - New Feature: Quick attachment selection (by The_Bob) o The popup will list attachments available for the given slot on the current weapon. Ones not in sector inventory will be greyed out. o It should show up after clicking on an empty attachment slot, provided these criteria are met: --> we are on the mapscreen --> the sector inventory is open --> the selected merc is in this sector --> there is no combat in this sector git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@4620 3b4a5df2-a311-0410-b5c6-a8a6f20db521 --- Strategic/mapscreen.cpp | 4 + Tactical/Interface Items.cpp | 177 ++- Tactical/Interface Items.h | 12 + Utils/Utils_VS2005.vcproj | 12 + Utils/Utils_VS2008.vcproj | 12 + Utils/Utils_VS2010.vcxproj | 3 + Utils/Utils_VS2010.vcxproj.filters | 3 + Utils/popup_callback.h | 171 +++ Utils/popup_class.cpp | 1655 ++++++++++++++++++++++++++++ Utils/popup_class.h | 283 +++++ ja2_VS2005.vcproj | 2 +- 11 files changed, 2332 insertions(+), 2 deletions(-) create mode 100644 Utils/popup_callback.h create mode 100644 Utils/popup_class.cpp create mode 100644 Utils/popup_class.h diff --git a/Strategic/mapscreen.cpp b/Strategic/mapscreen.cpp index 5714b759..52d80f6d 100644 --- a/Strategic/mapscreen.cpp +++ b/Strategic/mapscreen.cpp @@ -5502,6 +5502,10 @@ UINT32 MapScreenHandle(void) UpdatePausedStatesDueToTimeCompression( ); // is there a description to be displayed? + // BOB : if we're displaying the attachment popup, don't redraw the IDB + if (giActiveAttachmentPopup > -1) + gItemDescAttachmentPopups[giActiveAttachmentPopup]->show(); + else RenderItemDescriptionBox( ); // render clock diff --git a/Tactical/Interface Items.cpp b/Tactical/Interface Items.cpp index ee283d79..7bb23a5d 100644 --- a/Tactical/Interface Items.cpp +++ b/Tactical/Interface Items.cpp @@ -76,8 +76,11 @@ #include "Map Screen Interface Map.h" #include "Interface Enhanced.h" #include "InterfaceItemImages.h" + #include "Auto Resolve.h" + #include "popup_callback.h" + // BOB : quick attachment popup + #include "popup_class.h" #endif - //////////////////////////////////////////////////////////////////////////////////////////////////////// // SANDRO - all "APBPConstants[AP_PICKUP_ITEM]" were replaced by GetBasicAPsToPickupItem() //////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -280,6 +283,16 @@ BOOLEAN fItemDescDelete = FALSE; MOUSE_REGION gItemDescAttachmentRegions[MAX_ATTACHMENTS]; MOUSE_REGION gProsAndConsRegions[2]; +// BOB : quick attachment popups +BOOLEAN gItemDescAttachmentPopupsInitialized = FALSE; + +POPUP* gItemDescAttachmentPopups[MAX_ATTACHMENTS]; +INT32 giActiveAttachmentPopup = -1; + +POPUP* gEquipPopups[NUM_INV_SLOTS]; +INT32 giActiveEquipPopup = -1; + + void BtnMoneyButtonCallback(GUI_BUTTON *btn,INT32 reason); UINT32 guiMoneyButtonBtn[OLD_MAX_ATTACHMENTS_101]; INT32 guiMoneyButtonImage; @@ -510,6 +523,65 @@ INV_DESC_REGIONS gItemDescAdvRegions[NUM_UDB_ADV_LINES][4]; // Advanced data reg INV_DESC_REGIONS gODBItemDescRegions[4][8]; // Four regions of eight sub-regions each. +// ------------------- Attachment popup callbacks + +// BOB : globals for telling attachment popups _where_ should the attachment go +UINT8 gubPopupStatusIndex; +UINT32 guiPopupItemPos; +void popupCallbackItem(INT16 itemId){ + + + for(UINT16 i = 0; i < pInventoryPoolList.size(); i++){ + if( pInventoryPoolList[i].object.usItem == itemId ) { + + gpItemPointer = &pInventoryPoolList[i].object; // pick up the object (or stack) + DoAttachment((UINT8)gubPopupStatusIndex, guiPopupItemPos); // try to attach it + gpItemPointer = NULL; // and drop it + + gItemDescAttachmentPopups[giActiveAttachmentPopup]->hide(); + RenderItemDescriptionBox(); + giActiveAttachmentPopup = -1; + + //UpdateAttachmentTooltips(gpItemDescObject, gubItemDescStatusIndex); + return; + + } + } + +} + +bool popupCallbackItemInSector(INT16 itemId){ + for(UINT16 i = 0; i < pInventoryPoolList.size(); i++) + if( pInventoryPoolList[i].object.usItem == itemId ) return true; + + return false; +} + +void hideAttachmentPopup(){ + giActiveAttachmentPopup = -1; + + if (giInvDescTabButton[0] != giItemDescAmmoButton) + ShowButton(giItemDescAmmoButton); +} + +void hideOtherAttachmentPopups(UINT32 cnt){ + + // if there's a bullet icon, hide it. It tends to overlap my popup boxes + if (giInvDescTabButton[0] != giItemDescAmmoButton) + HideButton(giItemDescAmmoButton); + + RenderItemDescriptionBox(); // also, redraw the IDB to clean up helptext + + if( cnt > MAX_ATTACHMENTS ) return; + + for(UINT32 i = 0; i < cnt; i++){ + if (gItemDescAttachmentPopups[i] != NULL) + gItemDescAttachmentPopups[i]->hide(); + } +} + + + BOOLEAN AttemptToAddSubstring( STR16 zDest, STR16 zTemp, UINT32 * puiStringLength, UINT32 uiPixLimit ) { UINT32 uiRequiredStringLength, uiTempStringLength; @@ -3592,6 +3664,7 @@ BOOLEAN InternalInitItemDescriptionBox( OBJECTTYPE *pObject, INT16 sX, INT16 sY, } //CHRISL: This function is designed to recreate the attachment tooltips +extern BOOLEAN CanPlayerUseSectorInventory( SOLDIERTYPE *pSelectedSoldier ); void UpdateAttachmentTooltips(OBJECTTYPE *pObject, UINT8 ubStatusIndex) { UINT32 slotCount = 0; @@ -3609,11 +3682,19 @@ void UpdateAttachmentTooltips(OBJECTTYPE *pObject, UINT8 ubStatusIndex) std::vector usAttachmentSlotIndexVector = GetItemSlots(pObject); //start by deleting the currently defined regions if they exist + //BOB : also, clean up the popup boxes (in case they're still around) + // and init them to NULL in case they contain garbage for (INT32 cnt = 0; cnt < MAX_ATTACHMENTS; cnt++ ) { if( gItemDescAttachmentRegions[cnt].IDNumber != 0 ) MSYS_RemoveRegion( &gItemDescAttachmentRegions[cnt]); + + if( gItemDescAttachmentPopupsInitialized && gItemDescAttachmentPopups[cnt] != NULL ){ + delete(gItemDescAttachmentPopups[cnt]); + } + gItemDescAttachmentPopups[cnt] = NULL; } + gItemDescAttachmentPopupsInitialized = TRUE; //now, create new regions for (slotCount = 0; ;++slotCount ) @@ -3711,6 +3792,47 @@ void UpdateAttachmentTooltips(OBJECTTYPE *pObject, UINT8 ubStatusIndex) } } } + BOOLEAN showAttachmentPopups = FALSE; + + if( guiCurrentItemDescriptionScreen == MAP_SCREEN + && fShowMapInventoryPool + && ( (Menptr[ gCharactersList[ bSelectedInfoChar ].usSolID ].sSectorX == sSelMapX ) + && ( Menptr[ gCharactersList[ bSelectedInfoChar ].usSolID ].sSectorY == sSelMapY ) + && ( Menptr[ gCharactersList[ bSelectedInfoChar ].usSolID ].bSectorZ == iCurrentMapSectorZ ) + ) + && CanPlayerUseSectorInventory( &Menptr[ gCharactersList[ bSelectedInfoChar ].usSolID ] ) + ) + { + showAttachmentPopups = TRUE; + } + + // create quick attachment popup boxes here + if (showAttachmentPopups) + { + gItemDescAttachmentPopups[slotCount] = new POPUP("Attachment list"); // init attachment popup for this slot + + UINT8 thisPopupsPositionType; + if ( gsInvDescX + gItemDescAttachmentsXY[slotCount].sX < 170 && gsInvDescY + gItemDescAttachmentsXY[slotCount].sY < 180 ){ + thisPopupsPositionType = POPUP_POSITION_TOP_LEFT; + } else if ( gsInvDescX + gItemDescAttachmentsXY[slotCount].sX > 170 && gsInvDescY + gItemDescAttachmentsXY[slotCount].sY < 180 ){ + thisPopupsPositionType = POPUP_POSITION_TOP_RIGHT; + } else if ( gsInvDescX + gItemDescAttachmentsXY[slotCount].sX > 170 && gsInvDescY + gItemDescAttachmentsXY[slotCount].sY > 180 ){ + thisPopupsPositionType = POPUP_POSITION_BOTTOM_RIGHT; + } else if ( gsInvDescX + gItemDescAttachmentsXY[slotCount].sX < 170 && gsInvDescY + gItemDescAttachmentsXY[slotCount].sY > 180 ){ + thisPopupsPositionType = POPUP_POSITION_BOTTOM_LEFT; + } else { + thisPopupsPositionType = POPUP_POSITION_TOP_LEFT; + } + + gItemDescAttachmentPopups[slotCount]->setPosition( (gsInvDescX + gItemDescAttachmentsXY[slotCount].sX) + 12 , + /* Put it near the current slot */ (gsInvDescY + gItemDescAttachmentsXY[slotCount].sY) + 32 , + thisPopupsPositionType ); + + // the show callback should redraw the description box (in case we had any helptext and close other attachment popups) + gItemDescAttachmentPopups[slotCount]->setCallback( POPUP_CALLBACK_SHOW, new popupCallbackFunction( &hideOtherAttachmentPopups, usAttachmentSlotIndexVector.size() ) ); + // the hide callback tells the program we're no longer displaying an attachment callback + gItemDescAttachmentPopups[slotCount]->setCallback( POPUP_CALLBACK_HIDE, new popupCallbackFunction( &hideAttachmentPopup ) ); + } for(UINT16 loop = 0; loop < attachList.size(); loop++){ usAttachment = attachList[loop]; // If the attachment is not hidden @@ -3728,6 +3850,36 @@ void UpdateAttachmentTooltips(OBJECTTYPE *pObject, UINT8 ubStatusIndex) swprintf( attachStr2, L"\n%s", Item[ usAttachment ].szItemName ); wcscat( attachStr3, attachStr2); } + + if (showAttachmentPopups) + { // add the current attachment to the popup assigned to this attachment slot + POPUP_OPTION * o = new POPUP_OPTION( &std::wstring( Item[ usAttachment ].szItemName ), + new popupCallbackFunction(&popupCallbackItem,usAttachment)); + // set an availiability callback to gray out any compatible attachments not found in this sector + o->setAvail( new popupCallbackFunction(&popupCallbackItemInSector,usAttachment) ); + + if (loop == 11 && attachList.size() > 11){ // if there's too much stuff to list, we create a subpopup for the rest + gItemDescAttachmentPopups[slotCount]->addSubMenuOption( &std::wstring(L"More...") ); + POPUP_SUB_POPUP_OPTION * tmp = gItemDescAttachmentPopups[slotCount]->getSubPopupOption(0); + + // positioning sub popups is handled through the option that holds them + tmp->setPopupPosition( (gsInvDescX + gItemDescAttachmentsXY[slotCount].sX), + (gsInvDescY + gItemDescAttachmentsXY[slotCount].sY) + 32 , + POPUP_POSITION_TOP_RIGHT); // put it to the right of the main box + + // hide the other box too + // note that we're working with the sub popup options's sub-popup here, not the option itself + tmp->subPopup->setCallback( POPUP_CALLBACK_HIDE, new popupCallbackFunction( &hideOtherAttachmentPopups, usAttachmentSlotIndexVector.size() ) ); + + // finally add the option + tmp->subPopup->addOption(*o); + + } else if (loop > 11){ // add surplus options to the subpopup + gItemDescAttachmentPopups[slotCount]->getSubPopupOption(0)->subPopup->addOption(*o); + } else { // options 0-11 go into the main popup + gItemDescAttachmentPopups[slotCount]->addOption(*o); + } + } } } @@ -4159,7 +4311,22 @@ void ItemDescAttachmentsCallback( MOUSE_REGION * pRegion, INT32 iReason ) UpdateItemHatches(); } + + // BOB : show the quick attachment popup + } else if( guiCurrentItemDescriptionScreen == MAP_SCREEN // if we're in the map screen + && fShowMapInventoryPool // and are viweing the sector inventory + && !pAttachment->exists() // and the clicked attachment slot is empty + && gItemDescAttachmentPopupsInitialized && gItemDescAttachmentPopups[uiItemPos] != 0 ) { // and the popup exists + + // the popup slot that is going to be displayed + giActiveAttachmentPopup = uiItemPos; + // which slot was this ? No better (simple) way to let the callbacks know. + gubPopupStatusIndex = (UINT8)ubStatusIndex; + guiPopupItemPos = uiItemPos; + + return; // and leave before UpdateAttachmentTooltips overwrites the popup } + if(gpItemDescObject != NULL) { InitDescStatCoords(gpItemDescObject); @@ -5655,7 +5822,15 @@ void DeleteItemDescriptionBox( ) for ( cnt = 0; cnt < (INT32)(*gpItemDescObject)[0]->attachments.size(); cnt++ ) { MSYS_RemoveRegion( &gItemDescAttachmentRegions[cnt]); + + //BOB : also, clean up the popup boxes + if( gItemDescAttachmentPopupsInitialized && gItemDescAttachmentPopups[cnt] != NULL ){ + delete(gItemDescAttachmentPopups[cnt]); + gItemDescAttachmentPopups[cnt] = NULL; + } } + + giActiveAttachmentPopup = -1; } } else diff --git a/Tactical/Interface Items.h b/Tactical/Interface Items.h index 221c45c0..5fe62ddd 100644 --- a/Tactical/Interface Items.h +++ b/Tactical/Interface Items.h @@ -3,6 +3,7 @@ #include "items.h" #include "Handle Items.h" +#include "popup_class.h" // DEFINES FOR ITEM SLOT SIZES IN PIXELS #define BIG_INV_SLOT_WIDTH 61 @@ -304,4 +305,15 @@ INT16 CycleItems( INT16 usOldItem ); BOOLEAN InitializeStealItemPickupMenu( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pOpponent, ITEM_POOL *pItemPool, UINT8 ubCount); +// BOB : quick attachment selection popups +extern POPUP* gItemDescAttachmentPopups[MAX_ATTACHMENTS]; // popup list for attachment slots +extern INT32 giActiveAttachmentPopup; // the attachment popup to display in mapscreen + +// BOB : quick equip popups +extern POPUP* gEquipPopups[NUM_INV_SLOTS]; // popup list for attachment slots +extern INT32 giActiveEquipPopup; // the attachment popup to display in mapscreen + +// BOB : duh... +void DoAttachment( UINT8 subObject, INT32 iItemPos ); + #endif diff --git a/Utils/Utils_VS2005.vcproj b/Utils/Utils_VS2005.vcproj index c43e03eb..3b53a4b0 100644 --- a/Utils/Utils_VS2005.vcproj +++ b/Utils/Utils_VS2005.vcproj @@ -454,6 +454,14 @@ RelativePath=".\Music Control.h" > + + + + @@ -680,6 +688,10 @@ RelativePath=".\Music Control.cpp" > + + diff --git a/Utils/Utils_VS2008.vcproj b/Utils/Utils_VS2008.vcproj index fafecee4..a414fa5a 100644 --- a/Utils/Utils_VS2008.vcproj +++ b/Utils/Utils_VS2008.vcproj @@ -458,6 +458,14 @@ RelativePath="Music Control.h" > + + + + @@ -682,6 +690,10 @@ RelativePath="Music Control.cpp" > + + diff --git a/Utils/Utils_VS2010.vcxproj b/Utils/Utils_VS2010.vcxproj index b578f2b2..d54398e8 100644 --- a/Utils/Utils_VS2010.vcxproj +++ b/Utils/Utils_VS2010.vcxproj @@ -45,6 +45,8 @@ + + @@ -92,6 +94,7 @@ + diff --git a/Utils/Utils_VS2010.vcxproj.filters b/Utils/Utils_VS2010.vcxproj.filters index 0acf8db6..678a0600 100644 --- a/Utils/Utils_VS2010.vcxproj.filters +++ b/Utils/Utils_VS2010.vcxproj.filters @@ -147,6 +147,8 @@ Header Files + + @@ -317,5 +319,6 @@ Source Files + \ No newline at end of file diff --git a/Utils/popup_callback.h b/Utils/popup_callback.h new file mode 100644 index 00000000..00af54b0 --- /dev/null +++ b/Utils/popup_callback.h @@ -0,0 +1,171 @@ +#ifndef POPUP_CALLBACK_CLASS + #define POPUP_CALLBACK_CLASS + + class popupCallback; + + template class popupCallbackFunction; + + class popupCallback{ + public: + popupCallback(void){} + ~popupCallback(void){} + + virtual void bind(void* newFun) = 0; + virtual bool call(void) = 0; + }; + + template + class popupCallbackFunction : public popupCallback{ + protected: + R (*fun)(P1); + P1 param_1; + public: + popupCallbackFunction(void); + popupCallbackFunction(void * newFun, P1 param); + virtual void bind(void * newFun); + virtual bool call(void); + }; + + template + popupCallbackFunction::popupCallbackFunction(void){ + this->fun = 0; + this->param_1 = P1(); + }; + + template + popupCallbackFunction::popupCallbackFunction(void * newFun, P1 param){ + this->fun = static_cast< R(*)(P1)>(newFun); + this->param_1 = param; + }; + + template + void popupCallbackFunction::bind(void * newFun){ + this->fun = static_cast< R(*)(P1)>(newFun); + }; + + template + bool popupCallbackFunction::call(void){ + return (bool)(this->fun)(this->param_1); + } + + // no return type, one parameter + template + class popupCallbackFunction : public popupCallback{ + protected: + void (*fun)(P1); + P1 param_1; + public: + popupCallbackFunction(void); + popupCallbackFunction(void * newFun, P1 param); + virtual void bind(void * newFun); + virtual bool call(void); + }; + + template + popupCallbackFunction::popupCallbackFunction(void){ + this->fun = 0; + this->param_1 = P1(); + }; + + template + popupCallbackFunction::popupCallbackFunction(void * newFun, P1 param){ + this->fun = static_cast< void(*)(P1)>(newFun); + this->param_1 = param; + }; + + template + void popupCallbackFunction::bind(void * newFun){ + this->fun = static_cast< void(*)(P1)>(newFun); + }; + + + template + bool popupCallbackFunction::call(void){ + try { + (this->fun)(this->param_1); + } catch (...) { + return false; + } + return true; + } + + // returns something, no parameter + template + class popupCallbackFunction : public popupCallback{ + protected: + R (*fun)(void); + public: + popupCallbackFunction(void); + popupCallbackFunction(void * newFun); + virtual void bind(void * newFun); + virtual bool call(void); + }; + + template + popupCallbackFunction::popupCallbackFunction(void){ + this->fun = 0; + }; + + template + popupCallbackFunction::popupCallbackFunction(void * newFun){ + this->fun = static_cast< R(*)(void)>(newFun); + }; + + template + void popupCallbackFunction::bind(void * newFun){ + this->fun = static_cast< R(*)(void)>(newFun); + }; + + template + bool popupCallbackFunction::call(void){ + return (bool)(this->fun)(); + } + + + //template<> + //bool popupCallbackFunction::call(void){ + // return (this->fun)(); + //} + + // no parameters/return types + template <> + class popupCallbackFunction : public popupCallback{ + protected: + void (*fun)(void); + public: + popupCallbackFunction(void){ + this->fun = 0; + }; + popupCallbackFunction(void * newFun){ + this->fun = static_cast< void(*)(void)>(newFun); + }; + virtual void bind(void * newFun){ + this->fun = static_cast< void(*)(void)>(newFun); + }; + virtual bool call(void){ + try { + (this->fun)(); + } catch (...) { + return false; + } + return true; + }; + }; + + class popupCallbackLua : public popupCallback{ + protected: + CHAR16 * functionName; + public: + popupCallbackLua(void); + popupCallbackLua(CHAR16 * newFunctionName){ + this->functionName = newFunctionName; + }; + virtual void bind(void * newFun){ + this->functionName = static_cast< CHAR16* >(newFun); + }; + virtual bool call(void){ + return true; + }; + }; + +#endif \ No newline at end of file diff --git a/Utils/popup_class.cpp b/Utils/popup_class.cpp new file mode 100644 index 00000000..1f7d41b1 --- /dev/null +++ b/Utils/popup_class.cpp @@ -0,0 +1,1655 @@ + #include "Map Screen Interface.h" + #include "popupbox.h" + #include "interface control.h" + #include "renderworld.h" + #include "Text.h" + #include "utilities.h" + #include "Interface.h" + #include "GameSettings.h" + #include "Input.h" + + #include "Console.h" + #include "lwstring.h" + #include "message.h" + #include "mousesystem.h" + + #include "Lua Interpreter.h" + #include "popup_callback.h" + #include "popup_class.h" + + ////////////////////////////////////////////////////////////////// + // functions and variable declarations for binding the class with C callbacks +////////////////////////////////////////////////////////////////// + +vector gPopupRegionIndex; +vector gPopupIndex; +UINT32 gPopupRegionIndexCounter = 0; +UINT32 gPopupIndexCounter = 0; +UINT32 POPUP::nextid = 0; + +UINT32 POPUP::uiPOPUPBORDERS = 0; +UINT32 POPUP::uiPOPUPTEX = 0; + + +/////////////////////// +// Lua vars +///////////////// + +BOOLEAN gfPopupInit = FALSE; + +POPUP * gPopup; // single popup + +/////////////////////// +// Lua Popup functions +///////////////// + +void initPopupIndex(void) +{ + /* + int i; + for (i=0; i~POPUP(); + gPopupIndex[i] = NULL; + } + } +*/ +} + +POPUP * findPopupInIndex( UINT32 cID ) +{ + for(std::vector::iterator cPopup=gPopupIndex.begin(); cPopup != gPopupIndex.end(); ++cPopup) + if ((*cPopup)->id == cID){ + return (*cPopup); + } + + #ifdef JA2TESTVERSION + CHAR8 debugStr[120]; + wsprintf(debugStr,"Failed to find popup id: %i \n",cID); + OutputDebugString( debugStr ); + #endif + + return NULL; +} + +void rebuildPopupIndex(void) +{ + /*UINT8 i,j; + POPUP* TempPopupIndex[MAX_POPUPS]; + //cout << "cleaning index"<name = L"unnamed option"; + + this->action = 0; + this->avail = 0; + this->hover = 0; +} + +POPUP_OPTION::~POPUP_OPTION(void) +{ + if(this->action) delete(this->action); + if(this->avail) delete(this->avail); + if(this->hover) delete(this->hover); +} + + +POPUP_OPTION::POPUP_OPTION(std::wstring *newName, popupCallback * newFunction) +{ + this->name = *newName; + + this->action = newFunction; + this->avail = 0; + this->hover = 0; +} + +BOOLEAN POPUP_OPTION::setName( WCHAR* newName ) +{ + this->name = newName; + return TRUE; +} + +BOOLEAN POPUP_OPTION::setAction( popupCallback *fun ) +{ + this->action = fun; + + return TRUE; +} + +BOOLEAN POPUP_OPTION::setAvail( popupCallback *fun ) +{ + this->avail = fun; + + return TRUE; +} + +BOOLEAN POPUP_OPTION::setHover( popupCallback *fun ) +{ + this->hover = fun; + + return TRUE; +} + + +BOOLEAN POPUP_OPTION::checkAvailability() +{ + if (this->avail != 0) + return ( this->avail->call() == true ); + else + return true; +} + +BOOLEAN POPUP_OPTION::runHoverCallback(MOUSE_REGION * pRegion) +{ + // TODO: pass the mouse region data to the function (if it can accept it) + if (this->hover != 0) + return ( this->hover->call() == true ); + else + return true; +} + +BOOLEAN POPUP_OPTION::run() +{ + // check if it's aaliable at this time + if ( this->action != 0 && this->checkAvailability() ) + { + this->action->call(); + + return TRUE; + } + else + return FALSE; +} + +BOOLEAN POPUP_OPTION::forceRun() +{ + if (this->action != 0) + this->action->call(); + else + return FALSE; + + return TRUE; +} + + ////////////////////////////////////////////////////////////////// + // POPUP_SUB_POPUP_OPTION methods +////////////////////////////////////////////////////////////////// + +// constructor +POPUP_SUB_POPUP_OPTION::POPUP_SUB_POPUP_OPTION(void) : POPUP_OPTION() +{ + this->initSubPopup(); +} + +POPUP_SUB_POPUP_OPTION::POPUP_SUB_POPUP_OPTION(wstring* newName, const POPUP * parent) : POPUP_OPTION(newName, 0) +{ + this->parent = parent; + this->initSubPopup(); +} + +// destructor +POPUP_SUB_POPUP_OPTION::~POPUP_SUB_POPUP_OPTION(void) +{ + +} + +void POPUP_SUB_POPUP_OPTION::showPopup() +{ + // check if it's available at this time + if ( this->checkAvailability() ) + { + if (!this->customPositionSet) this->positionSubPopup(); + this->subPopup->show(); + } +} + +void POPUP_SUB_POPUP_OPTION::hidePopup() +{ + this->subPopup->hide(); +} + +void POPUP_SUB_POPUP_OPTION::positionSubPopup() +{ + INT16 x,y; + +// x = this->parent->Position.iX + this->parent->Dimensions.iLeft + this->parent->Dimensions.iRight + 10; + x = this->parent->X + this->parent->Dimensions.iLeft + this->parent->Dimensions.iRight + 10; +// y = this->parent->Position.iY + 10; + y = this->parent->Y + 10; + + this->subPopup->setPosition(x,y); +} + +BOOLEAN POPUP_SUB_POPUP_OPTION::run() +{ + //cout << "running function " << utf8string::as_utf8(this->name.c_str()).c_str() << endl; + this->showPopup(); + + return TRUE; +} + +BOOLEAN POPUP_SUB_POPUP_OPTION::setPopupPosition(UINT16 x, UINT16 y, UINT8 positioningRule){ + this->customPositionSet = true; + + if (positioningRule != POPUP_POSITION_RELATIVE){ + return this->subPopup->setPosition(x,y,positioningRule); + } else { + return this->subPopup->setPosition(this->parent->X + x, this->parent->Y + y,POPUP_POSITION_TOP_LEFT); + } +} + +void POPUP_SUB_POPUP_OPTION::initSubPopup() +{ + this->subPopup = new POPUP( (CHAR*) wstring(this->name).c_str() ); + this->customPositionSet = false; +} + +void POPUP_SUB_POPUP_OPTION::destroySubPopup() +{ + this->subPopup->~POPUP(); +} + + ////////////////////////////////////////////////////////////////// + // POPUP methods +////////////////////////////////////////////////////////////////// + +// constructors +POPUP::POPUP(void) +{ + strcpy((char*) this->name, (char*) "unNamed popup"); + this->optionCount = 0; + + this->addToIndex(); + this->setInitialValues(); +} + + +POPUP::POPUP(CHAR* name) +{ + strcpy((char*) this->name, (char*) name); + this->optionCount = 0; + + this->addToIndex(); + this->setInitialValues(); + + #ifdef JA2TESTVERSION + CHAR8 debugStr[120]; + wsprintf(debugStr,"Created popup: %s \n",this->name); + OutputDebugString( debugStr ); + #endif +} + +// destructor + +POPUP::~POPUP(void) +{ + if(this->PopupVisible) + this->hide(); + + for (UINT16 i = 0; ioptions.size(); i++) + { + this->options[i]->~POPUP_OPTION(); + } + + for (UINT16 i = 0; isubPopupOptions.size(); i++) + { + this->subPopupOptions[i]->subPopup->hide(); + this->subPopupOptions[i]->~POPUP_SUB_POPUP_OPTION(); + } + + #ifdef JA2TESTVERSION + CHAR8 debugStr[120]; + wsprintf(debugStr,"Destroyed popup: %s \n",this->name); + OutputDebugString( debugStr ); + #endif + + this->removeFromIndex(); + + if (this->initCallback) this->initCallback->~popupCallback(); + if (this->ShowCallback) this->ShowCallback->~popupCallback(); + if (this->HideCallback) this->HideCallback->~popupCallback(); + + if (this->EndCallback) { + this->EndCallback->call(); + this->EndCallback->~popupCallback(); + } +} + +// callback handlers + +BOOLEAN POPUP::setCallback(UINT8 type, popupCallback * callback){ + if(callback == NULL) return FALSE; + + switch(type){ + case POPUP_CALLBACK_INIT: + if (this->initCallback) this->initCallback->~popupCallback(); + this->initCallback = callback; + break; + case POPUP_CALLBACK_END: + if (this->EndCallback) this->EndCallback->~popupCallback(); + this->EndCallback = callback; + break; + case POPUP_CALLBACK_SHOW: + if (this->ShowCallback) this->ShowCallback->~popupCallback(); + this->ShowCallback = callback; + break; + case POPUP_CALLBACK_HIDE: + if (this->HideCallback) this->HideCallback->~popupCallback(); + this->HideCallback = callback; + break; + + default: return false; + } + + return true; +} + +BOOLEAN POPUP::isCallbackSet(UINT8 type){ + + switch(type){ + case POPUP_CALLBACK_INIT: if (this->initCallback) return true; break; + case POPUP_CALLBACK_END: if (this->EndCallback) return true; break; + case POPUP_CALLBACK_SHOW: if (this->ShowCallback) return true; break; + case POPUP_CALLBACK_HIDE: if (this->HideCallback) return true; break; + + default: return false; + } + + return false; +} + +// popup index handlers + +BOOLEAN POPUP::addToIndex() +{ + /* + if (gPopupIndexCounter == MAX_POPUPS) + { + rebuildPopupIndex(); // if index full, try to rebuild it before giving up + if (gPopupIndexCounter == MAX_POPUPS) + return FALSE; + } + */ + + // assign the ID and increment the counter. + this->id = this->nextid; + this->nextid++; + + //gPopupIndex[gPopupIndexCounter] = this; + gPopupIndex.push_back( this ); + gPopupIndexCounter++; + + return TRUE; +} + +BOOLEAN POPUP::removeFromIndex() +{ + + for(std::vector::iterator cPopup=gPopupIndex.begin(); cPopup != gPopupIndex.end(); ++cPopup) + if ((*cPopup)->id == this->id){ + gPopupIndex.erase(cPopup); + return TRUE; + } + + #ifdef JA2TESTVERSION + CHAR8 debugStr[120]; + wsprintf(debugStr,"Failed to remove popup from index: %i \n",this->id); + OutputDebugString( debugStr ); + #endif + + return FALSE; +} + +// set defaults + +void POPUP::setInitialValues(void) +{ + this->Position.iX=20; + this->Position.iY=20; + + this->OrigPosition.iX = 0 ; + this->OrigPosition.iY = 0 ; + + this->Dimensions.iLeft=0; + this->Dimensions.iTop=0; + this->Dimensions.iBottom=100; + this->Dimensions.iRight=120; + + this->BoxesX = 20; + this->BoxesY = 20; + + // the x,y position of the pop up in tactical + this->X = 20; + this->Y = 20; + + this->positioningRule = POPUP_POSITION_TOP_LEFT; + + //int i = 0; + //for (i=0; ioptions[i] = NULL; + // //this->MenuRegion[i] = NULL; + //} + + this->PopupVisible = FALSE; + this->FirstClickInScreenMask = FALSE; + this->BoxPersist = FALSE; + + this->subPopupOptionCount = 0; + this->optionCount = 0; + + this->initCallback = NULL; + this->EndCallback = NULL; + this->ShowCallback = NULL; + this->HideCallback = NULL; +} + +// setup functions + +POPUP_OPTION * POPUP::addOption(wstring * name, popupCallback* action) +{ + if (this->optionCount < POPUP_MAX_OPTIONS) + { + this->options.push_back( new POPUP_OPTION ( name, action ) ); + this->optionCount++; + return this->options.back(); + } + else + return NULL; +} +/* +INT16 POPUP::findFreeOptionIndex() +{ + int i; + for (i=0; ioptions[i] == NULL ) + return i; + + return -1; +} +*/ +BOOLEAN POPUP::addOption(POPUP_OPTION &option) +{ + if (this->optionCount < POPUP_MAX_OPTIONS) + { + this->options.push_back( &option ); + optionCount++; + return TRUE; + } + else + return FALSE; + +} + +POPUP_OPTION * POPUP::getOption(UINT16 n) +{ + if (n < this->options.size() && this->options[n]) + return this->options[n]; + + return NULL; +} + +POPUP * POPUP::addSubMenuOption(wstring * name) +{ + if (this->subPopupOptionCount < POPUP_MAX_SUB_POPUPS) + { + this->subPopupOptions.push_back( new POPUP_SUB_POPUP_OPTION ( name, this ) ); + this->subPopupOptionCount++; + return this->subPopupOptions.back()->subPopup; + } + else + return NULL; +} + +POPUP_SUB_POPUP_OPTION * POPUP::getSubPopupOption(UINT8 n) +{ + if (n < this->subPopupOptions.size() && this->subPopupOptions[n]) + return this->subPopupOptions[n]; + else + return NULL; +} + + +BOOLEAN POPUP::setPosition(UINT16 x, UINT16 y, UINT8 positioningRule ) +{ + //TODO: check if the desired position is valid. + + // why the hell are there three sets of box positions ? + this->Position.iX=x; + this->Position.iY=y; + + this->BoxesX = x; + this->BoxesY = y; + + this->X = x; + this->Y = y; + + // make that four + this->OrigPosition.iX = x ; + this->OrigPosition.iY = y ; + + this->positioningRule = positioningRule; + + #ifdef JA2TESTVERSION + CHAR8 debugStr[120]; + wsprintf(debugStr,"Positioning popup %i at (x/y) %i / %i ; positioning rule: %i \n",this->id, x, y, positioningRule); + OutputDebugString( debugStr ); + #endif + + return TRUE; +} + +////////////////////////////////// +// usage functions + +BOOLEAN POPUP::show() +{ + + if (this->PopupVisible) { + // this->RebuildBox(); + return false; + } + + if (this->ShowCallback) this->ShowCallback->call(); + + // can't show an empty popup. + if ( (this->optionCount + this->subPopupOptionCount) == 0) return FALSE; + + // set the box to visible + this->PopupVisible = TRUE; + // should take care of creating the box + this->CreatePopUpBoxes(); + // set the position before creating the screen mask and mouse regions + this->DetermineBoxPositions(); + // create all the GUI areas + this->CreateScreenMask(); + this->CreateMouseRegions(); + // make SURE the regions have been repositioned + this->CheckAndUpdateTacticalPopUpPositions(); + // shade unavaliable options + this->HandleShadingOfLines(); + + #ifdef JA2TESTVERSION + CHAR8 debugStr[120]; + wsprintf(debugStr,"Showing popup id: %i \n",this->boxId); + OutputDebugString( debugStr ); + #endif + + // showtime ! + ShowBox(this->boxId); + + return TRUE; +} + +BOOLEAN POPUP::hide() +{ + if (!this->PopupVisible) { + + #ifdef JA2TESTVERSION + // __debugbreak(); + #else + // Assert(false); + #endif + + return false; + } + + + for (UINT16 i = 0; isubPopupOptions.size(); i++) + { + this->subPopupOptions[i]->subPopup->hide(); + } + + #ifdef JA2TESTVERSION + CHAR8 debugStr[120]; + wsprintf(debugStr,"Hiding popup id: %i \n",this->boxId); + OutputDebugString( debugStr ); + #endif + + this->DestroyMouseRegions(); + this->DestroyScreenMask(); + + HideBox(this->boxId); + RemoveBox(this->boxId); + + this->DestroyPopUpBoxes(); + + this->boxId = -1; + this->PopupVisible = FALSE; + + if (this->HideCallback) this->HideCallback->call(); + + return TRUE; +} + +BOOLEAN POPUP::callOption(int optIndex) +{ + if ( this->optionCount > 0 + && optIndex < 32 + && optIndex < optionCount + && optIndex >= 0) + { + return this->options[optIndex]->run(); + } + else + return FALSE; + +} + +BOOLEAN POPUP::forceDraw(){ + + if (!this->PopupVisible) { + // set the box to visible + this->PopupVisible = TRUE; + // should take care of creating the box + this->CreatePopUpBoxes(); + // set the position before creating the screen mask and mouse regions + this->DetermineBoxPositions(); + // create all the GUI areas + this->CreateScreenMask(); + this->CreateMouseRegions(); + // make SURE the regions have been repositioned + this->CheckAndUpdateTacticalPopUpPositions(); + // shade unavaliable options + this->HandleShadingOfLines(); + + + // showtime ! + ShowBox(this->boxId); + } else { + this->RebuildBox(); + } + + DisplayOnePopupBox(this->boxId, FRAME_BUFFER); + ForceUpDateOfBox(this->boxId); + + return true; +} + +//////////////////////////// +// private utility functions + +////// +// external flag access functions +////// + +BOOLEAN POPUP::TeamPanelDirty(void) +{ + extern BOOLEAN fTeamPanelDirty; + return fTeamPanelDirty; +} +BOOLEAN POPUP::CharacterInfoPanelDirty(void) +{ + extern BOOLEAN fCharacterInfoPanelDirty; + return fCharacterInfoPanelDirty; +} +BOOLEAN POPUP::MapScreenBottomDirty(void) +{ + extern BOOLEAN fMapScreenBottomDirty; + return fMapScreenBottomDirty; +} +BOOLEAN POPUP::RenderPBInterface(void) +{ + extern BOOLEAN gfRenderPBInterface ; + return gfRenderPBInterface ; +} + + +void POPUP::setTeamPanelDirty(BOOLEAN flag ) +{ + extern BOOLEAN fTeamPanelDirty; + fTeamPanelDirty = flag; +} +void POPUP::setCharacterInfoPanelDirty(BOOLEAN flag ) +{ + extern BOOLEAN fCharacterInfoPanelDirty; + fCharacterInfoPanelDirty = flag; +} +void POPUP::setMapScreenBottomDirty(BOOLEAN flag ) +{ + extern BOOLEAN fMapScreenBottomDirty; + fMapScreenBottomDirty = flag; +} +void POPUP::setRenderPBInterface(BOOLEAN flag ) +{ + extern BOOLEAN gfRenderPBInterface ; + gfRenderPBInterface = flag; +} + + + +////// +// internal box setup methods +////// + +// rewrites all the text lines in the box and adjusts +// the box's size and mouse regions to potential changes +// less expensive then hide();show(); +void POPUP::RebuildBox( void ) +{ if ( this->boxId != -1 && this->id < POPUP::nextid ) + { + // make sure we're working with the right popup! + SetCurrentBox( this->boxId ); + + // remove all the 'old' text from the box + RemoveAllCurrentBoxStrings(); + + // add the sub popups (they go first) + this->AddSubPopupStrings(); + + // add the options + this->AddOptionStrings(); + + // set fonts and what not + this->UpdateTextProperties(); + + // adjust the mouse regions (might've changed substantially) + this->AdjustMouseRegions(); + + // shade/unshade accordingly + this->HandleShadingOfLines(); + } else if ( this->id > POPUP::nextid ) { + // chances are buggered up data will have impossible boxid + + #ifdef JA2TESTVERSION + __debugbreak(); + #else + Assert(false); + #endif + } +} + +BOOLEAN POPUP::CreateBox() +{ + // this->Position.iX = this->OrigPosition.iX; + + if( giBoxY != 0 ) + { + this->Position.iY = giBoxY; + } + + // create basic box + CreatePopUpBox(&this->boxId, this->Dimensions, this->Position, (POPUP_BOX_FLAG_CLIP_TEXT|POPUP_BOX_FLAG_CENTER_TEXT|POPUP_BOX_FLAG_RESIZE )); + + // which buffer will box render to + SetBoxBuffer(this->boxId, FRAME_BUFFER); + + // border type? + SetBorderType(this->boxId,POPUP::uiPOPUPBORDERS); + + // background texture + SetBackGroundSurface(this->boxId, POPUP::uiPOPUPTEX); + + // margin sizes + SetMargins(this->boxId, 6, 6, 4, 4 ); + + // space between lines + SetLineSpace(this->boxId, 2); + + // set current box to this one + SetCurrentBox( this->boxId ); + + + // add the sub popups (they go first) + + this->AddSubPopupStrings(); + + // add the options + + this->AddOptionStrings(); + + // set fonts and what not + + this->UpdateTextProperties(); + + //UpdateMapScreenthis->Positions(); + + return TRUE; +} + +void POPUP::AddSubPopupStrings() +{ + UINT32 hStringHandle; + CHAR16 sString[ 128 ]; + + if (this->subPopupOptionCount > 0) + + for(std::vector::iterator cOption=this->subPopupOptions.begin(); cOption != this->subPopupOptions.end(); ++cOption) + { + swprintf( sString, (*cOption)->name.c_str() ); + + AddMonoString((UINT32 *)&hStringHandle, sString ); + + // make sure it is unhighlighted + UnHighLightLine(hStringHandle); + } +} + +void POPUP::AddOptionStrings() +{ + UINT32 hStringHandle; + CHAR16 sString[ 128 ]; + + if (this->optionCount > 0) + for(std::vector::iterator cOption=this->options.begin(); cOption != this->options.end(); ++cOption) + { + swprintf( sString, (*cOption)->name.c_str() ); + + AddMonoString((UINT32 *)&hStringHandle, sString ); + + // make sure it is unhighlighted + UnHighLightLine(hStringHandle); + } +} + + +void POPUP::UpdateTextProperties() +{ + // set font type + SetBoxFont(this->boxId, MAP_SCREEN_FONT); + + // set highlight color + SetBoxHighLight(this->boxId, FONT_WHITE); + + // unhighlighted color + SetBoxForeground(this->boxId, FONT_LTGREEN); + + // background color + SetBoxBackground(this->boxId, FONT_BLACK); + + // shaded color..for darkened text + SetBoxShade( this->boxId, FONT_GRAY7 ); + + // is this for the second row ? + SetBoxSecondaryShade( this->boxId, FONT_YELLOW ); + + // resize box to text + ResizeBoxToText( this->boxId ); +} + +BOOLEAN POPUP::CreateDestroyPopUpBoxes( void ) +{ + static BOOLEAN fCreated = FALSE; + BOOLEAN returnStatus = TRUE; + + if( ( this->PopupVisible == TRUE ) && ( fCreated == FALSE ) ) + { + returnStatus = this->CreatePopUpBoxes(); + fCreated = TRUE; + } + else if( ( this->PopupVisible == FALSE ) && ( fCreated == TRUE ) ) + { + returnStatus = this->DestroyPopUpBoxes(); + fCreated = FALSE; + } + + + return( returnStatus ); +} + +BOOLEAN POPUP::CreatePopUpBoxes() +{ + VSURFACE_DESC vs_desc; + VOBJECT_DESC VObjectDesc; + + // load textures + VObjectDesc.fCreateFlags=VOBJECT_CREATE_FROMFILE; + FilenameForBPP("INTERFACE\\popup.sti", VObjectDesc.ImageFile); + CHECKF(AddVideoObject(&VObjectDesc, &POPUP::uiPOPUPBORDERS)); + + vs_desc.fCreateFlags = VSURFACE_CREATE_FROMFILE | VSURFACE_SYSTEM_MEM_USAGE; + strcpy(vs_desc.ImageFile, "INTERFACE\\popupbackground.pcx"); + CHECKF(AddVideoSurface(&vs_desc, &POPUP::uiPOPUPTEX)); + + // does some other stff + this->CreateBox(); + + return TRUE; +} + +BOOLEAN POPUP::DestroyPopUpBoxes() +{ + if ( gPopupIndex.size() < 2 ){ + DeleteVideoObjectFromIndex(POPUP::uiPOPUPBORDERS); + DeleteVideoSurfaceFromIndex(POPUP::uiPOPUPTEX); + } + + gfIgnoreScrolling = FALSE; + return TRUE; +} + +void POPUP::CreateDestroyScreenMask( void ) +{ + static BOOLEAN fCreated = FALSE; + + // not created, create + if( ( fCreated == FALSE ) ) + { + this->CreateScreenMask(); + fCreated = TRUE; + } + else if( ( fCreated == TRUE ) ) + { + this->DestroyScreenMask(); + fCreated = FALSE; + } + + return; +} + +void POPUP::CreateScreenMask( void ) +{ +/* void (POPUP::*ScreenMaskBtnCallbackMethod) (MOUSE_REGION *, INT32 ); + ScreenMaskBtnCallbackMethod = &POPUP::ScreenMaskBtnCallback; +*/ + // will create a screen mask to catch mouse input to disable LPC menus + + + MSYS_DefineRegion( &this->ScreenMaskRegion, + 0, + 0, + SCREEN_WIDTH, + SCREEN_HEIGHT, + POPUP_SCREEN_MASK_PRIORITY , + MSYS_NO_CURSOR, + MSYS_NO_CALLBACK, + popupMaskCallback ); + + // if in tactical... + if ( !(guiTacticalInterfaceFlags & INTERFACE_MAPSCREEN) ) + MSYS_ChangeRegionCursor( &this->ScreenMaskRegion, 0 ); + + if (!registerPopupRegion( this->ScreenMaskRegion.IDNumber, this->id)){ + #ifdef JA2TESTVERSION + CHAR8 debugStr[120]; + wsprintf(debugStr,"Failed to register screen mask for box id: %i \n",this->boxId); + OutputDebugString( debugStr ); + #endif + } + + + return; +} + +void POPUP::DestroyScreenMask( void ) +{ + unregisterPopupRegion(this->ScreenMaskRegion.IDNumber); // unregister it before removing it + // otherwise the ID might get lost somewhere + MSYS_RemoveRegion( &this->ScreenMaskRegion ); + return; +} + + + +void POPUP::CreateDestroyMouseRegions( void ) +{ + static BOOLEAN fCreated = FALSE; + + if( ( this->PopupVisible == TRUE ) && ( fCreated == FALSE ) ) + { + this->CreateMouseRegions(); + fCreated = TRUE; + } + else if( ( this->PopupVisible == FALSE ) && ( fCreated == TRUE ) ) + { + this->DestroyMouseRegions(); + fCreated = FALSE; + } +} + +void POPUP::CreateMouseRegions( void ) +{ + UINT32 iCounter = 0; + UINT32 iTotal = 0; + INT32 iFontHeight = 0; + INT32 iBoxXPosition = 0; + INT32 iBoxYPosition = 0; + SGPPoint pPosition={0,0}; + INT32 iBoxWidth = 0; + SGPRect pDimensions={0,0,0,0}; + static BOOLEAN fShowRemoveMenu = FALSE; + + gfIgnoreScrolling = FALSE; + + if( ( guiCurrentScreen == MAP_SCREEN ) ) + { + SetBoxPosition( this->boxId, this->Position ); + } + + // grab height of font + iFontHeight = GetLineSpace( this->boxId ) + GetFontHeight( GetBoxFont( this->boxId ) ); + + // get x.y position of box + GetBoxPosition( this->boxId, &pPosition); + + // grab box x and y position + iBoxXPosition = pPosition.iX; + iBoxYPosition = pPosition.iY; + + // get dimensions..mostly for width + GetBoxSize( this->boxId, &pDimensions ); + + // get width + iBoxWidth = pDimensions.iRight; + + SetCurrentBox( this->boxId ); + + // define regions for sub popups + for( iCounter = 0; iCounter < this->subPopupOptionCount ; iCounter++ ) + { + // add mouse region for each line of text..and set user data + + MSYS_DefineRegion( &this->MenuRegion[ iTotal ], + ( INT16 )( iBoxXPosition ), + ( INT16 )( iBoxYPosition + GetTopMarginSize( this->boxId ) + + ( iFontHeight ) * iTotal ), + ( INT16 )( iBoxXPosition + iBoxWidth ), + ( INT16 )( iBoxYPosition + GetTopMarginSize( this->boxId ) + + ( iFontHeight ) * ( iTotal + 1 ) ), + POPUP_OPTION_PRIORITY , + MSYS_NO_CURSOR, + popupMouseMoveCallback, + popupMouseClickCallback ); + + MSYS_SetRegionUserData( &this->MenuRegion[ iTotal ], 0, iCounter ); + MSYS_SetRegionUserData( &this->MenuRegion[ iTotal ], 1, REGION_SUB_POPUP ); + MSYS_SetRegionUserData( &this->MenuRegion[ iTotal ], 2, iTotal ); + + if (!registerPopupRegion( this->MenuRegion[ iTotal ].IDNumber, this->id)){} + + iTotal++; + } + + // define regions for options + for( iCounter = 0; iCounter < this->optionCount ; iCounter++ ) + { + // add mouse region for each line of text..and set user data + + MSYS_DefineRegion( &this->MenuRegion[ iTotal ], + ( INT16 )( iBoxXPosition ), + ( INT16 )( iBoxYPosition + GetTopMarginSize( this->boxId ) + ( iFontHeight ) * iTotal ), + ( INT16 )( iBoxXPosition + iBoxWidth ), + ( INT16 )( iBoxYPosition + GetTopMarginSize( this->boxId ) + ( iFontHeight ) * ( iTotal + 1 ) ), + POPUP_OPTION_PRIORITY , + MSYS_NO_CURSOR, + popupMouseMoveCallback, + popupMouseClickCallback ); + + MSYS_SetRegionUserData( &this->MenuRegion[ iTotal ], 0, iCounter ); + MSYS_SetRegionUserData( &this->MenuRegion[ iTotal ], 1, REGION_OPTION ); + MSYS_SetRegionUserData( &this->MenuRegion[ iTotal ], 2, iTotal ); + + if (!registerPopupRegion( this->MenuRegion[ iTotal ].IDNumber, this->id)){} + + iTotal++; + } + + + + // unhighlight all strings in box + UnHighLightBox( this->boxId ); + this->CheckAndUpdateTacticalPopUpPositions(); +} + +void POPUP::DestroyMouseRegions( void ) +{ + UINT32 iCounter = 0; + + for( iCounter = 0; iCounter < GetNumberOfLinesOfTextInBox( this->boxId ); iCounter++ ) + { + unregisterPopupRegion(this->MenuRegion[ iCounter ].IDNumber); + MSYS_RemoveRegion( &this->MenuRegion[ iCounter ] ); + } + + SetRenderFlags( RENDER_FLAG_FULL ); +} + +void POPUP::AdjustMouseRegions( void ) +{ + UINT32 iCounter = 0; + UINT32 iTotal = 0; + + INT32 iFontHeight = 0; + INT32 iBoxXPosition = 0; + INT32 iBoxYPosition = 0; + INT32 iBoxWidth = 0; + + SGPPoint pPosition={0,0}; + SGPRect pDimensions={0,0,0,0}; + + // grab height of font + iFontHeight = GetLineSpace( this->boxId ) + GetFontHeight( GetBoxFont( this->boxId ) ); + + // get x.y position of box + GetBoxPosition( this->boxId, &pPosition); + + // grab box x and y position + iBoxXPosition = pPosition.iX; + iBoxYPosition = pPosition.iY; + + // get dimensions..mostly for width + GetBoxSize( this->boxId, &pDimensions ); + + // get width + iBoxWidth = pDimensions.iRight; + + // adjust regions for sub popups + for( iCounter = 0; iCounter < this->subPopupOptionCount ; iCounter++ ) + { + this->MenuRegion[ iTotal ].RegionTopLeftX = ( INT16 )( iBoxXPosition ); + this->MenuRegion[ iTotal ].RegionTopLeftY = ( INT16 )( iBoxYPosition + + GetTopMarginSize( this->boxId ) + + ( iFontHeight ) * iTotal ); + + this->MenuRegion[ iTotal ].RegionBottomRightX = ( INT16 )( iBoxXPosition + iBoxWidth ); + this->MenuRegion[ iTotal ].RegionBottomRightY = ( INT16 )( iBoxYPosition + + GetTopMarginSize( this->boxId ) + + ( iFontHeight ) * ( iTotal + 1 ) ); + iTotal++; + } + + // adjust regions for options + for( iCounter = 0; iCounter < this->optionCount ; iCounter++ ) + { + this->MenuRegion[ iTotal ].RegionTopLeftX = ( INT16 )( iBoxXPosition ); + this->MenuRegion[ iTotal ].RegionTopLeftY = ( INT16 )( iBoxYPosition + + GetTopMarginSize( this->boxId ) + + ( iFontHeight ) * iTotal ); + + this->MenuRegion[ iTotal ].RegionBottomRightX = ( INT16 )( iBoxXPosition + iBoxWidth ); + this->MenuRegion[ iTotal ].RegionBottomRightY = ( INT16 )( iBoxYPosition + + GetTopMarginSize( this->boxId ) + + ( iFontHeight ) * ( iTotal + 1 ) ); + iTotal++; + } +} + +void POPUP::ScreenMaskBtnCallback(MOUSE_REGION * pRegion, INT32 iReason ) +{ + // btn callback handler for screen mask region + + if( ( iReason & MSYS_CALLBACK_REASON_LBUTTON_UP ) || ( iReason & MSYS_CALLBACK_REASON_RBUTTON_UP ) ) + { + if( this->FirstClickInScreenMask == TRUE ) + { + this->FirstClickInScreenMask = FALSE; + return; + } + + // button event, stop showing menus + if (!this->BoxPersist) + { + this->hide(); + } + + // update mapscreen + setTeamPanelDirty(TRUE); + setCharacterInfoPanelDirty(TRUE); + setMapScreenBottomDirty(TRUE); + setRenderPBInterface(TRUE); + + SetRenderFlags( RENDER_FLAG_FULL ); + } + return; +} + +void POPUP::MenuBtnCallBack( MOUSE_REGION * pRegion, INT32 iReason ) +{ + // btn callback handler for LPC region + INT32 iValue = -1; + INT32 iType = 0; + INT32 iTotal = 0; + SOLDIERTYPE * pSoldier = NULL; + UINT8 ubVolume = 10; + + // sanity check #1 + if (!this || this->boxId < 0 || this->id > POPUP::nextid){ + #ifdef JA2TESTVERSION + __debugbreak(); + #else + Assert(false); + #endif + } + + iValue = MSYS_GetRegionUserData( pRegion, 0 ); + iType = MSYS_GetRegionUserData( pRegion, 1 ); + iTotal = MSYS_GetRegionUserData( pRegion, 2 ); + + switch (iType) + { + case REGION_OPTION: + if (iReason & MSYS_CALLBACK_REASON_LBUTTON_UP) + { + UnHighLightBox( this->boxId ); + + if (iValue < POPUP_MAX_OPTIONS + && iValue < this->optionCount + && iValue >= 0 + && this->options[iValue] != NULL) + { + this->options[iValue]->run(); // run the option's callback + + // sanity check #2 + // if this popup was fine in check #1 but is broken now, chances are + // we got deleted (or just plain broken) by the callback. + if (!this || this->id > POPUP::nextid){ + #ifdef JA2TESTVERSION + __debugbreak(); + #else + Assert(false); + #endif + } + + + this->RebuildBox(); // rebuild the box so that the changes can take effect + + if( GetBoxShadeFlag( this->boxId, iTotal ) == FALSE ) // highlight the line again, if appropriate + HighLightBoxLine( this->boxId, iTotal ); + } + } + break; + + case REGION_SUB_POPUP: + if (iReason & MSYS_CALLBACK_REASON_LBUTTON_UP) + { + UnHighLightBox( this->boxId ); + + if (iValue < POPUP_MAX_SUB_POPUPS + && iValue < this->subPopupOptionCount + && iValue >= 0 + && this->subPopupOptions[iValue] != NULL) + { + this->subPopupOptions[iValue]->run(); + } + } + break; + } +} + +void POPUP::MenuMvtCallBack(MOUSE_REGION * pRegion, INT32 iReason ) +{ + // mvt callback handler for LPC region + INT32 iTotal = -1; + INT32 iType = 0; + INT32 iValue = 0; + + if (!this || this->boxId < 0){ + __debugbreak(); + } + + iTotal = MSYS_GetRegionUserData( pRegion, 2 ); // set this to the total value of all mouse regions + iType = MSYS_GetRegionUserData( pRegion, 1 ); + iValue = MSYS_GetRegionUserData( pRegion, 0 ); + + if (iReason & MSYS_CALLBACK_REASON_GAIN_MOUSE ) + { + // highlight string + if( GetBoxShadeFlag( this->boxId, iTotal ) == FALSE ) + { + // get the string line handle + HighLightBoxLine( this->boxId, iTotal ); + if ( iType == REGION_OPTION && this->options[iValue]->HoverFunctionSet() ) // if it has been set... + this->options[iValue]->runHoverCallback(pRegion); // run the custom mouse callback + } + } + else if (iReason & MSYS_CALLBACK_REASON_LOST_MOUSE ) + { + // unhighlight all strings in box + UnHighLightBox( this->boxId ); + } + else if (iReason & MSYS_CALLBACK_REASON_MOVE) + { + // if the hover callback is set then also react to mouse movement within the region (only when available) + if( iType == REGION_OPTION && this->options[iValue]->HoverFunctionSet() && GetBoxShadeFlag( this->boxId, iTotal ) == FALSE ) + { + this->options[iValue]->runHoverCallback(pRegion); // run the custom mouse callback + + if ( (pRegion->ButtonState & MSYS_LEFT_BUTTON) || (pRegion->ButtonState & MSYS_RIGHT_BUTTON) ) + { // if drag detedted,rebuild the boxstrings + this->RebuildBox(); + } + } + } +} + +void POPUP::HandleShadingOfLines( void ) +{ + UINT8 i = 0; + + // check if valid + if( ( this->PopupVisible == FALSE ) || ( this->boxId == - 1 ) ) + { + return; + } + + //for (i=0; i < this->optionCount; i++) + for(std::vector::iterator cOption=this->options.begin(); cOption != this->options.end(); ++cOption) + { + if ( (*cOption)->checkAvailability() ) + UnShadeStringInBox( this->boxId, i+this->subPopupOptionCount); // workaround - sub-popups don't check + else // for availability + ShadeStringInBox( this->boxId, i+this->subPopupOptionCount); + i++; + } + + return; +} + +void POPUP::DetermineBoxPositions( void ) +{ + // depending on how many boxes there are, reposition as needed + SGPPoint pPoint; + SGPPoint pNewPoint; + SGPRect pDimensions; + + if( ( this->PopupVisible == FALSE ) || ( this->boxId == -1 ) ) + { + return; + } + + // get an idea about what size the box ought to be + pPoint.iX = 0; + pPoint.iY = 0; + + SetBoxPosition( this->boxId, pPoint ); + GetBoxSize( this->boxId, &pDimensions ); + + INT32 boxWidth = pDimensions.iRight; + INT32 boxHeight = pDimensions.iBottom; + + /* + if ( (guiTacticalInterfaceFlags & INTERFACE_MAPSCREEN ) ) + { + GetBoxPosition( this->boxId, &pPoint ); + this->BoxesX = ( INT16 )pPoint.iX; + this->BoxesY = ( INT16 )pPoint.iY; + } + */ + + switch (this->positioningRule){ + case POPUP_POSITION_TOP_LEFT: + + pPoint.iX = this->OrigPosition.iX; + pPoint.iY = this->OrigPosition.iY; + + break; + + case POPUP_POSITION_TOP_RIGHT: + + pPoint.iX = this->OrigPosition.iX - boxWidth; + pPoint.iY = this->OrigPosition.iY; + + break; + + case POPUP_POSITION_BOTTOM_RIGHT: + + pPoint.iX = this->OrigPosition.iX - boxWidth; + pPoint.iY = this->OrigPosition.iY - boxHeight; + + break; + + case POPUP_POSITION_BOTTOM_LEFT: + + pPoint.iX = this->OrigPosition.iX; + pPoint.iY = this->OrigPosition.iY - boxHeight; + + break; + + default: + #ifdef JA2TESTVERSION + CHAR8 debugStr[120]; + wsprintf(debugStr,"Incorrect positioning rule for box id: %i \n",this->boxId); + OutputDebugString( debugStr ); + #endif + + // assume default + pPoint.iX = this->OrigPosition.iX; + pPoint.iY = this->OrigPosition.iY; + + return; + } + + // set all the other positions to match this one + this->Position = pPoint; + this->BoxesX = pPoint.iX; + this->BoxesY = pPoint.iY; + this->X= pPoint.iX; + this->Y= pPoint.iY; + + SetBoxPosition( this->boxId, pPoint ); + GetBoxSize( this->boxId, &pDimensions ); + + // hang it right beside the LPC/EPC box menu + pNewPoint.iX = pPoint.iX + pDimensions.iRight; + pNewPoint.iY = pPoint.iY; + + return; +} + +void POPUP::CheckAndUpdateTacticalPopUpPositions( void ) +{ + SGPRect pDimensions2; + SGPPoint pPoint; + + if( this->PopupVisible == FALSE ) + { + return; + } + + if ( (guiTacticalInterfaceFlags & INTERFACE_MAPSCREEN ) ) + { + return; + } + + GetBoxSize( this->boxId, &pDimensions2 ); + + if( this->BoxesX + pDimensions2.iRight >= SCREEN_WIDTH ) + { + this->BoxesX = ( INT16 ) ( SCREEN_WIDTH - 1 - ( pDimensions2.iRight ) ); + SetRenderFlags( RENDER_FLAG_FULL ); + } + + if( this->BoxesY + pDimensions2.iBottom >= SCREEN_HEIGHT-120 ) + { + this->BoxesY = ( INT16 )( SCREEN_HEIGHT - 121 - ( pDimensions2.iBottom ) ); + SetRenderFlags( RENDER_FLAG_FULL ); + } + + pPoint.iX = this->BoxesX; + pPoint.iY = this->BoxesY; + + SetBoxPosition( this->boxId, pPoint ); + + this->RepositionMouseRegions( ); +} + +void POPUP::RepositionMouseRegions( void ) +{ + INT16 sDeltaX, sDeltaY; + INT32 iCounter = 0; + + if( this->PopupVisible == TRUE ) + { + sDeltaX = this->BoxesX - this->MenuRegion[ 0 ].RegionTopLeftX; + sDeltaY = ( INT16 ) ( this->BoxesY - this->MenuRegion[ 0 ].RegionTopLeftY + GetTopMarginSize( this->boxId ) ); + + // find the delta from the old to the new, and alter values accordingly + for( iCounter = 0; iCounter < ( INT32 )GetNumberOfLinesOfTextInBox( this->boxId ); iCounter++ ) + { + this->MenuRegion[ iCounter ].RegionTopLeftX += sDeltaX; + this->MenuRegion[ iCounter ].RegionTopLeftY += sDeltaY; + + this->MenuRegion[ iCounter ].RegionBottomRightX += sDeltaX; + this->MenuRegion[ iCounter ].RegionBottomRightY += sDeltaY; + } + + gfPausedTacticalRenderFlags = RENDER_FLAG_FULL; + } +} + +void POPUP::PositionCursorForBox(void) +{ + // position cursor over y of on duty in tactical assignments + SGPPoint pPosition; + SGPRect pDimensions; + INT32 iFontHeight; + + // get x.y position of box + GetBoxPosition( this->boxId, &pPosition); + + // get dimensions..mostly for width + GetBoxSize( this->boxId, &pDimensions ); + + iFontHeight = GetLineSpace( this->boxId ) + GetFontHeight( GetBoxFont( this->boxId ) ); + + if( gGameSettings.fOptions[ TOPTION_DONT_MOVE_MOUSE ] == FALSE ) + { + SimulateMouseMovement( pPosition.iX + pDimensions.iRight - 6, pPosition.iY + ( iFontHeight / 2 ) + 2 ); + } +} + + ////////////////////////////////////////////////////////////////// + // Functions for binding POPUP class with MSYS callbacks +////////////////////////////////////////////////////////////////// + +PopupIndex * findMouseRegionInIndex(UINT16 regionId) +{ + for(std::vector::iterator cPopupIndex=gPopupRegionIndex.begin(); cPopupIndex != gPopupRegionIndex.end(); ++cPopupIndex) + if ((*cPopupIndex).regionId == regionId){ + return &(*cPopupIndex); + } + + #ifdef JA2TESTVERSION + CHAR8 debugStr[120]; + wsprintf(debugStr,"Failed to find callback to mouse region id: %i \n",regionId); + OutputDebugString( debugStr ); + #endif + + return NULL; +} + +BOOLEAN registerPopupRegion(UINT16 rID, UINT32 cID) +{ + /* + if (gPopupRegionIndexCounter == MAX_REGIONS_IN_INDEX) + { // If we can't fit in any more regions, try to rebuild the index before giving up + rebuildPopupRegionIndex(); // since there may be some unregistered regions + if (gPopupRegionIndexCounter == MAX_REGIONS_IN_INDEX) + return FALSE; // if index still full, return false + } + */ + + PopupIndex * pi = new PopupIndex; + pi->regionId = rID; + pi->classId = cID; + + gPopupRegionIndex.push_back(*pi); + gPopupRegionIndexCounter++; + + return TRUE; +} + +BOOLEAN unregisterPopupRegion(UINT16 regionId) +{ + for(std::vector::iterator cPopupIndex=gPopupRegionIndex.begin(); cPopupIndex != gPopupRegionIndex.end(); ++cPopupIndex) + if ((*cPopupIndex).regionId == regionId){ + gPopupRegionIndex.erase(cPopupIndex); + return TRUE; + } + + #ifdef JA2TESTVERSION + CHAR8 debugStr[120]; + wsprintf(debugStr,"Failed to erase mouse region index: %i \n",regionId); + OutputDebugString( debugStr ); + #endif + return FALSE; +} + +void rebuildPopupRegionIndex(void) +{/* + UINT8 i,j; + PopupIndex TempPopupIndex[MAX_REGIONS_IN_INDEX]; + // cout << "cleaning index"<IDNumber)->classId; + if (cID < 0) return; + + POPUP * p = findPopupInIndex(cID); + if (p) { p->ScreenMaskBtnCallback(pRegion, iReason); } + +} + +void popupMouseMoveCallback(MOUSE_REGION *pRegion, INT32 iReason) +{ + UINT32 cID = findMouseRegionInIndex(pRegion->IDNumber)->classId; + if (cID < 0) return; + + POPUP * p = findPopupInIndex(cID); + if (p) p->MenuMvtCallBack(pRegion, iReason); +} + +void popupMouseClickCallback(MOUSE_REGION *pRegion, INT32 iReason) +{ + UINT32 cID = findMouseRegionInIndex(pRegion->IDNumber)->classId; + if (cID < 0) return; + + POPUP * p = findPopupInIndex(cID); + if (p) { + p->MenuBtnCallBack(pRegion, iReason); + } +} \ No newline at end of file diff --git a/Utils/popup_class.h b/Utils/popup_class.h new file mode 100644 index 00000000..e258409c --- /dev/null +++ b/Utils/popup_class.h @@ -0,0 +1,283 @@ +#ifndef POPUP_CLASS + #define POPUP_CLASS + + #include + #include "popup_callback.h" + + #define MAX_POPUPS 8 + #define POPUP_MAX_SUB_POPUPS 2 + #define POPUP_MAX_OPTIONS 32 + #define MAX_REGIONS_IN_INDEX MAX_POPUPS*POPUP_MAX_OPTIONS*POPUP_MAX_SUB_POPUPS + + #define REGION_SUB_POPUP 1 + #define REGION_OPTION 0 + +#ifdef MSYS_PRIORITY_VERY_HIGH + #define POPUP_SCREEN_MASK_PRIORITY (MSYS_PRIORITY_VERY_HIGH + 10) // MSYS priority for popup screen mask + #define POPUP_OPTION_PRIORITY (MSYS_PRIORITY_VERY_HIGH + 12) // MSYS priority for popup options +#else // compatibility with 1.13 versions without the VERY_HIGH priority defined + #define POPUP_SCREEN_MASK_PRIORITY MSYS_PRIORITY_HIGHEST + #define POPUP_OPTION_PRIORITY MSYS_PRIORITY_HIGHEST +#endif + + #define POPUP_CALLBACK_INIT 1 // called at the end of init + #define POPUP_CALLBACK_END 2 // called after cleanup + #define POPUP_CALLBACK_SHOW 3 // called before showing + #define POPUP_CALLBACK_HIDE 4 // called after hiding + + #define POPUP_POSITION_TOP_LEFT 1 // default positioning rule when setting position + #define POPUP_POSITION_TOP_RIGHT 2 // user defined point (position) is the top right corner of the popup + #define POPUP_POSITION_BOTTOM_RIGHT 3 // user defined point (position) is the bottom right corner of the popup + #define POPUP_POSITION_BOTTOM_LEFT 4 // user defined point (position) is the bottom left corner of the popup + + #define POPUP_POSITION_RELATIVE 0 // only used for sub-popups, left corner is relative to parent popup's point of origin + + class POPUP_OPTION; + class POPUP_SUB_POPUP_OPTION; + class POPUP; + + typedef void (POPUP::*POPUP_CALLBACK)(MOUSE_REGION *, INT32); + + typedef struct { + UINT16 regionId; + UINT32 classId; + } PopupIndex ; + + extern std::vector gPopupRegionIndex; + extern std::vector gPopupIndex; + + extern UINT32 gPopupRegionIndexCounter; + extern UINT32 gPopupIndexCounter; + + PopupIndex * findMouseRegionInIndex(UINT16 regionId); + BOOLEAN registerPopupRegion(UINT16 rID, UINT32 cID); + BOOLEAN unregisterPopupRegion(UINT16 regionId); + void rebuildPopupRegionIndex(void); + void popupMaskCallback(MOUSE_REGION *pRegion, INT32 iReason); + void popupMouseMoveCallback(MOUSE_REGION *pRegion, INT32 iReason); + void popupMouseClickCallback(MOUSE_REGION *pRegion, INT32 iReason); + + POPUP * findPopupInIndex( UINT32 cID ); + void rebuildPopupIndex(void); + void reinitPopupIndex(void); + void initPopupIndex(void); + + class POPUP_OPTION + { + public: + POPUP_OPTION::POPUP_OPTION(void); // default constructor + POPUP_OPTION(std::wstring* name, popupCallback* newFunction); // constructor + ~POPUP_OPTION(); // destructor + // setup + BOOLEAN setName(WCHAR* name); + BOOLEAN setAction(popupCallback*fun); + BOOLEAN setAvail(popupCallback *fun); + BOOLEAN setHover(popupCallback *fun); + + BOOLEAN run(); + BOOLEAN forceRun(); + + BOOLEAN runHoverCallback(MOUSE_REGION * pRegion); + BOOLEAN checkAvailability(); + + BOOLEAN HoverFunctionSet(){ return (this->hover != 0); }; + BOOLEAN AvailabilityFunctionSet(){ return (this->avail != 0); }; + + std::wstring name; + std::wstring hint; +// protected: + popupCallback * action; + popupCallback * avail; + popupCallback * hover; + }; + + + class POPUP_SUB_POPUP_OPTION : public POPUP_OPTION + { + public: + // constructor/destructor + POPUP_SUB_POPUP_OPTION(void); + POPUP_SUB_POPUP_OPTION(std::wstring* name); + POPUP_SUB_POPUP_OPTION(std::wstring* newName, const POPUP * parent); + ~POPUP_SUB_POPUP_OPTION(); + + void showPopup(); + void hidePopup(); + + BOOLEAN run(); + + void initSubPopup(); + void destroySubPopup(); + void positionSubPopup(); + + BOOLEAN setPopupPosition(UINT16 x, UINT16 y, UINT8 positioningRule = POPUP_POSITION_RELATIVE ); + + BOOLEAN customPositionSet; + INT32 customX; + INT32 customY; + UINT8 customRule; + + POPUP * subPopup; + const POPUP * parent; + }; + + + class POPUP + { + ///////////////////////// + // public functions + public: + POPUP(void); // constructor + POPUP(CHAR* name); // constructor + ~POPUP(void); // destructor + // setup + POPUP_OPTION * addOption(std::wstring * name, popupCallback * action); + /*INT16 findFreeOptionIndex();*/ + BOOLEAN addOption(POPUP_OPTION &option); + POPUP_OPTION * getOption(UINT16 n); + + BOOLEAN delOption(CHAR* name); // Another index to through and clean, aargh + BOOLEAN delOption(UINT8 optIndex); + + POPUP* addSubMenuOption(std::wstring * name); + /*INT16 findFreeSubMenuOptionIndex();*/ + POPUP_SUB_POPUP_OPTION * getSubPopupOption(UINT8 n); + + BOOLEAN setPosition(UINT16 x, UINT16 y, UINT8 positioningRule = POPUP_POSITION_TOP_LEFT ); + BOOLEAN setSize(UINT16 x, UINT16 y ); + // usage + BOOLEAN show(void); + BOOLEAN hide(void); + BOOLEAN toggle(void); + BOOLEAN refresh(void); + BOOLEAN forceDraw(void); + BOOLEAN callOption(int optIndex); + + INT32 getBoxId(){ + return this->boxId; + } + + BOOLEAN setCallback(UINT8 type, popupCallback * callback); + BOOLEAN isCallbackSet(UINT8 type); + + ///////////////////////// + // public variables + public: + CHAR name[32]; + SGPPoint Position; + SGPRect Dimensions; + UINT32 id; + static UINT32 nextid ; + UINT8 optionCount; + UINT8 subPopupOptionCount; + + ///////////////////////// + // private functions + private: + + void setInitialValues(void); + BOOLEAN addToIndex( void ); + BOOLEAN removeFromIndex( void ); + + // Box init functions + BOOLEAN CreateDestroyPopUpBoxes(void); + BOOLEAN CreatePopUpBoxes(void); + BOOLEAN DestroyPopUpBoxes(void); + + BOOLEAN CreateBox( void ); + void AddOptionStrings(); + void AddSubPopupStrings(); + + void RebuildBox( void ); + + // Screen mask + void CreateDestroyScreenMask( void ); + void CreateScreenMask( void ); + void DestroyScreenMask( void ); + + // Mouse regions + void CreateDestroyMouseRegions( void ); + void CreateMouseRegions( void ); + void DestroyMouseRegions( void ); + void AdjustMouseRegions( void ); + + void RepositionMouseRegions( void ); + public: + // MSYS Callbacks + void MenuMvtCallBack(MOUSE_REGION * pRegion, INT32 iReason ); + void MenuBtnCallBack( MOUSE_REGION * pRegion, INT32 iReason ); + void ScreenMaskBtnCallback(MOUSE_REGION * pRegion, INT32 iReason ); + private: + // These are mostly used in the map screen + void UpdateMapScreenPosition(void); + void DetermineWhichLMenusCanBeShown( void ); + + // Misc utility functions + void HandleShadingOfLines( void ); + void PositionCursorForBox( void ); + void CheckAndUpdateTacticalPopUpPositions( void ); + void DetermineBoxPositions( void ); + void UpdateTextProperties( void ); + + // external flag access functiona + BOOLEAN MapScreenBottomDirty(void); + BOOLEAN CharacterInfoPanelDirty(void); + BOOLEAN TeamPanelDirty(void); + BOOLEAN RenderPBInterface(void); + + void setMapScreenBottomDirty(BOOLEAN); + void setCharacterInfoPanelDirty(BOOLEAN); + void setTeamPanelDirty(BOOLEAN); + void setRenderPBInterface(BOOLEAN); + + + ///////////////////////// + // private variables + private: + BOOLEAN PopupVisible; + + popupCallback * initCallback; + popupCallback * EndCallback; + popupCallback * ShowCallback; + popupCallback * HideCallback; + + /////////////////////// + // Popup box vars + ///////////////// + + BOOLEAN FirstClickInScreenMask; + BOOLEAN BoxPersist; + INT16 BoxesX, BoxesY; + + // Textures + + static UINT32 uiPOPUPBORDERS; + static UINT32 uiPOPUPTEX; + + // PopUp Box Handles + INT32 boxId; + + // which corner of the popup should be aligned with the supplied coordinates ? + UINT8 positioningRule; + + + // the x,y position of the pop up in tactical + public: + INT16 X, Y; + + // assignment menu mouse regions + + MOUSE_REGION MenuRegion[ POPUP_MAX_OPTIONS ]; + MOUSE_REGION ScreenMaskRegion; + private: + // Box position and size + SGPPoint OrigPosition; + + // Options + std::vector options; + + // Subpopups + std::vector subPopupOptions; + + }; +#endif diff --git a/ja2_VS2005.vcproj b/ja2_VS2005.vcproj index 68fd9fda..8cf88fe4 100644 --- a/ja2_VS2005.vcproj +++ b/ja2_VS2005.vcproj @@ -145,7 +145,7 @@