- UI 포커스에 관한 구현.
간단한 기능인데, 생각보다 고려할 게 많았다.
// CUIMgr.h
...
class CUIMgr
{
SINGLETON(CUIMgr)
private:
CUI* m_pFocusParentUI; // 현재 포커스된 parent UI.
CUI* m_pSelectedParentUI; // 현재 선택된(클릭된) parent UI.
public:
void SetSelectedParentUI(CUI* pUI);
private:
void UIMouseCheck(CUI* pUI);
CUI* FindFocusedChildUI(CUI* pUI);
CUI* FindFocusedParentUI();
...
};
먼저 focus 된 것과 select 된 것을 분리해서 기록하기로 함.
그리고 일단 parent ui 만을 기준으로 했다. child ui 는 그냥 이후에 추가하면 될 듯?
// CUIMgr.cpp
...
void CUIMgr::late_update()
{
// 현재 씬에서 포커스된 UI 요소의 최상위 부모 UI를 찾음.
m_pFocusParentUI = FindFocusedParentUI();
// 그 부모 UI로부터 포커스를 받는 자식 UI를 찾고 마우스 입력을 검사.
// nullptr 일 때도 처리.
if (m_pFocusParentUI) UIMouseCheck(m_pFocusParentUI->GetFocusedChildUI());
else UIMouseCheck(nullptr);
...
우선 focus 된 부모를 찾는다. 찾는 과정에서 각 부모 ui는 최종적으로 focus 된 child 를 저장해둘 거임.
부모를 찾았다면, 여기서 최종 focus 된 child 를 GetFocusedChildUI 로 불러온다. 이걸 UIMouseCheck 에 넘겨주면?
최종 UI 에 대한 마우스 입력 처리를 가능하게 함.
없다면 nullptr 에 대한 처리를 하도록 해줌.
// CUIMgr.cpp
...
CUI* CUIMgr::FindFocusedParentUI()
{
CScene* pCurScene = CSceneMgr::GetInstance()->GetCurScene();
if (pCurScene == nullptr)
return nullptr;
const vector<CObject*>& vecUI = pCurScene->GetObjByGroup(GROUP_TYPE::UI);
CUI* pFocusedParentUI = nullptr;
for (CObject* pObj : vecUI)
{
// UI 그룹이므로 static_cast 사용.
CUI* pParentUI = static_cast<CUI*>(pObj);
if (pParentUI == nullptr)
continue;
// 자식 UI에서 포커스된 UI 요소를 찾음
if (CUI* pFocusedChildUI = FindFocusedChildUI(pParentUI))
{
// 해당 parent ui 의 포커스된 자식 UI 설정.
pParentUI->SetFocusedChildUI(pFocusedChildUI);
// 최종 포커스된 부모 UI 갱신.
pFocusedParentUI = pParentUI;
}
else
{
pParentUI->SetFocusedChildUI(nullptr);
}
}
return pFocusedParentUI;
}
FindFocusedParentUI 는 단순히 vector 를 순회하면서 자식중에 포커스된 것이 있으면, 해당 parent ui 를 반환값으로 지정한다.
이렇게 하면 뒤에 있는 UI 가 우선권을 가짐.
// CUIMgr.cpp
...
CUI* CUIMgr::FindFocusedChildUI(CUI* pParentUI)
{
if(pParentUI == nullptr)
return nullptr;
static queue<CUI*> qUI = {};
// 기존 포커스 UI 에 대한 button release 처리해줘야 함.
bool bLButtonRelease = KEYRELEASECHECK(KEY::LBUTTON);
// 큐 초기화.
while (!qUI.empty())
qUI.pop();
// 부모 UI도 focus 검사 대상에 포함.
qUI.push(pParentUI);
CUI* pFocusedChildUI = nullptr;
while (!qUI.empty())
{
CUI* pCurrentUI = qUI.front();
qUI.pop();
if(pCurrentUI == nullptr)
continue;
// 현재 UI가 마우스 Hover or LButtonDown 상태라면, 포커스를 받는 UI로 설정
if (pCurrentUI->IsMouseHover() || pCurrentUI->IsLButtonDown())
{
// 기존 포커스 UI에 대한 button release 처리
if (pFocusedChildUI && bLButtonRelease)
{
if (pFocusedChildUI->IsLButtonDown())
{
pFocusedChildUI->OnLButtonUp();
}
}
// 최종 포커스 UI 갱신
pFocusedChildUI = pCurrentUI;
}
// 자식 UI들을 큐에 추가
const vector<CUI*>& vecChildUIs = pCurrentUI->GetChildUIs();
for (CUI* pChildUI : vecChildUIs)
{
qUI.push(pChildUI);
}
}
return pFocusedChildUI;
}
이전에 GetTargetUI 를 이름 바꾸고 조금 수정한 버전. 이제보니 이름만 바꾼 듯 ㅇㅅㅇ.
// CUIMgr.cpp
...
void CUIMgr::UIMouseCheck(CUI* pUI)
{
bool bLButtonTap = KEYTAPCHECK(KEY::LBUTTON);
bool bLButtonRelease = KEYRELEASECHECK(KEY::LBUTTON);
// LButton 이 눌렸다면 m_pFocusParentUI 를 맨 뒤로 보냄.
// nullptr 일 때도 처리.
if(bLButtonTap)
{
SetSelectedParentUI(m_pFocusParentUI);
}
// 이후는 nullptr 이면 수행하지 않음.
if(pUI == nullptr)
return;
...
}
UIMouseCheck 에서는 기존 코드에 전처리로 몇 줄 추가함.
LButton 이 눌린 상태면, m_pFocusParentUI 를 Select 된 것으로 갱신한다. nullptr 일 때도 해줌.
// CUIMgr.cpp
...
void CUIMgr::SetSelectedParentUI(CUI* pUI)
{
if (pUI == nullptr)
{
// nullptr이 전달되면 선택된 UI를 해제.
m_pSelectedParentUI = nullptr;
return;
}
CScene* pCurScene = CSceneMgr::GetInstance()->GetCurScene();
if (pCurScene)
{
// 선택된 UI를 맨 뒤로 보냄.
pCurScene->MoveObjectToBack(pUI, GROUP_TYPE::UI);
}
// 선택된 UI 설정.
m_pSelectedParentUI = pUI;
}
해당 함수에서는 입력된 UI 를 Selected 로 선택한다. nullptr 이 아니라면 해당 UI 는 벡터 맨 뒤로 보내서
맨 앞 렌더링될 수 있도록 함.
'Win32 api' 카테고리의 다른 글
| Win32 api 강의 54화. (0) | 2025.09.27 |
|---|---|
| Win32 api 강의 53화. (0) | 2025.09.26 |
| Win32 api 강의 51화. (0) | 2025.09.25 |
| Win32 api 강의 49 - 50화. (0) | 2025.09.25 |
| Win32 api 강의 48화. (0) | 2025.09.24 |