Ares
|
#include <src/Misc/Interface.h>
Classes | |
struct | CampaignData |
struct | ColorData |
struct | MenuItem |
Public Types | |
enum | eUIAction { uia_Default = 0, uia_Message = 1, uia_Disable = 2, uia_Hide = 3, uia_SneakPeek = 13, uia_Credits = 15 } |
Static Public Member Functions | |
static bool | invokeClickAction (eUIAction, char *, int *, int) |
Overrides the default action and queue the user defined one. | |
static void | updateMenuItems (HWND, MenuItem *, int) |
Disables, hides and moves menu items so there are no gaps in the menu navigation. | |
static void | updateMenu (HWND hDlg) |
Updates the dialogs after creation to better fit the user's needs. | |
static eUIAction | parseUIAction (char *, eUIAction) |
Parses an eUIAction from a string. | |
static int | getSlotIndex (int) |
Converts a control ID to its corresponding index in slots. | |
Static Public Attributes | |
static int | lastDialogTemplateID = 0 |
static int | nextReturnMenu = -1 |
static int | nextAction = -1 |
static const wchar_t * | nextMessageText = NULL |
static int | slots [4] |
Private Member Functions | |
Interface (void) | |
~Interface (void) | |
Static Private Member Functions | |
static void | moveItem (HWND, RECT, POINT) |
Moves a menu item to a new location using an optional offset. | |
static void | swapItems (HWND, int, int) |
Swaps the bounds of two dialog items. |
enum Interface::eUIAction |
{ uia_Default = 0, uia_Message = 1, uia_Disable = 2, uia_Hide = 3, uia_SneakPeek = 13, uia_Credits = 15 };
Interface::Interface | ( | void | ) | [private] |
Interface::~Interface | ( | void | ) | [private] |
int Interface::getSlotIndex | ( | int | iID | ) | [static] |
Converts a control ID to its corresponding index in slots.
Converts an control ID to a slot index.
iID | The control ID. |
{ if(iID == 1770) { return 0; } else if (iID == 1772) { return 1; } else if (iID == 1771) { return 2; } else if (iID == 1773) { return 3; } return -1; }
bool Interface::invokeClickAction | ( | eUIAction | action, |
char * | name, | ||
int * | pResult, | ||
int | nextMenu | ||
) | [static] |
Overrides the default action and queue the user defined one.
Called from within the button click event to override the game's default action. Sets the user defined action and/or the message.
action | The eUIAction to perform. |
name | The button name to get the message string of. |
pResult | A pointer to the game dialog's user info. |
nextMenu | The menu to go to after showing the message. |
{ // reset nextAction = -1; nextReturnMenu = -1; nextMessageText = NULL; auto ret = [&](int _nextAction) -> bool { *pResult = nextAction = _nextAction; nextReturnMenu = nextMenu; return (_nextAction > -1); }; if(action == Interface::uia_Message) { // generate the label name char *buffer = new char[0x20]; StringCchPrintfA(buffer, 0x20, "TXT_%s_MSG", name); nextMessageText = StringTable::LoadStringA(buffer); delete [] &buffer; // hide dialog temporarily and show a message box return ret(6); } if(action == Interface::uia_SneakPeek) { // show the preview video return ret(13); } if(action == Interface::uia_Credits) { // show the credits return ret(15); } // do default stuff return false; }
void Interface::moveItem | ( | HWND | hItem, |
RECT | rcItem, | ||
POINT | ptOffset | ||
) | [static, private] |
Moves a menu item to a new location using an optional offset.
Helper function to move an dialog item and offset in one go. The offset is needed to account for non-client areas of the windowed game.
hItem | Handle of the item to update. |
rcItem | The item's new bounds. |
ptOffset | Special offset. |
{
OffsetRect(&rcItem, ptOffset.x, ptOffset.y);
MoveWindow(hItem, rcItem.left, rcItem.top,
rcItem.right - rcItem.left, rcItem.bottom - rcItem.top, false);
}
Interface::eUIAction Interface::parseUIAction | ( | char * | value, |
Interface::eUIAction | def | ||
) | [static] |
Parses an eUIAction from a string.
Converts the string to an eUIAction.
value | The string to parse. |
def | The eUIAction returned for invalid values. |
{ if(!_strcmpi(value, "message")) { return Interface::uia_Message; } else if(!_strcmpi(value, "disable")) { return Interface::uia_Disable; } else if(!_strcmpi(value, "hide")) { return Interface::uia_Hide; } else if(!_strcmpi(value, "credits")) { return Interface::uia_Credits; } else if(!_strcmpi(value, "sneakpeek")) { return Interface::uia_SneakPeek; } else if(_strcmpi(value, "default")) { Debug::DevLog(Debug::Warning, "Unrecognized UI action value: %s\n", value); } return def; }
void Interface::swapItems | ( | HWND | hDlg, |
int | nIDDlgItem1, | ||
int | nIDDlgItem2 | ||
) | [static, private] |
Swaps the bounds of two dialog items.
Both button's bounds are swapped. This can be used to fix unintuitive menu button order if some items are hidden.
hDlg | The dialog to update. |
nIDDlgItem1 | Item one. |
nIDDlgItem2 | Item two. |
{ HWND hFirst = GetDlgItem(hDlg, nIDDlgItem1); HWND hSecond = GetDlgItem(hDlg, nIDDlgItem2); if(hFirst && hSecond) { RECT rcFirst, rcSecond; if(GetWindowRect(hFirst, &rcFirst) && GetWindowRect(hSecond, &rcSecond)) { POINT ptDlg = {0, 0}; ScreenToClient(hDlg, &ptDlg); moveItem(hFirst, rcSecond, ptDlg); moveItem(hSecond, rcFirst, ptDlg); } } }
void Interface::updateMenu | ( | HWND | hDlg | ) | [static] |
Updates the dialogs after creation to better fit the user's needs.
This function does dialog dependent stuff. Some controls are moved, or disabled, new Ares controls are hidden if not explicitly enabled.
hDlg | The dialog to update. |
{ int iID = Interface::lastDialogTemplateID; // campaign selection if(iID == 148) { // hide item by iID auto hide = [hDlg](int nIDDlgItem) { if(HWND hItem = GetDlgItem(hDlg, nIDDlgItem)) { ShowWindow(hItem, SW_HIDE); } }; // show item by iID auto show = [hDlg](int nIDDlgItem) { if(HWND hItem = GetDlgItem(hDlg, nIDDlgItem)) { ShowWindow(hItem, SW_SHOW); } }; // move item by some pixels auto offset = [hDlg](int nIDDlgItem, int x, int y) { if(HWND hItem = GetDlgItem(hDlg, nIDDlgItem)) { POINT ptDlg = {0, 0}; ScreenToClient(hDlg, &ptDlg); RECT rcItem; GetWindowRect(hItem, &rcItem); OffsetRect(&rcItem, x, y); moveItem(hItem, rcItem, ptDlg); } }; POINT ptDlg = {0, 0}; ScreenToClient(hDlg, &ptDlg); // new campaign list versus default click selection if(Ares::UISettings::CampaignList) { if(HWND hItem = GetDlgItem(hDlg, 1109)) { // extensive stuff show(1109); show(1038); hide(1770); hide(1772); hide(1771); hide(1773); // use the position of the Allied button to place the // new campaign selection list. RECT rcItem = {125, 34, 125 + 174, 34 + 87}; if(HWND hAllImage = GetDlgItem(hDlg, 1770)) { GetWindowRect(hAllImage, &rcItem); } offset(1959, 0, -rcItem.bottom + rcItem.top); // center the list above the difficulty selection. the list may // contain seven items, after that, a scroll bar will appear. // acount for its width, too. int offList = (CampaignExt::countVisible() < 8 ? -2 : -12); OffsetRect(&rcItem, offList, 32); moveItem(hItem, rcItem, ptDlg); // let the Allied label be the caption if(HWND hAllLabel = GetDlgItem(hDlg, 1959)) { SendMessageA(hAllLabel, 0x4B2, 0, (LPARAM)StringTable::LoadStringA("GUI:SelectCampaign")); } // call the load button "Play" if(HWND hLoad = GetDlgItem(hDlg, 1038)) { SendMessageA(hLoad, 0x4B2, 0, (LPARAM)StringTable::LoadStringA("GUI:Play")); } // move the soviet label to a new location and reuse // it to show the selected campaigns summary. if(HWND hSovImage = GetDlgItem(hDlg, 1772)) { GetWindowRect(hSovImage, &rcItem); if(HWND hSovLabel = GetDlgItem(hDlg, 1960)) { // remove default text and move label SendMessageA(hSovLabel, 0x4B2, 0, (LPARAM)L""); moveItem(hSovLabel, rcItem, ptDlg); // left align text DWORD style = GetWindowLong(hSovLabel, GWL_STYLE); style = SS_LEFT | WS_CHILD | WS_VISIBLE; SetWindowLong(hSovLabel, GWL_STYLE, style); } } // reset the selection cache CampaignExt::lastSelectedCampaign = -1; } } else { // default way with starting a campaign by clicking on its image. // The allied image defines the image size. RECT rcItem = {125, 34, 125 + 174, 34 + 87}; if(HWND hAllImage = GetDlgItem(hDlg, 1770)) { GetWindowRect(hAllImage, &rcItem); } SIZE szImage; szImage.cx = (int)((rcItem.right - rcItem.left) * .8); szImage.cy = (int)((rcItem.bottom - rcItem.top) * 1.0); // the soviet image's top is used for the second row RECT rcSovImage = {0, 216, 0, 0}; if(HWND hSovImage = GetDlgItem(hDlg, 1772)) { GetWindowRect(hSovImage, &rcSovImage); } int row2Offset = rcSovImage.top - rcItem.top; // call the load button "Play" if(HWND hLoad = GetDlgItem(hDlg, 1038)) { SendMessageA(hLoad, 0x4B2, 0, (LPARAM)StringTable::LoadStringA("GUI:PlayMission")); } // position values RECT rcWidth = rcItem; OffsetRect(&rcWidth, ptDlg.x, ptDlg.y); int width = rcWidth.left + rcWidth.right; int lefts[3]; lefts[0] = (width - szImage.cx) / 2; lefts[1] = (width - 2 * szImage.cx) / 3; lefts[2] = width - lefts[1] - szImage.cx; // create seven slot rects auto setRect = [&](RECT *rcRect, int x, int y) { rcRect->left = x - ptDlg.x; rcRect->top = y; rcRect->right = rcRect->left + szImage.cx; rcRect->bottom = rcRect->top + szImage.cy; }; RECT *rcSlots = new RECT[7]; setRect(&rcSlots[0], lefts[0], rcItem.top); setRect(&rcSlots[1], lefts[0], rcItem.top + row2Offset); setRect(&rcSlots[2], lefts[1], rcItem.top); setRect(&rcSlots[3], lefts[2], rcItem.top); setRect(&rcSlots[4], lefts[1], rcItem.top + row2Offset); setRect(&rcSlots[5], lefts[2], rcItem.top + row2Offset); setRect(&rcSlots[6], -szImage.cx, -szImage.cy); // move the images to their new locations auto fillSlot = [&](int iIDDlgItem, int slot, int iIDLabel) { if(HWND hItem = GetDlgItem(hDlg, iIDDlgItem)) { moveItem(hItem, rcSlots[slot], ptDlg); } if(HWND hLabel = GetDlgItem(hDlg, iIDLabel)) { if(slot < 6) { RECT rcLabel = rcSlots[slot]; OffsetRect(&rcLabel, 0, (rcLabel.bottom - rcLabel.top)); rcLabel.bottom = rcLabel.top + 20; // make the subtitle a little wider int widen = (int)(slot < 2 ? (width - rcLabel.right + rcLabel.left) / 2 : 15); rcLabel.left -= widen; rcLabel.right += widen; moveItem(hLabel, rcLabel, ptDlg); ShowWindow(hLabel, SW_SHOW); } else { ShowWindow(hLabel, SW_HIDE); } } }; // move image and label. auto-center, if there is no neighbour. auto moveToPlace = [&](int iID, int index, int neighbour, int slot, int center, int iIDLabel) { if(slots[index]) { fillSlot(iID, (slots[neighbour] ? slot : center), iIDLabel); } else { fillSlot(iID, 6, iIDLabel); } }; // move click zones and labels moveToPlace(1770, 0, 1, 2, 0, 1959); moveToPlace(1772, 1, 0, 3, 0, 1960); moveToPlace(1771, 2, 3, 4, 1, 1961); moveToPlace(1773, 3, 2, 5, 1, 1962); delete [] &rcSlots; } } // main menu if(iID == 226) { struct Interface::MenuItem items[] = {{0x683, Ares::UISettings::SinglePlayerButton}, {0x684, Ares::UISettings::WWOnlineButton}, {0x578, Ares::UISettings::NetworkButton}, {0x686, Ares::UISettings::MoviesAndCreditsButton}, {0x55C, Interface::uia_Default}}; Interface::updateMenuItems(hDlg, items, 5); } // singleplayer menu if(iID == 256) { // swap skirmish and load buttons so load will not appear first if(Ares::UISettings::CampaignButton != Interface::uia_Hide) { struct Interface::MenuItem items[] = {{1672, Ares::UISettings::CampaignButton}, {1673, Interface::uia_Default}, {1401, Ares::UISettings::SkirmishButton}}; Interface::updateMenuItems(hDlg, items, 3); } else { Interface::swapItems(hDlg, 0x688, 0x579); struct Interface::MenuItem items[] = {{1401, Ares::UISettings::SkirmishButton}, {1673, Interface::uia_Default}, {1672, Ares::UISettings::CampaignButton}}; Interface::updateMenuItems(hDlg, items, 3); } } // movies and credits menu if(iID == 257) { struct Interface::MenuItem items[] = {{0x68D, Ares::UISettings::SneakPeeksButton}, {0x68E, Ares::UISettings::PlayMoviesButton}, {0x68F, Ares::UISettings::ViewCreditsButton}}; Interface::updateMenuItems(hDlg, items, 3); } // one-button message box if(iID == 206) { // more room for text if(HWND hItem = GetDlgItem(hDlg, 0x5B0)) { POINT ptDlg = {0, 0}; ScreenToClient(hDlg, &ptDlg); RECT rcItem; GetWindowRect(hItem, &rcItem); rcItem.bottom = rcItem.top + 200; moveItem(hItem, rcItem, ptDlg); } } }
void Interface::updateMenuItems | ( | HWND | hDlg, |
MenuItem * | items, | ||
int | count | ||
) | [static] |
Disables, hides and moves menu items so there are no gaps in the menu navigation.
Menu items will be disabled or hidden. For the latter, all succeeding items are moved to the next free position, closing all gaps.
hDlg | The dialog to update. |
items | An array of MenuItems to update. |
count | Length of items. |
{ // account for dialog nc size POINT ptDlg = {0, 0}; ScreenToClient(hDlg, &ptDlg); int iButton = 0; RECT* rcOriginal = new RECT[count]; for(int i=0; i<count; ++i) { if(HWND hItem = GetDlgItem(hDlg, items[i].nIDDlgItem)) { GetWindowRect(hItem, &rcOriginal[i]); if(items[i].uiaAction == Interface::uia_Hide) { // hide the window ShowWindow(hItem, SW_HIDE); } else { if(items[i].uiaAction == Interface::uia_Disable) { // disable the button EnableWindow(hItem, false); } if(i != iButton) { // move the button to the next free position moveItem(hItem, rcOriginal[iButton], ptDlg); } ++iButton; } } } delete [] &rcOriginal; }
int Interface::lastDialogTemplateID = 0 [static] |
int Interface::nextAction = -1 [static] |
const wchar_t * Interface::nextMessageText = NULL [static] |
int Interface::nextReturnMenu = -1 [static] |
int Interface::slots [static] |