doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
PropertyGrid.cpp
Go to the documentation of this file.
1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
8 
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 
29 #include "../../idlib/precompiled.h"
30 #pragma hdrstop
31 
32 #include "../../sys/win32/win_local.h"
33 #include "PropertyGrid.h"
34 
36 {
37 public:
38 
40  {
41  }
42 
46 };
47 
48 /*
49 ================
50 rvPropertyGrid::rvPropertyGrid
51 
52 constructor
53 ================
54 */
56 {
57  mWindow = NULL;
58  mEdit = NULL;
60  mSplitter = 100;
61  mSelectedItem = -1;
62  mEditItem = -1;
64 }
65 
66 /*
67 ================
68 rvPropertyGrid::Create
69 
70 Create a new property grid control with the given id and parent
71 ================
72 */
73 bool rvPropertyGrid::Create ( HWND parent, int id, int style )
74 {
75  mStyle = style;
76 
77  // Create the List view
78  mWindow = CreateWindowEx ( 0, "LISTBOX", "", WS_VSCROLL|WS_CHILD|WS_VISIBLE|LBS_OWNERDRAWFIXED|LBS_NOINTEGRALHEIGHT|LBS_NOTIFY, 0, 0, 0, 0, parent, (HMENU)id, win32.hInstance, 0 );
79  mListWndProc = (WNDPROC)GetWindowLong ( mWindow, GWL_WNDPROC );
80  SetWindowLong ( mWindow, GWL_USERDATA, (LONG)this );
81  SetWindowLong ( mWindow, GWL_WNDPROC, (LONG)WndProc );
82 
83  LoadLibrary ( "Riched20.dll" );
84  mEdit = CreateWindowEx ( 0, "RichEdit20A", "", WS_CHILD, 0, 0, 0, 0, mWindow, (HMENU) 999, win32.hInstance, NULL );
85  SendMessage ( mEdit, EM_SETEVENTMASK, 0, ENM_KEYEVENTS );
86 
87  // Set the font of the list box
88  HDC dc;
89  LOGFONT lf;
90 
91  dc = GetDC ( mWindow );
92  ZeroMemory ( &lf, sizeof(lf) );
93  lf.lfHeight = -MulDiv(8, GetDeviceCaps(dc, LOGPIXELSY), 72);
94  strcpy ( lf.lfFaceName, "MS Shell Dlg" );
95  SendMessage ( mWindow, WM_SETFONT, (WPARAM)CreateFontIndirect ( &lf ), 0 );
96  SendMessage ( mEdit, WM_SETFONT, (WPARAM)CreateFontIndirect ( &lf ), 0 );
97  ReleaseDC ( mWindow, dc );
98 
99  RemoveAllItems ( );
100 
101  return true;
102 }
103 
104 /*
105 ================
106 rvPropertyGrid::Move
107 
108 Move the window
109 ================
110 */
111 void rvPropertyGrid::Move ( int x, int y, int w, int h, BOOL redraw )
112 {
113  MoveWindow ( mWindow, x, y, w, h, redraw );
114 }
115 
116 /*
117 ================
118 rvPropertyGrid::StartEdit
119 
120 Start editing
121 ================
122 */
123 void rvPropertyGrid::StartEdit ( int item, bool label )
124 {
125  rvPropertyGridItem* gitem;
126  RECT rItem;
127 
128  gitem = (rvPropertyGridItem*)SendMessage ( mWindow, LB_GETITEMDATA, item, 0 );
129  if ( NULL == gitem )
130  {
131  return;
132  }
133 
134  SendMessage ( mWindow, LB_GETITEMRECT, item, (LPARAM)&rItem );
135  if ( label )
136  {
137  rItem.right = rItem.left + mSplitter - 1;
138  }
139  else
140  {
141  rItem.left = rItem.left + mSplitter + 1;
142  }
143 
144  mState = STATE_EDIT;
145  mEditItem = item;
146  mEditLabel = label;
147 
148  SetWindowText ( mEdit, label?gitem->mName:gitem->mValue );
149  MoveWindow ( mEdit, rItem.left, rItem.top + 2,
150  rItem.right - rItem.left,
151  rItem.bottom - rItem.top - 2, TRUE );
152  ShowWindow ( mEdit, SW_SHOW );
153 
154  SetFocus ( mEdit );
155 }
156 
157 /*
158 ================
159 rvPropertyGrid::FinishEdit
160 
161 Finish editing by copying the data in the edit control to the internal value
162 ================
163 */
165 {
166  char value[1024];
167  rvPropertyGridItem* item;
168  bool update;
169 
170  if ( mState != STATE_EDIT )
171  {
172  return;
173  }
174 
175  assert ( mEditItem >= 0 );
176 
178 
179  update = false;
180  item = (rvPropertyGridItem*)SendMessage ( mWindow, LB_GETITEMDATA, mEditItem, 0 );
181  assert ( item );
182 
183  GetWindowText ( mEdit, value, 1023 );
184 
185  if ( !value[0] )
186  {
187  mState = STATE_EDIT;
188  MessageBeep ( MB_ICONASTERISK );
189  return;
190  }
191 
192  if ( !mEditLabel && item->mValue.Cmp ( value ) )
193  {
194  NMPROPGRID nmpg;
195  nmpg.hdr.code = PGN_ITEMCHANGED;
196  nmpg.hdr.hwndFrom = mWindow;
197  nmpg.hdr.idFrom = GetWindowLong ( mWindow, GWL_ID );
198  nmpg.mName = item->mName;
199  nmpg.mValue = value;
200 
201  if ( !SendMessage ( GetParent ( mWindow ), WM_NOTIFY, 0, (LONG)&nmpg ) )
202  {
203  mState = STATE_EDIT;
204  SetFocus ( mEdit );
205  return;
206  }
207 
208  // The item may have been destroyed and recreated in the notify call so get it again
209  item = (rvPropertyGridItem*)SendMessage ( mWindow, LB_GETITEMDATA, mEditItem, 0 );
210  if ( item )
211  {
212  item->mValue = value;
213  update = true;
214  }
215  }
216  else if ( mEditLabel && item->mName.Cmp ( value ) )
217  {
218  int sel;
219  sel = AddItem ( value, "", PGIT_STRING );
220  SetCurSel ( sel );
221  StartEdit ( sel, false );
222  return;
223  }
224 
225  SetCurSel ( mEditItem );
226 
228  mEditItem = -1;
229 
230  ShowWindow ( mEdit, SW_HIDE );
231  SetFocus ( mWindow );
232 }
233 
234 /*
235 ================
236 rvPropertyGrid::CancelEdit
237 
238 Stop editing without saving the data
239 ================
240 */
242 {
243  if ( mState == STATE_EDIT && !mEditLabel )
244  {
245  if ( !*GetItemValue ( mEditItem ) )
246  {
247  RemoveItem ( mEditItem );
248  }
249  }
250 
252  mEditItem = -1;
254  ShowWindow ( mEdit, SW_HIDE );
255  SetFocus ( mWindow );
257 }
258 
259 /*
260 ================
261 rvPropertyGrid::AddItem
262 
263 Add a new item to the property grid
264 ================
265 */
266 int rvPropertyGrid::AddItem ( const char* name, const char* value, EItemType type )
267 {
268  rvPropertyGridItem* item;
269  int insert;
270 
271  // Cant add headers if headers arent enabled
272  if ( type == PGIT_HEADER && !(mStyle&PGS_HEADERS) )
273  {
274  return -1;
275  }
276 
277  item = new rvPropertyGridItem;
278  item->mName = name;
279  item->mValue = value;
280  item->mType = type;
281 
282  insert = SendMessage(mWindow,LB_GETCOUNT,0,0) - ((mStyle&PGS_ALLOWINSERT)?1:0);
283 
284  return SendMessage ( mWindow, LB_INSERTSTRING, insert, (LONG)item );
285 }
286 
287 /*
288 ================
289 rvPropertyGrid::RemoveItem
290 
291 Remove the item at the given index
292 ================
293 */
295 {
296  if ( index < 0 || index >= SendMessage ( mWindow, LB_GETCOUNT, 0, 0 ) )
297  {
298  return;
299  }
300 
301  delete (rvPropertyGridItem*)SendMessage ( mWindow, LB_GETITEMDATA, index, 0 );
302 
303  SendMessage ( mWindow, LB_DELETESTRING, index, 0 );
304 }
305 
306 /*
307 ================
308 rvPropertyGrid::RemoveAllItems
309 
310 Remove all items from the property grid
311 ================
312 */
314 {
315  int i;
316 
317  // free the memory for all the items
318  for ( i = SendMessage ( mWindow, LB_GETCOUNT, 0, 0 ); i > 0; i -- )
319  {
320  delete (rvPropertyGridItem*)SendMessage ( mWindow, LB_GETITEMDATA, i - 1, 0 );
321  }
322 
323  // remove all items from the listbox itself
324  SendMessage ( mWindow, LB_RESETCONTENT, 0, 0 );
325 
326  if ( mStyle & PGS_ALLOWINSERT )
327  {
328  // Add the item used to add items
329  rvPropertyGridItem* item;
330  item = new rvPropertyGridItem;
331  item->mName = "";
332  item->mValue = "";
333  SendMessage ( mWindow, LB_ADDSTRING, 0, (LONG)item );
334  }
335 }
336 
337 /*
338 ================
339 rvPropertyGrid::GetItemName
340 
341 Return name of item at given index
342 ================
343 */
345 {
346  rvPropertyGridItem* item;
347 
348  item = (rvPropertyGridItem*)SendMessage ( mWindow, LB_GETITEMDATA, index, 0 );
349  if ( !item )
350  {
351  return "";
352  }
353 
354  return item->mName;
355 }
356 
357 /*
358 ================
359 rvPropertyGrid::GetItemValue
360 
361 Return value of item at given index
362 ================
363 */
365 {
366  rvPropertyGridItem* item;
367 
368  item = (rvPropertyGridItem*)SendMessage ( mWindow, LB_GETITEMDATA, index, 0 );
369  if ( !item )
370  {
371  return "";
372  }
373 
374  return item->mValue;
375 }
376 
377 /*
378 ================
379 rvPropertyGrid::WndProc
380 
381 Window procedure for property grid
382 ================
383 */
384 LRESULT CALLBACK rvPropertyGrid::WndProc ( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
385 {
386  rvPropertyGrid* grid = (rvPropertyGrid*) GetWindowLong ( hWnd, GWL_USERDATA );
387 
388  switch ( msg )
389  {
390  case WM_SETFOCUS:
391 // grid->mEditItem = -1;
392  break;
393 
394  case WM_KEYDOWN:
395  {
396  NMKEY nmkey;
397  nmkey.hdr.code = NM_KEYDOWN;
398  nmkey.hdr.hwndFrom = grid->mWindow;
399  nmkey.nVKey = wParam;
400  nmkey.uFlags = HIWORD(lParam);
401  nmkey.hdr.idFrom = GetWindowLong ( hWnd, GWL_ID );
402  SendMessage ( GetParent ( hWnd ), WM_NOTIFY, nmkey.hdr.idFrom, (LPARAM)&nmkey );
403  break;
404  }
405 
406  case WM_CHAR:
407  {
408  switch ( wParam )
409  {
410  case VK_RETURN:
411  if ( grid->mSelectedItem >= 0 )
412  {
413  grid->StartEdit ( grid->mSelectedItem, (*grid->GetItemName ( grid->mSelectedItem ))?false:true);
414  }
415  break;
416  }
417  break;
418  }
419 
420  case WM_KILLFOCUS:
421  grid->mSelectedItem = -1;
422  break;
423 
424  case WM_NOTIFY:
425  {
426  NMHDR* hdr;
427  hdr = (NMHDR*)lParam;
428  if ( hdr->idFrom == 999 )
429  {
430  if ( hdr->code == EN_MSGFILTER )
431  {
432  MSGFILTER* filter;
433  filter = (MSGFILTER*)lParam;
434  if ( filter->msg == WM_KEYDOWN )
435  {
436  switch ( filter->wParam )
437  {
438  case VK_RETURN:
439  case VK_TAB:
440  grid->FinishEdit ( );
441  return 1;
442 
443  case VK_ESCAPE:
444  grid->CancelEdit ( );
445  return 1;
446  }
447  }
448 
449  if ( filter->msg == WM_CHAR || filter->msg == WM_KEYUP )
450  {
451  switch ( filter->wParam )
452  {
453  case VK_RETURN:
454  case VK_TAB:
455  case VK_ESCAPE:
456  return 1;
457  }
458  }
459  }
460  }
461  break;
462  }
463 
464  case WM_COMMAND:
465  if ( lParam == (long)grid->mEdit )
466  {
467  if ( HIWORD(wParam) == EN_KILLFOCUS )
468  {
469  grid->FinishEdit ( );
470  return true;
471  }
472  }
473  break;
474 
475  case WM_LBUTTONDBLCLK:
476  grid->mSelectedItem = SendMessage ( hWnd, LB_ITEMFROMPOINT, 0, lParam );
477 
478  // fall through
479 
480  case WM_LBUTTONDOWN:
481  {
482  int item;
483  rvPropertyGridItem* gitem;
484  RECT rItem;
485  POINT pt;
486 
487  if ( grid->mState == rvPropertyGrid::STATE_EDIT )
488  {
489  break;
490  }
491 
492  item = (short)LOWORD(SendMessage ( hWnd, LB_ITEMFROMPOINT, 0, lParam ));
493  if ( item == -1 )
494  {
495  break;
496  }
497 
498  gitem = (rvPropertyGridItem*)SendMessage ( hWnd, LB_GETITEMDATA, item, 0 );
499  pt.x = LOWORD(lParam);
500  pt.y = HIWORD(lParam);
501 
502  SendMessage ( hWnd, LB_GETITEMRECT, item, (LPARAM)&rItem );
503 
504  if ( !gitem->mName.Icmp ( "" ) )
505  {
506  rItem.right = rItem.left + grid->mSplitter - 1;
507  if ( PtInRect ( &rItem, pt) )
508  {
509  grid->SetCurSel ( item );
510  grid->StartEdit ( item, true );
511  }
512  }
513  else if ( grid->mSelectedItem == item )
514  {
515  rItem.left = rItem.left + grid->mSplitter + 1;
516  if ( PtInRect ( &rItem, pt) )
517  {
518  grid->StartEdit ( item, false );
519  }
520  }
521 
522  if ( grid->mState == rvPropertyGrid::STATE_EDIT )
523  {
524  ClientToScreen ( hWnd, &pt );
525  ScreenToClient ( grid->mEdit, &pt );
526  SendMessage ( grid->mEdit, WM_LBUTTONDOWN, wParam, MAKELONG(pt.x,pt.y) );
527  return 0;
528  }
529 
530  break;
531  }
532 
533  case WM_ERASEBKGND:
534  {
535  RECT rClient;
536  GetClientRect ( hWnd, &rClient );
537  FillRect ( (HDC)wParam, &rClient, GetSysColorBrush ( COLOR_3DFACE ) );
538  return TRUE;
539  }
540 
541  case WM_SETCURSOR:
542  {
543  POINT point;
544  GetCursorPos ( &point );
545  ScreenToClient ( hWnd, &point );
546  if ( point.x >= grid->mSplitter - 2 && point.x <= grid->mSplitter + 2 )
547  {
548  SetCursor ( LoadCursor ( NULL, MAKEINTRESOURCE(IDC_SIZEWE)));
549  return TRUE;
550  }
551  break;
552  }
553  }
554 
555  return CallWindowProc ( grid->mListWndProc, hWnd, msg, wParam, lParam );
556 }
557 
558 /*
559 ================
560 rvPropertyGrid::ReflectMessage
561 
562 Handle messages sent to the parent window
563 ================
564 */
565 bool rvPropertyGrid::ReflectMessage ( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
566 {
567  switch ( msg )
568  {
569  case WM_COMMAND:
570  {
571  if ( (HWND)lParam == mWindow )
572  {
573  switch ( HIWORD(wParam) )
574  {
575  case LBN_SELCHANGE:
576  mSelectedItem = SendMessage ( mWindow, LB_GETCURSEL, 0, 0 );
577  break;
578  }
579  }
580  break;
581  }
582 
583  case WM_DRAWITEM:
584  HandleDrawItem ( wParam, lParam );
585  return true;
586 
587  case WM_MEASUREITEM:
588  {
589  MEASUREITEMSTRUCT* mis = (MEASUREITEMSTRUCT*) lParam;
590  mis->itemHeight = 18;
591  return true;
592  }
593  }
594 
595  return false;
596 }
597 
598 /*
599 ================
600 rvPropertyGrid::HandleDrawItem
601 
602 Handle the draw item message
603 ================
604 */
605 int rvPropertyGrid::HandleDrawItem ( WPARAM wParam, LPARAM lParam )
606 {
607  DRAWITEMSTRUCT* dis = (DRAWITEMSTRUCT*) lParam;
608  rvPropertyGridItem* item = (rvPropertyGridItem*) dis->itemData;
609  RECT rTemp;
610  HBRUSH brush;
611 
612  if ( !item )
613  {
614  return 0;
615  }
616 
617  rTemp = dis->rcItem;
618  if ( mStyle & PGS_HEADERS )
619  {
620  brush = GetSysColorBrush ( COLOR_SCROLLBAR );
621  rTemp.right = rTemp.left + 10;
622  FillRect ( dis->hDC, &rTemp, brush );
623  rTemp.left = rTemp.right;
624  rTemp.right = dis->rcItem.right;
625  }
626 
627  if ( item->mType == PGIT_HEADER )
628  {
629  brush = GetSysColorBrush ( COLOR_SCROLLBAR );
630  }
631  else if ( dis->itemState & ODS_SELECTED )
632  {
633  brush = GetSysColorBrush ( COLOR_HIGHLIGHT );
634  }
635  else
636  {
637  brush = GetSysColorBrush ( COLOR_WINDOW );
638  }
639 
640  FillRect ( dis->hDC, &rTemp, brush );
641 
642  HPEN pen = CreatePen ( PS_SOLID, 1, GetSysColor ( COLOR_SCROLLBAR ) );
643  HPEN oldpen = (HPEN)SelectObject ( dis->hDC, pen );
644  MoveToEx ( dis->hDC, dis->rcItem.left, dis->rcItem.top, NULL );
645  LineTo ( dis->hDC, dis->rcItem.right, dis->rcItem.top );
646  MoveToEx ( dis->hDC, dis->rcItem.left, dis->rcItem.bottom, NULL );
647  LineTo ( dis->hDC, dis->rcItem.right, dis->rcItem.bottom);
648 
649  if ( item->mType != PGIT_HEADER )
650  {
651  MoveToEx ( dis->hDC, dis->rcItem.left + mSplitter, dis->rcItem.top, NULL );
652  LineTo ( dis->hDC, dis->rcItem.left + mSplitter, dis->rcItem.bottom );
653  }
654  SelectObject ( dis->hDC, oldpen );
655  DeleteObject ( pen );
656 
657  int colorIndex = ( (dis->itemState & ODS_SELECTED ) ? COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT );
658  SetTextColor ( dis->hDC, GetSysColor ( colorIndex ) );
659  SetBkMode ( dis->hDC, TRANSPARENT );
660  SetBkColor ( dis->hDC, GetSysColor ( COLOR_3DFACE ) );
661 
662  RECT rText;
663  rText = rTemp;
664  rText.right = rText.left + mSplitter;
665  rText.left += 2;
666 
667  DrawText ( dis->hDC, item->mName, item->mName.Length(), &rText, DT_LEFT|DT_VCENTER|DT_SINGLELINE );
668 
669  rText.left = dis->rcItem.left + mSplitter + 2;
670  rText.right = dis->rcItem.right;
671  DrawText ( dis->hDC, item->mValue, item->mValue.Length(), &rText, DT_LEFT|DT_VCENTER|DT_SINGLELINE );
672 
673  return 0;
674 }
const char * mName
Definition: PropertyGrid.h:41
void FinishEdit(void)
GLsizei const GLfloat * value
Definition: glext.h:3614
assert(prefInfo.fullscreenBtn)
int Cmp(const char *text) const
Definition: Str.h:652
void CancelEdit(void)
CONST PIXELFORMATDESCRIPTOR UINT
Definition: win_qgl.cpp:47
int Length(void) const
Definition: Str.h:702
GLenum GLint GLint y
Definition: glext.h:2849
void RemoveAllItems(void)
GLuint GLuint GLsizei GLenum type
Definition: glext.h:2845
void Move(int x, int y, int w, int h, BOOL redraw=FALSE)
GLenum GLint x
Definition: glext.h:2849
int i
Definition: process.py:33
#define BOOL
Definition: mprintf.c:71
const char * GetItemValue(int index)
int Icmp(const char *text) const
Definition: Str.h:667
const char * mValue
Definition: PropertyGrid.h:42
bool Create(HWND parent, int id, int style=0)
int AddItem(const char *name, const char *value, EItemType type=PGIT_STRING)
GLuint index
Definition: glext.h:3476
#define PGS_ALLOWINSERT
Definition: PropertyGrid.h:35
GLubyte GLubyte GLubyte GLubyte w
Definition: glext.h:3454
WNDPROC mListWndProc
Definition: PropertyGrid.h:97
#define NULL
Definition: Lib.h:88
#define PGN_ITEMCHANGED
Definition: PropertyGrid.h:32
bool ReflectMessage(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
void RemoveItem(int index)
typedef HDC(WINAPI *PFNWGLGETCURRENTREADDCARBPROC)(void)
void SetCurSel(int index)
Definition: PropertyGrid.h:117
#define PGS_HEADERS
Definition: PropertyGrid.h:34
void StartEdit(int item, bool label)
int HandleDrawItem(WPARAM wParam, LPARAM lParam)
long LONG
GLenum filter
Definition: glext.h:3704
MFnDagNode * GetParent(MFnDagNode *joint)
Definition: maya_main.cpp:350
const GLcharARB * name
Definition: glext.h:3629
Definition: Str.h:116
#define TRUE
Definition: mprintf.c:69
HINSTANCE hInstance
Definition: win_local.h:102
if(!ValidDisplayID(prefInfo.prefDisplayID)) prefInfo.prefDisplayID
static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
Win32Vars_t win32
Definition: win_main.cpp:65
rvPropertyGrid::EItemType mType
const char * GetItemName(int index)