| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684 |
- /*
- ** Command & Conquer Renegade(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- #include "IMECandidateCtrl.h"
- #include "IMECandidate.h"
- #include "DialogBase.h"
- #include "StyleMgr.h"
- #include "MouseMgr.h"
- #define BORDER_WIDTH 2
- #define BORDER_HEIGHT 2
- /******************************************************************************
- *
- * NAME
- * IMECandidateCtrl::IMECandidateCtrl
- *
- * DESCRIPTION
- *
- * INPUTS
- * NONE
- *
- * RESULT
- * NONE
- *
- ******************************************************************************/
- IMECandidateCtrl::IMECandidateCtrl() :
- mFullRect(0,0,0,0),
- mCellSize(0,0),
- mCurrSel(-1),
- mScrollPos(0),
- mCellsPerPage(0),
- mCandidate(NULL)
- {
- StyleMgrClass::Assign_Font(&mTextRenderer, StyleMgrClass::FONT_LISTS);
- // Candidate control never wants to take focus
- Set_Wants_Focus(false);
- // Setup child scrollbar
- mScrollBarCtrl.Set_Wants_Focus(false);
- mScrollBarCtrl.Set_Small_BMP_Mode(true);
- mScrollBarCtrl.Set_Advise_Sink(this);
- }
- /******************************************************************************
- *
- * NAME
- * IMECandidateCtrl::~IMECandidateCtrl
- *
- * DESCRIPTION
- *
- * INPUTS
- * NONE
- *
- * RESULT
- * NONE
- *
- ******************************************************************************/
- IMECandidateCtrl::~IMECandidateCtrl()
- {
- }
- /******************************************************************************
- *
- * NAME
- * IMECandidateCtrl::Init
- *
- * DESCRIPTION
- *
- * INPUTS
- *
- * RESULT
- * NONE
- *
- ******************************************************************************/
- void IMECandidateCtrl::Init(IME::IMECandidate* candidate)
- {
- WWDEBUG_SAY(("IMECandidateCtrl: Init\n"));
- Reset();
- mCandidate = candidate;
- Changed(candidate);
- }
- /******************************************************************************
- *
- * NAME
- * IMECandidateCtrl::Changed
- *
- * DESCRIPTION
- *
- * INPUTS
- *
- * RESULT
- * NONE
- *
- ******************************************************************************/
- void IMECandidateCtrl::Changed(IME::IMECandidate* candidate)
- {
- WWDEBUG_SAY(("IMECandidateCtrl: Changed\n"));
- WWASSERT(mCandidate == candidate);
- if (candidate)
- {
- mScrollPos = candidate->GetPageStart();
- unsigned long candSel = candidate->GetSelection();
- if (candSel != (unsigned long)mCurrSel)
- {
- mCurrSel = candSel;
- UpdateScrollPos();
- }
- }
- Set_Dirty();
- }
- /******************************************************************************
- *
- * NAME
- * IMECandidateCtrl::Reset
- *
- * DESCRIPTION
- *
- * INPUTS
- * NONE
- *
- * RESULT
- * NONE
- *
- ******************************************************************************/
- void IMECandidateCtrl::Reset(void)
- {
- mCellSize.Set(0,0);
- mCurrSel = -1;
- mScrollPos = 0;
- mCellsPerPage = 0;
- mScrollBarCtrl.Show(false);
- mCandidate = NULL;
- }
- /******************************************************************************
- *
- * NAME
- * IMECandidateCtrl::CreateControlRenderer
- *
- * DESCRIPTION
- *
- * INPUTS
- * NONE
- *
- * RESULT
- * NONE
- *
- ******************************************************************************/
- void IMECandidateCtrl::CreateControlRenderer(void)
- {
- Render2DClass& renderer = mControlRenderer;
- // Configure this renderer
- renderer.Reset();
- renderer.Enable_Texturing(false);
- renderer.Set_Coordinate_Range(Render2DClass::Get_Screen_Resolution());
- renderer.Add_Quad(mFullRect, RGBA_TO_INT32(0, 0, 0, 170));
- // Determine which color to draw the outline in
- int color = StyleMgrClass::Get_Line_Color();
- int bkColor = StyleMgrClass::Get_Bk_Color();
- if (IsEnabled == false)
- {
- color = StyleMgrClass::Get_Disabled_Line_Color();
- bkColor = StyleMgrClass::Get_Disabled_Bk_Color();
- }
- // Draw the control outline
- RectClass rect = Rect;
- renderer.Add_Outline(rect, 1.0F, color);
- // Now draw the background
- rect.Right -= 1;
- rect.Bottom -= 1;
- renderer.Add_Quad(rect, bkColor);
- }
- /******************************************************************************
- *
- * NAME
- * IMECandidateCtrl::CreateTextRenderer
- *
- * DESCRIPTION
- *
- * INPUTS
- * NONE
- *
- * RESULT
- * NONE
- *
- ******************************************************************************/
- void IMECandidateCtrl::CreateTextRenderer(void)
- {
- mHilightRenderer.Reset();
- mHilightRenderer.Set_Coordinate_Range(Render2DClass::Get_Screen_Resolution());
- StyleMgrClass::Configure_Hilighter(&mHilightRenderer);
- mTextRenderer.Reset();
- if (mCandidate)
- {
- // Add each candidate to the list
- const unsigned int selIndexBias = (mCandidate->IsStartFrom1() ? 1 : 0);
- float currYPos = ClientRect.Top;
- const unsigned long candidateCount = mCandidate->GetCount();
- for (unsigned long index = mScrollPos; index < candidateCount; ++index)
- {
- // Build the rectangle we will draw the text into
- RectClass textRect;
- textRect.Left = ClientRect.Left;
- textRect.Top = currYPos;
- textRect.Right = (textRect.Left + mCellSize.X);
- textRect.Bottom = (textRect.Top + mCellSize.Y);
- // If this cell extends past the end of the control then stop
- if (textRect.Bottom > ClientRect.Bottom)
- {
- break;
- }
- // Draw the text
- const WCHAR* text = mCandidate->GetCandidate(index);
- WideStringClass entry(0, true);
- entry.Format(L"%d. %s", ((index - mScrollPos) + selIndexBias), text);
-
- StyleMgrClass::Render_Text(entry, &mTextRenderer, textRect, true, true);
- // Hilight this entry (if its the currently selected one)
- if ((int)index == mCurrSel)
- {
- StyleMgrClass::Render_Hilight(&mHilightRenderer, textRect);
- }
- currYPos += mCellSize.Y;
- }
- }
- }
- /******************************************************************************
- *
- * NAME
- * IMECandidateCtrl::Render
- *
- * DESCRIPTION
- *
- * INPUTS
- * NONE
- *
- * RESULT
- * NONE
- *
- ******************************************************************************/
- void IMECandidateCtrl::Render(void)
- {
- // Recreate the renderers (if necessary)
- if (IsDirty)
- {
- CreateControlRenderer();
- CreateTextRenderer();
- }
- mControlRenderer.Render();
- mTextRenderer.Render();
- mHilightRenderer.Render();
- DialogControlClass::Render();
- }
- /******************************************************************************
- *
- * NAME
- * IMECandidateCtrl::SetCurrSel
- *
- * DESCRIPTION
- *
- * INPUTS
- *
- * RESULT
- * NONE
- *
- ******************************************************************************/
- void IMECandidateCtrl::SetCurrSel(int index)
- {
- if (mCandidate)
- {
- if ((index != mCurrSel) && (index == -1) || ((index >= 0) && (unsigned long)index < mCandidate->GetCount()))
- {
- mCurrSel = index;
- Set_Dirty();
- }
- }
- }
- /******************************************************************************
- *
- * NAME
- * IMECandidateCtrl::EntryFromPos
- *
- * DESCRIPTION
- *
- * INPUTS
- *
- * RESULT
- *
- ******************************************************************************/
- int IMECandidateCtrl::EntryFromPos(const Vector2& mousePos)
- {
- if (mCandidate)
- {
- // Loop over all the entries in our current view
- float currYPos = ClientRect.Top;
- const unsigned long candidateCount = mCandidate->GetCount();
- for (unsigned long index = mScrollPos; index < candidateCount; ++index)
- {
- // Is ths mouse over this entry?
- if ((mousePos.Y >= currYPos && mousePos.Y <= (currYPos + mCellSize.Y))
- || mousePos.Y > ClientRect.Bottom)
- {
- return index;
- }
- currYPos += mCellSize.Y;
- }
- }
-
- return -1;
- }
- /******************************************************************************
- *
- * NAME
- * IMECandidateCtrl::UpdateScrollPos
- *
- * DESCRIPTION
- *
- * INPUTS
- * NONE
- *
- * RESULT
- * NONE
- *
- ******************************************************************************/
- void IMECandidateCtrl::UpdateScrollPos(void)
- {
- if (mCurrSel != -1)
- {
- unsigned int scrollPos = mScrollPos;
- if (mCurrSel < (int)scrollPos)
- {
- // Scroll up so the current selection is in view
- scrollPos = mCurrSel;
- Set_Dirty();
- }
- else if (mCurrSel >= (int)(scrollPos + mCellsPerPage))
- {
- // Scroll down so the current selection is in view
- scrollPos = max<unsigned int>((unsigned int)mCurrSel - (mCellsPerPage - 1), 0);
- Set_Dirty();
- }
- if (scrollPos != mScrollPos)
- {
- // Update the scrollbar
- mScrollBarCtrl.Set_Pos(mScrollPos, false);
- if (mCandidate)
- {
- mCandidate->SetPageStart(mScrollPos);
- }
- }
- }
- }
- /******************************************************************************
- *
- * NAME
- * IMECandidateCtrl::Update_Client_Rect
- *
- * DESCRIPTION
- *
- * INPUTS
- * NONE
- *
- * RESULT
- * NONE
- *
- ******************************************************************************/
- void IMECandidateCtrl::Update_Client_Rect(void)
- {
- WWDEBUG_SAY(("IMECandidateCtrl: Update_Client_Rect()\n"));
- Vector2 pageSize;
- CalculateCandidatePageExtent(pageSize, mCellSize);
- mCellsPerPage = (unsigned int)(pageSize.Y / mCellSize.Y);
- Rect.Right = (Rect.Left + (pageSize.X + (BORDER_WIDTH * 2.0f)));
- Rect.Bottom = (Rect.Top + (pageSize.Y + (BORDER_HEIGHT * 2.0f)));
-
- mFullRect = Rect;
- ClientRect = Rect;
- ClientRect.Inflate(Vector2(-BORDER_WIDTH, -BORDER_HEIGHT));
- if (mCandidate)
- {
- WWASSERT(mCandidate->GetPageSize() <= mCellsPerPage);
- // Do we need to show a scroll bar?
- const unsigned long candidateCount = mCandidate->GetCount();
- if ((unsigned long)mCellsPerPage < candidateCount)
- {
- // Position the scrollbar to the right of the list
- RectClass scrollRect;
- scrollRect.Left = mFullRect.Right;
- scrollRect.Top = mFullRect.Top;
- scrollRect.Right = -1;
- scrollRect.Bottom = mFullRect.Bottom;
- // Size the scroll bar
- mScrollBarCtrl.Set_Window_Rect(scrollRect);
- mScrollBarCtrl.Set_Page_Size(mCellsPerPage - 1);
- mScrollBarCtrl.Set_Range(0, (candidateCount - mCellsPerPage));
- mScrollBarCtrl.Show(true);
- const RectClass& rect = mScrollBarCtrl.Get_Window_Rect();
- mFullRect.Right = rect.Right;
- }
- }
- Set_Dirty();
- }
- /******************************************************************************
- *
- * NAME
- * IMECandidateCtrl::
- *
- * DESCRIPTION
- *
- * INPUTS
- *
- * RESULT
- * NONE
- *
- ******************************************************************************/
- void IMECandidateCtrl::CalculateCandidatePageExtent(Vector2& outExtent, Vector2& outCellSize)
- {
- if (mCandidate)
- {
- // Get the size of the widest candidate string.
- float maxCandWidth = 0.0f;
- const unsigned long candidateCount = mCandidate->GetCount();
- for (unsigned long index = 0; index < candidateCount; ++index)
- {
- // Get the extent of the current entry
- const WCHAR* text = mCandidate->GetCandidate(index);
- Vector2 textExtent = mTextRenderer.Get_Text_Extents(text);
- if (textExtent.X > maxCandWidth)
- {
- maxCandWidth = textExtent.X;
- }
- }
- Vector2 charSize = mTextRenderer.Get_Text_Extents(L"W");
- // The cell size is the maximum candidate size plus some spacing.
- outCellSize.X = (maxCandWidth + (charSize.X * 3.0f));
- outCellSize.Y = (charSize.Y * 1.25f);
- outExtent.X = outCellSize.X;
- outExtent.Y = (mCellSize.Y * (float)mCandidate->GetPageSize());
- }
- else
- {
- outExtent.X = 0.0f;
- outExtent.Y = 0.0f;
- outCellSize.X = 0.0f;
- outCellSize.Y = 0.0f;
- }
- }
- /******************************************************************************
- *
- * NAME
- * IMECandidateCtrl::On_Set_Cursor
- *
- * DESCRIPTION
- *
- * INPUTS
- *
- * RESULT
- * NONE
- *
- ******************************************************************************/
- void IMECandidateCtrl::On_Set_Cursor(const Vector2& mousePos)
- {
- // Change the mouse cursor if necessary
- if (ClientRect.Contains(mousePos))
- {
- MouseMgrClass::Set_Cursor(MouseMgrClass::CURSOR_ACTION);
- }
- }
- /******************************************************************************
- *
- * NAME
- * IMECandidateCtrl::On_LButton_Down
- *
- * DESCRIPTION
- *
- * INPUTS
- *
- * RESULT
- * NONE
- *
- ******************************************************************************/
- void IMECandidateCtrl::On_LButton_Down(const Vector2& mousePos)
- {
- SetCurrSel(EntryFromPos(mousePos));
- }
- /******************************************************************************
- *
- * NAME
- * IMECandidateCtrl::On_LButton_Up
- *
- * DESCRIPTION
- *
- * INPUTS
- *
- * RESULT
- * NONE
- *
- ******************************************************************************/
- void IMECandidateCtrl::On_LButton_Up(const Vector2& mousePos)
- {
- int sel = EntryFromPos(mousePos);
- SetCurrSel(sel);
- // Process candidate selection here
- if (mCandidate && (sel >= 0))
- {
- const wchar_t* string = mCandidate->GetCandidate(sel);
- WWDEBUG_SAY(("*** Selected Candidate: %d %04x\n", sel, *string));
- mCandidate->SelectCandidate((unsigned long)sel);
- }
- }
- /******************************************************************************
- *
- * NAME
- * IMECandidateCtrl::On_Add_To_Dialog
- *
- * DESCRIPTION
- *
- * INPUTS
- * NONE
- *
- * RESULT
- * NONE
- *
- ******************************************************************************/
- void IMECandidateCtrl::On_Add_To_Dialog(void)
- {
- Parent->Add_Control(&mScrollBarCtrl);
- }
- /******************************************************************************
- *
- * NAME
- * IMECandidateCtrl::On_Remove_From_Dialog
- *
- * DESCRIPTION
- *
- * INPUTS
- * NONE
- *
- * RESULT
- * NONE
- *
- ******************************************************************************/
- void IMECandidateCtrl::On_Remove_From_Dialog(void)
- {
- Parent->Remove_Control(&mScrollBarCtrl);
- }
- /******************************************************************************
- *
- * NAME
- * IMECandidateCtrl::On_VScroll
- *
- * DESCRIPTION
- *
- * INPUTS
- *
- * RESULT
- * NONE
- *
- ******************************************************************************/
- void IMECandidateCtrl::On_VScroll(ScrollBarCtrlClass*, int , int newPos)
- {
- mScrollPos = newPos;
- if (mCandidate)
- {
- mCandidate->SetPageStart(mScrollPos);
- }
- Set_Dirty();
- }
|