]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/tools/radiant/EntityDlg.cpp
Various Mac OS X tweaks to get this to build. Probably breaking things.
[icculus/iodoom3.git] / neo / tools / radiant / EntityDlg.cpp
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 "qe3.h"
33 #include "Radiant.h"
34 #include "GLWidget.h"
35 #include "PropertyList.h"
36 #include "entitydlg.h"
37 #include "PreviewDlg.h"
38 #include "CurveDlg.h"
39
40 #include "../../renderer/model_local.h"         // for idRenderModelPrt
41
42 void    Select_Ungroup();
43
44 // CEntityDlg dialog
45
46 IMPLEMENT_DYNAMIC(CEntityDlg, CDialog)
47 CEntityDlg::CEntityDlg(CWnd* pParent /*=NULL*/)
48         : CDialog(CEntityDlg::IDD, pParent)
49 {
50         editEntity = NULL;
51         multipleEntities = false;
52         currentAnimation = NULL;
53 }
54
55 CEntityDlg::~CEntityDlg()
56 {
57 }
58
59 void CEntityDlg::DoDataExchange(CDataExchange* pDX)
60 {
61         CDialog::DoDataExchange(pDX);
62         DDX_Control(pDX, IDC_LIST_KEYVAL, listKeyVal);
63         DDX_Control(pDX, IDC_COMBO_CLASS, comboClass);
64         DDX_Control(pDX, IDC_EDIT_KEY, editKey);
65         DDX_Control(pDX, IDC_EDIT_VAL, editVal);
66         DDX_Control(pDX, IDC_STATIC_TITLE, staticTitle);
67         DDX_Control(pDX, IDC_STATIC_KEY, staticKey);
68         DDX_Control(pDX, IDC_STATIC_VAL, staticVal);
69         DDX_Control(pDX, IDC_BUTTON_BROWSE, btnBrowse);
70         DDX_Control(pDX, IDC_E_135, btn135);
71         DDX_Control(pDX, IDC_E_90, btn90);
72         DDX_Control(pDX, IDC_E_45, btn45);
73         DDX_Control(pDX, IDC_E_180, btn180);
74         DDX_Control(pDX, IDC_E_0, btn360);
75         DDX_Control(pDX, IDC_E_225, btn225);
76         DDX_Control(pDX, IDC_E_270, btn270);
77         DDX_Control(pDX, IDC_E_315, btn315);
78         DDX_Control(pDX, IDC_E_UP, btnUp);
79         DDX_Control(pDX, IDC_E_DOWN, btnDown);
80         DDX_Control(pDX, IDC_BUTTON_MODEL, btnModel);
81         DDX_Control(pDX, IDC_BUTTON_SOUND, btnSound);
82         DDX_Control(pDX, IDC_BUTTON_GUI, btnGui);
83         DDX_Control(pDX, IDC_BUTTON_PARTICLE, btnParticle);
84         DDX_Control(pDX, IDC_BUTTON_SKIN, btnSkin);
85         DDX_Control(pDX, IDC_BUTTON_CURVE, btnCurve);
86         DDX_Control(pDX, IDC_BUTTON_CREATE, btnCreate);
87         DDX_Control(pDX, IDC_LIST_VARS, listVars);
88         DDX_Control(pDX, IDC_ENTITY_ANIMATIONS , cbAnimations);
89         DDX_Control(pDX, IDC_ANIMATION_SLIDER , slFrameSlider);
90         DDX_Control(pDX, IDC_ENTITY_CURRENT_ANIM , staticFrame);
91         DDX_Control(pDX, IDC_ENTITY_PLAY_ANIM , btnPlayAnim);
92         DDX_Control(pDX, IDC_ENTITY_STOP_ANIM , btnStopAnim);
93 }
94
95
96
97 BOOL CEntityDlg::OnInitDialog()
98 {
99         CDialog::OnInitDialog();
100         listKeyVal.SetUpdateInspectors(true);
101         listKeyVal.SetDivider(100);
102         listVars.SetDivider(100);
103         staticFrame.SetWindowText ( "0" );
104
105         return TRUE;  // return TRUE unless you set the focus to a control
106         // EXCEPTION: OCX Property Pages should return FALSE
107 }
108
109 int CEntityDlg::OnToolHitTest(CPoint point, TOOLINFO* pTI) const
110 {
111         // TODO: Add your specialized code here and/or call the base class
112
113         return CDialog::OnToolHitTest(point, pTI);
114 }
115
116
117 void CEntityDlg::AddClassNames() {
118         comboClass.ResetContent();
119         for (eclass_t *pec = eclass; pec; pec = pec->next) {
120                 comboClass.AddString(pec->name);
121         }
122
123 }
124
125 BEGIN_MESSAGE_MAP(CEntityDlg, CDialog)
126         ON_WM_SIZE()
127         ON_CBN_SELCHANGE(IDC_COMBO_CLASS, OnCbnSelchangeComboClass)
128         ON_LBN_SELCHANGE(IDC_LIST_KEYVAL, OnLbnSelchangeListkeyval)
129         ON_BN_CLICKED(IDC_E_135, OnBnClickedE135)
130         ON_BN_CLICKED(IDC_E_90, OnBnClickedE90)
131         ON_BN_CLICKED(IDC_E_45, OnBnClickedE45)
132         ON_BN_CLICKED(IDC_E_180, OnBnClickedE180)
133         ON_BN_CLICKED(IDC_E_0, OnBnClickedE0)
134         ON_BN_CLICKED(IDC_E_225, OnBnClickedE225)
135         ON_BN_CLICKED(IDC_E_270, OnBnClickedE270)
136         ON_BN_CLICKED(IDC_E_315, OnBnClickedE315)
137         ON_BN_CLICKED(IDC_E_UP, OnBnClickedEUp)
138         ON_BN_CLICKED(IDC_E_DOWN, OnBnClickedEDown)
139         ON_BN_CLICKED(IDC_BUTTON_MODEL, OnBnClickedButtonModel)
140         ON_BN_CLICKED(IDC_BUTTON_SOUND, OnBnClickedButtonSound)
141         ON_BN_CLICKED(IDC_BUTTON_GUI, OnBnClickedButtonGui)
142         ON_BN_CLICKED(IDC_BUTTON_BROWSE, OnBnClickedButtonBrowse)
143         ON_CBN_DBLCLK(IDC_COMBO_CLASS, OnCbnDblclkComboClass)
144         ON_BN_CLICKED(IDC_BUTTON_CREATE, OnBnClickedButtonCreate)
145         ON_LBN_DBLCLK(IDC_LIST_KEYVAL, OnLbnDblclkListkeyval)
146         ON_LBN_SELCHANGE(IDC_LIST_VARS, OnLbnSelchangeListVars)
147         ON_LBN_DBLCLK(IDC_LIST_VARS, OnLbnDblclkListVars)
148         ON_NOTIFY(NM_RELEASEDCAPTURE, IDC_ANIMATION_SLIDER, OnNMReleasedcaptureSlider1)
149         ON_BN_CLICKED(IDC_BUTTON_PARTICLE, OnBnClickedButtonParticle)
150         ON_BN_CLICKED(IDC_BUTTON_SKIN, OnBnClickedButtonSkin)
151         ON_BN_CLICKED(IDC_BUTTON_CURVE, OnBnClickedButtonCurve)
152         ON_CBN_SELCHANGE(IDC_ENTITY_ANIMATIONS, OnCbnAnimationChange)
153         ON_BN_CLICKED(IDC_ENTITY_PLAY_ANIM , OnBnClickedStartAnimation)
154         ON_BN_CLICKED(IDC_ENTITY_STOP_ANIM , OnBnClickedStopAnimation)
155         ON_WM_TIMER()
156         ON_BN_CLICKED(IDOK, OnOK)
157 END_MESSAGE_MAP()
158
159 void CEntityDlg::OnSize(UINT nType, int cx, int cy)
160 {
161         if (staticTitle.GetSafeHwnd() == NULL) {
162                 return;
163         }
164         CDialog::OnSize(nType, cx, cy);
165         CRect rect, crect, crect2;
166         GetClientRect(rect);
167         int bh = (float)rect.Height() * (rect.Height() - 210) / rect.Height() / 2;
168         staticTitle.GetWindowRect(crect);
169         staticTitle.SetWindowPos(NULL, 4, 4, rect.Width() -8, crect.Height(), SWP_SHOWWINDOW);
170         int top = 4 + crect.Height() + 4;
171         comboClass.GetWindowRect(crect);
172         btnCreate.GetWindowRect(crect2);
173         comboClass.SetWindowPos(NULL, 4, top, rect.Width() - 12 - crect2.Width(), crect.Height(), SWP_SHOWWINDOW);
174         btnCreate.SetWindowPos(NULL, rect.Width() - crect2.Width() - 4, top, crect2.Width(), crect.Height(), SWP_SHOWWINDOW);
175         top += crect.Height() + 4;
176         listVars.SetWindowPos(NULL, 4, top, rect.Width() - 8, bh, SWP_SHOWWINDOW);
177         top += bh + 4;
178         listKeyVal.SetWindowPos(NULL, 4, top, rect.Width() - 8, bh, SWP_SHOWWINDOW);
179         top += bh + 4;
180         staticKey.GetWindowRect(crect);
181         staticKey.SetWindowPos(NULL, 4, top + 2, crect.Width(), crect.Height(), SWP_SHOWWINDOW);
182         int left = 4 + crect.Width() + 4;
183         int pad = crect.Width();
184         editKey.GetWindowRect(crect);
185         editKey.SetWindowPos(NULL, left, top, rect.Width() - 12 - pad, crect.Height(), SWP_SHOWWINDOW);
186         top += crect.Height() + 4;
187         staticVal.GetWindowRect(crect);
188         staticVal.SetWindowPos(NULL, 4, top + 2, crect.Width(), crect.Height(), SWP_SHOWWINDOW);
189         editVal.GetWindowRect(crect);
190         bh = crect.Height();
191         editVal.SetWindowPos(NULL, left, top, rect.Width() - 16 - bh - pad, crect.Height(), SWP_SHOWWINDOW);
192         btnBrowse.SetWindowPos(NULL, rect.right - 4 - bh, top, bh, bh, SWP_SHOWWINDOW);
193         top += crect.Height() + 8;
194         btnModel.GetWindowRect(crect);
195         btnModel.SetWindowPos(NULL, rect.right - 4 - crect.Width(), top + 8, crect.Width(), crect.Height(), SWP_SHOWWINDOW);
196         btnSound.SetWindowPos(NULL, rect.right - 4 - crect.Width(), top + 12 + crect.Height(), crect.Width(), crect.Height(), SWP_SHOWWINDOW);
197         btnGui.SetWindowPos(NULL, rect.right - 4 - crect.Width(), top + 16 + crect.Height() * 2, crect.Width(), crect.Height(), SWP_SHOWWINDOW);
198         btnParticle.SetWindowPos(NULL, rect.right - 8 - (crect.Width() * 2), top + 16 + crect.Height() * 2, crect.Width(), crect.Height(), SWP_SHOWWINDOW);
199         btnSkin.SetWindowPos( NULL, rect.right - 8 - ( crect.Width() * 2 ), top + 12 + crect.Height(), crect.Width(), crect.Height(), SWP_SHOWWINDOW ); 
200         btnCurve.SetWindowPos( NULL, rect.right - 8 - ( crect.Width() * 2 ), top + 8, crect.Width(), crect.Height(), SWP_SHOWWINDOW ); 
201
202         //*************************************
203         //animation controls
204         //*************************************
205         int rightAnimAreaBorder = rect.right - 75 - crect.Width (); /*models, etc button width*/
206
207         btnStopAnim.GetWindowRect(crect);
208         btnStopAnim.SetWindowPos(NULL,rightAnimAreaBorder - crect.Width (),
209                 top + 8  ,crect.Width(),crect.Height(),SWP_SHOWWINDOW);
210
211         left = rightAnimAreaBorder - crect.Width() - 4;
212         btnPlayAnim.GetWindowRect(crect);
213         btnPlayAnim.SetWindowPos(NULL,left-crect.Width () ,top + 8 , crect.Width(),crect.Height(),SWP_SHOWWINDOW);
214
215         left -= crect.Width() + 4;
216         cbAnimations.GetWindowRect(crect);
217         cbAnimations.SetWindowPos(NULL,left-crect.Width (),top + 8  ,crect.Width(),crect.Height(),SWP_SHOWWINDOW);
218
219         staticFrame.GetWindowRect(crect);
220         staticFrame.SetWindowPos(NULL,rightAnimAreaBorder - crect.Width (),
221                 top + 34  ,crect.Width(),crect.Height(),SWP_SHOWWINDOW);
222
223         left = rightAnimAreaBorder - crect.Width () - 4;
224
225         slFrameSlider.GetWindowRect(crect);
226         slFrameSlider.SetWindowPos(NULL,left - crect.Width (),
227         top + 32  ,crect.Width(),crect.Height(),SWP_SHOWWINDOW);
228
229         //*************************************
230         //*************************************
231
232         btn135.GetWindowRect(crect);
233         bh = crect.Width();
234         btn135.SetWindowPos(NULL, 4, top, bh, bh, SWP_SHOWWINDOW);
235         btn90.SetWindowPos(NULL, 4 + 2 + bh, top, bh, bh, SWP_SHOWWINDOW);
236         btn45.SetWindowPos(NULL, 4 + 2 + 2 + bh * 2, top, bh, bh, SWP_SHOWWINDOW);
237         btnUp.SetWindowPos(NULL, 4 + 2 + 2 + 6 + bh * 3, top + bh / 2,bh,bh, SWP_SHOWWINDOW);
238         btnDown.SetWindowPos(NULL, 4 + 2 + 2 + 6 + bh *3, top + bh / 2 + bh + 2,bh,bh, SWP_SHOWWINDOW);
239         top += bh + 2;
240         btn180.SetWindowPos(NULL, 4, top, bh, bh, SWP_SHOWWINDOW);
241         btn360.SetWindowPos(NULL, 4 + 2 + 2 + bh * 2, top, bh, bh, SWP_SHOWWINDOW);
242         top += bh + 2;
243         btn225.SetWindowPos(NULL, 4, top, bh, bh, SWP_SHOWWINDOW);
244         btn270.SetWindowPos(NULL, 4 + 2 + bh, top, bh, bh, SWP_SHOWWINDOW);
245         btn315.SetWindowPos(NULL, 4 + 2 + 2 + bh * 2, top, bh, bh, SWP_SHOWWINDOW);
246         Invalidate();
247 }
248
249 void CEntityDlg::OnCbnSelchangeComboClass()
250 {
251         int index = comboClass.GetCurSel();
252         if (index != LB_ERR) {
253                 CString str;
254                 comboClass.GetLBText(index, str);
255                 eclass_t *ent = Eclass_ForName (str, false);
256                 if (ent) {
257                         if (selected_brushes.next == &selected_brushes) {
258                                 editEntity = world_entity;
259                                 multipleEntities = false;
260                         } else {
261                                 editEntity = selected_brushes.next->owner;
262                                 for (brush_t *b = selected_brushes.next->next; b != &selected_brushes; b = b->next) {
263                                         if (b->owner != editEntity) {
264                                                 multipleEntities = true;
265                                                 break;
266                                         }
267                                 }
268                         }
269                         listVars.ResetContent();
270                         CPropertyItem *pi = new CPropertyItem("Usage:", ent->desc.c_str(), PIT_VAR, "");
271                         listVars.AddPropItem(pi);
272
273                         int c = ent->vars.Num();
274                         for (int i = 0; i < c; i++) {
275                                 pi = new CPropertyItem(ent->vars[i].name.c_str(), ent->vars[i].desc.c_str(), PIT_VAR, "");
276                                 pi->SetData(ent->vars[i].type);
277                                 listVars.AddPropItem(pi);
278                         }
279                         listVars.Invalidate();
280                         SetKeyValPairs();
281                 }
282         }
283 }
284
285 const char *CEntityDlg::TranslateString(const char *buf) {
286         static char buf2[32768];
287         int                     i, l;
288         char            *out;
289
290         l = strlen(buf);
291         out = buf2;
292         for (i = 0; i < l; i++) {
293                 if (buf[i] == '\n') {
294                         *out++ = '\r';
295                         *out++ = '\n';
296                 }
297                 else {
298                         *out++ = buf[i];
299                 }
300         }
301
302         *out++ = 0;
303
304         return buf2;
305
306 }
307
308 void CEntityDlg::UpdateFromListBox() {
309         if (editEntity == NULL) {
310                 return;
311         }
312         int c = listKeyVal.GetCount();
313         for (int i = 0 ; i < c; i++) {
314                 CPropertyItem* pItem = (CPropertyItem*)listKeyVal.GetItemDataPtr(i);
315                 if (pItem) {
316                         editEntity->epairs.Set(pItem->m_propName, pItem->m_curValue);
317                 }
318         }
319         SetKeyValPairs();
320 }
321
322 void CEntityDlg::SetKeyValPairs( bool updateAnims ) {
323         if (editEntity) {
324                 listKeyVal.ResetContent();
325                 int c = editEntity->epairs.GetNumKeyVals();
326                 for (int i = 0; i < c; i++) {
327                         const idKeyValue *kv = editEntity->epairs.GetKeyVal(i);
328                         CPropertyItem *pi = new CPropertyItem(kv->GetKey().c_str(), kv->GetValue().c_str(), PIT_EDIT, "");
329                         bool found = false;
330                         int vc = editEntity->eclass->vars.Num();
331                         for (int j = 0; j < vc; j++) {
332                                 if (editEntity->eclass->vars[j].name.Icmp(kv->GetKey()) == 0) {
333                                         switch (editEntity->eclass->vars[j].type) {
334                                                 case EVAR_STRING :
335                                                 case EVAR_INT :
336                                                 case EVAR_FLOAT :
337                                                         pi->m_nItemType = PIT_EDIT;
338                                                         break;
339                                                 case EVAR_BOOL :
340                                                         pi->m_nItemType = PIT_EDIT;
341                                                         //pi->m_cmbItems = "0|1";
342                                                         break;
343                                                 case EVAR_COLOR :
344                                                         pi->m_nItemType = PIT_COLOR;
345                                                         break;
346                                                 case EVAR_MATERIAL :
347                                                         pi->m_nItemType = PIT_MATERIAL;
348                                                         break;
349                                                 case EVAR_MODEL :
350                                                         pi->m_nItemType = PIT_MODEL;
351                                                         break;
352                                                 case EVAR_GUI :
353                                                         pi->m_nItemType = PIT_GUI;
354                                                         break;
355                                                 case EVAR_SOUND :
356                                                         pi->m_nItemType = PIT_SOUND;
357                                                         break;
358                                         }
359                                         found = true;
360                                         break;
361                                 }
362                         }
363                         if (!found) {
364                                 if (kv->GetKey().Icmp("model") == 0) {
365                                         pi->m_nItemType = PIT_MODEL;
366                                 }
367                                 if (kv->GetKey().Icmp("_color") == 0) {
368                                         pi->m_nItemType = PIT_COLOR;
369                                 }
370                                 if (kv->GetKey().Icmp("gui") == 0) {
371                                         pi->m_nItemType = PIT_GUI;
372                                 }
373                                 if (kv->GetKey().Icmp("gui2") == 0) {
374                                         pi->m_nItemType = PIT_GUI;
375                                 }
376                                 if (kv->GetKey().Icmp("gui3") == 0) {
377                                         pi->m_nItemType = PIT_GUI;
378                                 }
379                                 if (kv->GetKey().Icmp("s_shader") == 0) {
380                                         pi->m_nItemType = PIT_SOUND;
381                                 }
382                         }
383                         listKeyVal.AddPropItem(pi);
384                 }
385
386                 if ( updateAnims ) {
387                         int i, num;
388
389                         cbAnimations.ResetContent();
390                         num = gameEdit->ANIM_GetNumAnimsFromEntityDef( &editEntity->eclass->defArgs );
391                         for( i = 0; i < num; i++ ) {
392                                 cbAnimations.AddString( gameEdit->ANIM_GetAnimNameFromEntityDef( &editEntity->eclass->defArgs, i ) );
393                         }
394
395                         const idKeyValue* kv = editEntity->epairs.FindKey ( "anim" );
396                         if ( kv ) {
397                                 int selIndex = cbAnimations.FindStringExact( 0 , kv->GetValue().c_str() );
398                                 if ( selIndex != -1 ) {
399                                         cbAnimations.SetCurSel( selIndex );
400                                         OnCbnAnimationChange ();
401                                 }
402                         }
403                 }
404         }
405 }
406
407 void CEntityDlg::UpdateEntitySel(eclass_t *ent) {
408         assert ( ent );
409         assert ( ent->name );
410         int index = comboClass.FindString(-1, ent->name);
411         if (index != LB_ERR) {
412                 comboClass.SetCurSel(index);
413                 OnCbnSelchangeComboClass();
414         }
415 }
416
417 void CEntityDlg::OnLbnSelchangeListkeyval()
418 {
419         int index = listKeyVal.GetCurSel();
420         if (index != LB_ERR) {
421                 CString str;
422                 listKeyVal.GetText(index, str);
423                 int i;
424                 for (i = 0; str[i] != '\t' && str[i] != '\0'; i++) {
425                 }
426
427                 idStr key = str.Left(i);
428                 while (str[i] == '\t' && str[i] != '\0') {
429                         i++;
430                 }
431
432                 idStr val = str.Right(str.GetLength() - i);
433
434                 editKey.SetWindowText(key);
435                 editVal.SetWindowText(val);
436         }
437 }
438
439 static int TabOrder[] = {
440         IDC_COMBO_CLASS,
441         IDC_BUTTON_CREATE,
442         //IDC_EDIT_INFO,
443         IDC_LIST_KEYVAL,
444         IDC_EDIT_KEY,
445         IDC_EDIT_VAL,
446         IDC_BUTTON_BROWSE,
447         IDC_E_135,
448         IDC_E_90,
449         IDC_E_45,
450         IDC_E_180,
451         IDC_E_0,
452         IDC_E_225,
453         IDC_E_270,
454         IDC_E_315,
455         IDC_E_UP,
456         IDC_E_DOWN,
457         IDC_BUTTON_MODEL,
458         IDC_BUTTON_SOUND,
459         IDC_BUTTON_GUI,
460         IDC_ENTITY_ANIMATIONS
461 };
462
463 int TabCount = sizeof(TabOrder) / sizeof(int);
464
465 void CEntityDlg::DelProp() {
466         CString key;
467
468         if (editEntity == NULL) {
469                 return;
470         }
471
472         editKey.GetWindowText(key);
473         if (multipleEntities) {
474                 for (brush_t *b = selected_brushes.next; b != &selected_brushes; b = b->next) {
475                         DeleteKey(b->owner, key);
476                         Entity_UpdateCurveData( b->owner );
477                 }
478         } else {
479                 DeleteKey(editEntity, key);
480                 Entity_UpdateCurveData( editEntity );
481         }
482
483         // refresh the prop listbox
484         SetKeyValPairs();
485         Sys_UpdateWindows( W_ENTITY | W_XY | W_CAMERA );
486 }
487
488
489 BOOL CEntityDlg::PreTranslateMessage(MSG* pMsg)
490 {
491
492         if (pMsg->hwnd == editVal.GetSafeHwnd()) {
493                 if (pMsg->message == WM_LBUTTONDOWN) {
494                         editVal.SetFocus();
495                         return TRUE;
496                 }
497         }
498
499         if (pMsg->hwnd == editKey.GetSafeHwnd()) {
500                 if (pMsg->message == WM_LBUTTONDOWN) {
501                         editKey.SetFocus();
502                         return TRUE;
503                 }
504         }
505
506         if (GetFocus() == &editVal || GetFocus() == &editKey) {
507                 if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN ) {
508                                 AddProp();
509                                 return TRUE;
510                 }
511
512         }
513
514         if (GetFocus() == listKeyVal.GetEditBox()) {
515                 if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN ) {
516                         listKeyVal.OnChangeEditBox();
517                         listKeyVal.OnSelchange();
518                         listKeyVal.OnKillfocusEditBox();
519                         AddProp();
520                         SetKeyValPairs();
521                         return TRUE;
522                 }
523         }
524
525         if (GetFocus() == &listKeyVal) {
526                 if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_DELETE && editEntity) {
527                         DelProp();
528                         return TRUE;
529                 } 
530         }
531
532         if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_ESCAPE) {
533                 if (pMsg->wParam == VK_ESCAPE) {
534                         g_pParentWnd->GetCamera()->SetFocus();
535                         Select_Deselect();
536                 }
537                 return TRUE;
538         }
539
540         if ( pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN ) {
541                 // keeps ENTER from closing the dialog
542                 return TRUE;
543         }
544
545         if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_TAB) {
546                 if (GetFocus()) {
547                         int id = GetFocus()->GetDlgCtrlID();
548                         for (int i = 0; i < TabCount; i++) {
549                                 if (TabOrder[i] == id) {
550                                         i++;
551                                         if (i >= TabCount) {
552                                                 i = 0;
553                                         }
554                                         CWnd *next = GetDlgItem(TabOrder[i]);
555                                         if (next) {
556                                                 next->SetFocus();
557                                                 if (TabOrder[i] == IDC_EDIT_VAL) {
558                                                         editVal.SetSel(0, -1);
559                                                 }
560                                                 return TRUE;
561                                         }
562                                 }
563                         }
564                 }
565         }
566         
567         if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RIGHT && pMsg->hwnd == slFrameSlider.GetSafeHwnd()) {
568                 int pos = slFrameSlider.GetPos() + 1;
569                 pos = (pos % slFrameSlider.GetRangeMax());
570                 slFrameSlider.SetPos ( pos );
571                 UpdateFromAnimationFrame ();
572                 return TRUE;
573         }
574
575         if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_LEFT && pMsg->hwnd == slFrameSlider.GetSafeHwnd()) {
576                 int pos = slFrameSlider.GetPos() - 1;
577
578                 if ( pos < 1 ) {
579                         pos = slFrameSlider.GetRangeMax();
580                 }
581
582                 slFrameSlider.SetPos ( pos );
583                 UpdateFromAnimationFrame ();
584                 return TRUE;
585         }
586
587         return CDialog::PreTranslateMessage(pMsg);
588 }
589
590
591 /*
592  =======================================================================================================================
593     AddProp
594  =======================================================================================================================
595  */
596 void CEntityDlg::AddProp() {
597
598         if (editEntity == NULL) {
599                 return;
600         }
601
602         CString Key, Value;
603         editKey.GetWindowText(Key);
604         editVal.GetWindowText(Value);
605
606         bool isName = (stricmp(Key, "name") == 0);
607         bool isModel = static_cast<bool>((stricmp(Key, "model") == 0 && Value.GetLength() > 0));
608         bool isOrigin = ( idStr::Icmp( Key, "origin" ) == 0 );
609
610         if (multipleEntities) {
611                 brush_t *b;
612                 for (b = selected_brushes.next; b != &selected_brushes; b = b->next) {
613                         if (isName) {
614                                 Entity_SetName(b->owner, Value);
615                         } else {
616                                 if ( ! ( ( isModel || isOrigin ) && ( b->owner->eclass->nShowFlags & ECLASS_WORLDSPAWN ) ) ) { 
617                                         SetKeyValue(b->owner, Key, Value);
618                                 }
619                         }
620                 }
621         }
622         else {
623                 if (isName) {
624                         Entity_SetName(editEntity, Value);
625                 } else {
626                         if ( ! ( ( isModel || isOrigin ) && ( editEntity->eclass->nShowFlags & ECLASS_WORLDSPAWN ) ) ) { 
627                                 SetKeyValue(editEntity, Key, Value);
628                         }
629                 }
630
631                 if ( isModel && !( editEntity->eclass->nShowFlags & ECLASS_WORLDSPAWN ) ) {
632                         idBounds        bo;
633                         idVec3  mins, maxs;
634
635                         selected_brushes.next->modelHandle = renderModelManager->FindModel( Value );
636                         if ( dynamic_cast<idRenderModelPrt*>( selected_brushes.next->modelHandle ) || dynamic_cast<idRenderModelLiquid*>( selected_brushes.next->modelHandle ) ) {
637                                 bo.Zero();
638                                 bo.ExpandSelf( 12.0f );
639                         } else {
640                                 bo = selected_brushes.next->modelHandle->Bounds( NULL );
641                         }
642
643                         VectorCopy(bo[0], mins);
644                         VectorCopy(bo[1], maxs);
645                         VectorAdd(mins, editEntity->origin, mins);
646                         VectorAdd(maxs, editEntity->origin, maxs);
647                         Brush_RebuildBrush(selected_brushes.next, mins, maxs, false);
648                         Brush_Build ( selected_brushes.next , false, false , false, true );
649                 }
650         }
651
652         // refresh the prop listbox
653         SetKeyValPairs();
654         Sys_UpdateWindows(W_ALL);
655
656 }
657
658 const char *CEntityDlg::AngleKey() {
659         if (editEntity == NULL) {
660                 return "";
661         }
662         
663         if (editEntity->eclass->nShowFlags & ECLASS_MOVER) {
664                 return "movedir";
665         }
666
667         return "angle";
668 }
669
670
671 void CEntityDlg::OnBnClickedE135()
672 {
673         if (editEntity == NULL) {
674                 return;
675         }
676         editKey.SetWindowText(AngleKey());
677         editVal.SetWindowText("135");
678         AddProp();
679 }
680
681 void CEntityDlg::OnBnClickedE90()
682 {
683         if (editEntity == NULL) {
684                 return;
685         }
686         editKey.SetWindowText(AngleKey());
687         editVal.SetWindowText("90");
688         AddProp();
689 }
690
691 void CEntityDlg::OnBnClickedE45()
692 {
693         if (editEntity == NULL) {
694                 return;
695         }
696         editKey.SetWindowText(AngleKey());
697         editVal.SetWindowText("45");
698         AddProp();
699 }
700
701 void CEntityDlg::OnBnClickedE180()
702 {
703         if (editEntity == NULL) {
704                 return;
705         }
706         editKey.SetWindowText(AngleKey());
707         editVal.SetWindowText("180");
708         AddProp();
709 }
710
711 void CEntityDlg::OnBnClickedE0()
712 {
713         if (editEntity == NULL) {
714                 return;
715         }
716         editKey.SetWindowText(AngleKey());
717         editVal.SetWindowText("0");
718         AddProp();
719 }
720
721 void CEntityDlg::OnBnClickedE225()
722 {
723         if (editEntity == NULL) {
724                 return;
725         }
726         editKey.SetWindowText(AngleKey());
727         editVal.SetWindowText("225");
728         AddProp();
729 }
730
731 void CEntityDlg::OnBnClickedE270()
732 {
733         if (editEntity == NULL) {
734                 return;
735         }
736         editKey.SetWindowText(AngleKey());
737         editVal.SetWindowText("270");
738         AddProp();
739 }
740
741 void CEntityDlg::OnBnClickedE315()
742 {
743         if (editEntity == NULL) {
744                 return;
745         }
746         editKey.SetWindowText(AngleKey());
747         editVal.SetWindowText("315");
748         AddProp();
749 }
750
751 void CEntityDlg::OnBnClickedEUp()
752 {
753         if (editEntity == NULL) {
754                 return;
755         }
756         editKey.SetWindowText(AngleKey());
757         editVal.SetWindowText("-1");
758         AddProp();
759 }
760
761 void CEntityDlg::OnBnClickedEDown()
762 {
763         if (editEntity == NULL) {
764                 return;
765         }
766         editKey.SetWindowText(AngleKey());
767         editVal.SetWindowText("-2");
768         AddProp();
769 }
770
771 CPreviewDlg *CEntityDlg::ShowModelChooser() {
772         static CPreviewDlg modelDlg;
773         modelDlg.SetMode(CPreviewDlg::MODELS);
774         modelDlg.SetModal();
775         if (modelDlg.GetSafeHwnd() == NULL) {
776                 modelDlg.Create(MAKEINTRESOURCE(IDD_DIALOG_PREVIEW));
777         }
778         modelDlg.ShowWindow( SW_SHOW );
779         modelDlg.BringWindowToTop();
780         while (modelDlg.Waiting()) {
781         }
782         return &modelDlg;
783 }
784
785 CPreviewDlg *CEntityDlg::ShowParticleChooser() {
786         static CPreviewDlg modelDlg;
787         modelDlg.SetMode(CPreviewDlg::PARTICLES);
788         modelDlg.SetModal();
789         if (modelDlg.GetSafeHwnd() == NULL) {
790                 modelDlg.Create(MAKEINTRESOURCE(IDD_DIALOG_PREVIEW));
791         }
792         modelDlg.ShowWindow(SW_SHOW);
793         modelDlg.BringWindowToTop();
794         while (modelDlg.Waiting()) {
795         }
796         return &modelDlg;
797 }
798
799 CPreviewDlg *CEntityDlg::ShowSkinChooser(entity_t *ent) {
800         static CPreviewDlg modelDlg;
801         modelDlg.SetMode(CPreviewDlg::SKINS);
802         modelDlg.SetModal();
803         if (modelDlg.GetSafeHwnd() == NULL) {
804                 modelDlg.Create(MAKEINTRESOURCE(IDD_DIALOG_PREVIEW));
805         }
806         modelDlg.RebuildTree( ( ent ) ? ent->epairs.GetString( "model" ) : "" );
807         modelDlg.ShowWindow(SW_SHOW);
808         modelDlg.BringWindowToTop();
809         while (modelDlg.Waiting()) {
810         }
811         return &modelDlg;
812 }
813
814 CPreviewDlg *CEntityDlg::ShowGuiChooser() {
815         static CPreviewDlg guiDlg;
816         guiDlg.SetMode(CPreviewDlg::GUIS);
817         guiDlg.SetModal();
818         if (guiDlg.GetSafeHwnd() == NULL) {
819                 guiDlg.Create(MAKEINTRESOURCE(IDD_DIALOG_PREVIEW));
820         }
821         guiDlg.ShowWindow(SW_SHOW);
822         guiDlg.BringWindowToTop();
823         while (guiDlg.Waiting()) {
824         }
825         return &guiDlg;
826 }
827
828 CPreviewDlg *CEntityDlg::ShowSoundChooser() {
829         static CPreviewDlg soundDlg;
830         soundDlg.SetMode(CPreviewDlg::SOUNDS);
831         soundDlg.SetModal();
832         if (soundDlg.GetSafeHwnd() == NULL) {
833                 soundDlg.Create(MAKEINTRESOURCE(IDD_DIALOG_PREVIEW));
834         }
835         soundDlg.ShowWindow(SW_SHOW);
836         while (soundDlg.Waiting()) {
837         }
838         return &soundDlg;
839 }
840
841 CPreviewDlg *CEntityDlg::ShowMaterialChooser() {
842         static CPreviewDlg matDlg;
843         matDlg.SetMode(CPreviewDlg::MATERIALS);
844         matDlg.SetModal();
845         if (matDlg.GetSafeHwnd() == NULL) {
846                 matDlg.Create(MAKEINTRESOURCE(IDD_DIALOG_PREVIEW));
847         }
848         matDlg.ShowWindow(SW_SHOW);
849         matDlg.BringWindowToTop();
850         while (matDlg.Waiting()) {
851         }
852         return &matDlg;
853 }
854
855 void CEntityDlg::AssignModel ()
856 {
857         OnBnClickedButtonModel();
858 }
859 void CEntityDlg::OnBnClickedButtonModel() {
860         CPreviewDlg *dlg = ShowModelChooser();
861         if (dlg->returnCode == IDOK) {
862                 editKey.SetWindowText("model");
863                 editVal.SetWindowText(dlg->mediaName);
864                 AddProp();
865         }
866 }
867
868 void CEntityDlg::OnBnClickedButtonSound() {
869         CPreviewDlg *dlg = ShowSoundChooser();
870         if (dlg->returnCode == IDOK) {
871                 editKey.SetWindowText("s_shader");
872                 editVal.SetWindowText(dlg->mediaName);
873                 AddProp();
874         }
875 }
876
877 void CEntityDlg::OnBnClickedButtonGui() {
878         CPreviewDlg *dlg = ShowGuiChooser();
879         if (dlg->returnCode == IDOK) {
880                 editKey.SetWindowText("gui");
881                 editVal.SetWindowText(dlg->mediaName);
882                 AddProp();
883         }
884 }
885
886 void CEntityDlg::OnBnClickedButtonParticle() {
887         CPreviewDlg *dlg = ShowParticleChooser();
888         if (dlg->returnCode == IDOK) {
889                 editKey.SetWindowText("model");
890                 editVal.SetWindowText(dlg->mediaName);
891                 AddProp();
892         }
893 }
894
895 void CEntityDlg::OnBnClickedButtonSkin() {
896         CPreviewDlg *dlg = ShowSkinChooser( editEntity );
897         if (dlg->returnCode == IDOK) {
898                 editKey.SetWindowText("skin");
899                 editVal.SetWindowText(dlg->mediaName);
900                 AddProp();
901         }
902
903 }
904
905 void CEntityDlg::OnBnClickedButtonCurve() {
906         CCurveDlg dlg;
907         if ( dlg.DoModal() == IDOK ) {
908                 if ( editEntity ) {
909                         idStr str = "curve_" + dlg.strCurveType;
910                         editKey.SetWindowText( str );
911                         idVec3 org = editEntity->origin;
912                         str = "3 ( ";
913                         str += org.ToString();
914                         org.x += 64;
915                         str += " ";
916                         str += org.ToString();
917                         org.y += 64;
918                         str += " ";
919                         str += org.ToString();
920                         str += " )";
921                         editVal.SetWindowText( str );
922                         AddProp();
923                         Entity_SetCurveData( editEntity );
924                 }
925         }
926 }
927
928 void CEntityDlg::OnBnClickedButtonBrowse() {
929         DelProp();
930 }
931
932 void CEntityDlg::OnCbnDblclkComboClass()
933 {
934         // TODO: Add your control notification handler code here
935 }
936
937 //
938 // =======================================================================================================================
939 //    CreateEntity Creates a new entity based on the currently selected brush and entity type.
940 // =======================================================================================================================
941 //
942 void CEntityDlg::CreateEntity() {
943         entity_t        *petNew;
944         bool            forceFixed = false;
945
946         // check to make sure we have a brush
947         CXYWnd  *pWnd = g_pParentWnd->ActiveXY();
948         if (pWnd) {
949                 CRect   rctZ;
950                 pWnd->GetClientRect(rctZ);
951
952                 brush_t *pBrush;
953                 if (selected_brushes.next == &selected_brushes) {
954                         pBrush = CreateEntityBrush(g_nSmartX, rctZ.Height() - 1 - g_nSmartY, pWnd);
955                         forceFixed = true;
956                 }
957         }
958         else {
959                 if (selected_brushes.next == &selected_brushes) {
960                         MessageBox("You must have a selected brush to create an entity", "info", 0);
961                         return;
962                 }
963         }
964
965         int index = comboClass.GetCurSel();
966         if (index == LB_ERR) {
967                 MessageBox("You must have a selected class to create an entity", "info", 0);
968                 return;
969         }
970         
971         CString str;
972         comboClass.GetLBText(index, str);
973
974         if (!stricmp(str, "worldspawn")) {
975                 MessageBox("Can't create an entity with worldspawn.", "info", 0);
976                 return;
977         }
978
979         eclass_t *pecNew = Eclass_ForName (str, false);
980
981         // create it
982         if ((GetAsyncKeyState(VK_CONTROL) & 0x8000)) {
983                 // MAJOR hack for xian
984 extern void Brush_CopyList(brush_t *pFrom, brush_t *pTo);
985                 brush_t temp_brushes;
986                 temp_brushes.next = &temp_brushes;
987                 Brush_CopyList(&selected_brushes, &temp_brushes);
988                 Select_Deselect();
989                 brush_t *pBrush = temp_brushes.next;
990                 while (pBrush != NULL && pBrush != &temp_brushes) {
991                         brush_t *pNext = pBrush->next;
992                         Brush_RemoveFromList(pBrush);
993                         Brush_AddToList(pBrush, &selected_brushes);
994                         pBrush = pNext;
995                         petNew = Entity_Create(pecNew, forceFixed);
996                         Select_Deselect();
997                 }
998         } else if ((GetAsyncKeyState(VK_SHIFT) & 0x8000)) {
999                 Select_Ungroup();
1000                 petNew = Entity_Create(pecNew, forceFixed);
1001         } else {
1002                 petNew = Entity_Create(pecNew, forceFixed);
1003         }
1004
1005         if (petNew == NULL) {
1006                 MessageBox("Failed to create entity.", "info", 0);
1007                 return;
1008         }
1009
1010         if (selected_brushes.next == &selected_brushes) {
1011                 editEntity = world_entity;
1012         }
1013         else {
1014                 editEntity = selected_brushes.next->owner;
1015         }
1016
1017         SetKeyValPairs();
1018         Select_Deselect();
1019         Select_Brush(editEntity->brushes.onext);
1020         Sys_UpdateWindows(W_ALL);
1021 }
1022
1023 void CEntityDlg::OnBnClickedButtonCreate()
1024 {
1025         CreateEntity();
1026 }
1027
1028 void CEntityDlg::OnLbnDblclkListkeyval()
1029 {
1030         CString Key, Value;
1031         idStr work;
1032         editKey.GetWindowText( Key );
1033         editVal.GetWindowText( Value );
1034         if ( stricmp( Key, "script" ) == 0 ) {
1035                 Key = Value;
1036                 Value = "script/" + Key;
1037                 if ( fileSystem->ReadFile( Value, NULL, NULL ) == -1) {
1038                         sprintf( work, "// Script for %s\n// \n\nvoid main() {\n\n}\n\n", currentmap );
1039                         fileSystem->WriteFile( Value, work.c_str(), work.Length(), "fs_devpath" );
1040                 }
1041                 work = fileSystem->RelativePathToOSPath( Value );
1042                 WinExec( va( "notepad.exe %s", work.c_str() ), SW_SHOW );
1043         }
1044 }
1045
1046 void CEntityDlg::OnLbnSelchangeListVars() {
1047
1048 }
1049
1050 void CEntityDlg::OnLbnDblclkListVars() {
1051         if (editEntity == NULL) {
1052                 return;
1053         }
1054         int sel = listVars.GetCurSel();
1055         CPropertyItem *pi = (CPropertyItem*)listVars.GetItemDataPtr(sel);
1056         if (pi) {
1057                 if (editEntity->epairs.FindKey(pi->m_propName) == NULL) {
1058                         editKey.SetWindowText(pi->m_propName);
1059                         editVal.SetWindowText("");
1060                         editVal.SetFocus();
1061                 }
1062         }
1063 }
1064
1065
1066 void CEntityDlg::UpdateKeyVal(const char *key, const char *val) {
1067         if (editEntity) {
1068                 editEntity->epairs.Set(key, val);
1069                 SetKeyValPairs();
1070                 g_pParentWnd->GetCamera()->BuildEntityRenderState(editEntity, true);
1071                 Entity_UpdateSoundEmitter(editEntity);
1072         }
1073 }
1074
1075
1076 void CEntityDlg::OnNMReleasedcaptureSlider1(NMHDR *pNMHDR, LRESULT *pResult)
1077 {
1078         if ( !editEntity )
1079         {
1080                 return;
1081         }
1082         
1083         UpdateFromAnimationFrame ();
1084
1085         *pResult = 0;
1086 }
1087
1088 void CEntityDlg::UpdateFromAnimationFrame ( bool updateKeyValueDisplay )
1089 {
1090         int frame = slFrameSlider.GetPos ();
1091         editEntity->epairs.SetInt( "frame" , frame );
1092         SetDlgItemText ( IDC_ENTITY_CURRENT_ANIM , va ( "%i" , frame));
1093         if ( updateKeyValueDisplay ) {
1094                 SetKeyValPairs();
1095         }
1096
1097         g_pParentWnd->GetCamera ()->BuildEntityRenderState (editEntity , true );
1098         Sys_UpdateWindows ( W_ALL );
1099
1100 }
1101
1102 void CEntityDlg::OnCbnAnimationChange ()
1103 {
1104         if ( !editEntity )
1105         {
1106                 return;
1107         }
1108
1109         int sel = cbAnimations.GetCurSel();
1110         CString animName;
1111         currentAnimation = NULL;
1112         int currFrame = 0;
1113
1114         if ( sel != -1 ) {
1115                 cbAnimations.GetLBText( sel , animName );
1116                 if ( animName.GetLength() > 0 ) {
1117                         //preserve the existing frame number
1118                         currFrame = editEntity->epairs.GetInt ( "frame" , "1" );
1119
1120                         editEntity->epairs.Set("anim" , animName.GetBuffer(0));
1121                         SetKeyValPairs(false/*don't update anims combo box :)*/ );
1122                         
1123                         //update the slider
1124                         currentAnimation = gameEdit->ANIM_GetAnimFromEntityDef(editEntity->eclass->name , animName.GetBuffer(0));
1125                         currentAnimationFrame = 0;
1126
1127                         if ( currentAnimation ) {
1128                                 slFrameSlider.SetRange( 1 , gameEdit->ANIM_GetNumFrames( currentAnimation ), TRUE );
1129                                 slFrameSlider.SetPos( currFrame );
1130                                 currentAnimationFrame = currFrame;
1131                         }
1132
1133                         Sys_UpdateWindows(W_ALL);
1134                 }
1135         }
1136 }
1137
1138 void CEntityDlg::OnBnClickedStartAnimation()
1139 {       
1140         if (!editEntity) {
1141                 return;
1142         }
1143         SetTimer ( 0 , 1000/24 , NULL );
1144 }
1145
1146 void CEntityDlg::OnBnClickedStopAnimation()
1147 {
1148         KillTimer ( 0 );
1149 }
1150
1151 void CEntityDlg::OnTimer(UINT nIDEvent)
1152 {
1153         if ( !editEntity ) {
1154                 OnBnClickedStopAnimation ();
1155                 return;
1156         }
1157         
1158         if ( currentAnimation ) {
1159                 currentAnimationFrame = ( (currentAnimationFrame++) % gameEdit->ANIM_GetNumFrames( currentAnimation ) );
1160                 editEntity->epairs.SetInt ( "frame" , currentAnimationFrame );
1161                 slFrameSlider.SetPos ( currentAnimationFrame );
1162                 UpdateFromAnimationFrame (false/*don't update key/value display*/);             
1163
1164                 Sys_UpdateWindows ( W_CAMERA | W_XY );
1165         }
1166 }
1167
1168 void CEntityDlg::AddCurvePoints() {
1169         if ( editEntity == NULL || editEntity->curve == NULL ) {
1170                 return;
1171         }
1172
1173         // add one point 64 units from the direction of the two points int he curve
1174         int c = editEntity->curve->GetNumValues();
1175         idVec3 start;
1176         idVec3 end;
1177         if ( c > 1 ) {
1178                 start = editEntity->curve->GetValue( c - 2 );
1179                 end = editEntity->curve->GetValue( c - 1 );
1180                 idVec3 dir = end - start;
1181                 dir.Normalize();
1182                 start = end + 64 * dir;
1183         } else  if ( c > 0 ) {
1184                 start = editEntity->curve->GetValue( 0 );
1185                 start.x += 64;
1186                 start.y += 64; 
1187         } else {
1188                 start = editEntity->origin;
1189         }
1190         
1191         editEntity->curve->AddValue( editEntity->curve->GetNumValues() * 100, start );
1192
1193         if ( g_qeglobals.d_select_mode == sel_editpoint ) {
1194                 g_qeglobals.d_select_mode = sel_brush;
1195                 EditCurvePoints();
1196         }
1197
1198         Sys_UpdateWindows( W_CAMERA | W_XY );
1199
1200 }
1201
1202 void CEntityDlg::EditCurvePoints() {
1203
1204         if ( editEntity == NULL || editEntity->curve == NULL ) {
1205                 return;
1206         }
1207
1208         if ( g_qeglobals.d_select_mode == sel_editpoint ) {
1209                 g_qeglobals.d_select_mode = sel_brush;
1210                 return;
1211         }
1212
1213         g_qeglobals.d_select_mode = sel_editpoint;
1214
1215         g_qeglobals.d_numpoints = 0;
1216         g_qeglobals.d_num_move_points = 0;
1217         int c = editEntity->curve->GetNumValues();
1218         for ( int i = 0; i < c; i++ ) {
1219                 if ( g_qeglobals.d_numpoints < MAX_POINTS - 1 ) {
1220                         g_qeglobals.d_points[g_qeglobals.d_numpoints++] = editEntity->curve->GetValue( i );
1221                 }
1222         }
1223         Sys_UpdateWindows( W_XY | W_CAMERA );
1224
1225 }
1226
1227 void CEntityDlg::InsertCurvePoint() {
1228         if ( editEntity == NULL || editEntity->curve == NULL ) {
1229                 return;
1230         }
1231
1232         if ( g_qeglobals.d_select_mode != sel_editpoint ) {
1233                 return;
1234         }
1235
1236         if ( g_qeglobals.d_num_move_points == 0 ) {
1237                 return;
1238         }
1239
1240         for ( int i = 0; i < editEntity->curve->GetNumValues(); i++ ) {
1241                 if ( PointInMoveList( editEntity->curve->GetValueAddress( i ) ) >= 0 ) {
1242                         if ( i == editEntity->curve->GetNumValues() - 1 ) {
1243                                 // just do an add
1244                                 AddCurvePoints();
1245                         } else {
1246                                 idCurve<idVec3> *newCurve = Entity_MakeCurve( editEntity );
1247
1248                                 if ( newCurve == NULL ) {
1249                                         return;
1250                                 }
1251
1252                                 for ( int j = 0; j < editEntity->curve->GetNumValues(); j++ ) {
1253                                         if ( j == i ) {
1254                                                 idVec3 start;
1255                                                 idVec3 end;
1256                                                 if ( i > 0 ) {
1257                                                         start = editEntity->curve->GetValue( i - 1 );
1258                                                         end = editEntity->curve->GetValue( i );
1259                                                         start += end;
1260                                                         start *= 0.5f;
1261                                                 } else {
1262                                                         start = editEntity->curve->GetValue( 0 );
1263                                                         if ( editEntity->curve->GetNumValues() > 1 ) {
1264                                                                 end = start;
1265                                                                 start = editEntity->curve->GetValue ( 1 );
1266                                                                 idVec3 dir = end - start;
1267                                                                 dir.Normalize();
1268                                                                 start = end + 64 * dir;
1269                                                         } else {
1270                                                                 end = start;
1271                                                                 end.x += 64;
1272                                                                 end.y += 64;
1273                                                         }
1274                                                 }
1275                                                 newCurve->AddValue( newCurve->GetNumValues() * 100, start );
1276                                         } 
1277                                         newCurve->AddValue( newCurve->GetNumValues() * 100, editEntity->curve->GetValue( j ) );
1278                                 }
1279                                 delete editEntity->curve;
1280                                 editEntity->curve = newCurve;
1281                         }
1282                         g_qeglobals.d_num_move_points = 0;
1283                         break;
1284                 }
1285         }
1286         UpdateEntityCurve();
1287
1288         Sys_UpdateWindows( W_XY | W_CAMERA );
1289
1290 }
1291
1292 void CEntityDlg::DeleteCurvePoint() {
1293
1294         if ( editEntity == NULL || editEntity->curve == NULL ) {
1295                 return;
1296         }
1297
1298         if ( g_qeglobals.d_select_mode != sel_editpoint ) {
1299                 return;
1300         }
1301
1302
1303         if ( g_qeglobals.d_num_move_points == 0 ) {
1304                 return;
1305         }
1306
1307         for ( int i = 0; i < editEntity->curve->GetNumValues(); i++ ) {
1308                 if ( PointInMoveList( editEntity->curve->GetValueAddress( i ) ) >= 0 ) {
1309                         editEntity->curve->RemoveIndex( i );
1310                         g_qeglobals.d_num_move_points = 0;
1311                         break;
1312                 }
1313         }
1314         UpdateEntityCurve();
1315
1316         Sys_UpdateWindows( W_XY | W_CAMERA );
1317
1318 }
1319
1320
1321 void CEntityDlg::UpdateEntityCurve() {
1322         
1323         if ( editEntity == NULL ) {
1324                 return;
1325         }
1326
1327         Entity_UpdateCurveData( editEntity );
1328
1329         if ( g_qeglobals.d_select_mode == sel_editpoint ) {
1330                 g_qeglobals.d_numpoints = 0;
1331                 int c = editEntity->curve->GetNumValues();
1332                 for ( int i = 0; i < c; i++ ) {
1333                         if ( g_qeglobals.d_numpoints < MAX_POINTS - 1 ) {
1334                                 g_qeglobals.d_points[g_qeglobals.d_numpoints++] = editEntity->curve->GetValue( i );
1335                         }
1336                 }
1337         }
1338
1339         Sys_UpdateWindows( W_ENTITY );
1340 }
1341
1342
1343 void CEntityDlg::SelectCurvePointByRay(const idVec3 &org, const idVec3 &dir, int buttons) {
1344         int             i, besti;
1345         float   d, bestd;
1346         idVec3  temp;
1347
1348         if ( editEntity == NULL ) {
1349                 return;
1350         }
1351         // find the point closest to the ray
1352         float scale = g_pParentWnd->ActiveXY()->Scale();
1353         besti = -1;
1354         bestd = 8 / scale / 2;
1355         //bestd = 8;
1356
1357         for (i = 0; i < g_qeglobals.d_numpoints; i++) {
1358                 temp = g_qeglobals.d_points[i] - org;
1359                 d = temp * dir;
1360                 temp = org + d * dir;
1361                 temp = g_qeglobals.d_points[i] - temp;
1362                 d = temp.Length();
1363                 if ( d <= bestd ) {
1364                         bestd = d;
1365                         besti = i;
1366                 }
1367         }
1368
1369         if (besti == -1) {
1370                 return;
1371         }
1372
1373         g_qeglobals.d_num_move_points = 0;
1374         assert ( besti < editEntity->curve->GetNumValues() );
1375         g_qeglobals.d_move_points[ g_qeglobals.d_num_move_points++ ] = editEntity->curve->GetValueAddress( besti );
1376 }
1377