Ticket #2414: minimapIconHover_v1.patch

File minimapIconHover_v1.patch, 13.0 KB (added by Michael, 10 years ago)

Adds a hover effect to the minimap icons and removes the approximation of the button.

  • binaries/data/mods/public/gui/session/session.xml

     
    947947
    948948        <object name="minimapOverlay" size="4 4 100%-4 100%-4" type="image" sprite="stretched:session/minimap_circle_modern.png" ghost="true"/>
    949949
     950        <!-- Score Button (deactivated until function is implemented)-->
     951        <object size="100%-75 0 100% 75">
     952            <object name="minimap_button[1]" size="0 0 100% 100%" type="button" ghost="true"
     953            sprite="stretched:grayscale:session/icons/minimap/score_border.png"
     954            sprite_over="stretched:session/icons/minimap/score_border_hover.png"
     955            enabled="false">
     956            </object>
     957        </object>
     958       
    950959        <!-- Idle Worker Button -->
    951         <object size="100%-36 100%-36 100%-5 100%-5">
    952             <!-- TODO: should highlight the button if there's non-zero idle workers -->
    953             <object name="idle-overlay" size="-85 -85 100% 100%" type="image" sprite="stretched:session/minimap-idle.png" ghost="true"/>
    954             <!-- Since we don't support non-rectangular buttons, we approximate the area using 3 rectangles TODO: Make this cleaner -->
    955             <object type="button"
    956                 tooltip_style="sessionToolTip"
    957                 tooltip="Find idle worker"
    958                 hotkey="selection.idleworker"
    959             >
    960                 <action on="Press">findIdleUnit(["Female", "Trade", "FishingBoat", "CitizenSoldier", "Healer"]);</action>
     960        <object size="100%-75 100%-75 100% 100%">
     961            <object name="minimap_button[2]" size="0 0 100% 100%" type="button" ghost="true"
     962            sprite="stretched:session/icons/minimap/idle_border.png"
     963            sprite_over="stretched:session/icons/minimap/idle_border_hover.png"
     964            tooltip_style="sessionToolTip"
     965            tooltip="Find idle worker"
     966            hotkey="selection.idleworker">
     967            <action on="Press">findIdleUnit(["Female", "Trade", "FishingBoat", "CitizenSoldier", "Healer"]);</action>
    961968            </object>
    962             <object type="button"
    963                 tooltip_style="sessionToolTip"
    964                 tooltip="Find idle worker"
    965                 size="15 -15 100% 0"
    966             >
    967                 <action on="Press">findIdleUnit(["Female", "Trade", "FishingBoat", "CitizenSoldier", "Healer"]);</action>
     969        </object>
     970       
     971        <!-- Zoom Button (deactivated until function is implemented)-->
     972        <object size="0 100%-75 75 100%">
     973            <object name="minimap_button[3]" size="0 0 100% 100%" type="button" ghost="true"
     974            sprite="stretched:grayscale:session/icons/minimap/zoom_border.png"
     975            sprite_over="stretched:session/icons/minimap/zoom_border_hover.png"
     976            enabled="false">
    968977            </object>
    969             <object type="button"
    970                 tooltip_style="sessionToolTip"
    971                 tooltip="Find idle worker"
    972                 size="-15 15 0 100%"
    973             >
    974                 <action on="Press">findIdleUnit(["Female", "Trade", "FishingBoat", "CitizenSoldier", "Healer"]);</action>
     978        </object>
     979       
     980        <!-- Flare Button (deactivated until function is implemented)-->
     981        <object size="0 0 75 75">
     982            <object name="minimap_button[4]" size="0 0 100% 100%" type="button" ghost="true"
     983            sprite="stretched:grayscale:session/icons/minimap/flare_border.png"
     984            sprite_over="stretched:session/icons/minimap/flare_border_hover.png"
     985            enabled="false">
    975986            </object>
    976987        </object>
    977988    </object>
  • source/gui/IGUIObject.cpp

     
    223223    }
    224224}
    225225
     226void IGUIObject::UpdateMouseOverExternCall(IGUIObject * const &pMouseOver)
     227{
     228    UpdateMouseOver(pMouseOver);
     229}
     230
    226231bool IGUIObject::SettingExists(const CStr& Setting) const
    227232{
    228233    // Because GetOffsets will direct dynamically defined
  • source/gui/IGUIObject.h

     
    390390     */
    391391    void SetFocus();
    392392
     393    /**
     394     * calls UpdateMouseOver which is protected;
     395     * this should only be used in RARE cases where no other solution can be found.
     396     */
     397    void UpdateMouseOverExternCall(IGUIObject * const &pMouseOver);
     398
    393399protected:
    394400    /**
    395401     * Check if object is focused.
  • source/gui/MiniMap.cpp

     
    6969    AddSetting(GUIST_CStr,      "tooltip_style");
    7070    m_Clicking = false;
    7171    m_MouseHovering = false;
     72    m_lastHoveredButton = NULL;
     73    m_px = 0.5;
     74    m_py = 0.5;
    7275   
    7376    // Get the maximum height for unit passage in water.
    7477    CParamNode externalParamNode;
     
    137140
    138141void CMiniMap::HandleMessage(SGUIMessage &Message)
    139142{
     143    // get scaled map coordinates
     144    UpdateScaledMapCoordinates();
     145   
     146    // mouse position is within the circle
     147    if (IsPostionInCircle(m_px, m_py))
     148        DisableMinimapButtonHovering();
     149
     150    // choose what action should be performed
    140151    switch(Message.type)
    141152    {
    142153    case GUIM_MOUSE_PRESS_LEFT:
     
    151162    case GUIM_MOUSE_RELEASE_LEFT:
    152163        {
    153164            if(m_MouseHovering && m_Clicking)
    154             {
    155165                SetCameraPos();
    156             }
     166
    157167            m_Clicking = false;
    158168            break;
    159169        }
     
    160170    case GUIM_MOUSE_DBLCLICK_LEFT:
    161171        {
    162172            if(m_MouseHovering && m_Clicking)
    163             {
    164173                SetCameraPos();
    165             }
     174
    166175            m_Clicking = false;
    167176            break;
    168177        }
     
    175184        {
    176185            m_Clicking = false;
    177186            m_MouseHovering = false;
     187            DisableMinimapButtonHovering();
    178188            break;
    179189        }
    180190    case GUIM_MOUSE_RELEASE_RIGHT:
     
    203213    default:
    204214        break;
    205215    }   // switch
     216
     217    // check, if mouse position starts after little spacing to the circle
     218    if (m_MouseHovering && IsPostionInButtonRange(m_px, m_py))
     219    {
     220        int buttonID;
     221        GetNumberOfButton(m_px, m_py, buttonID);
     222        if (!m_lastHoveredButton && buttonID != 0)
     223        {
     224            char buttonName[32];
     225            sprintf(buttonName, "minimap_button[%d]", buttonID);
     226
     227            // get the button and trigger hover effect
     228            m_lastHoveredButton = g_GUI->FindObjectByName(buttonName);
     229            if (m_lastHoveredButton)
     230                m_lastHoveredButton->UpdateMouseOverExternCall(m_lastHoveredButton);
     231        }
     232        else if(buttonID == 0)
     233            DisableMinimapButtonHovering();
     234        else
     235        {
     236            // let the button handle it's states by itself
     237            m_lastHoveredButton->HandleMessage(Message);
     238
     239            // fix: after release of button hover is not there
     240            if (Message.type == GUIM_MOUSE_RELEASE_LEFT || Message.type == GUIM_MOUSE_RELEASE_RIGHT)
     241            {
     242                // TODO: Why is this not working ?!? How does it work for a "regular" button ?
     243                m_lastHoveredButton->UpdateMouseOverExternCall(NULL);
     244                m_lastHoveredButton->UpdateMouseOverExternCall(m_lastHoveredButton);
     245            }
     246        }
     247    }
    206248}
    207249
    208 void CMiniMap::GetMouseWorldCoordinates(float& x, float& z)
     250void CMiniMap::GetNumberOfButton(float px, float py, int& buttonID)
    209251{
    210     // Determine X and Z according to proportion of mouse position and minimap
     252    // get the clock angle
     253    float angleFloat;
     254    GetClockAngle(px, py, angleFloat);
     255    int angle = (int) angleFloat;
     256       
     257    // check, if any button is hit
     258    int mod45 = angle % 45;
     259    int mod90 = angle % 90;
     260       
     261    // some button is hovered (approximation with angles (45° +- 16°, 135° +- 16°, ...)
     262    if ((mod45 <= 16 || (mod45-45) >= -16) && !(mod90 <= 16 || (mod90-90) >= -16))
     263        buttonID = ((int) angle/90) + 1;
     264    else
     265        buttonID = 0;
     266}
    211267
     268void CMiniMap::DisableMinimapButtonHovering()
     269{
     270    if (m_lastHoveredButton)
     271    {
     272        m_lastHoveredButton->UpdateMouseOverExternCall(NULL); // button is not hovered anymore
     273        m_lastHoveredButton = NULL;
     274    }
     275}
     276
     277void CMiniMap::UpdateScaledMapCoordinates()
     278{
     279    GetScaledMapCoordinates(m_px, m_py);
     280}
     281
     282void CMiniMap::GetScaledMapCoordinates(float& px, float &py)
     283{
    212284    CPos mousePos = GetMousePos();
    213285
    214     float px = (mousePos.x - m_CachedActualSize.left) / m_CachedActualSize.GetWidth();
    215     float py = (m_CachedActualSize.bottom - mousePos.y) / m_CachedActualSize.GetHeight();
     286    px = (mousePos.x - m_CachedActualSize.left) / m_CachedActualSize.GetWidth();
     287    py = (m_CachedActualSize.bottom - mousePos.y) / m_CachedActualSize.GetHeight();
     288}
    216289
    217     float angle = GetAngle();
     290void CMiniMap::GetDistanceFromCenter(float px, float py, float& distance)
     291{
     292    // calculate distance from center of circle
     293    float dx = px-0.5f;
     294    float dy = py-0.5f;
     295   
     296    distance = sqrt(dx*dx + dy*dy);
     297}
    218298
    219     // Scale world coordinates for shrunken square map
    220     x = TERRAIN_TILE_SIZE * m_MapSize * (m_MapScale * (cos(angle)*(px-0.5) - sin(angle)*(py-0.5)) + 0.5);
    221     z = TERRAIN_TILE_SIZE * m_MapSize * (m_MapScale * (cos(angle)*(py-0.5) + sin(angle)*(px-0.5)) + 0.5);
     299bool CMiniMap::IsPostionInButtonRange(float px, float py)
     300{
     301    float distance;
     302    GetDistanceFromCenter(px, py, distance);
     303   
     304    return (distance >= 0.55f);
    222305}
    223306
     307bool CMiniMap::IsPostionInCircle(float px, float py)
     308{
     309    float distance;
     310    GetDistanceFromCenter(px, py, distance);
     311   
     312    return (distance <= 0.5f); 
     313}
     314
     315void CMiniMap::GetClockAngle(float px, float py, float& angleClock)
     316{
     317    // set up some points
     318    CVector3D center = CVector3D(0.5f, 0.5f, 0.0f);
     319    CVector3D vertical = CVector3D(0.5f, 1.0f, 0.0f);
     320    CVector3D direction = CVector3D(px, py, 0.0f);
     321   
     322    // calculate vectors
     323    CVector3D vc = CVector3D(vertical.X - center.X, vertical.Y - center.Y, 0.0f);
     324    CVector3D dc = CVector3D(direction.X - center.X, direction.Y - center.Y, 0.0f);
     325
     326    // calculate length of vectors
     327    float lengthVC = sqrt(vc.X*vc.X + vc.Y*vc.Y);
     328    float lengthDC = sqrt(dc.X*dc.X + dc.Y*dc.Y);
     329    // calculate scalar prodcut of cectors
     330    float scalar = vc.X*dc.X + vc.Y*dc.Y;
     331    // calculate angle between two vectors
     332    angleClock = acos(scalar / (lengthVC*lengthDC)) * 180.0f / M_PI;
     333   
     334    // check for correct oriantation
     335    if (px < 0.5f)
     336    {
     337        if (py > 0.5f)
     338            angleClock = angleClock + 270.0f;
     339        else
     340            angleClock = angleClock + 90.0f;
     341    }
     342}
     343
     344void CMiniMap::GetMouseWorldCoordinates(float& x, float& z, int& buttonID)
     345{
     346    // inside the circle
     347    if (IsPostionInCircle(m_px, m_py))
     348    {
     349        float angle = GetAngle();
     350
     351        // Scale world coordinates for shrunken square map
     352        x = TERRAIN_TILE_SIZE * m_MapSize * (m_MapScale * (cos(angle)*(m_px-0.5) - sin(angle)*(m_py-0.5)) + 0.5);
     353        z = TERRAIN_TILE_SIZE * m_MapSize * (m_MapScale * (cos(angle)*(m_py-0.5) + sin(angle)*(m_px-0.5)) + 0.5);
     354        buttonID = 0; // set buttonID to dummy value
     355    }
     356    else if(IsPostionInButtonRange(m_px, m_py))
     357    {
     358        GetNumberOfButton(m_px, m_py, buttonID);
     359        // set x and z to dummy values
     360        x = -1;
     361        z = -1;
     362    }
     363}
     364
    224365void CMiniMap::SetCameraPos()
    225366{
    226367    CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
    227368
    228369    CVector3D target;
    229     GetMouseWorldCoordinates(target.X, target.Z);
    230     target.Y = terrain->GetExactGroundLevel(target.X, target.Z);
    231     g_Game->GetView()->MoveCameraTarget(target);
     370    int buttonID;
     371    GetMouseWorldCoordinates(target.X, target.Z, buttonID);
     372    // click within the circle
     373    if (IsPostionInCircle(m_px, m_py))
     374    {
     375        target.Y = terrain->GetExactGroundLevel(target.X, target.Z);
     376        g_Game->GetView()->MoveCameraTarget(target);
     377    }
    232378}
    233379
    234380float CMiniMap::GetAngle()
     
    239385
    240386void CMiniMap::FireWorldClickEvent(int button, int clicks)
    241387{
     388    int buttonID;
    242389    float x, z;
    243     GetMouseWorldCoordinates(x, z);
     390    GetMouseWorldCoordinates(x, z, buttonID);
    244391
    245     CScriptValRooted coords;
    246     g_GUI->GetActiveGUI()->GetScriptInterface()->Eval("({})", coords);
    247     g_GUI->GetActiveGUI()->GetScriptInterface()->SetProperty(coords.get(), "x", x, false);
    248     g_GUI->GetActiveGUI()->GetScriptInterface()->SetProperty(coords.get(), "z", z, false);
    249     ScriptEvent("worldclick", coords);
     392    CScriptValRooted data;
     393    g_GUI->GetActiveGUI()->GetScriptInterface()->Eval("({})", data);
     394    // click within the circle
     395    if (IsPostionInCircle(m_px, m_py))
     396    {
     397        g_GUI->GetActiveGUI()->GetScriptInterface()->SetProperty(data.get(), "x", x, false);
     398        g_GUI->GetActiveGUI()->GetScriptInterface()->SetProperty(data.get(), "z", z, false);
     399        ScriptEvent("worldclick", data);    // send the event
     400    }
     401   
    250402
    251403    UNUSED2(button);
    252404    UNUSED2(clicks);
  • source/gui/MiniMap.h

     
    2020
    2121#include "gui/GUI.h"
    2222#include "renderer/VertexArray.h"
     23#include <cmath>
    2324
    24 
    2525class CCamera;
    2626class CTerrain;
    2727
     
    8383    // maximal water height to allow the passage of a unit (for underwater shallows).
    8484    float m_ShallowPassageHeight;
    8585
     86    // last hovered button of the minimap
     87    IGUIObject* m_lastHoveredButton;
     88
     89    // scaled x and y values are cached here
     90    float m_px, m_py;
     91
    8692    void DrawTexture(CShaderProgramPtr shader, float coordMax, float angle, float x, float y, float x2, float y2, float z);
    8793
    8894    void DrawViewRect();
    8995
    90     void GetMouseWorldCoordinates(float& x, float& z);
    91 
     96    void GetMouseWorldCoordinates(float& x, float& z, int& buttonID);
     97    void GetDistanceFromCenter(float px, float py, float& distance);
     98    void UpdateScaledMapCoordinates();
     99    void GetScaledMapCoordinates(float& px, float &py);
     100    bool IsPostionInCircle(float px, float py);
     101    bool IsPostionInButtonRange(float px, float py);
     102    void GetClockAngle(float px, float py, float& angleClock);
     103    void DisableMinimapButtonHovering();
     104    void GetNumberOfButton(float px, float py, int& buttonID);
     105   
    92106    float GetAngle();
    93107
    94108    VertexIndexArray m_IndexArray;