dsrc isn't necessary for this repo
[client-tools.git] / src / external / 3rd / application / UiBuilder / UIWindow.cpp
blob3060313eb3ab7d22332584b9620bf396179e3606
1 #include "FirstUiBuilder.h"
3 #include "UIBuilderHistory.h"
4 #include "UIDirect3DPrimaryCanvas.h"
5 #include "UIManager.h"
6 #include "UIPage.h"
7 #include "UIScriptEngine.h"
8 #include "uicanvas.h"
9 #include "uimessage.h"
10 #include "uipalette.h"
11 #include "UIUndo.h"
12 #include "UIWidget.h"
13 #include "UIUtils.h"
15 #include <cmath>
16 #include <commctrl.h>
17 #include <process.h>
18 #include <windowsx.h>
20 #include "objectinspector.h"
21 #include "resource.h"
23 static const int UITimerID = 100;
25 extern bool g_showShaders;
27 HWND gUIWindow = 0;
28 HWND gCanvasWindow = 0;
29 HWND gTabControlWindow = 0;
31 HANDLE gEngineThread = 0;
32 HANDLE gStopEvent = 0;
33 HANDLE gFrameRenderingMutex = 0;
35 long gTriangleCount = 0;
36 long gFlushCount = 0;
37 long gFrameCount = 0;
39 bool gButtonDown;
40 UIPoint gMouseDownPoint;
42 UIBaseObject::UISmartObjectList gCurrentSelection;
44 bool gMoving;
45 UIPoint gOriginalLocation;
46 bool gSizing;
47 UISize gOriginalSize;
49 UIRect gTabControlPadding;
50 UIPage *gCurrentlySelectedPage = 0;
52 bool gDrawHighlightRect = true;
53 bool gLimitFrameRate = true;
54 bool gInVisualEditingMode = false;
55 UIColor gHighlightOutlineColor(0xff,0,0,0xaa);
56 UIColor gHighlightFillColor(0xff,0,0,0);
58 bool gSizeUp = false;
59 bool gSizeDown = false;
60 bool gSizeLeft = false;
61 bool gSizeRight = false;
63 bool gNoChangeSelection = false;
65 bool gDrawGrid = false;
66 bool gSnapToGrid = false;
67 UIColor gGridColor(255,255,255,32);
68 unsigned long gXGridStep = 10;
69 unsigned long gYGridStep = 10;
70 unsigned long gGridMajorTicks = 10;
72 bool gDrawCursor = true;
74 const long LineWidth = 1;
75 const long HandleSize = 4;
76 const double MoveThreshold = 5.0;
77 const double SizeThreshold = 3.0;
79 extern HWND gObjectTree;
80 extern HWND gMainWindow;
81 extern HWND gTooltip;
82 extern ObjectInspector *gObjectInspector;
83 extern UIDirect3DPrimaryCanvas *gPrimaryDisplay;
85 const char *gVisualEditLockPropertyName = "VisualEditLock";
87 void AddTooltipFromControlID( HWND TooltipWindow, HWND ParentWindow, UINT ControlID, char *Tooltip );
88 void ClearDefPushButtonLook( HWND hwndDlg, UINT nControlID );
89 void CopySelectedObjectInTreeToClipboard( HWND hTree );
90 void PasteObjectFromClipboard( HWND hTree );
91 void DeleteSelectedObjectInTree( HWND hTree );
92 void EnableHistoryButtons();
95 // Undo Stuff
96 void RebuildTreeView(UIBaseObject * newObject);
98 void recordUndo(UIBaseObject * const object, bool force = false);
99 void recordUndo(UIBaseObject * const object, UILowerString property, UIString oldValue, UIString newValue, bool force = false);
100 void undo();
102 typedef std::vector<UIUndo> UndoQueue;
103 UndoQueue s_UndoQueue;
104 bool volatile s_UndoReady = false;
105 bool volatile s_UndoQueueEmpty = true;
106 extern HMENU gMenu;
107 int const MaxUndoSteps = 128;
108 // End Undo Stuff
110 enum Align
112 LeftAlignment,
113 HCenterAlignment,
114 RightAlignment,
115 TopAlignment,
116 VCenterAlignment,
117 BottomAlignment,
120 void UIThread( void * );
122 void AlignSelection( Align NewAlignment )
124 if( gCurrentSelection.size() < 2 )
125 return;
127 UIRect ReferenceRect;
128 bool bFirst = true;
129 bool const forceUndo = s_UndoReady;
131 for( UIBaseObject::UISmartObjectList::iterator i = gCurrentSelection.begin(); i != gCurrentSelection.end(); ++i )
133 if( (*i)->IsA( TUIWidget ) )
135 UIWidget * w = UI_ASOBJECT(UIWidget, *i );
137 if( bFirst )
139 w->GetWorldRect( ReferenceRect );
140 bFirst = false;
142 else
144 UIRect ControlRect;
145 UIPoint MovementRequired(0,0);
147 w->GetWorldRect( ControlRect );
149 switch( NewAlignment )
151 case LeftAlignment:
152 MovementRequired.x = ReferenceRect.left - ControlRect.left;
153 break;
154 case HCenterAlignment:
155 MovementRequired.x = (ReferenceRect.right + ReferenceRect.left ) / 2 -
156 (ControlRect.right + ControlRect.left ) / 2;
157 break;
158 case RightAlignment:
159 MovementRequired.x = ReferenceRect.right - ControlRect.right;
160 break;
161 case TopAlignment:
162 MovementRequired.y = ReferenceRect.top - ControlRect.top;
163 break;
164 case VCenterAlignment:
165 MovementRequired.y = (ReferenceRect.bottom + ReferenceRect.top ) / 2 -
166 (ControlRect.bottom + ControlRect.top ) / 2;
167 break;
168 case BottomAlignment:
169 MovementRequired.y = ReferenceRect.bottom - ControlRect.bottom;
170 break;
173 recordUndo(w, forceUndo);
174 w->SetLocation( w->GetLocation() + MovementRequired );
180 void SizeSelection( bool MatchWidth, bool MatchHeight )
182 if( gCurrentSelection.size() < 2 )
183 return;
185 UISize ReferenceSize;
186 bool bFirst = true;
187 bool const forceUndo = s_UndoReady;
189 for( UIBaseObject::UISmartObjectList::iterator i = gCurrentSelection.begin(); i != gCurrentSelection.end(); ++i )
191 if( (*i)->IsA( TUIWidget ) )
193 UIWidget *w = UI_ASOBJECT(UIWidget, *i );
195 if( bFirst )
197 ReferenceSize = w->GetSize();
198 bFirst = false;
200 else
202 UISize ControlSize (w->GetSize());
204 if( MatchWidth )
205 ControlSize.x = ReferenceSize.x;
207 if( MatchHeight )
208 ControlSize.y = ReferenceSize.y;
210 recordUndo(w, forceUndo);
211 w->SetSize( ControlSize );
217 void UpdateAlignmentControlEnabledState( void )
219 BOOL NewState;
221 if( gCurrentSelection.size() >=2 )
222 NewState = TRUE;
223 else
224 NewState = FALSE;
226 EnableWindow( GetDlgItem(gUIWindow,IDC_ALIGNLEFT), NewState );
227 EnableWindow( GetDlgItem(gUIWindow,IDC_ALIGNHCENTER), NewState );
228 EnableWindow( GetDlgItem(gUIWindow,IDC_ALIGNRIGHT), NewState );
229 EnableWindow( GetDlgItem(gUIWindow,IDC_ALIGNTOP), NewState );
230 EnableWindow( GetDlgItem(gUIWindow,IDC_ALIGNVCENTER), NewState );
231 EnableWindow( GetDlgItem(gUIWindow,IDC_ALIGNBOTTOM), NewState );
233 EnableWindow( GetDlgItem(gUIWindow,IDC_SIZEWIDTH), NewState );
234 EnableWindow( GetDlgItem(gUIWindow,IDC_SIZEHEIGHT), NewState );
237 //-----------------------------------------------------------------
239 UIWidget *GetObjectInSelection( const UIPoint &PointToTest )
241 for( UIBaseObject::UISmartObjectList::iterator i = gCurrentSelection.begin(); i != gCurrentSelection.end(); ++i )
243 if( (*i)->IsA( TUIWidget ) )
245 UIWidget *w = UI_ASOBJECT(UIWidget, *i);
247 UIRect ObjectRect;
249 w->GetWorldRect( ObjectRect );
250 if( ObjectRect.ContainsPoint( PointToTest ) )
251 return w;
254 return 0;
257 //-----------------------------------------------------------------
260 bool SelectionContains( const UIBaseObject *ObjectToQuery )
262 return std::find (gCurrentSelection.begin(),gCurrentSelection.end(), ObjectToQuery) != gCurrentSelection.end ();
265 //-----------------------------------------------------------------
267 void SetSelection( UIBaseObject *NewSelection, bool pushHistory )
269 if( gNoChangeSelection )
270 return;
272 WaitForSingleObject( gFrameRenderingMutex, INFINITE );
274 const bool skip = !gCurrentSelection.empty () && gCurrentSelection.front () == static_cast<const UIBaseObject *>(NewSelection);
276 if (!skip)
278 gCurrentSelection.clear();
280 if( NewSelection)
282 gCurrentSelection.push_front(UIBaseObject::UIBaseObjectPointer(NewSelection));
284 if( NewSelection->IsA( TUIWidget ) )
286 UIWidget *w = static_cast<UIWidget *>( NewSelection );
288 gOriginalLocation = w->GetLocation();
289 gOriginalSize = w->GetSize();
292 if (pushHistory)
293 UIBuilderHistory::pushNode (NewSelection->GetFullPath ());
295 EnableHistoryButtons ();
299 UpdateAlignmentControlEnabledState();
301 ReleaseMutex( gFrameRenderingMutex );
304 //-----------------------------------------------------------------
306 bool RemoveFromSelection( const UIBaseObject *ObjectToRemove )
308 bool selectionChanged = false;
310 if( gNoChangeSelection )
311 return selectionChanged;
313 if( ObjectToRemove )
315 WaitForSingleObject( gFrameRenderingMutex, INFINITE );
317 for( UIBaseObject::UISmartObjectList::iterator i = gCurrentSelection.begin(); i != gCurrentSelection.end(); ++i )
319 if( *i == ObjectToRemove )
321 gCurrentSelection.erase( i );
322 selectionChanged = true;
323 break;
326 UpdateAlignmentControlEnabledState();
328 ReleaseMutex( gFrameRenderingMutex );
331 return selectionChanged;
334 //-----------------------------------------------------------------
336 void AddToSelection( UIBaseObject *ObjectToAdd, bool pushHistory )
338 if( gNoChangeSelection )
339 return;
341 if( ObjectToAdd )
343 WaitForSingleObject( gFrameRenderingMutex, INFINITE );
345 RemoveFromSelection( ObjectToAdd );
346 gCurrentSelection.push_front(UIBaseObject::UIBaseObjectPointer(ObjectToAdd));
347 UpdateAlignmentControlEnabledState();
349 if (pushHistory)
350 UIBuilderHistory::pushNode (ObjectToAdd->GetFullPath ());
352 EnableHistoryButtons ();
354 ReleaseMutex( gFrameRenderingMutex );
358 //-----------------------------------------------------------------
360 HTREEITEM GetObjectInTreeControlFromHandle( HWND hTree, HTREEITEM hParentItem, UIBaseObject *o )
362 HTREEITEM hItem;
364 if( hParentItem )
365 hItem = TreeView_GetChild(hTree, hParentItem);
366 else
367 hItem = TreeView_GetRoot(hTree);
369 while( hItem )
371 TVITEM tvi;
373 tvi.mask = TVIF_HANDLE | TVIF_PARAM;
374 tvi.hItem = hItem;
376 TreeView_GetItem( hTree, &tvi );
378 if( reinterpret_cast<UIBaseObject *>( tvi.lParam ) == o )
379 return hItem;
381 HTREEITEM hChildFound = GetObjectInTreeControlFromHandle( gObjectTree, hItem, o );
383 if( hChildFound )
384 return hChildFound;
386 hItem = TreeView_GetNextSibling( gObjectTree, hItem );
388 return 0;
391 void SizeWindowToCurrentPageSelection( void )
393 int iCurrentTab = TabCtrl_GetCurSel( gTabControlWindow );
395 if( iCurrentTab >= 0 )
397 TCITEM tci;
399 tci.mask = TCIF_PARAM;
400 TabCtrl_GetItem( gTabControlWindow, iCurrentTab, &tci );
401 assert(tci.lParam);
403 if( gCurrentlySelectedPage )
404 gCurrentlySelectedPage->ForceVisible( false );
406 gCurrentlySelectedPage = reinterpret_cast<UIPage *>( tci.lParam );
407 const UISize & s = gCurrentlySelectedPage->GetSize();
408 gCurrentlySelectedPage->ForceVisible( true );
410 SetWindowPos( gCanvasWindow, 0, 0, 0, s.x, s.y, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
412 RECT rc;
413 rc.left = 0;
414 rc.top = 0;
415 rc.right = s.x;
416 rc.bottom = s.y;
417 TabCtrl_AdjustRect( gTabControlWindow, TRUE, &rc );
419 SetWindowPos( gTabControlWindow, 0, 0, 0, rc.right - rc.left, rc.bottom - rc.top, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
421 rc.left -= gTabControlPadding.left;
422 rc.top -= gTabControlPadding.top;
423 rc.right += gTabControlPadding.right;
424 rc.bottom += gTabControlPadding.bottom;
426 AdjustWindowRectEx( &rc, GetWindowLong( gUIWindow, GWL_STYLE ), FALSE, GetWindowLong( gUIWindow, GWL_EXSTYLE ) );
427 SetWindowPos( gUIWindow, 0, 0, 0, rc.right - rc.left, rc.bottom - rc.top, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
431 void RefreshContents( void )
433 WaitForSingleObject( gFrameRenderingMutex, INFINITE );
434 UIManager::gUIManager().RefreshGraphics();
435 ReleaseMutex( gFrameRenderingMutex );
438 LRESULT CALLBACK CanvasWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
440 UIMessage UIMsg;
442 // Convert lParam to local coordinate space if needed
443 if( gCurrentlySelectedPage )
445 switch( uMsg )
447 case WM_MOUSEMOVE:
448 case WM_LBUTTONDOWN:
449 case WM_LBUTTONUP:
450 case WM_MBUTTONDOWN:
451 case WM_MBUTTONUP:
452 case WM_RBUTTONDOWN:
453 case WM_RBUTTONUP:
455 UIPoint CanvasTranslation = gCurrentlySelectedPage->GetLocation();
456 POINTS MouseCoord = MAKEPOINTS( lParam );
458 const long x = MouseCoord.x + CanvasTranslation.x;
459 const long y = MouseCoord.y + CanvasTranslation.y;
461 lParam = MAKELPARAM( x, y );
462 break;
467 // First stage: Handle ONLY things that the rendering thread is not
468 // in contention for. Return is prefered to break unless you want the
469 // second stage to process the message as well
470 switch( uMsg )
472 case WM_CREATE:
474 gFrameRenderingMutex = CreateMutex( 0, 0, 0 );
475 gStopEvent = CreateEvent( 0, 1, 0, 0 );
477 if( !InitializeCanvasSystem( hwnd ) )
479 MessageBox( NULL, "Could not initialize canvas system", NULL, MB_OK );
480 return -1;
483 RECT rc;
485 // Create the primary display before we invoke the loader so that the global gPrimaryDisplay
486 // is set up - so that we can make the textures with the correct pixelformat.
487 GetClientRect( hwnd, &rc );
488 gPrimaryDisplay = new UIDirect3DPrimaryCanvas( UISize( rc.right, rc.bottom ), hwnd, false );
489 gPrimaryDisplay->ShowShaders (g_showShaders);
490 gPrimaryDisplay->Attach( 0 );
492 UIManager::gUIManager().SetScriptEngine( new UIScriptEngine );
494 gEngineThread = (HANDLE)_beginthread( UIThread, 0, 0 );
495 return DefWindowProc( hwnd, uMsg, wParam, lParam );
498 case WM_SIZE:
499 WaitForSingleObject( gFrameRenderingMutex, INFINITE );
500 gPrimaryDisplay->SetSize( UISize( LOWORD(lParam), HIWORD(lParam) ) );
501 ReleaseMutex( gFrameRenderingMutex );
503 InvalidateRect( hwnd, NULL, FALSE );
504 return DefWindowProc( hwnd, uMsg, wParam, lParam );
506 case WM_PAINT:
508 PAINTSTRUCT ps;
510 BeginPaint( hwnd, &ps );
511 EndPaint( hwnd, &ps );
512 return 0;
515 case WM_DESTROY:
517 SetEvent( gStopEvent );
518 WaitForSingleObject( gEngineThread, INFINITE );
519 ShutdownCanvasSystem( hwnd );
521 CloseHandle( gFrameRenderingMutex );
522 CloseHandle( gStopEvent );
524 gFrameRenderingMutex = 0;
525 gStopEvent = 0;
527 delete UIManager::gUIManager().GetScriptEngine();
528 UIManager::gUIManager().SetScriptEngine(0);
530 return DefWindowProc( hwnd, uMsg, wParam, lParam );
533 case WM_LBUTTONDOWN:
534 case WM_MBUTTONDOWN:
535 case WM_RBUTTONDOWN:
536 SetCapture( hwnd );
537 break; // Pass through to second stage
538 case WM_LBUTTONDBLCLK:
539 case WM_MBUTTONDBLCLK:
540 case WM_RBUTTONDBLCLK:
542 if (gInVisualEditingMode)
544 UIPage * const RootPage = UIManager::gUIManager ().GetRootPage ();
546 if (RootPage)
548 UIWidget * ClickedWidget = RootPage->GetWidgetFromPoint( gMouseDownPoint, true );
550 if (!ClickedWidget)
551 ClickedWidget = RootPage->GetWidgetFromPoint( gMouseDownPoint, false );
552 else
554 const UIPoint & pt = gMouseDownPoint - ClickedWidget->GetWorldLocation ();
556 UIWidget * const ClickedWidgetNoInput = ClickedWidget->GetWidgetFromPoint( pt, false );
558 UIBaseObject * p = ClickedWidgetNoInput;
560 while (p)
562 if (p == ClickedWidget)
564 ClickedWidget = ClickedWidgetNoInput;
565 break;
568 p = p->GetParent ();
572 //-- don't allow selection of transients
573 while (ClickedWidget && ClickedWidget->IsTransient ())
574 ClickedWidget = ClickedWidget->GetParentWidget ();
576 UIWidget * const ObjectInSelection = GetObjectInSelection( gMouseDownPoint );
578 // Drill down
579 while( ClickedWidget && (ClickedWidget->GetParent() != ObjectInSelection) )
581 UIWidget * const SearchObject = ClickedWidget->GetParentWidget ();
583 if( SearchObject )
585 if( ClickedWidget != SearchObject->GetParent() )
586 ClickedWidget = SearchObject;
588 else
589 ClickedWidget = 0;
592 if (ClickedWidget)
594 SetSelection( ClickedWidget, true);
596 HTREEITEM hItemToSelect = GetObjectInTreeControlFromHandle( gObjectTree, 0, ClickedWidget );
598 gNoChangeSelection = true;
599 TreeView_SelectItem( gObjectTree, hItemToSelect );
600 gNoChangeSelection = false;
606 break; // Pass through to second stage
608 case WM_LBUTTONUP:
609 case WM_MBUTTONUP:
610 case WM_RBUTTONUP:
611 if( GetCapture() == hwnd )
612 ReleaseCapture();
614 break; // Pass through to second stage
616 case WM_KEYDOWN:
617 case WM_KEYUP:
618 case WM_CHAR:
619 if( gInVisualEditingMode )
621 RECT rcClient;
622 POINT CursorPosition;
624 GetCursorPos( &CursorPosition );
625 GetWindowRect( hwnd, &rcClient );
627 if( PtInRect( &rcClient, CursorPosition ) )
629 HCURSOR hCursor;
631 if( GetAsyncKeyState( VK_SHIFT ) & 0x80000000 )
632 hCursor = LoadCursor( GetModuleHandle(0), MAKEINTRESOURCE(IDC_ADDTOSEL) );
633 else if( GetAsyncKeyState( VK_CONTROL ) & 0x80000000 )
634 hCursor = LoadCursor( GetModuleHandle(0), MAKEINTRESOURCE(IDC_REMOVEFROMSEL) );
635 else
636 hCursor = LoadCursor( 0, IDC_ARROW );
638 SetCursor( hCursor );
641 break; // Pass through to second stage
643 case WM_MOUSEMOVE:
645 POINTS MousePoint = MAKEPOINTS( lParam );
646 HCURSOR hCursor = 0;
648 if( gInVisualEditingMode )
650 UIWidget * const SelectedObject = GetObjectInSelection( UIPoint( MousePoint.x, MousePoint.y ) );
652 if( !gButtonDown )
654 gSizeUp = false;
655 gSizeDown = false;
656 gSizeLeft = false;
657 gSizeRight = false;
659 if( SelectedObject )
661 UIRect HighlightRect;
662 long HHandleLoc;
663 long VHandleLoc;
665 SelectedObject->GetWorldRect( HighlightRect );
667 HHandleLoc = (HighlightRect.bottom + HighlightRect.top - HandleSize) / 2;
668 VHandleLoc = (HighlightRect.right + HighlightRect.left - HandleSize) / 2;
670 // Ordered so when very small the control will prefer to size down and to the right
671 if( MousePoint.x > HighlightRect.right - HandleSize )
673 if( (MousePoint.y <= HighlightRect.top + HandleSize ) ||
674 (MousePoint.y >= HighlightRect.bottom - HandleSize ) ||
675 (MousePoint.y >= HHandleLoc && MousePoint.y <= HHandleLoc + HandleSize) )
677 gSizeRight = true;
680 else if( MousePoint.x < HighlightRect.left + HandleSize )
682 if( (MousePoint.y <= HighlightRect.top + HandleSize ) ||
683 (MousePoint.y >= HighlightRect.bottom - HandleSize ) ||
684 (MousePoint.y >= HHandleLoc && MousePoint.y <= HHandleLoc + HandleSize) )
686 gSizeLeft = true;
690 if( MousePoint.y > HighlightRect.bottom - HandleSize )
692 if( (MousePoint.x <= HighlightRect.left + HandleSize ) ||
693 (MousePoint.x >= HighlightRect.right - HandleSize ) ||
694 (MousePoint.x >= VHandleLoc && MousePoint.x <= VHandleLoc + HandleSize) )
696 gSizeDown = true;
699 else if( MousePoint.y < HighlightRect.top + HandleSize )
701 if( (MousePoint.x <= HighlightRect.left + HandleSize ) ||
702 (MousePoint.x >= HighlightRect.right - HandleSize ) ||
703 (MousePoint.x >= VHandleLoc && MousePoint.x <= VHandleLoc + HandleSize) )
705 gSizeUp = true;
711 if( gSizeUp )
713 if( gSizeLeft )
714 hCursor = LoadCursor( 0, IDC_SIZENWSE );
715 else if( gSizeRight )
716 hCursor = LoadCursor( 0, IDC_SIZENESW );
717 else
718 hCursor = LoadCursor( 0, IDC_SIZENS );
720 else if( gSizeDown )
722 if( gSizeLeft )
723 hCursor = LoadCursor( 0, IDC_SIZENESW );
724 else if( gSizeRight )
725 hCursor = LoadCursor( 0, IDC_SIZENWSE );
726 else
727 hCursor = LoadCursor( 0, IDC_SIZENS );
729 else if( gSizeLeft || gSizeRight )
730 hCursor = LoadCursor( 0, IDC_SIZEWE );
733 if( !hCursor )
735 hCursor = LoadCursor( 0, IDC_ARROW );
737 if( gInVisualEditingMode )
739 if( wParam & MK_SHIFT )
740 hCursor = LoadCursor( GetModuleHandle(0), MAKEINTRESOURCE(IDC_ADDTOSEL) );
741 else if( wParam & MK_CONTROL )
742 hCursor = LoadCursor( GetModuleHandle(0), MAKEINTRESOURCE(IDC_REMOVEFROMSEL) );
746 if( gInVisualEditingMode || !gDrawCursor )
747 SetCursor( hCursor );
748 else
749 SetCursor( 0 );
751 break; // Pass through to second stage
754 case WM_GETDLGCODE:
755 return DLGC_WANTALLKEYS;
757 case WM_MOUSEACTIVATE:
758 SetFocus( hwnd );
759 return MA_ACTIVATE;
761 default:
762 return DefWindowProc( hwnd, uMsg, wParam, lParam );
765 // Second stage, handle things that the rendering thread
766 // is in contention for.
767 WaitForSingleObject( gFrameRenderingMutex, INFINITE );
769 if( !gInVisualEditingMode )
771 if( UIMsg.CreateFromWindowsMessage( uMsg, wParam, lParam ) )
772 UIManager::gUIManager().ProcessMessage( UIMsg );
774 else if( UIManager::gUIManager().GetRootPage() )
776 UIPage *RootPage = UIManager::gUIManager().GetRootPage();
778 switch( uMsg )
780 case WM_KEYUP:
782 s_UndoReady = true;
784 switch (wParam)
786 case VK_DELETE:
788 SendMessage (gMainWindow, WM_COMMAND, ID_EDIT_DELETE, 0);
789 break;
790 case 'C':
791 case 'c':
792 if ( GetAsyncKeyState( VK_CONTROL ) & 0x80000000 )
793 CopySelectedObjectInTreeToClipboard( gObjectTree );
794 break;
795 case 'v':
796 case 'V':
797 if ( GetAsyncKeyState( VK_CONTROL ) & 0x80000000 )
798 PasteObjectFromClipboard( gObjectTree );
799 break;
800 case 'x':
801 case 'X':
802 if ( GetAsyncKeyState( VK_CONTROL ) & 0x80000000 )
804 CopySelectedObjectInTreeToClipboard( gObjectTree );
805 DeleteSelectedObjectInTree( gObjectTree );
807 break;
808 default:
809 s_UndoReady = false;
813 break;
814 case WM_KEYDOWN:
816 s_UndoReady = true;
818 UIPoint Nudge(0,0);
820 switch( wParam )
822 case VK_UP:
823 Nudge.y = -1;
824 break;
825 case VK_DOWN:
826 Nudge.y = 1;
827 break;
828 case VK_LEFT:
829 Nudge.x = -1;
830 break;
831 case VK_RIGHT:
832 Nudge.x = 1;
833 break;
834 default:
835 s_UndoReady = false;
838 bool const forceUndo = s_UndoReady;
839 for( UIBaseObject::UISmartObjectList::iterator i = gCurrentSelection.begin(); i != gCurrentSelection.end(); ++i )
841 if( (*i)->IsA( TUIWidget ) )
843 UIWidget * w = UI_ASOBJECT(UIWidget, *i );
845 if( w != RootPage )
847 recordUndo(w, forceUndo);
848 w->SetLocation( w->GetLocation() + Nudge );
853 break;
856 case WM_MOUSEMOVE:
858 if( gButtonDown )
860 POINTS CurrentMousePoint = MAKEPOINTS( lParam );
861 bool const forceUndo = s_UndoReady;
863 if( gMoving )
865 UIPoint GroupMovement(0,0);
866 bool bFirst = true;
868 for( UIBaseObject::UISmartObjectList::iterator i = gCurrentSelection.begin(); i != gCurrentSelection.end(); ++i )
870 if( !(*i)->IsA( TUIWidget ) )
871 continue;
873 UIWidget * w = UI_ASOBJECT(UIWidget, *i );
875 if( (w == RootPage) || w->HasProperty( UILowerString (gVisualEditLockPropertyName )) )
876 continue;
878 if( !bFirst )
880 recordUndo(w, forceUndo);
881 w->SetLocation( w->GetLocation() + GroupMovement );
882 continue;
886 UIPoint NewLocation;
888 UIPoint LocationDiff (CurrentMousePoint.x - gMouseDownPoint.x,
889 CurrentMousePoint.y - gMouseDownPoint.y);
891 NewLocation.x = gOriginalLocation.x + LocationDiff.x;
892 NewLocation.y = gOriginalLocation.y + LocationDiff.y;
894 const UIPoint OldLocation (w->GetLocation());
896 if( gSnapToGrid )
898 UIRect SnapRect;
900 w->GetWorldRect( SnapRect );
902 SnapRect.left += LocationDiff.x;
903 SnapRect.top += LocationDiff.y;
904 SnapRect.right += LocationDiff.x;
905 SnapRect.bottom += LocationDiff.y;
907 SnapRect.left %= gXGridStep;
908 SnapRect.top %= gYGridStep;
910 //-- jww hack to prevent jumping
912 NewLocation.x -= SnapRect.left;
913 NewLocation.y -= SnapRect.top;
916 if( SnapRect.left < halfStepX )
917 NewLocation.x -= SnapRect.left;
918 else
919 NewLocation.x += gXGridStep - SnapRect.left;
921 if( SnapRect.top < halfStepY )
922 NewLocation.y -= SnapRect.top;
923 else
924 NewLocation.y += gYGridStep - SnapRect.top;
928 recordUndo(w, forceUndo);
929 w->SetLocation( NewLocation );
931 GroupMovement = NewLocation - OldLocation;
932 bFirst = false;
936 else if( gSizing )
938 UIPoint GroupMoveAmount(0,0);
939 UISize GroupSizeAmount(0,0);
940 bool bFirst = true;
942 for( UIBaseObject::UISmartObjectList::iterator i = gCurrentSelection.begin(); i != gCurrentSelection.end(); ++i )
944 if( !(*i)->IsA( TUIWidget ) )
945 continue;
947 UIWidget * w = UI_ASOBJECT(UIWidget, *i );
949 if( w->HasProperty( UILowerString (gVisualEditLockPropertyName ) ))
950 continue;
952 if( !bFirst )
954 recordUndo(w, forceUndo);
955 w->SetLocation( w->GetLocation() + GroupMoveAmount );
956 w->SetSize( w->GetSize() + GroupSizeAmount );
957 continue;
960 UISize NewSize;
961 UIPoint NewLocation;
963 const UIPoint OldLocation (w->GetLocation());
964 const UISize OldSize (w->GetSize());
966 if( gSizeLeft )
968 NewSize.x = gOriginalSize.x + (gMouseDownPoint.x - CurrentMousePoint.x);
969 NewLocation.x = gOriginalLocation.x - (gMouseDownPoint.x - CurrentMousePoint.x);
971 else if( gSizeRight )
973 NewSize.x = gOriginalSize.x - (gMouseDownPoint.x - CurrentMousePoint.x);
974 NewLocation.x = gOriginalLocation.x;
976 else
978 NewSize.x = gOriginalSize.x;
979 NewLocation.x = gOriginalLocation.x;
982 if( gSizeUp )
984 NewSize.y = gOriginalSize.y + (gMouseDownPoint.y - CurrentMousePoint.y);
985 NewLocation.y = gOriginalLocation.y - (gMouseDownPoint.y - CurrentMousePoint.y);
987 else if( gSizeDown )
989 NewSize.y = gOriginalSize.y - (gMouseDownPoint.y - CurrentMousePoint.y);
990 NewLocation.y = gOriginalLocation.y;
992 else
994 NewSize.y = gOriginalSize.y;
995 NewLocation.y = gOriginalLocation.y;
998 if( gSnapToGrid )
1000 UIRect SnapRect;
1002 if (w->GetParent () && w->GetParent ()->IsA (TUIWidget))
1004 UIWidget * parentalWidget = static_cast<UIWidget *> (w->GetParent ());
1006 UIPoint parentalWorldLoc;
1007 parentalWidget->GetWorldLocation (parentalWorldLoc);
1009 SnapRect.left = parentalWorldLoc.x;
1010 SnapRect.top = parentalWorldLoc.y;
1013 SnapRect.left += NewLocation.x;
1014 SnapRect.top += NewLocation.y;
1016 SnapRect.right = SnapRect.left + NewSize.x;
1017 SnapRect.bottom = SnapRect.top + NewSize.y;
1019 SnapRect.left %= gXGridStep;
1020 SnapRect.top %= gYGridStep;
1021 SnapRect.right %= gXGridStep;
1022 SnapRect.bottom %= gYGridStep;
1024 if( NewLocation.x != gOriginalLocation.x )
1026 if( (unsigned long)SnapRect.left < gXGridStep / 2 )
1028 NewLocation.x -= SnapRect.left;
1029 NewSize.x += SnapRect.left;
1031 else
1033 NewLocation.x += gXGridStep - SnapRect.left;
1034 NewSize.x -= gXGridStep - SnapRect.left;
1037 else if( NewSize.x != gOriginalSize.x )
1039 if( (unsigned long)SnapRect.right < gXGridStep / 2 )
1040 NewSize.x -= SnapRect.right;
1041 else
1042 NewSize.x += gXGridStep - SnapRect.right;
1045 if( NewLocation.y != gOriginalLocation.y )
1047 if( (unsigned long)SnapRect.top < gYGridStep / 2 )
1049 NewLocation.y -= SnapRect.top;
1050 NewSize.y += SnapRect.top;
1052 else
1054 NewLocation.y += gYGridStep - SnapRect.top;
1055 NewSize.y -= gYGridStep - SnapRect.top;
1058 else if( NewSize.y != gOriginalSize.y )
1060 if( (unsigned long)SnapRect.bottom < gYGridStep / 2 )
1061 NewSize.y -= SnapRect.bottom;
1062 else
1063 NewSize.y += gYGridStep - SnapRect.bottom;
1067 if( NewSize.x < 1 )
1068 NewSize.x = 1;
1069 if( NewSize.y < 1 )
1070 NewSize.y = 1;
1072 recordUndo(w, forceUndo);
1073 w->SetSize( NewSize );
1074 w->SetLocation( NewLocation );
1076 GroupMoveAmount = NewLocation - OldLocation;
1077 GroupSizeAmount = NewSize - OldSize;
1078 bFirst = false;
1083 else
1085 int dx = CurrentMousePoint.x - gMouseDownPoint.x;
1086 int dy = CurrentMousePoint.y - gMouseDownPoint.y;
1087 double d = sqrt( (double)(dx * dx + dy * dy) );
1089 if( gSizeUp || gSizeDown || gSizeLeft || gSizeRight )
1091 if( d > SizeThreshold )
1092 gSizing = true;
1094 else if( d > MoveThreshold )
1095 gMoving = true;
1098 break;
1100 case WM_LBUTTONDOWN:
1101 case WM_MBUTTONDOWN:
1102 case WM_RBUTTONDOWN:
1104 gMouseDownPoint.x = GET_X_LPARAM( lParam );
1105 gMouseDownPoint.y = GET_Y_LPARAM( lParam );
1107 UIWidget * ClickedWidget = 0;
1109 ClickedWidget = RootPage->GetWidgetFromPoint( gMouseDownPoint, true);
1111 if (!ClickedWidget)
1112 ClickedWidget = RootPage->GetWidgetFromPoint( gMouseDownPoint, false );
1114 //-- don't allow selection of transients
1115 while (ClickedWidget && (ClickedWidget->IsTransient ()))
1117 if (ClickedWidget->GetParent ()->IsA (TUIWidget))
1118 ClickedWidget = static_cast<UIWidget *>(ClickedWidget->GetParent ());
1121 gButtonDown = true;
1122 gMoving = false;
1123 gSizing = false;
1125 if( ClickedWidget )
1127 bool ResetMoveSize = true;
1129 if( wParam & MK_SHIFT )
1130 AddToSelection( ClickedWidget, true );
1131 else if( wParam & MK_CONTROL )
1133 RemoveFromSelection( ClickedWidget );
1134 ResetMoveSize = false;
1136 else
1138 UIWidget *ObjectInSelection = GetObjectInSelection( gMouseDownPoint );
1139 const bool theSelectionContains = SelectionContains( ClickedWidget );
1141 if( ObjectInSelection && !theSelectionContains)
1144 UIBaseObject * p = ObjectInSelection;
1146 while (p)
1148 if (p == ClickedWidget)
1149 break;
1151 p = p->GetParent ();
1154 if (!p)
1155 SetSelection( ClickedWidget, true );
1156 else
1158 ResetMoveSize = false;
1160 else
1162 if(theSelectionContains)
1164 // Move clicked item to the start of the selection
1165 RemoveFromSelection( ClickedWidget );
1166 AddToSelection( ClickedWidget, true );
1168 else
1169 SetSelection( ClickedWidget, true );
1173 if( ResetMoveSize && ClickedWidget )
1175 gOriginalSize = ClickedWidget->GetSize();
1176 gOriginalLocation = ClickedWidget->GetLocation();
1177 HTREEITEM hItemToSelect = GetObjectInTreeControlFromHandle( gObjectTree, 0, ClickedWidget );
1179 gNoChangeSelection = true;
1180 TreeView_SelectItem( gObjectTree, hItemToSelect );
1181 gNoChangeSelection = false;
1184 else
1186 //-- reset the original location and size - jww
1188 for( UIBaseObject::UISmartObjectList::iterator i = gCurrentSelection.begin(); i != gCurrentSelection.end(); ++i )
1190 if( !(*i)->IsA( TUIWidget ) )
1191 continue;
1193 UIWidget * w = UI_ASOBJECT(UIWidget, *i );
1194 gOriginalSize = w->GetSize ();
1195 gOriginalLocation = w->GetLocation ();
1196 break;
1202 break;
1205 case WM_LBUTTONUP:
1206 case WM_MBUTTONUP:
1207 case WM_RBUTTONUP:
1209 s_UndoReady = true;
1210 gButtonDown = false;
1211 break;
1216 ReleaseMutex( gFrameRenderingMutex );
1217 return DefWindowProc( hwnd, uMsg, wParam, lParam );
1220 void UIThread( void * )
1222 UIManager &GUIManager = UIManager::gUIManager();
1224 while( WaitForSingleObject( gStopEvent, 0 ) == WAIT_TIMEOUT )
1226 if( WaitForSingleObject( gFrameRenderingMutex, 100 ) == WAIT_OBJECT_0 )
1228 UIPage *RootPage = GUIManager.GetRootPage();
1230 if( !gInVisualEditingMode )
1231 GUIManager.SendHeartbeats();
1233 if( !RootPage || !IsWindowVisible( gPrimaryDisplay->GetWindow() ) )
1235 ReleaseMutex( gFrameRenderingMutex );
1236 Sleep( 100 );
1237 continue;
1240 if( gPrimaryDisplay->BeginRendering() )
1242 UIPoint CanvasTranslation(0,0);
1244 gPrimaryDisplay->ClearTo( UIColor( 0, 0, 0 ), UIRect (0, 0, gPrimaryDisplay->GetWidth (), gPrimaryDisplay->GetHeight () ));
1245 gPrimaryDisplay->PushState();
1247 if( gCurrentlySelectedPage )
1249 CanvasTranslation = -gCurrentlySelectedPage->GetLocation();
1250 gPrimaryDisplay->Translate( CanvasTranslation );
1253 GUIManager.DrawCursor( gDrawCursor );
1254 GUIManager.Render( *gPrimaryDisplay );
1256 if( gDrawGrid )
1258 int x;
1259 int y;
1260 int linecount;
1261 int width = RootPage->GetWidth();
1262 int height = RootPage->GetHeight();
1264 float LineOpacity = gGridColor.a / 255.0f;
1265 float ThickLineOpacity = 2.0f * LineOpacity;
1267 gPrimaryDisplay->SetOpacity( LineOpacity );
1269 for( x = 0, linecount = 0; x <= width; x += gXGridStep, ++linecount )
1271 if( (linecount % gGridMajorTicks) == 0 )
1273 gPrimaryDisplay->SetOpacity( ThickLineOpacity );
1274 gPrimaryDisplay->ClearTo( gGridColor, UIRect( x, CanvasTranslation.y, x+1, height ) );
1275 gPrimaryDisplay->SetOpacity( LineOpacity );
1277 else
1278 gPrimaryDisplay->ClearTo( gGridColor, UIRect( x, CanvasTranslation.y, x+1, height ) );
1281 for( y = 0, linecount = 0; y <= height; y += gYGridStep, ++linecount )
1283 if( (linecount % gGridMajorTicks) == 0 )
1285 gPrimaryDisplay->SetOpacity( ThickLineOpacity );
1286 gPrimaryDisplay->ClearTo( gGridColor, UIRect( CanvasTranslation.x, y, width, y+1 ) );
1287 gPrimaryDisplay->SetOpacity( LineOpacity );
1289 else
1290 gPrimaryDisplay->ClearTo( gGridColor, UIRect( CanvasTranslation.x, y, width, y+1 ) );
1294 if( gDrawHighlightRect )
1296 for( UIBaseObject::UISmartObjectList::iterator i = gCurrentSelection.begin(); i != gCurrentSelection.end(); ++i )
1298 if( !(*i)->IsA( TUIWidget ) )
1299 continue;
1301 UIWidget * w = UI_ASOBJECT(UIWidget, *i );
1302 UIRect HighlightRect;
1304 w->GetWorldRect( HighlightRect );
1306 gPrimaryDisplay->SetOpacity( gHighlightFillColor.a / 255.0f );
1308 gPrimaryDisplay->ClearTo( gHighlightFillColor, UIRect( HighlightRect.left, HighlightRect.top,
1309 HighlightRect.right, HighlightRect.bottom ) );
1311 gPrimaryDisplay->SetOpacity( gHighlightOutlineColor.a / 255.0f );
1313 gPrimaryDisplay->ClearTo( gHighlightOutlineColor, UIRect( HighlightRect.left, HighlightRect.top,
1314 HighlightRect.left + LineWidth, HighlightRect.bottom ) );
1316 gPrimaryDisplay->ClearTo( gHighlightOutlineColor, UIRect( HighlightRect.right - LineWidth, HighlightRect.top,
1317 HighlightRect.right, HighlightRect.bottom ) );
1319 gPrimaryDisplay->ClearTo( gHighlightOutlineColor, UIRect( HighlightRect.left + LineWidth, HighlightRect.top,
1320 HighlightRect.right - LineWidth, HighlightRect.top + LineWidth ) );
1322 gPrimaryDisplay->ClearTo( gHighlightOutlineColor, UIRect( HighlightRect.left + LineWidth, HighlightRect.bottom - LineWidth,
1323 HighlightRect.right - LineWidth, HighlightRect.bottom ) );
1325 if( gInVisualEditingMode && (HighlightRect.Height() >= 8) && (HighlightRect.Width() >= 8) && !w->HasProperty(UILowerString (gVisualEditLockPropertyName) ))
1327 gPrimaryDisplay->ClearTo( gHighlightOutlineColor, UIRect( HighlightRect.left + LineWidth, HighlightRect.top + LineWidth,
1328 HighlightRect.left + HandleSize, HighlightRect.top + HandleSize ) );
1330 gPrimaryDisplay->ClearTo( gHighlightOutlineColor, UIRect( HighlightRect.right - HandleSize, HighlightRect.top + LineWidth,
1331 HighlightRect.right - LineWidth, HighlightRect.top + HandleSize ) );
1333 gPrimaryDisplay->ClearTo( gHighlightOutlineColor, UIRect( HighlightRect.left + LineWidth, HighlightRect.bottom - HandleSize,
1334 HighlightRect.left + HandleSize, HighlightRect.bottom - LineWidth ) );
1336 gPrimaryDisplay->ClearTo( gHighlightOutlineColor, UIRect( HighlightRect.right - HandleSize, HighlightRect.bottom - HandleSize,
1337 HighlightRect.right - LineWidth, HighlightRect.bottom - LineWidth ) );
1339 if( HighlightRect.Height() >= 16 && HighlightRect.Width() >= 16 )
1341 long HHandleLoc, VHandleLoc;
1343 HHandleLoc = (HighlightRect.bottom + HighlightRect.top - HandleSize) / 2;
1344 VHandleLoc = (HighlightRect.right + HighlightRect.left - HandleSize) / 2;
1346 gPrimaryDisplay->ClearTo( gHighlightOutlineColor, UIRect( HighlightRect.left + LineWidth, HHandleLoc,
1347 HighlightRect.left + HandleSize, HHandleLoc + HandleSize ) );
1349 gPrimaryDisplay->ClearTo( gHighlightOutlineColor, UIRect( HighlightRect.right - HandleSize, HHandleLoc,
1350 HighlightRect.right - LineWidth, HHandleLoc + HandleSize ) );
1352 gPrimaryDisplay->ClearTo( gHighlightOutlineColor, UIRect( VHandleLoc, HighlightRect.top + LineWidth,
1353 VHandleLoc + HandleSize, HighlightRect.top + HandleSize ) );
1355 gPrimaryDisplay->ClearTo( gHighlightOutlineColor, UIRect( VHandleLoc, HighlightRect.bottom - HandleSize,
1356 VHandleLoc + HandleSize, HighlightRect.bottom - LineWidth ) );
1362 gPrimaryDisplay->PopState();
1363 gPrimaryDisplay->EndRendering();
1364 gPrimaryDisplay->Flip();
1366 gTriangleCount = gPrimaryDisplay->GetTriangleCount();
1367 gFlushCount = gPrimaryDisplay->GetFlushCount();
1369 ++gFrameCount;
1371 ReleaseMutex( gFrameRenderingMutex );
1373 if( gLimitFrameRate && !(gFrameCount % 2) )
1374 Sleep(18);
1379 void InitializeButtonGraphic( HWND hwndDlg, UINT ControlID, UINT ResourceID )
1381 SendDlgItemMessage( hwndDlg, ControlID, BM_SETIMAGE, IMAGE_ICON,
1382 (LPARAM)LoadImage( GetModuleHandle(0), MAKEINTRESOURCE(ResourceID), IMAGE_ICON, 16, 16, 0 ) );
1385 void InitializeButtonGraphicAndState( HWND hwndDlg, UINT ControlID, UINT ResourceID, bool bPressed )
1387 InitializeButtonGraphic( hwndDlg, ControlID, ResourceID );
1389 if( bPressed )
1390 CheckDlgButton( hwndDlg, ControlID, BST_CHECKED );
1391 else
1392 CheckDlgButton( hwndDlg, ControlID, BST_UNCHECKED );
1395 BOOL CALLBACK UIWindowDlgProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
1397 switch( uMsg )
1399 case WM_INITDIALOG:
1401 WNDCLASSEX wc = { sizeof( wc ) };
1402 RECT rcClient;
1403 RECT rcCanvas;
1404 RECT rcCanvasClient;
1406 gUIWindow = hwndDlg;
1408 wc.lpfnWndProc = CanvasWindowProc;
1409 wc.hInstance = GetModuleHandle(0);
1410 wc.lpszMenuName = MAKEINTRESOURCE( IDR_MAIN_MENU );
1411 wc.hCursor = NULL;
1412 wc.lpszClassName = "UICanvas";
1413 wc.style |= CS_DBLCLKS;
1415 if( !RegisterClassEx( &wc ) )
1416 return 1;
1418 gTabControlWindow = GetDlgItem( hwndDlg, IDC_ROOTPAGE );
1420 GetClientRect( gTabControlWindow, &rcCanvas );
1421 MapWindowPoints( gTabControlWindow, hwndDlg, (LPPOINT)&rcCanvas, 2 );
1422 CopyRect( &rcCanvasClient, &rcCanvas );
1424 TCITEM tci;
1425 tci.mask = TCIF_TEXT;
1426 tci.pszText = "Size Test";
1427 TabCtrl_InsertItem( gTabControlWindow, 0, &tci );
1428 TabCtrl_AdjustRect( gTabControlWindow, FALSE, &rcCanvasClient );
1429 TabCtrl_DeleteAllItems( gTabControlWindow );
1431 GetClientRect( hwndDlg, &rcClient );
1433 gTabControlPadding.left = rcCanvas.left;
1434 gTabControlPadding.top = rcCanvas.top;
1435 gTabControlPadding.right = rcClient.right - rcCanvas.right;
1436 gTabControlPadding.bottom = rcClient.bottom - rcCanvas.bottom;
1438 gCanvasWindow = CreateWindow( "UICanvas", "UICanvas", WS_CHILD | WS_VISIBLE | WS_TABSTOP,
1439 rcCanvasClient.left, rcCanvasClient.top, rcCanvas.right, rcCanvas.bottom, hwndDlg,
1440 (HMENU)100, GetModuleHandle(0), NULL );
1442 InitializeButtonGraphicAndState( hwndDlg, IDC_PLAY, IDI_PLAY, !gInVisualEditingMode );
1443 AddTooltipFromControlID( gTooltip, hwndDlg, IDC_PLAY, "Run / Stop User Interface" );
1445 InitializeButtonGraphic( hwndDlg, IDC_REFRESH, IDI_REFRESH );
1446 AddTooltipFromControlID( gTooltip, hwndDlg, IDC_REFRESH, "Refresh" );
1448 InitializeButtonGraphicAndState( hwndDlg, IDC_DRAWCURSOR, IDI_CURSOR, gDrawCursor );
1449 AddTooltipFromControlID( gTooltip, hwndDlg, IDC_DRAWCURSOR, "Draw Cursor" );
1451 InitializeButtonGraphicAndState( hwndDlg, IDC_DRAWHIGHLIGHT, IDI_DRAWHIGHLIGHT, gDrawHighlightRect );
1452 AddTooltipFromControlID( gTooltip, hwndDlg, IDC_DRAWHIGHLIGHT, "Draw Selection Highlight" );
1454 InitializeButtonGraphicAndState( hwndDlg, IDC_DRAWGRID, IDI_DRAWGRID, gDrawGrid );
1455 AddTooltipFromControlID( gTooltip, hwndDlg, IDC_DRAWGRID, "Draw Grid" );
1457 InitializeButtonGraphicAndState( hwndDlg, IDC_SNAPTOGRID, IDI_SNAPTOGRID, gSnapToGrid );
1458 AddTooltipFromControlID( gTooltip, hwndDlg, IDC_SNAPTOGRID, "Snap to Grid" );
1460 InitializeButtonGraphic( hwndDlg, IDC_ALIGNLEFT, IDI_ALIGNLEFT );
1461 AddTooltipFromControlID( gTooltip, hwndDlg, IDC_ALIGNLEFT, "Align Left" );
1463 InitializeButtonGraphic( hwndDlg, IDC_ALIGNHCENTER, IDI_ALIGNHCENTER );
1464 AddTooltipFromControlID( gTooltip, hwndDlg, IDC_ALIGNHCENTER, "Align on Horzontal Center" );
1466 InitializeButtonGraphic( hwndDlg, IDC_ALIGNRIGHT, IDI_ALIGNRIGHT );
1467 AddTooltipFromControlID( gTooltip, hwndDlg, IDC_ALIGNRIGHT, "Align Right" );
1469 InitializeButtonGraphic( hwndDlg, IDC_ALIGNTOP, IDI_ALIGNTOP );
1470 AddTooltipFromControlID( gTooltip, hwndDlg, IDC_ALIGNTOP, "Align Top" );
1472 InitializeButtonGraphic( hwndDlg, IDC_ALIGNVCENTER, IDI_ALIGNVCENTER );
1473 AddTooltipFromControlID( gTooltip, hwndDlg, IDC_ALIGNVCENTER, "Align on Vertical Center" );
1475 InitializeButtonGraphic( hwndDlg, IDC_ALIGNBOTTOM, IDI_ALIGNBOTTOM );
1476 AddTooltipFromControlID( gTooltip, hwndDlg, IDC_ALIGNBOTTOM, "Align Bottom" );
1478 InitializeButtonGraphic( hwndDlg, IDC_SIZEWIDTH, IDI_SIZEWIDTH );
1479 AddTooltipFromControlID( gTooltip, hwndDlg, IDC_SIZEWIDTH, "Make Controls Same Width" );
1481 InitializeButtonGraphic( hwndDlg, IDC_SIZEHEIGHT, IDI_SIZEHEIGHT );
1482 AddTooltipFromControlID( gTooltip, hwndDlg, IDC_SIZEHEIGHT, "Make Controls Same Height" );
1484 InitializeButtonGraphic( hwndDlg, IDC_RESET, IDI_RESET );
1485 AddTooltipFromControlID( gTooltip, hwndDlg, IDC_RESET, "Reset the Palette Data" );
1487 UpdateAlignmentControlEnabledState();
1489 SetTimer( hwndDlg, UITimerID, 100, 0 );
1490 return 0;
1493 case WM_MOVE:
1495 RECT rc;
1496 RECT rcMainWindow;
1497 GetWindowRect( hwndDlg, &rc );
1498 GetWindowRect( gMainWindow, &rcMainWindow );
1500 SetWindowPos( gMainWindow, 0, rc.left - (rcMainWindow.right - rcMainWindow.left), rc.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
1501 return 0;
1504 case WM_NOTIFY:
1505 if( wParam == IDC_ROOTPAGE )
1507 LPNMHDR GenericHeader = (LPNMHDR)lParam;
1509 if( GenericHeader->code == TCN_SELCHANGE )
1511 HTREEITEM hRoot;
1513 SizeWindowToCurrentPageSelection();
1514 hRoot = GetObjectInTreeControlFromHandle( gObjectTree, 0, gCurrentlySelectedPage );
1515 TreeView_SelectItem( gObjectTree, hRoot );
1516 TreeView_EnsureVisible( gObjectTree, hRoot );
1519 return 0;
1521 case WM_COMMAND:
1522 if( HIWORD(wParam) == BN_CLICKED )
1524 if( LOWORD(wParam) == IDC_PLAY )
1525 gInVisualEditingMode = !gInVisualEditingMode;
1526 if( LOWORD(wParam) == IDC_REFRESH )
1528 RefreshContents();
1529 ClearDefPushButtonLook( hwndDlg, IDC_REFRESH );
1531 else if( LOWORD( wParam ) == IDC_DRAWCURSOR )
1532 gDrawCursor = !gDrawCursor;
1533 else if( LOWORD( wParam ) == IDC_DRAWHIGHLIGHT )
1534 gDrawHighlightRect = !gDrawHighlightRect;
1535 else if( LOWORD( wParam ) == IDC_DRAWGRID )
1536 gDrawGrid = !gDrawGrid;
1537 else if( LOWORD( wParam ) == IDC_SNAPTOGRID )
1538 gSnapToGrid = !gSnapToGrid;
1539 else if( LOWORD( wParam ) == IDC_ALIGNLEFT )
1541 AlignSelection( LeftAlignment );
1542 ClearDefPushButtonLook( hwndDlg, IDC_ALIGNLEFT );
1544 else if( LOWORD( wParam ) == IDC_ALIGNHCENTER )
1546 AlignSelection( HCenterAlignment );
1547 ClearDefPushButtonLook( hwndDlg, IDC_ALIGNHCENTER );
1549 else if( LOWORD( wParam ) == IDC_ALIGNRIGHT )
1551 AlignSelection( RightAlignment );
1552 ClearDefPushButtonLook( hwndDlg, IDC_ALIGNRIGHT );
1554 else if( LOWORD( wParam ) == IDC_ALIGNTOP )
1556 AlignSelection( TopAlignment );
1557 ClearDefPushButtonLook( hwndDlg, IDC_ALIGNTOP );
1559 else if( LOWORD( wParam ) == IDC_ALIGNVCENTER )
1561 AlignSelection( VCenterAlignment );
1562 ClearDefPushButtonLook( hwndDlg, IDC_ALIGNVCENTER );
1564 else if( LOWORD( wParam ) == IDC_ALIGNBOTTOM )
1566 AlignSelection( BottomAlignment );
1567 ClearDefPushButtonLook( hwndDlg, IDC_ALIGNBOTTOM );
1569 else if( LOWORD( wParam ) == IDC_SIZEWIDTH )
1571 SizeSelection( true, false );
1572 ClearDefPushButtonLook( hwndDlg, IDC_SIZEWIDTH );
1574 else if( LOWORD( wParam ) == IDC_SIZEHEIGHT )
1576 SizeSelection( false, true );
1577 ClearDefPushButtonLook( hwndDlg, IDC_SIZEHEIGHT );
1579 else if( LOWORD( wParam ) == IDC_RESET )
1581 UIPalette * palette = UIPalette::GetInstance();
1582 if(palette)
1583 palette->Reset();
1586 SetFocus( gCanvasWindow );
1587 return 0;
1589 case WM_TIMER:
1590 if( UIManager::gUIManager().GetRootPage() )
1592 RECT rc;
1594 const UISize & RootSize = UIManager::gUIManager().GetRootPage()->GetSize();
1595 GetClientRect( gCanvasWindow, &rc );
1597 if( ((rc.right - rc.left) != RootSize.x) || ((rc.bottom - rc.top) != RootSize.y) )
1598 SizeWindowToCurrentPageSelection();
1600 return 0;
1602 case WM_DESTROY:
1603 KillTimer( hwndDlg, UITimerID );
1604 return 0;
1606 default:
1607 return 0;
1611 //----------------------------------------------------------------------
1613 void recordUndo(UIBaseObject * const object, bool force)
1615 WaitForSingleObject( gFrameRenderingMutex, INFINITE );
1617 if (s_UndoReady || force)
1619 if (object && object->GetParent())
1621 UIUndo undo(object);
1622 s_UndoQueue.push_back(undo);
1624 // Don't let the list grow too big.
1625 if (s_UndoQueue.size() > MaxUndoSteps)
1627 s_UndoQueue.erase(s_UndoQueue.begin());
1630 s_UndoReady = false;
1634 s_UndoQueueEmpty = s_UndoQueue.empty();
1635 EnableMenuItem(gMenu, ID_EDIT_UNDO, s_UndoQueueEmpty ? (MF_BYCOMMAND | MF_GRAYED) : (MF_BYCOMMAND | MF_ENABLED));
1637 ReleaseMutex( gFrameRenderingMutex );
1641 //----------------------------------------------------------------------
1643 void recordUndo(UIBaseObject * const object, UILowerString property, UIString oldValue, UIString newValue, bool force)
1645 //Can't undo operations to the root object
1646 if(object == UIManager::gUIManager().GetRootPage())
1647 return;
1649 WaitForSingleObject( gFrameRenderingMutex, INFINITE );
1651 if (s_UndoReady || force)
1653 UIUndo undo(object, property, oldValue, newValue);
1654 s_UndoQueue.push_back(undo);
1656 // Don't let the list grow too big.
1657 if (s_UndoQueue.size() > MaxUndoSteps)
1659 s_UndoQueue.erase(s_UndoQueue.begin());
1662 s_UndoReady = false;
1665 s_UndoQueueEmpty = s_UndoQueue.empty();
1666 EnableMenuItem(gMenu, ID_EDIT_UNDO, s_UndoQueueEmpty ? (MF_BYCOMMAND | MF_GRAYED) : (MF_BYCOMMAND | MF_ENABLED));
1668 ReleaseMutex( gFrameRenderingMutex );
1671 //----------------------------------------------------------------------
1673 void undo()
1675 WaitForSingleObject( gFrameRenderingMutex, INFINITE );
1677 UIBaseObject * selectedObject = NULL;
1679 if(!s_UndoQueue.empty())
1681 UIUndo & undoObject = s_UndoQueue.back();
1683 selectedObject = undoObject.getObject();
1685 bool rebuildTree = true;
1686 undoObject.undo(rebuildTree, &selectedObject);
1688 if (rebuildTree && selectedObject)
1690 // delete old tree, and add a new one.
1691 RebuildTreeView(NULL);
1695 s_UndoQueue.pop_back();
1697 s_UndoQueueEmpty = s_UndoQueue.empty();
1698 EnableMenuItem(gMenu, ID_EDIT_UNDO, s_UndoQueueEmpty ? (MF_BYCOMMAND | MF_GRAYED) : (MF_BYCOMMAND | MF_ENABLED));
1701 ReleaseMutex( gFrameRenderingMutex );
1704 //----------------------------------------------------------------------
1706 void clearUndoHistory()
1708 s_UndoQueue.clear();