Files
Leviathan/Client/Game/engine/Ui/Controls/KUIControlCombo.cpp
T
2026-06-01 12:46:52 +02:00

479 lines
12 KiB
C++

#include "stdafx.h"
#include "KUIDefine.h"
#include "KUIWndManager.h"
#include "KResourceManager.h"
#include "KUITextureManager.h"
#include "KUIControlButton.h"
#include "KUIControlStatic.h"
#include "KUIControlCombo.h"
namespace
{
KUIWnd* Creator()
{
return new KUIControlCombo;
}
bool bRegister = KUIFactory::GetInstance()->RegisterCreator( Creator, "combo_box");
LPCSTR COMBO_BTN_ANI_NAME = "button_common_down";
LPCSTR COMBO_BTN_ID = "_combo_btn_id";
LPCSTR COMBO_FRAME_ANI_NAME = "static_common_background00";
LPCSTR COMBO_UNFOLD_FRAME_ANI_NAME = "static_common_background00";
LPCSTR COMBO_UNFOLD_FRAME_ID = "_combo_unfold_frame_id";
LPCSTR COMBO_UNFOLD_SELECT_ANI_NAME = "static_combo_select";
LPCSTR COMBO_UNFOLD_SELECT_ID = "_combo_unfold_select_id";
const int COMBO_UNFOLD_Y_OFFSET = 0;
const int COMBO_BTN_Y_OFFSET = 1;
const int COMBO_TEXT_HEIGHT = 12;
const int COMBO_TEXT_GAP = 3;
const int COMBO_ITEM_HEIGHT = 20;
const int COMBO_PHRASE_Y_OFFSET = COMBO_UNFOLD_Y_OFFSET + 3;
const int COMBO_MAX_VIEW_LINE = 20;
const int COMBO_LEFT_FRAME_WIDTH = 4;
const int COMBO_UNFOLD_Y_ADD_HEIGHT = 6;
const int COMBO_UNFOLD_SELECT_Y_OFFSET = 3;
const int COMBO_UNFOLD_SELECT_WIDTH_MARGIN = 6;
const int COMBO_UNFOLD_SELECT_HEIGHT_MARGIN = 4;
const int COMBO_UNFOLD_SELECT_HEIGHT = 16;
}
using namespace KUI_MESSAGE;
KUIControlCombo::KUIControlCombo()
{
m_bFold = true;
m_bUpdate = true;
m_itemWidth = 0;
m_maxViewItemCount = COMBO_MAX_VIEW_LINE;
m_selectItem = -1;
m_preSelectItem = -1;
m_pDownButton = NULL;
m_pUnfoldBack = NULL;
m_pUnfoldSelectBack = NULL;
_registerPhrase(&m_ComboPhrase);
}
void KUIControlCombo::Render( KViewportObject *pViewport, bool isFront)
{
_UpdateComboItem();
KUIControl::Render(pViewport,isFront);
}
void KUIControlCombo::PumpUpMessage( LPCSTR lpszControlID, DWORD nMessage, DWORD lparam, DWORD wparam )
{
switch ( nMessage )
{
case KBUTTON_CLICK:
{
if( strcmp(lpszControlID,COMBO_BTN_ID ) == 0)
{
KUIControl::PumpUpMessage(GetID(), KCOMBO_CLICK, 0, 0);
_SetFold(!m_bFold);
}
}
break;
default:
break;
}
KUIControl::PumpUpMessage(lpszControlID,nMessage,lparam,wparam);
}
DWORD KUIControlCombo::OnMouseMessage(DWORD dwMessage,int x, int y)
{
if( IsDisable() ) return 0;
// 펼처진 상태
if(m_bFold == false)
{
if(m_pUnfoldBack->GetRect().IsInRect(x,y))
{
switch(dwMessage)
{
case KMOUSE_MOVE:
_SetPreSelectItem(x,y);
break;
// Item을 선택했음
case KLBUTTON_UP:
_SetPreSelectItem(x,y);
if(m_selectItem != m_preSelectItem)
{
KUIControl::PumpUpMessage(GetID(), KCOMBO_CHANGE, m_selectItem, 0);
}
SetCurSel(m_preSelectItem);
KUIControl::PumpUpMessage(GetID(), KCOMBO_SELECT, m_selectItem, 0);
_SetFold(true);
break;
}
}
else if(false == m_rcRegion.IsInRect(x,y) )
{
// 범위를 벗어나서 클릭하면 Fold 상태
if(dwMessage == KLBUTTON_UP)
_SetFold(true);
}
}
return KUIControl::OnMouseMessage(dwMessage,x,y);
}
bool KUIControlCombo::AddItem(LPCSTR itemName)
{
m_vtComboItems.push_back(itemName);
m_bUpdate = true;
return true;
}
bool KUIControlCombo::InsertItem(int index, LPCSTR lpszItem)
{
if(index >= m_vtComboItems.size() )
return false;
m_vtComboItems.insert(m_vtComboItems.begin() + index, lpszItem);
m_bUpdate = true;
return true;
}
bool KUIControlCombo::RemoveItem(int index)
{
if(index >= m_vtComboItems.size() )
return false;
m_vtComboItems.erase(m_vtComboItems.begin() + index);
m_bUpdate = true;
// 아이템이 지워졌으므로 예전 index가 바뀌므로 선택‰榮彭?다 취소
SetCurSel(-1);
_SetPreSelectItem(-1);
// Scroll Setting
_SetScrollMaxRange();
return true;
}
int KUIControlCombo::FindItemIndex(LPCSTR itemName)
{
for(int i = 0; i < m_vtComboItems.size(); ++i)
{
if(m_vtComboItems.at(i) == itemName)
return i;
}
return -1;
}
void KUIControlCombo::ClearItem()
{
m_vtComboItems.clear();
// 모든 아이템이 지워지면 선택도 못하게 되므로
SetCurSel(-1);
_SetPreSelectItem(-1);
m_bUpdate = true;
}
// Combo Item의 정렬
void KUIControlCombo::SetItemAlign(DWORD align)
{
m_ComboPhrase.SetAlign(align);
m_bUpdate = true;
}
// Comobo Item의 최고 넒이
void KUIControlCombo::SetItemWidth(DWORD itemWidth)
{
m_itemWidth = itemWidth;
m_bUpdate = true;
}
// 스크롤 없이 한번에 보여지는 Item의 갯수
void KUIControlCombo::SetMaxViewItem(DWORD maxViewCount)
{
m_maxViewItemCount = maxViewCount;
m_bUpdate = true;
}
int KUIControlCombo::GetCount()
{
return m_vtComboItems.size();
}
// 현재 선택된 Item을 알려줌 (선택된게 없으면 - 1을 리턴)
int KUIControlCombo::GetCurSel()
{
return m_selectItem;
}
bool KUIControlCombo::SetCurSel(int index)
{
if(index >= GetCount() )
return false;
// 이미 같은 걸로 선택되어 있으면 업데이트 할 필요 없음.
if(m_selectItem == index)
return true;
m_selectItem = index;
if(index < 0)
SetCaption(m_sNotSelectedItem.c_str());
else
SetCaption( m_vtComboItems.at(index).c_str() );
UpdateCaption();
return true;
}
void KUIControlCombo::_initControl()
{
if(m_sAniName.empty() )
m_sAniName = COMBO_FRAME_ANI_NAME;
m_rcRegion.bottom = m_rcRegion.top + COMBO_ITEM_HEIGHT;
UpdateBack();
int xSize = 0;
KUITextureManager::GetManager()->GetSprAni( m_sSprName.c_str(), COMBO_BTN_ANI_NAME );
KResSprite * pFrame = _getSpriteSet()->GetSpriteRes(COMBO_BTN_ANI_NAME,0);
if(pFrame)
xSize = pFrame->GetSizeX();
m_itemWidth = GetRect().GetWidth() - xSize;
// Back Ground Set
m_rcCaptionArea.left += COMBO_LEFT_FRAME_WIDTH;
m_rcCaptionArea.right -= xSize;
m_dwCaptionAlign = KTextRender::KTALIGN_HCENTER | KTextRender::KTALIGN_VCENTER;
UpdateCaption();
m_sNotSelectedItem = m_sCaption;
// Down Button 초기화
KUIWND_CREATE_ARG CHILD_ARG;
CHILD_ARG.pParent = this;
CHILD_ARG.pWndManager = m_pManager;
CHILD_ARG.lpszSprName = m_sSprName.c_str();
CHILD_ARG.lpszClassName = "simplebutton";
CHILD_ARG.lpszID = COMBO_BTN_ID;
CHILD_ARG.lpszAniName = COMBO_BTN_ANI_NAME;
CHILD_ARG.rcRect = KRect(GetRect().right - xSize - 2, GetRect().top + COMBO_BTN_Y_OFFSET,-1,-1);
m_pDownButton = static_cast<KUIControlSimpleButton*>( m_pManager->CreateControl(CHILD_ARG) );
// UnFold Frame
CHILD_ARG.lpszClassName = "static";
CHILD_ARG.lpszID = COMBO_UNFOLD_FRAME_ID;
CHILD_ARG.lpszAniName = COMBO_UNFOLD_FRAME_ANI_NAME;
CHILD_ARG.rcRect = KRect(GetRect().left, GetRect().bottom, GetRect().left + m_itemWidth,
GetRect().bottom + _GetMaxViewLineHeight());
m_pUnfoldBack = static_cast<KUIControlStatic*>( m_pManager->CreateControl(CHILD_ARG) );
KUITextureManager::GetManager()->GetSprAni( m_sSprName.c_str(), COMBO_UNFOLD_FRAME_ANI_NAME );
CHILD_ARG.lpszClassName = "static";
CHILD_ARG.lpszID = COMBO_UNFOLD_SELECT_ID;
CHILD_ARG.lpszAniName = COMBO_UNFOLD_SELECT_ANI_NAME;
CHILD_ARG.rcRect = KRect(GetRect().left, GetRect().bottom, GetRect().left + m_itemWidth,
GetRect().bottom + _GetMaxViewLineHeight());
m_pUnfoldSelectBack = static_cast<KUIControlStatic*>( m_pManager->CreateControl(CHILD_ARG) );
KUITextureManager::GetManager()->GetSprAni( m_sSprName.c_str(), COMBO_UNFOLD_SELECT_ANI_NAME );
// TextPhrse Initialize
_InitComboPhrase();
_SetFold(true);
}
void KUIControlCombo::_InitComboPhrase()
{
m_ComboPhrase.Initialize(m_itemWidth, _GetMaxViewLineHeight());
m_ComboPhrase.SetAlign(KTextRender::KTALIGN_HCENTER | KTextRender::KTALIGN_TOP);
m_ComboPhrase.SetPosition(GetRect().left, GetRect().bottom + COMBO_PHRASE_Y_OFFSET , m_fZPos);
}
void KUIControlCombo::_SetFold(bool bFold)
{
m_bFold = bFold;
m_pUnfoldBack->SetShow(!bFold);
m_pUnfoldSelectBack->SetShow(!bFold);
m_ComboPhrase.SetVisibility(bFold ? 0.f : 1.f);
}
void KUIControlCombo::_UpdateComboItem()
{
// 접혀져 있는 상태이면 업데이트 할 필요가 없음.
if(m_bFold || !m_bUpdate)
return;
std::vector<std::string>::iterator it = m_vtComboItems.begin();
std::vector<std::string>::iterator end = m_vtComboItems.end();
std::string sNewString = "<size:10>";
// 아무것도 없는 경우 ==;;
// disable 된거면 회색으로. -_-
if( IsDisable() ) sNewString += "<#777777>";
int lineCount = 0;
if(it == end)
{
sNewString += m_sNotSelectedItem;
}
else
{
while(1)
{
sNewString += *it;
++it;
lineCount++;
if( it == end)
break;
sNewString +="<BR>";
}
}
// 새 Text를 textphrase에 셋팅
m_ComboPhrase.Clear();
_InitComboPhrase();
m_ComboPhrase.AddString(sNewString.c_str());
// 배경 Background를 알맞은 크기로 셋팅하자.
KRect rcRect(GetRect() );
rcRect.top = GetRect().bottom + COMBO_UNFOLD_Y_OFFSET;
rcRect.right = rcRect.left + m_itemWidth;
#ifdef _COUNTRY_ME_
rcRect.bottom = rcRect.top + _GetUnfoldBackHeight(); //이 함수가 오작동함 (지나치게 큰 값을 리턴) 그래서 다시 구함
#else
DWORD dwStringWidth, dwStringHeight;
#ifdef _COUNTRY_TL_
dwStringHeight = 16; // 하드코딩 -_-
#else
KTextRender::GetStringSize("default", 10, false, "ABC123", 6,&dwStringWidth, &dwStringHeight);
#endif
rcRect.bottom = rcRect.top + (dwStringHeight + 3) * lineCount + 3;
#endif
m_pUnfoldBack->SetRect(rcRect);
m_pUnfoldBack->UpdateBack();
// Scroll을 알맞은 Range로 셋팅
_SetScrollMaxRange();
_SetPreSelectItem(m_preSelectItem);
m_bUpdate = false;
}
int KUIControlCombo::_GetUnfoldBackHeight()
{
int totalHeight = min( m_ComboPhrase.GetTotalLineHeigt(), _GetMaxViewLineHeight() );
return (totalHeight + COMBO_UNFOLD_Y_ADD_HEIGHT);
}
void KUIControlCombo::_SetPreSelectItem(int x, int y)
{
if(m_vtComboItems.size() == 0)
{
_SetPreSelectItem(-1);
}
else
{
int itemCount = m_vtComboItems.size();
int backHegiht = m_pUnfoldBack->GetRect().GetHeight();
int offset = y - m_pUnfoldBack->GetRect().top;
float fRatio = static_cast<float>( offset) / static_cast<float>( backHegiht );
int index = fRatio * itemCount;
index = max(index,0);
index = min(index,itemCount - 1);
_SetPreSelectItem(index);
//if(_IsScrollEnable() )
//{
// m_preSelectItem += m_pComboScroll->GetPosition();
//}
}
}
void KUIControlCombo::_SetPreSelectItem(int index)
{
int addHeight = 0;
KRect rcRect(0,0,0,0);
if(index < 0)
{
m_preSelectItem = -1;
}
else if( false == m_vtComboItems.empty() )
{
m_preSelectItem = index;
int itemCount = m_vtComboItems.size();
int backHegiht = m_pUnfoldBack->GetRect().GetHeight();
int heightPerItem = (backHegiht - 3) / itemCount; // 저 위에서 m_pUnfoldBack 높이에 3을 더했으니 3을 •弧?
addHeight = m_preSelectItem * heightPerItem;
rcRect.left = GetRect().left;
rcRect.top = m_pUnfoldBack->GetRect().top + addHeight + COMBO_UNFOLD_SELECT_Y_OFFSET;
rcRect.right = rcRect.left + m_itemWidth;
rcRect.bottom = rcRect.top + COMBO_UNFOLD_SELECT_HEIGHT;
rcRect.left += COMBO_UNFOLD_SELECT_WIDTH_MARGIN / 2;
rcRect.right -= COMBO_UNFOLD_SELECT_WIDTH_MARGIN / 2;
rcRect.top += COMBO_UNFOLD_SELECT_HEIGHT_MARGIN / 2 - 3; // 위치조정을 위해 살짝 -3
rcRect.bottom -= COMBO_UNFOLD_SELECT_HEIGHT_MARGIN / 2;
}
m_pUnfoldSelectBack->SetRect(rcRect);
m_pUnfoldSelectBack->UpdateBack();
}
void KUIControlCombo::OnChangeCaptionNotify()
{
if( !IsDisable() )
{
size_t cpos = 0;
while( ( cpos = m_sCaption.find( "<#" ) ) != m_sCaption.npos )
{
m_sCaption.erase( cpos, 9 );
}
std::string strNewCaption = m_strEnableColor.c_str();
strNewCaption += m_sCaption;
m_sCaption = strNewCaption;
}
KUIControl::OnChangeCaptionNotify();
}
bool KUIControlCombo::_IsScrollEnable()
{
return m_vtComboItems.size() > m_maxViewItemCount;
}
void KUIControlCombo::_SetScrollMaxRange()
{
//if(_IsScrollEnable() )
//{
// m_pComboScroll->SetMaxRange( m_vtComboItems.size() - m_maxViewItemCount + 1 );
//}
}
DWORD KUIControlCombo::_GetMaxViewLineHeight()
{
return COMBO_TEXT_HEIGHT * m_maxViewItemCount + COMBO_TEXT_GAP * (m_maxViewItemCount - 1);
}