CustomComboWnd.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. /* Copyright (c) 2002-2012 Croteam Ltd.
  2. This program is free software; you can redistribute it and/or modify
  3. it under the terms of version 2 of the GNU General Public License as published by
  4. the Free Software Foundation
  5. This program is distributed in the hope that it will be useful,
  6. but WITHOUT ANY WARRANTY; without even the implied warranty of
  7. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  8. GNU General Public License for more details.
  9. You should have received a copy of the GNU General Public License along
  10. with this program; if not, write to the Free Software Foundation, Inc.,
  11. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
  12. // CustomComboWnd.cpp : implementation file
  13. //
  14. #include "stdafx.h"
  15. #include "WorldEditor.h"
  16. #include "CustomComboWnd.h"
  17. #ifdef _DEBUG
  18. #undef new
  19. #define new DEBUG_NEW
  20. #undef THIS_FILE
  21. static char THIS_FILE[] = __FILE__;
  22. #endif
  23. #define SPACING_H PIX(4)
  24. #define SPACING_V PIX(4)
  25. /*
  26. #define COLOR_UNDER_MOUSE (C_GRAY|CT_OPAQUE)
  27. #define COLOR_SELECTED (C_vdRED|CT_OPAQUE)
  28. #define COLOR_SELECTED_UNDER_MOUSE (C_RED|CT_OPAQUE)
  29. */
  30. #define COLOR_UNDER_MOUSE (C_RED|CT_OPAQUE)
  31. #define COLOR_SELECTED (C_mdGRAY|CT_OPAQUE)
  32. #define COLOR_SELECTED_UNDER_MOUSE (C_RED|CT_OPAQUE)
  33. /////////////////////////////////////////////////////////////////////////////
  34. // CCustomComboWnd
  35. CCustomComboWnd::CCustomComboWnd()
  36. {
  37. m_pfResult=NULL;
  38. m_pOnSelect=NULL;
  39. m_pDrawPort = NULL;
  40. m_pViewPort = NULL;
  41. // mark that timer is not yet started
  42. m_iTimerID = -1;
  43. }
  44. PIX GetFixedTextWidth( const CTString &strText, CFontData *pfd)
  45. {
  46. return strText.Length()*pfd->fd_pixCharWidth;
  47. }
  48. PIX GetFixedTextHeight( CFontData *pfd)
  49. {
  50. return pfd->fd_pixCharHeight;
  51. }
  52. void CCustomComboWnd::GetComboLineSize(PIX &pixMaxWidth, PIX &pixMaxHeight)
  53. {
  54. pixMaxWidth=0;
  55. pixMaxHeight=GetFixedTextHeight(_pfdConsoleFont)+SPACING_V;
  56. FOREACHINDYNAMICCONTAINER(m_dcComboLines, CComboLine, itcl)
  57. {
  58. CComboLine &cl=*itcl;
  59. PIX pixIconW=cl.cl_boxIcon.Max()(1)-cl.cl_boxIcon.Min()(1);
  60. PIX pixIconH=cl.cl_boxIcon.Max()(2)-cl.cl_boxIcon.Min()(2);
  61. PIX pixLineWidth=GetFixedTextWidth(cl.cl_strText, _pfdConsoleFont)+pixIconW;
  62. pixMaxWidth=Max(pixMaxWidth,pixLineWidth+SPACING_H);
  63. pixMaxHeight=Max(pixMaxHeight,pixIconH+SPACING_V);
  64. }
  65. }
  66. CCustomComboWnd::~CCustomComboWnd()
  67. {
  68. if( m_pViewPort != NULL)
  69. {
  70. _pGfx->DestroyWindowCanvas( m_pViewPort);
  71. m_pViewPort = NULL;
  72. }
  73. }
  74. #define LINES_PER_X 1
  75. #define LINES_PER_Y 10
  76. #define CLIENT_BORDER 2
  77. PIXaabbox2D CCustomComboWnd::GetLineBBox( INDEX iLine)
  78. {
  79. PIX pixWidth, pixHeight;
  80. GetComboLineSize(pixWidth, pixHeight);
  81. // return calculated box
  82. return PIXaabbox2D( PIX2D(0, pixHeight*iLine), PIX2D(pixWidth, pixHeight*(iLine+1)-1) );
  83. }
  84. BEGIN_MESSAGE_MAP(CCustomComboWnd, CWnd)
  85. //{{AFX_MSG_MAP(CCustomComboWnd)
  86. ON_WM_PAINT()
  87. ON_WM_KILLFOCUS()
  88. ON_WM_LBUTTONDOWN()
  89. ON_WM_MOUSEMOVE()
  90. ON_WM_DESTROY()
  91. ON_WM_TIMER()
  92. ON_WM_LBUTTONUP()
  93. //}}AFX_MSG_MAP
  94. END_MESSAGE_MAP()
  95. /////////////////////////////////////////////////////////////////////////////
  96. // CCustomComboWnd message handlers
  97. void CCustomComboWnd::OnPaint()
  98. {
  99. {
  100. CPaintDC dc(this); // device context for painting
  101. }
  102. if( m_iTimerID == -1)
  103. {
  104. m_iTimerID = (int) SetTimer( 1, 10, NULL);
  105. }
  106. POINT ptMouse;
  107. GetCursorPos( &ptMouse);
  108. ScreenToClient( &ptMouse);
  109. // if there is a valid drawport, and the drawport can be locked
  110. if( (m_pDrawPort != NULL) && (m_pDrawPort->Lock()) )
  111. {
  112. CWorldEditorView *pWorldEditorView = theApp.GetActiveView();
  113. ASSERT( pWorldEditorView != NULL);
  114. // clear background
  115. m_pDrawPort->Fill( C_vdGRAY|CT_OPAQUE);
  116. // erase z-buffer
  117. m_pDrawPort->FillZBuffer(ZBUF_BACK);
  118. // for all lines
  119. for( INDEX iLine=0; iLine<m_dcComboLines.Count(); iLine++)
  120. {
  121. // get current line's box in pixels inside window
  122. PIXaabbox2D boxLine = GetLineBBox( iLine);
  123. PIX2D pixMin=boxLine.Min();
  124. PIX2D pixMax=boxLine.Max();
  125. pixMax(1)-=1;
  126. pixMax(2)-=1;
  127. PIXaabbox2D boxLineDecreased=PIXaabbox2D(pixMin,pixMax);
  128. PIXaabbox2D boxPoint( PIX2D( ptMouse.x, ptMouse.y), PIX2D(ptMouse.x, ptMouse.y) );
  129. BOOL bUnderMouse=(boxLine & boxPoint) == boxPoint;
  130. BOOL bSelected=(m_pfResult!=NULL && iLine==*m_pfResult);
  131. COLOR colFill=C_BLACK|CT_TRANSPARENT;
  132. if(bUnderMouse&&bSelected) colFill=COLOR_SELECTED_UNDER_MOUSE;
  133. else if(bUnderMouse) colFill=COLOR_UNDER_MOUSE;
  134. else if(bSelected) colFill=COLOR_SELECTED;
  135. RenderOneLine( iLine, boxLineDecreased, m_pDrawPort, colFill);
  136. }
  137. m_pDrawPort->DrawBorder( 0,0, m_pDrawPort->GetWidth(),m_pDrawPort->GetHeight(), C_mdGRAY|CT_OPAQUE);
  138. // unlock the drawport
  139. m_pDrawPort->Unlock();
  140. // if there is a valid viewport
  141. if (m_pViewPort!=NULL)
  142. {
  143. m_pViewPort->SwapBuffers();
  144. }
  145. }
  146. }
  147. BOOL CCustomComboWnd::Initialize(FLOAT *pfResult, void (*pOnSelect)(INDEX iSelected),
  148. PIX pixX, PIX pixY, BOOL bDown/*=FALSE*/)
  149. {
  150. m_pfResult=pfResult;
  151. m_pOnSelect=pOnSelect;
  152. // calculate window's size
  153. CRect rectWindow;
  154. rectWindow.left = pixX;
  155. rectWindow.bottom = pixY;
  156. PIX pixWidth, pixHeight;
  157. GetComboLineSize(pixWidth, pixHeight);
  158. pixHeight=pixHeight*m_dcComboLines.Count()-1;
  159. rectWindow.right = rectWindow.left + pixWidth;
  160. if( bDown)
  161. {
  162. rectWindow.top = rectWindow.bottom;
  163. rectWindow.bottom+=pixHeight;
  164. }
  165. else
  166. {
  167. rectWindow.top = rectWindow.bottom - pixHeight;
  168. }
  169. if( IsWindow(m_hWnd))
  170. {
  171. SetWindowPos( NULL, rectWindow.left, rectWindow.top,
  172. rectWindow.right-rectWindow.left, rectWindow.top-rectWindow.bottom,
  173. SWP_NOZORDER | SWP_NOACTIVATE);
  174. ShowWindow(SW_SHOW);
  175. }
  176. else
  177. {
  178. // create window
  179. CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
  180. BOOL bResult = CreateEx( WS_EX_TOOLWINDOW,
  181. NULL, L"Custom combo", WS_CHILD|WS_POPUP|WS_VISIBLE,
  182. rectWindow.left, rectWindow.top, rectWindow.Width(), rectWindow.Height(),
  183. pMainFrame->m_hWnd, NULL, NULL);
  184. if( !bResult)
  185. {
  186. AfxMessageBox( L"Error: Failed to create custom combo!");
  187. return FALSE;
  188. }
  189. _pGfx->CreateWindowCanvas( m_hWnd, &m_pViewPort, &m_pDrawPort);
  190. }
  191. return TRUE;
  192. }
  193. INDEX CCustomComboWnd::InsertItem(CTString strText, CTFileName fnmIcons/*=""*/, MEXaabbox2D boxIcon/*=dummy box*/)
  194. {
  195. CComboLine *pcl=new(CComboLine);
  196. pcl->cl_fnmTexture=fnmIcons;
  197. pcl->cl_boxIcon=boxIcon;
  198. pcl->cl_strText=strText;
  199. m_dcComboLines.Add(pcl);
  200. INDEX iCount=m_dcComboLines.Count();
  201. pcl->cl_ulValue=iCount-1;
  202. pcl->cl_colText=C_YELLOW|CT_OPAQUE;
  203. return iCount-1;
  204. }
  205. void CCustomComboWnd::SetItemValue(INDEX iItem, ULONG ulValue)
  206. {
  207. m_dcComboLines[iItem].cl_ulValue=ulValue;
  208. }
  209. void CCustomComboWnd::SetItemColor(INDEX iItem, COLOR col)
  210. {
  211. m_dcComboLines[iItem].cl_colText=col;
  212. }
  213. void CCustomComboWnd::RenderOneLine( INDEX iLine, PIXaabbox2D rectLine, CDrawPort *pdp, COLOR colFill)
  214. {
  215. CComboLine &cl=m_dcComboLines[iLine];
  216. pdp->Fill(rectLine.Min()(1)-1, rectLine.Min()(2)-1,
  217. rectLine.Max()(1)-rectLine.Min()(1)+1, rectLine.Max()(2)-rectLine.Min()(2)+1,
  218. colFill);
  219. if(cl.cl_fnmTexture!="")
  220. {
  221. CTextureObject to;
  222. try
  223. {
  224. to.SetData_t(cl.cl_fnmTexture);
  225. PIXaabbox2D rectIcon=PIXaabbox2D( rectLine.Min()+PIX2D(SPACING_H/2,SPACING_V/2),
  226. PIX2D(rectLine.Min()+cl.cl_boxIcon.Size())-PIX2D(SPACING_H/2,SPACING_V/2));
  227. pdp->PutTexture( &to, rectIcon, cl.cl_boxIcon);
  228. }
  229. catch(char *strError)
  230. {
  231. (void) strError;
  232. }
  233. }
  234. pdp->SetFont( _pfdConsoleFont);
  235. pdp->SetTextAspect( 1.0f);
  236. pdp->SetTextScaling( 1.0f);
  237. PIX pixX=rectLine.Min()(1)+cl.cl_boxIcon.Size()(1)+SPACING_H/2;
  238. PIX pixTextH= GetFixedTextHeight( _pfdConsoleFont);
  239. PIX pixY=rectLine.Min()(2)+(rectLine.Size()(2)-pixTextH)/2;
  240. pdp->PutText( cl.cl_strText, pixX, pixY, cl.cl_colText);
  241. }
  242. void CCustomComboWnd::OnKillFocus(CWnd* pNewWnd)
  243. {
  244. CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
  245. if( pNewWnd!=pMainFrame->m_pwndToolTip && pNewWnd!=this)
  246. {
  247. // destroy combo
  248. DestroyWindow();
  249. DeleteTempMap();
  250. }
  251. }
  252. void CCustomComboWnd::OnLButtonDown(UINT nFlags, CPoint point)
  253. {
  254. }
  255. void CCustomComboWnd::OnMouseMove(UINT nFlags, CPoint point)
  256. {
  257. Invalidate(FALSE);
  258. CWnd::OnMouseMove(nFlags, point);
  259. }
  260. void CCustomComboWnd::OnDestroy()
  261. {
  262. KillTimer( m_iTimerID);
  263. CWnd::OnDestroy();
  264. }
  265. void CCustomComboWnd::OnTimer(UINT nIDEvent)
  266. {
  267. Invalidate(FALSE);
  268. CWnd::OnTimer(nIDEvent);
  269. }
  270. BOOL CCustomComboWnd::PreTranslateMessage(MSG* pMsg)
  271. {
  272. if( pMsg->message==WM_KEYDOWN && pMsg->wParam==VK_ESCAPE)
  273. {
  274. DestroyWindow();
  275. DeleteTempMap();
  276. return TRUE;
  277. }
  278. return CWnd::PreTranslateMessage(pMsg);
  279. }
  280. void CCustomComboWnd::OnLButtonUp(UINT nFlags, CPoint point)
  281. {
  282. PIXaabbox2D boxPoint( PIX2D( point.x, point.y), PIX2D(point.x, point.y) );
  283. // for all lines
  284. for( INDEX iLine=0; iLine<m_dcComboLines.Count(); iLine++)
  285. {
  286. if( (GetLineBBox( iLine) & boxPoint) == boxPoint)
  287. {
  288. if(m_pfResult!=NULL)
  289. {
  290. *m_pfResult= m_dcComboLines[iLine].cl_ulValue;
  291. // destroy combo
  292. DestroyWindow();
  293. DeleteTempMap();
  294. return;
  295. }
  296. if(m_pOnSelect!=NULL)
  297. {
  298. void (*pOnSelect)(INDEX iSelected)=m_pOnSelect;
  299. INDEX iValue=m_dcComboLines[iLine].cl_ulValue;
  300. // destroy combo
  301. DestroyWindow();
  302. DeleteTempMap();
  303. pOnSelect(iValue);
  304. return;
  305. }
  306. }
  307. }
  308. CWnd::OnLButtonUp(nFlags, point);
  309. }