Ares
Classes | Public Types | Static Public Member Functions | Static Public Attributes | Private Member Functions | Static Private Member Functions

Interface Class Reference

#include <src/Misc/Interface.h>

List of all members.

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.

Member Enumeration Documentation

Enumerator:
uia_Default 
uia_Message 
uia_Disable 
uia_Hide 
uia_SneakPeek 
uia_Credits 

Constructor & Destructor Documentation

Interface::Interface ( void  ) [private]
Interface::~Interface ( void  ) [private]

Member Function Documentation

int Interface::getSlotIndex ( int  iID) [static]

Converts a control ID to its corresponding index in slots.

Converts an control ID to a slot index.

Parameters:
iIDThe control ID.
Returns:
The index in the slot array.
Author:
AlexB
Date:
2010-06-20
                                   {
        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.

Parameters:
actionThe eUIAction to perform.
nameThe button name to get the message string of.
pResultA pointer to the game dialog's user info.
nextMenuThe menu to go to after showing the message.
Returns:
True if action has been overridden, false otherwise.
Author:
AlexB
Date:
2010-06-20
                                                                                          {
        // 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.

Parameters:
hItemHandle of the item to update.
rcItemThe item's new bounds.
ptOffsetSpecial offset.
Author:
AlexB
Date:
2010-06-20
                                                                {
        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.

Parameters:
valueThe string to parse.
defThe eUIAction returned for invalid values.
Returns:
Parsed eUIAction if value is valid, def otherwise.
Author:
AlexB
Date:
2010-06-20
                                                                               {
        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.

Parameters:
hDlgThe dialog to update.
nIDDlgItem1Item one.
nIDDlgItem2Item two.
Author:
AlexB
Date:
2010-06-20
                                                                     {
        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.

Parameters:
hDlgThe dialog to update.
Author:
AlexB
Date:
2010-06-20
                                    {
        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.

Parameters:
hDlgThe dialog to update.
itemsAn array of MenuItems to update.
countLength of items.
Author:
AlexB
Date:
2010-06-20
                                                                     {
        // 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;
}

Member Data Documentation

int Interface::nextAction = -1 [static]
const wchar_t * Interface::nextMessageText = NULL [static]
int Interface::nextReturnMenu = -1 [static]
int Interface::slots [static]

The documentation for this class was generated from the following files:
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Defines