aboutsummaryrefslogtreecommitdiff
path: root/Minecraft.Client/Common/UI/UIController.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Minecraft.Client/Common/UI/UIController.cpp')
-rw-r--r--Minecraft.Client/Common/UI/UIController.cpp262
1 files changed, 203 insertions, 59 deletions
diff --git a/Minecraft.Client/Common/UI/UIController.cpp b/Minecraft.Client/Common/UI/UIController.cpp
index 95423642..9109b85f 100644
--- a/Minecraft.Client/Common/UI/UIController.cpp
+++ b/Minecraft.Client/Common/UI/UIController.cpp
@@ -3,6 +3,7 @@
#include "UI.h"
#include "UIScene.h"
#include "UIControl_Slider.h"
+#include "UIControl_TexturePackList.h"
#include "..\..\..\Minecraft.World\StringHelpers.h"
#include "..\..\LocalPlayer.h"
#include "..\..\DLCTexturePack.h"
@@ -237,6 +238,8 @@ UIController::UIController()
m_winUserIndex = 0;
m_mouseDraggingSliderScene = eUIScene_COUNT;
m_mouseDraggingSliderId = -1;
+ m_mouseClickConsumedByScene = false;
+ m_bMouseHoverHorizontalList = false;
m_lastHoverMouseX = -1;
m_lastHoverMouseY = -1;
m_accumulatedTicks = 0;
@@ -784,40 +787,36 @@ void UIController::tickInput()
#endif
{
#ifdef _WINDOWS64
+ m_mouseClickConsumedByScene = false;
if (!g_KBMInput.IsMouseGrabbed() && g_KBMInput.IsKBMActive())
{
UIScene *pScene = NULL;
- for (int grp = 0; grp < eUIGroup_COUNT && !pScene; ++grp)
+ // Search by layer priority across all groups (layer-first).
+ // Tooltip layer is skipped because it holds non-interactive
+ // overlays (button hints, timer) that should never capture mouse.
+ // Old group-first order found those tooltips on eUIGroup_Fullscreen
+ // before reaching in-game menus on eUIGroup_Player1.
+ static const EUILayer mouseLayers[] = {
+#ifndef _CONTENT_PACKAGE
+ eUILayer_Debug,
+#endif
+ eUILayer_Error,
+ eUILayer_Alert,
+ eUILayer_Popup,
+ eUILayer_Fullscreen,
+ eUILayer_Scene,
+ };
+ for (int l = 0; l < _countof(mouseLayers) && !pScene; ++l)
{
- pScene = m_groups[grp]->GetTopScene(eUILayer_Debug);
- if (!pScene) pScene = m_groups[grp]->GetTopScene(eUILayer_Tooltips);
- if (!pScene) pScene = m_groups[grp]->GetTopScene(eUILayer_Error);
- if (!pScene) pScene = m_groups[grp]->GetTopScene(eUILayer_Alert);
- if (!pScene) pScene = m_groups[grp]->GetTopScene(eUILayer_Popup);
- if (!pScene) pScene = m_groups[grp]->GetTopScene(eUILayer_Fullscreen);
- if (!pScene) pScene = m_groups[grp]->GetTopScene(eUILayer_Scene);
+ for (int grp = 0; grp < eUIGroup_COUNT && !pScene; ++grp)
+ {
+ pScene = m_groups[grp]->GetTopScene(mouseLayers[l]);
+ }
}
if (pScene && pScene->getMovie())
{
- Iggy *movie = pScene->getMovie();
int rawMouseX = g_KBMInput.GetMouseX();
int rawMouseY = g_KBMInput.GetMouseY();
- F32 mouseX = (F32)rawMouseX;
- F32 mouseY = (F32)rawMouseY;
-
- extern HWND g_hWnd;
- if (g_hWnd)
- {
- RECT rc;
- GetClientRect(g_hWnd, &rc);
- int winW = rc.right - rc.left;
- int winH = rc.bottom - rc.top;
- if (winW > 0 && winH > 0)
- {
- mouseX = mouseX * (m_fScreenWidth / (F32)winW);
- mouseY = mouseY * (m_fScreenHeight / (F32)winH);
- }
- }
// Only update hover focus when the mouse has actually moved,
// so that mouse-wheel scrolling can change list selection
@@ -826,46 +825,24 @@ void UIController::tickInput()
m_lastHoverMouseX = rawMouseX;
m_lastHoverMouseY = rawMouseY;
- if (mouseMoved)
+ // Convert mouse to scene/movie coordinates
+ F32 sceneMouseX = (F32)rawMouseX;
+ F32 sceneMouseY = (F32)rawMouseY;
{
- IggyFocusHandle currentFocus = IGGY_FOCUS_NULL;
- IggyFocusableObject focusables[64];
- S32 numFocusables = 0;
- IggyPlayerGetFocusableObjects(movie, &currentFocus, focusables, 64, &numFocusables);
-
- if (numFocusables > 0 && numFocusables <= 64)
+ extern HWND g_hWnd;
+ RECT rc;
+ if (g_hWnd && GetClientRect(g_hWnd, &rc))
{
- IggyFocusHandle hitObject = IGGY_FOCUS_NULL;
- for (S32 i = 0; i < numFocusables; ++i)
- {
- if (mouseX >= focusables[i].x0 && mouseX <= focusables[i].x1 &&
- mouseY >= focusables[i].y0 && mouseY <= focusables[i].y1)
- {
- hitObject = focusables[i].object;
- break;
- }
- }
-
- if (hitObject != currentFocus)
+ int winW = rc.right - rc.left;
+ int winH = rc.bottom - rc.top;
+ if (winW > 0 && winH > 0)
{
- IggyPlayerSetFocusRS(movie, hitObject, 0);
+ sceneMouseX = sceneMouseX * ((F32)pScene->getRenderWidth() / (F32)winW);
+ sceneMouseY = sceneMouseY * ((F32)pScene->getRenderHeight() / (F32)winH);
}
}
}
- // Convert mouse to scene/movie coordinates for slider hit testing
- F32 sceneMouseX = mouseX;
- F32 sceneMouseY = mouseY;
- {
- S32 displayWidth = 0, displayHeight = 0;
- pScene->GetParentLayer()->getRenderDimensions(displayWidth, displayHeight);
- if (displayWidth > 0 && displayHeight > 0)
- {
- sceneMouseX = mouseX * ((F32)pScene->getRenderWidth() / (F32)displayWidth);
- sceneMouseY = mouseY * ((F32)pScene->getRenderHeight() / (F32)displayHeight);
- }
- }
-
// Get main panel offset (controls are positioned relative to it)
S32 panelOffsetX = 0, panelOffsetY = 0;
UIControl *pMainPanel = pScene->GetMainPanel();
@@ -876,6 +853,110 @@ void UIController::tickInput()
panelOffsetY = pMainPanel->getYPos();
}
+ // Mouse hover — hit test against C++ control bounds.
+ // Simple controls use SetFocusToElement; list controls
+ // use their own SetTouchFocus for Flash-side hit testing.
+ if (mouseMoved)
+ {
+ m_bMouseHoverHorizontalList = false;
+ vector<UIControl *> *controls = pScene->GetControls();
+ if (controls)
+ {
+ int hitControlId = -1;
+ S32 hitArea = INT_MAX;
+ UIControl *hitCtrl = NULL;
+ for (size_t i = 0; i < controls->size(); ++i)
+ {
+ UIControl *ctrl = (*controls)[i];
+ if (!ctrl || ctrl->getHidden() || !ctrl->getVisible() || ctrl->getId() < 0)
+ continue;
+
+ UIControl::eUIControlType type = ctrl->getControlType();
+ if (type != UIControl::eButton && type != UIControl::eTextInput &&
+ type != UIControl::eCheckBox && type != UIControl::eSlider &&
+ type != UIControl::eButtonList && type != UIControl::eTexturePackList)
+ continue;
+
+ // If the scene has an active panel (e.g. tab menus),
+ // skip controls that aren't children of that panel.
+ if (pMainPanel && ctrl->getParentPanel() != pMainPanel)
+ continue;
+
+ ctrl->UpdateControl();
+ S32 cx = ctrl->getXPos() + panelOffsetX;
+ S32 cy = ctrl->getYPos() + panelOffsetY;
+ S32 cw = ctrl->getWidth();
+ S32 ch = ctrl->getHeight();
+ // TexturePackList origin is where the slot area starts,
+ // not the top-left of the whole control — use GetRealHeight.
+ if (type == UIControl::eTexturePackList)
+ ch = ((UIControl_TexturePackList *)ctrl)->GetRealHeight();
+ if (cw <= 0 || ch <= 0)
+ continue;
+
+ if (sceneMouseX >= cx && sceneMouseX <= cx + cw &&
+ sceneMouseY >= cy && sceneMouseY <= cy + ch)
+ {
+ if (type == UIControl::eButtonList)
+ {
+ // ButtonList manages focus internally via Flash —
+ // pass mouse coords so it can highlight the right item.
+ ((UIControl_ButtonList *)ctrl)->SetTouchFocus(
+ (S32)sceneMouseX, (S32)sceneMouseY, false);
+ hitControlId = -1;
+ hitArea = INT_MAX;
+ hitCtrl = NULL;
+ break; // ButtonList takes priority
+ }
+ if (type == UIControl::eTexturePackList)
+ {
+ // TexturePackList expects coords relative to its origin.
+ UIControl_TexturePackList *pList = (UIControl_TexturePackList *)ctrl;
+ pScene->SetFocusToElement(ctrl->getId());
+ pList->SetTouchFocus(
+ (S32)(sceneMouseX - cx), (S32)(sceneMouseY - cy), false);
+ m_bMouseHoverHorizontalList = true;
+ hitControlId = -1;
+ hitArea = INT_MAX;
+ hitCtrl = NULL;
+ break;
+ }
+ S32 area = cw * ch;
+ if (area < hitArea)
+ {
+ hitControlId = ctrl->getId();
+ hitArea = area;
+ hitCtrl = ctrl;
+ if (type == UIControl::eSlider)
+ m_bMouseHoverHorizontalList = true;
+ }
+ }
+ }
+
+ if (hitControlId >= 0 && pScene->getControlFocus() != hitControlId)
+ {
+ // During direct editing, don't let hover move focus
+ // away to other TextInputs (e.g. sign lines).
+ if (hitCtrl && hitCtrl->getControlType() == UIControl::eTextInput
+ && pScene->isDirectEditBlocking())
+ {
+ // Skip — keep focus on the actively-edited input
+ }
+ else
+ {
+ pScene->SetFocusToElement(hitControlId);
+ // TextInput: SetFocusToElement triggers ChangeState which
+ // shows the caret. Hide it immediately — the render pass
+ // happens after both tickInput and scene tick, so no flicker.
+ if (hitCtrl && hitCtrl->getControlType() == UIControl::eTextInput)
+ {
+ ((UIControl_TextInput *)hitCtrl)->setCaretVisible(false);
+ }
+ }
+ }
+ }
+ }
+
bool leftPressed = g_KBMInput.IsMouseButtonPressed(KeyboardMouseInput::MOUSE_LEFT);
bool leftDown = leftPressed || g_KBMInput.IsMouseButtonDown(KeyboardMouseInput::MOUSE_LEFT);
@@ -890,12 +971,51 @@ void UIController::tickInput()
vector<UIControl *> *controls = pScene->GetControls();
if (controls)
{
+ // Set Iggy dispatch focus for TextInput on click (not hover)
+ // so ACTION_MENU_OK targets the correct text field.
+ for (size_t i = 0; i < controls->size(); ++i)
+ {
+ UIControl *ctrl = (*controls)[i];
+ if (!ctrl || ctrl->getControlType() != UIControl::eTextInput || !ctrl->getVisible())
+ continue;
+ if (pMainPanel && ctrl->getParentPanel() != pMainPanel)
+ continue;
+ ctrl->UpdateControl();
+ S32 cx = ctrl->getXPos() + panelOffsetX;
+ S32 cy = ctrl->getYPos() + panelOffsetY;
+ S32 cw = ctrl->getWidth();
+ S32 ch = ctrl->getHeight();
+ if (cw > 0 && ch > 0 &&
+ sceneMouseX >= cx && sceneMouseX <= cx + cw &&
+ sceneMouseY >= cy && sceneMouseY <= cy + ch)
+ {
+ Iggy *movie = pScene->getMovie();
+ IggyFocusHandle currentFocus = IGGY_FOCUS_NULL;
+ IggyFocusableObject focusables[64];
+ S32 numFocusables = 0;
+ IggyPlayerGetFocusableObjects(movie, &currentFocus, focusables, 64, &numFocusables);
+ for (S32 fi = 0; fi < numFocusables && fi < 64; ++fi)
+ {
+ if (sceneMouseX >= focusables[fi].x0 && sceneMouseX <= focusables[fi].x1 &&
+ sceneMouseY >= focusables[fi].y0 && sceneMouseY <= focusables[fi].y1)
+ {
+ IggyPlayerSetFocusRS(movie, focusables[fi].object, 0);
+ break;
+ }
+ }
+ break;
+ }
+ }
+
for (size_t i = 0; i < controls->size(); ++i)
{
UIControl *ctrl = (*controls)[i];
if (!ctrl || ctrl->getControlType() != UIControl::eSlider || !ctrl->getVisible())
continue;
+ if (pMainPanel && ctrl->getParentPanel() != pMainPanel)
+ continue;
+
UIControl_Slider *pSlider = (UIControl_Slider *)ctrl;
pSlider->UpdateControl();
S32 cx = pSlider->getXPos() + panelOffsetX;
@@ -942,6 +1062,12 @@ void UIController::tickInput()
m_mouseDraggingSliderScene = eUIScene_COUNT;
m_mouseDraggingSliderId = -1;
}
+
+ // Let the scene handle mouse clicks for custom navigation (e.g. crafting slots)
+ if (leftPressed && m_mouseDraggingSliderId < 0)
+ {
+ m_mouseClickConsumedByScene = pScene->handleMouseClick(sceneMouseX, sceneMouseY);
+ }
}
}
#endif
@@ -1206,7 +1332,7 @@ void UIController::handleKeyPress(unsigned int iPad, unsigned int key)
if ((key == ACTION_MENU_OK || key == ACTION_MENU_A) && !g_KBMInput.IsMouseGrabbed())
{
- if (m_mouseDraggingSliderId < 0)
+ if (m_mouseDraggingSliderId < 0 && !m_mouseClickConsumedByScene)
{
if (g_KBMInput.IsMouseButtonPressed(KeyboardMouseInput::MOUSE_LEFT)) { pressed = true; down = true; }
if (g_KBMInput.IsMouseButtonReleased(KeyboardMouseInput::MOUSE_LEFT)) { released = true; down = false; }
@@ -1214,6 +1340,14 @@ void UIController::handleKeyPress(unsigned int iPad, unsigned int key)
}
}
+ // Right click → ACTION_MENU_X (pick up half stack in inventory)
+ if (key == ACTION_MENU_X && !g_KBMInput.IsMouseGrabbed())
+ {
+ if (g_KBMInput.IsMouseButtonPressed(KeyboardMouseInput::MOUSE_RIGHT)) { pressed = true; down = true; }
+ if (g_KBMInput.IsMouseButtonReleased(KeyboardMouseInput::MOUSE_RIGHT)) { released = true; down = false; }
+ if (!pressed && !released && g_KBMInput.IsMouseButtonDown(KeyboardMouseInput::MOUSE_RIGHT)) { down = true; }
+ }
+
// Scroll wheel for list scrolling — only consume the wheel value when the
// action key actually matches, so the other direction isn't lost.
if (!g_KBMInput.IsMouseGrabbed() && (key == ACTION_MENU_OTHER_STICK_UP || key == ACTION_MENU_OTHER_STICK_DOWN))
@@ -1231,6 +1365,16 @@ void UIController::handleKeyPress(unsigned int iPad, unsigned int key)
pressed = true;
down = true;
}
+
+ // Remap scroll wheel to navigation actions. Use LEFT/RIGHT when
+ // hovering a horizontal list (e.g. TexturePackList), UP/DOWN otherwise.
+ if (pressed && g_KBMInput.IsKBMActive())
+ {
+ if (m_bMouseHoverHorizontalList)
+ key = (key == ACTION_MENU_OTHER_STICK_UP) ? ACTION_MENU_LEFT : ACTION_MENU_RIGHT;
+ else
+ key = (key == ACTION_MENU_OTHER_STICK_UP) ? ACTION_MENU_UP : ACTION_MENU_DOWN;
+ }
}
}
#endif