2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
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.
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.
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/>.
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.
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.
26 ===========================================================================
29 #include "../../idlib/precompiled.h"
32 #include "../../sys/win32/win_local.h"
33 #include "PropertyGrid.h"
35 class rvPropertyGridItem
39 rvPropertyGridItem ( )
45 rvPropertyGrid::EItemType mType;
50 rvPropertyGrid::rvPropertyGrid
55 rvPropertyGrid::rvPropertyGrid ( void )
63 mState = STATE_NORMAL;
68 rvPropertyGrid::Create
70 Create a new property grid control with the given id and parent
73 bool rvPropertyGrid::Create ( HWND parent, int id, int style )
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 );
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 );
87 // Set the font of the list box
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 );
111 void rvPropertyGrid::Move ( int x, int y, int w, int h, BOOL redraw )
113 MoveWindow ( mWindow, x, y, w, h, redraw );
118 rvPropertyGrid::StartEdit
123 void rvPropertyGrid::StartEdit ( int item, bool label )
125 rvPropertyGridItem* gitem;
128 gitem = (rvPropertyGridItem*)SendMessage ( mWindow, LB_GETITEMDATA, item, 0 );
134 SendMessage ( mWindow, LB_GETITEMRECT, item, (LPARAM)&rItem );
137 rItem.right = rItem.left + mSplitter - 1;
141 rItem.left = rItem.left + mSplitter + 1;
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 );
159 rvPropertyGrid::FinishEdit
161 Finish editing by copying the data in the edit control to the internal value
164 void rvPropertyGrid::FinishEdit ( void )
167 rvPropertyGridItem* item;
170 if ( mState != STATE_EDIT )
175 assert ( mEditItem >= 0 );
177 mState = STATE_FINISHEDIT;
180 item = (rvPropertyGridItem*)SendMessage ( mWindow, LB_GETITEMDATA, mEditItem, 0 );
183 GetWindowText ( mEdit, value, 1023 );
188 MessageBeep ( MB_ICONASTERISK );
192 if ( !mEditLabel && item->mValue.Cmp ( value ) )
195 nmpg.hdr.code = PGN_ITEMCHANGED;
196 nmpg.hdr.hwndFrom = mWindow;
197 nmpg.hdr.idFrom = GetWindowLong ( mWindow, GWL_ID );
198 nmpg.mName = item->mName;
201 if ( !SendMessage ( GetParent ( mWindow ), WM_NOTIFY, 0, (LONG)&nmpg ) )
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 );
212 item->mValue = value;
216 else if ( mEditLabel && item->mName.Cmp ( value ) )
219 sel = AddItem ( value, "", PGIT_STRING );
221 StartEdit ( sel, false );
225 SetCurSel ( mEditItem );
227 mState = STATE_NORMAL;
230 ShowWindow ( mEdit, SW_HIDE );
231 SetFocus ( mWindow );
236 rvPropertyGrid::CancelEdit
238 Stop editing without saving the data
241 void rvPropertyGrid::CancelEdit ( void )
243 if ( mState == STATE_EDIT && !mEditLabel )
245 if ( !*GetItemValue ( mEditItem ) )
247 RemoveItem ( mEditItem );
251 mSelectedItem = mEditItem;
253 mState = STATE_NORMAL;
254 ShowWindow ( mEdit, SW_HIDE );
255 SetFocus ( mWindow );
256 SetCurSel ( mSelectedItem );
261 rvPropertyGrid::AddItem
263 Add a new item to the property grid
266 int rvPropertyGrid::AddItem ( const char* name, const char* value, EItemType type )
268 rvPropertyGridItem* item;
271 // Cant add headers if headers arent enabled
272 if ( type == PGIT_HEADER && !(mStyle&PGS_HEADERS) )
277 item = new rvPropertyGridItem;
279 item->mValue = value;
282 insert = SendMessage(mWindow,LB_GETCOUNT,0,0) - ((mStyle&PGS_ALLOWINSERT)?1:0);
284 return SendMessage ( mWindow, LB_INSERTSTRING, insert, (LONG)item );
289 rvPropertyGrid::RemoveItem
291 Remove the item at the given index
294 void rvPropertyGrid::RemoveItem ( int index )
296 if ( index < 0 || index >= SendMessage ( mWindow, LB_GETCOUNT, 0, 0 ) )
301 delete (rvPropertyGridItem*)SendMessage ( mWindow, LB_GETITEMDATA, index, 0 );
303 SendMessage ( mWindow, LB_DELETESTRING, index, 0 );
308 rvPropertyGrid::RemoveAllItems
310 Remove all items from the property grid
313 void rvPropertyGrid::RemoveAllItems ( void )
317 // free the memory for all the items
318 for ( i = SendMessage ( mWindow, LB_GETCOUNT, 0, 0 ); i > 0; i -- )
320 delete (rvPropertyGridItem*)SendMessage ( mWindow, LB_GETITEMDATA, i - 1, 0 );
323 // remove all items from the listbox itself
324 SendMessage ( mWindow, LB_RESETCONTENT, 0, 0 );
326 if ( mStyle & PGS_ALLOWINSERT )
328 // Add the item used to add items
329 rvPropertyGridItem* item;
330 item = new rvPropertyGridItem;
333 SendMessage ( mWindow, LB_ADDSTRING, 0, (LONG)item );
339 rvPropertyGrid::GetItemName
341 Return name of item at given index
344 const char* rvPropertyGrid::GetItemName ( int index )
346 rvPropertyGridItem* item;
348 item = (rvPropertyGridItem*)SendMessage ( mWindow, LB_GETITEMDATA, index, 0 );
359 rvPropertyGrid::GetItemValue
361 Return value of item at given index
364 const char* rvPropertyGrid::GetItemValue ( int index )
366 rvPropertyGridItem* item;
368 item = (rvPropertyGridItem*)SendMessage ( mWindow, LB_GETITEMDATA, index, 0 );
379 rvPropertyGrid::WndProc
381 Window procedure for property grid
384 LRESULT CALLBACK rvPropertyGrid::WndProc ( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
386 rvPropertyGrid* grid = (rvPropertyGrid*) GetWindowLong ( hWnd, GWL_USERDATA );
391 // grid->mEditItem = -1;
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 );
411 if ( grid->mSelectedItem >= 0 )
413 grid->StartEdit ( grid->mSelectedItem, (*grid->GetItemName ( grid->mSelectedItem ))?false:true);
421 grid->mSelectedItem = -1;
427 hdr = (NMHDR*)lParam;
428 if ( hdr->idFrom == 999 )
430 if ( hdr->code == EN_MSGFILTER )
433 filter = (MSGFILTER*)lParam;
434 if ( filter->msg == WM_KEYDOWN )
436 switch ( filter->wParam )
440 grid->FinishEdit ( );
444 grid->CancelEdit ( );
449 if ( filter->msg == WM_CHAR || filter->msg == WM_KEYUP )
451 switch ( filter->wParam )
465 if ( lParam == (long)grid->mEdit )
467 if ( HIWORD(wParam) == EN_KILLFOCUS )
469 grid->FinishEdit ( );
475 case WM_LBUTTONDBLCLK:
476 grid->mSelectedItem = SendMessage ( hWnd, LB_ITEMFROMPOINT, 0, lParam );
483 rvPropertyGridItem* gitem;
487 if ( grid->mState == rvPropertyGrid::STATE_EDIT )
492 item = (short)LOWORD(SendMessage ( hWnd, LB_ITEMFROMPOINT, 0, lParam ));
498 gitem = (rvPropertyGridItem*)SendMessage ( hWnd, LB_GETITEMDATA, item, 0 );
499 pt.x = LOWORD(lParam);
500 pt.y = HIWORD(lParam);
502 SendMessage ( hWnd, LB_GETITEMRECT, item, (LPARAM)&rItem );
504 if ( !gitem->mName.Icmp ( "" ) )
506 rItem.right = rItem.left + grid->mSplitter - 1;
507 if ( PtInRect ( &rItem, pt) )
509 grid->SetCurSel ( item );
510 grid->StartEdit ( item, true );
513 else if ( grid->mSelectedItem == item )
515 rItem.left = rItem.left + grid->mSplitter + 1;
516 if ( PtInRect ( &rItem, pt) )
518 grid->StartEdit ( item, false );
522 if ( grid->mState == rvPropertyGrid::STATE_EDIT )
524 ClientToScreen ( hWnd, &pt );
525 ScreenToClient ( grid->mEdit, &pt );
526 SendMessage ( grid->mEdit, WM_LBUTTONDOWN, wParam, MAKELONG(pt.x,pt.y) );
536 GetClientRect ( hWnd, &rClient );
537 FillRect ( (HDC)wParam, &rClient, GetSysColorBrush ( COLOR_3DFACE ) );
544 GetCursorPos ( &point );
545 ScreenToClient ( hWnd, &point );
546 if ( point.x >= grid->mSplitter - 2 && point.x <= grid->mSplitter + 2 )
548 SetCursor ( LoadCursor ( NULL, MAKEINTRESOURCE(IDC_SIZEWE)));
555 return CallWindowProc ( grid->mListWndProc, hWnd, msg, wParam, lParam );
560 rvPropertyGrid::ReflectMessage
562 Handle messages sent to the parent window
565 bool rvPropertyGrid::ReflectMessage ( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
571 if ( (HWND)lParam == mWindow )
573 switch ( HIWORD(wParam) )
576 mSelectedItem = SendMessage ( mWindow, LB_GETCURSEL, 0, 0 );
584 HandleDrawItem ( wParam, lParam );
589 MEASUREITEMSTRUCT* mis = (MEASUREITEMSTRUCT*) lParam;
590 mis->itemHeight = 18;
600 rvPropertyGrid::HandleDrawItem
602 Handle the draw item message
605 int rvPropertyGrid::HandleDrawItem ( WPARAM wParam, LPARAM lParam )
607 DRAWITEMSTRUCT* dis = (DRAWITEMSTRUCT*) lParam;
608 rvPropertyGridItem* item = (rvPropertyGridItem*) dis->itemData;
618 if ( mStyle & PGS_HEADERS )
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;
627 if ( item->mType == PGIT_HEADER )
629 brush = GetSysColorBrush ( COLOR_SCROLLBAR );
631 else if ( dis->itemState & ODS_SELECTED )
633 brush = GetSysColorBrush ( COLOR_HIGHLIGHT );
637 brush = GetSysColorBrush ( COLOR_WINDOW );
640 FillRect ( dis->hDC, &rTemp, brush );
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);
649 if ( item->mType != PGIT_HEADER )
651 MoveToEx ( dis->hDC, dis->rcItem.left + mSplitter, dis->rcItem.top, NULL );
652 LineTo ( dis->hDC, dis->rcItem.left + mSplitter, dis->rcItem.bottom );
654 SelectObject ( dis->hDC, oldpen );
655 DeleteObject ( pen );
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 ) );
664 rText.right = rText.left + mSplitter;
667 DrawText ( dis->hDC, item->mName, item->mName.Length(), &rText, DT_LEFT|DT_VCENTER|DT_SINGLELINE );
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 );