/********************************************************************** *< FILE: indepos.cpp DESCRIPTION: An independent X, Y, Z position controller CREATED BY: Rolf Berteig HISTORY: created 13 June 1995 *> Copyright (c) 1994, All Rights Reserved. **********************************************************************/ #include "ctrl.h" #define IPOS_CONTROL_CLASS_ID Class_ID(0x118f7e02,0xffee238a) #define IPOS_CONTROL_CNAME GetString(IDS_RB_IPOS) #define IPOINT3_CONTROL_CLASS_ID Class_ID(0x118f7e02,0xfeee238b) #define IPOINT3_CONTROL_CNAME GetString(IDS_RB_IPOINT3) #define ICOLOR_CONTROL_CLASS_ID Class_ID(0x118f7c01,0xfeee238a) #define ICOLOR_CONTROL_CNAME GetString(IDS_RB_ICOLOR) #define IPOS_X_REF 0 #define IPOS_Y_REF 1 #define IPOS_Z_REF 2 class IPosDlg; static DWORD subColor[] = {PAINTCURVE_XCOLOR, PAINTCURVE_YCOLOR, PAINTCURVE_ZCOLOR}; class IndePosition : public Control { public: Control *posX; Control *posY; Control *posZ; Point3 curval; Interval ivalid; static IPosDlg *dlg; static IObjParam *ip; static ULONG beginFlags; static IndePosition *editControl; // The one being edited. IndePosition(BOOL loading=FALSE); IndePosition(const IndePosition &ctrl); ~IndePosition(); void Update(TimeValue t); // Animatable methods Class_ID ClassID() { return IPOS_CONTROL_CLASS_ID;} SClass_ID SuperClassID() {return CTRL_POSITION_CLASS_ID;} void GetClassName(TSTR& s) {s = IPOS_CONTROL_CNAME;} void DeleteThis() {delete this;} int IsKeyable() {return 1;} int NumSubs() {return 3;} Animatable* SubAnim(int i); TSTR SubAnimName(int i); int SubNumToRefNum(int subNum) {return subNum;} DWORD GetSubAnimCurveColor(int subNum) {return subColor[subNum];} ParamDimension* GetParamDimension(int i) {return stdWorldDim;} BOOL AssignController(Animatable *control,int subAnim); void AddNewKey(TimeValue t,DWORD flags); int NumKeys(); TimeValue GetKeyTime(int index); void CopyKeysFromTime(TimeValue src,TimeValue dst,DWORD flags); BOOL IsKeyAtTime(TimeValue t,DWORD flags); BOOL GetNextKeyTime(TimeValue t,DWORD flags,TimeValue &nt); void DeleteKeyAtTime(TimeValue t); void BeginEditParams( IObjParam *ip, ULONG flags,Animatable *prev ); void EndEditParams( IObjParam *ip, ULONG flags,Animatable *next ); // Reference methods int NumRefs() { return 3; }; RefTargetHandle GetReference(int i); void SetReference(int i, RefTargetHandle rtarg); RefResult NotifyRefChanged(Interval, RefTargetHandle, PartID&, RefMessage); // Control methods Control *GetXController() {return posX;} Control *GetYController() {return posY;} Control *GetZController() {return posZ;} void Copy(Control *from); RefTargetHandle Clone(RemapDir& remap); BOOL IsLeaf() {return FALSE;} void GetValue(TimeValue t, void *val, Interval &valid, GetSetMethod method); void SetValue(TimeValue t, void *val, int commit, GetSetMethod method); void CommitValue(TimeValue t); void RestoreValue(TimeValue t); }; IPosDlg *IndePosition::dlg = NULL; IObjParam *IndePosition::ip = NULL; ULONG IndePosition::beginFlags = 0; IndePosition *IndePosition::editControl = NULL; class IndePoint3 : public IndePosition { public: IndePoint3(BOOL loading=FALSE) : IndePosition(loading) {} SClass_ID SuperClassID() {return CTRL_POINT3_CLASS_ID;} Class_ID ClassID() { return IPOINT3_CONTROL_CLASS_ID;} void GetClassName(TSTR& s) {s = IPOINT3_CONTROL_CNAME;} void GetValue(TimeValue t, void *val, Interval &valid, GetSetMethod method); RefTargetHandle Clone(RemapDir& remap); }; class IndeColor : public IndePoint3 { public: IndeColor(BOOL loading=FALSE) : IndePoint3(loading) {} SClass_ID SuperClassID() {return CTRL_POINT3_CLASS_ID;} Class_ID ClassID() { return ICOLOR_CONTROL_CLASS_ID;} void GetClassName(TSTR& s) {s = ICOLOR_CONTROL_CNAME;} ParamDimension* GetParamDimension(int i) {return stdColor255Dim;} RefTargetHandle Clone(RemapDir& remap); }; class IPosClassDesc:public ClassDesc { public: int IsPublic() {return 1;} void * Create(BOOL loading) {return new IndePosition(loading);} const TCHAR * ClassName() {return IPOS_CONTROL_CNAME;} SClass_ID SuperClassID() {return CTRL_POSITION_CLASS_ID;} Class_ID ClassID() {return IPOS_CONTROL_CLASS_ID;} const TCHAR* Category() {return _T("");} }; static IPosClassDesc iposCD; ClassDesc* GetIPosCtrlDesc() {return &iposCD;} class IPoint3ClassDesc:public ClassDesc { public: int IsPublic() {return 1;} void * Create(BOOL loading) {return new IndePoint3(loading);} const TCHAR * ClassName() {return IPOINT3_CONTROL_CNAME;} SClass_ID SuperClassID() {return CTRL_POINT3_CLASS_ID;} Class_ID ClassID() {return IPOINT3_CONTROL_CLASS_ID;} const TCHAR* Category() {return _T("");} }; static IPoint3ClassDesc ipoint3CD; ClassDesc* GetIPoint3CtrlDesc() {return &ipoint3CD;} class IColorClassDesc:public ClassDesc { public: int IsPublic() {return 1;} void * Create(BOOL loading) {return new IndeColor(loading);} const TCHAR * ClassName() {return ICOLOR_CONTROL_CNAME;} SClass_ID SuperClassID() {return CTRL_POINT3_CLASS_ID;} Class_ID ClassID() {return ICOLOR_CONTROL_CLASS_ID;} const TCHAR* Category() {return _T("");} }; static IColorClassDesc icolorCD; ClassDesc* GetIColorCtrlDesc() {return &icolorCD;} static BOOL CALLBACK IPosParamDialogProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam); static const int editButs[] = {IDC_IPOS_X,IDC_IPOS_Y,IDC_IPOS_Z}; #define EDIT_X 0 #define EDIT_Y 1 #define EDIT_Z 2 #define IPOS_BEGIN 1 #define IPOS_MIDDLE 2 #define IPOS_END 3 class IPosDlg { public: IndePosition *cont; HWND hWnd; IObjParam *ip; ICustButton *iEdit[3]; static int cur; IPosDlg(IndePosition *cont,IObjParam *ip); ~IPosDlg(); void Init(); void EndingEdit(IndePosition *next); void BeginingEdit(IndePosition *cont,IObjParam *ip,IndePosition *prev); void SetCur(int c,int code=IPOS_MIDDLE); void WMCommand(int id, int notify, HWND hCtrl); }; int IPosDlg::cur = EDIT_X; IPosDlg::IPosDlg(IndePosition *cont,IObjParam *ip) { this->ip = ip; this->cont = cont; for (int i=0; i<3; i++) { iEdit[i] = NULL; } TCHAR *name; if (cont->ClassID()==IPOS_CONTROL_CLASS_ID) name = GetString(IDS_RB_IPOSPARAMS); else if (cont->ClassID()==IPOINT3_CONTROL_CLASS_ID) name = GetString(IDS_RB_IPOINT3PARAMS); else name = GetString(IDS_RB_ICOLORPARAMS); hWnd = ip->AddRollupPage( hInstance, MAKEINTRESOURCE(IDD_IPOS_PARAMS), IPosParamDialogProc, name, (LPARAM)this); ip->RegisterDlgWnd(hWnd); SetCur(cur,IPOS_BEGIN); UpdateWindow(hWnd); } IPosDlg::~IPosDlg() { SetCur(cur,IPOS_END); for (int i=0; i<3; i++) { ReleaseICustButton(iEdit[i]); } ip->UnRegisterDlgWnd(hWnd); ip->DeleteRollupPage(hWnd); hWnd = NULL; } void IPosDlg::EndingEdit(IndePosition *next) { switch (cur) { case EDIT_X: cont->posX->EndEditParams(ip,0,next->posX); break; case EDIT_Y: cont->posY->EndEditParams(ip,0,next->posY); break; case EDIT_Z: cont->posZ->EndEditParams(ip,0,next->posZ); break; } cont = NULL; ip = NULL; } void IPosDlg::BeginingEdit(IndePosition *cont,IObjParam *ip,IndePosition *prev) { this->ip = ip; this->cont = cont; switch (cur) { case EDIT_X: cont->posX->BeginEditParams(ip,BEGIN_EDIT_MOTION,prev->posX); break; case EDIT_Y: cont->posY->BeginEditParams(ip,BEGIN_EDIT_MOTION,prev->posY); break; case EDIT_Z: cont->posZ->BeginEditParams(ip,BEGIN_EDIT_MOTION,prev->posZ); break; } UpdateWindow(hWnd); } void IPosDlg::Init() { for (int i=0; i<3; i++) { iEdit[i] = GetICustButton(GetDlgItem(hWnd,editButs[i])); iEdit[i]->SetType(CBT_CHECK); } iEdit[cur]->SetCheck(TRUE); } void IPosDlg::SetCur(int c,int code) { if (c==cur && code==IPOS_MIDDLE) return; Control *prev = NULL, *next = NULL; if (code!=IPOS_END) { switch (c) { case EDIT_X: next = cont->posX; break; case EDIT_Y: next = cont->posY; break; case EDIT_Z: next = cont->posZ; break; } } if (code!=IPOS_BEGIN) { switch (cur) { case EDIT_X: cont->posX->EndEditParams(ip,END_EDIT_REMOVEUI,next); prev = cont->posX; break; case EDIT_Y: cont->posY->EndEditParams(ip,END_EDIT_REMOVEUI,next); prev = cont->posY; break; case EDIT_Z: cont->posZ->EndEditParams(ip,END_EDIT_REMOVEUI,next); prev = cont->posZ; break; } } cur = c; if (code!=IPOS_END) { switch (cur) { case EDIT_X: cont->posX->BeginEditParams(ip,BEGIN_EDIT_MOTION,prev); break; case EDIT_Y: cont->posY->BeginEditParams(ip,BEGIN_EDIT_MOTION,prev); break; case EDIT_Z: cont->posZ->BeginEditParams(ip,BEGIN_EDIT_MOTION,prev); break; } } } void IPosDlg::WMCommand(int id, int notify, HWND hCtrl) { switch (id) { case IDC_IPOS_X: SetCur(0); iEdit[0]->SetCheck(TRUE); iEdit[1]->SetCheck(FALSE); iEdit[2]->SetCheck(FALSE); break; case IDC_IPOS_Y: SetCur(1); iEdit[0]->SetCheck(FALSE); iEdit[1]->SetCheck(TRUE); iEdit[2]->SetCheck(FALSE); break; case IDC_IPOS_Z: SetCur(2); iEdit[0]->SetCheck(FALSE); iEdit[1]->SetCheck(FALSE); iEdit[2]->SetCheck(TRUE); break; } } static BOOL CALLBACK IPosParamDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam ) { IPosDlg *dlg = (IPosDlg*)GetWindowLong(hDlg,GWL_USERDATA); switch (message) { case WM_INITDIALOG: dlg = (IPosDlg*)lParam; SetWindowLong(hDlg,GWL_USERDATA,lParam); dlg->hWnd = hDlg; dlg->Init(); break; case WM_COMMAND: dlg->WMCommand(LOWORD(wParam),HIWORD(wParam),(HWND)lParam); break; case WM_LBUTTONDOWN:case WM_LBUTTONUP: case WM_MOUSEMOVE: dlg->ip->RollupMouseMessage(hDlg,message,wParam,lParam); break; default: return FALSE; } return TRUE; } IndePosition::IndePosition(const IndePosition &ctrl) { posX = NULL; posY = NULL; posZ = NULL; if (ctrl.posX) { ReplaceReference(IPOS_X_REF,ctrl.posX); } else { ReplaceReference(IPOS_X_REF,NewDefaultFloatController()); } if (ctrl.posY) { ReplaceReference(IPOS_Y_REF,ctrl.posY); } else { ReplaceReference(IPOS_Y_REF,NewDefaultFloatController()); } if (ctrl.posZ) { ReplaceReference(IPOS_Z_REF,ctrl.posZ); } else { ReplaceReference(IPOS_Z_REF,NewDefaultFloatController()); } curval = ctrl.curval; ivalid = ctrl.ivalid; } IndePosition::IndePosition(BOOL loading) { posX = NULL; posY = NULL; posZ = NULL; if (!loading) { ReplaceReference(IPOS_X_REF,NewDefaultFloatController()); ReplaceReference(IPOS_Y_REF,NewDefaultFloatController()); ReplaceReference(IPOS_Z_REF,NewDefaultFloatController()); ivalid = FOREVER; curval = Point3(0,0,0); } else { ivalid.SetEmpty(); } } RefTargetHandle IndePoint3::Clone(RemapDir& remap) { IndePoint3 *pos = new IndePoint3(TRUE); pos->ReplaceReference(IPOS_X_REF, remap.CloneRef(posX)); pos->ReplaceReference(IPOS_Y_REF, remap.CloneRef(posY)); pos->ReplaceReference(IPOS_Z_REF, remap.CloneRef(posZ)); return pos; } RefTargetHandle IndeColor::Clone(RemapDir& remap) { IndeColor *pos = new IndeColor(TRUE); pos->ReplaceReference(IPOS_X_REF, remap.CloneRef(posX)); pos->ReplaceReference(IPOS_Y_REF, remap.CloneRef(posY)); pos->ReplaceReference(IPOS_Z_REF, remap.CloneRef(posZ)); return pos; } RefTargetHandle IndePosition::Clone(RemapDir& remap) { IndePosition *pos = new IndePosition(TRUE); pos->ReplaceReference(IPOS_X_REF, remap.CloneRef(posX)); pos->ReplaceReference(IPOS_Y_REF, remap.CloneRef(posY)); pos->ReplaceReference(IPOS_Z_REF, remap.CloneRef(posZ)); return pos; } IndePosition::~IndePosition() { DeleteAllRefsFromMe(); } void IndePosition::Copy(Control *from) { if (from->ClassID()==ClassID()) { IndePosition *ctrl = (IndePosition*)from; ReplaceReference(IPOS_X_REF,ctrl->posX); ReplaceReference(IPOS_Y_REF,ctrl->posY); ReplaceReference(IPOS_Z_REF,ctrl->posZ); curval = ctrl->curval; ivalid = ctrl->ivalid; } else { Point3 v; Interval iv; int num; if (num=from->NumKeys()) { SuspendAnimate(); AnimateOn(); for (int i=0; iGetKeyTime(i); from->GetValue(t,&v,iv); SetValue(t,&v,TRUE,CTRL_ABSOLUTE); } ResumeAnimate(); } else { from->GetValue(0,&v,ivalid); SetValue(0,&v,TRUE,CTRL_ABSOLUTE); } } NotifyDependents(FOREVER,PART_ALL,REFMSG_CHANGE); } void IndePosition::Update(TimeValue t) { if (!ivalid.InInterval(t)) { ivalid = FOREVER; if (posX) posX->GetValue(t,&curval.x,ivalid); if (posY) posY->GetValue(t,&curval.y,ivalid); if (posZ) posZ->GetValue(t,&curval.z,ivalid); } } void IndePosition::SetValue(TimeValue t, void *val, int commit, GetSetMethod method) { Point3 *v = (Point3*)val; if (posX) posX->SetValue(t,&v->x,commit,method); if (posY) posY->SetValue(t,&v->y,commit,method); if (posZ) posZ->SetValue(t,&v->z,commit,method); ivalid.SetEmpty(); NotifyDependents(FOREVER,PART_ALL,REFMSG_CHANGE); } void IndePosition::GetValue(TimeValue t, void *val, Interval &valid, GetSetMethod method) { Update(t); valid &= ivalid; if (method==CTRL_RELATIVE) { Matrix3 *mat = (Matrix3*)val; mat->PreTranslate(curval); } else { *((Point3*)val) = curval; } } void IndePoint3::GetValue(TimeValue t, void *val, Interval &valid, GetSetMethod method) { Update(t); valid &= ivalid; if (method==CTRL_RELATIVE) { *((Point3*)val) += curval; } else { *((Point3*)val) = curval; } } void IndePosition::CommitValue(TimeValue t) { if (posX) posX->CommitValue(t); if (posY) posY->CommitValue(t); if (posZ) posZ->CommitValue(t); } void IndePosition::RestoreValue(TimeValue t) { if (posX) posX->RestoreValue(t); if (posY) posY->RestoreValue(t); if (posZ) posZ->RestoreValue(t); } RefTargetHandle IndePosition::GetReference(int i) { switch (i) { case IPOS_X_REF: return posX; case IPOS_Y_REF: return posY; case IPOS_Z_REF: return posZ; default: return NULL; } } void IndePosition::SetReference(int i, RefTargetHandle rtarg) { switch (i) { case IPOS_X_REF: posX = (Control*)rtarg; break; case IPOS_Y_REF: posY = (Control*)rtarg; break; case IPOS_Z_REF: posZ = (Control*)rtarg; break; } } Animatable* IndePosition::SubAnim(int i) { return GetReference(i); } TSTR IndePosition::SubAnimName(int i) { if (ClassID()==IPOS_CONTROL_CLASS_ID) { switch (i) { case IPOS_X_REF: return GetString(IDS_RB_XPOSITION); case IPOS_Y_REF: return GetString(IDS_RB_YPOSITION); case IPOS_Z_REF: return GetString(IDS_RB_ZPOSITION); default: return _T(""); } } else if (ClassID()==IPOINT3_CONTROL_CLASS_ID) { switch (i) { case IPOS_X_REF: return _T("X"); case IPOS_Y_REF: return _T("Y"); case IPOS_Z_REF: return _T("Z"); default: return _T(""); } } else { switch (i) { case IPOS_X_REF: return _T("R"); case IPOS_Y_REF: return _T("G"); case IPOS_Z_REF: return _T("B"); default: return _T(""); } } } RefResult IndePosition::NotifyRefChanged( Interval iv, RefTargetHandle hTarg, PartID& partID, RefMessage msg) { switch (msg) { case REFMSG_CHANGE: ivalid.SetEmpty(); break; case REFMSG_TARGET_DELETED: if (posX == hTarg) posX = NULL; if (posY == hTarg) posY = NULL; if (posZ == hTarg) posZ = NULL; break; case REFMSG_GET_CONTROL_DIM: { ParamDimension **dim = (ParamDimension **)partID; assert(dim); *dim = stdWorldDim; } } return REF_SUCCEED; } BOOL IndePosition::AssignController(Animatable *control,int subAnim) { switch (subAnim) { case IPOS_X_REF: ReplaceReference(IPOS_X_REF,(RefTargetHandle)control); break; case IPOS_Y_REF: ReplaceReference(IPOS_Y_REF,(RefTargetHandle)control); break; case IPOS_Z_REF: ReplaceReference(IPOS_Z_REF,(RefTargetHandle)control); break; } NotifyDependents(FOREVER,0,REFMSG_CONTROLREF_CHANGE,TREE_VIEW_CLASS_ID,FALSE); NotifyDependents(FOREVER,PART_ALL,REFMSG_CHANGE); return TRUE; } void IndePosition::AddNewKey(TimeValue t,DWORD flags) { if (posX) posX->AddNewKey(t,flags); if (posY) posY->AddNewKey(t,flags); if (posZ) posZ->AddNewKey(t,flags); } int IndePosition::NumKeys() { int num = 0; if (posX) num += posX->NumKeys(); if (posY) num += posY->NumKeys(); if (posZ) num += posZ->NumKeys(); return num; } TimeValue IndePosition::GetKeyTime(int index) { int onum,num = 0; if (posX) num += posX->NumKeys(); if (index < num) return posX->GetKeyTime(index); onum = num; if (posY) num += posY->NumKeys(); if (index < num) return posY->GetKeyTime(index-onum); onum = num; if (posZ) num += posZ->NumKeys(); if (index < num) return posZ->GetKeyTime(index-onum); return 0; } void IndePosition::CopyKeysFromTime(TimeValue src,TimeValue dst,DWORD flags) { if (posX) posX->CopyKeysFromTime(src,dst,flags); if (posY) posY->CopyKeysFromTime(src,dst,flags); if (posZ) posZ->CopyKeysFromTime(src,dst,flags); } BOOL IndePosition::IsKeyAtTime(TimeValue t,DWORD flags) { if (posX && posX->IsKeyAtTime(t,flags)) return TRUE; if (posY && posY->IsKeyAtTime(t,flags)) return TRUE; if (posZ && posZ->IsKeyAtTime(t,flags)) return TRUE; return FALSE; } void IndePosition::DeleteKeyAtTime(TimeValue t) { if (posX) posX->DeleteKeyAtTime(t); if (posY) posY->DeleteKeyAtTime(t); if (posZ) posZ->DeleteKeyAtTime(t); } BOOL IndePosition::GetNextKeyTime(TimeValue t,DWORD flags,TimeValue &nt) { TimeValue at,tnear; BOOL tnearInit = FALSE; if (posX && posX->GetNextKeyTime(t,flags,at)) { if (!tnearInit) { tnear = at; tnearInit = TRUE; } else if (ABS(at-t) < ABS(tnear-t)) tnear = at; } if (posY && posY->GetNextKeyTime(t,flags,at)) { if (!tnearInit) { tnear = at; tnearInit = TRUE; } else if (ABS(at-t) < ABS(tnear-t)) tnear = at; } if (posZ && posZ->GetNextKeyTime(t,flags,at)) { if (!tnearInit) { tnear = at; tnearInit = TRUE; } else if (ABS(at-t) < ABS(tnear-t)) tnear = at; } if (tnearInit) { nt = tnear; return TRUE; } else { return FALSE; } } void IndePosition::BeginEditParams( IObjParam *ip, ULONG flags,Animatable *prev) { this->ip = ip; if (dlg) { dlg->BeginingEdit(this,ip,(IndePosition*)prev); } else { dlg = new IPosDlg(this,ip); } } void IndePosition::EndEditParams( IObjParam *ip, ULONG flags,Animatable *next) { IndePosition *cont=NULL; if (next && next->ClassID()==ClassID()) { cont = (IndePosition*)next; } if (dlg) { if (cont) { dlg->EndingEdit(cont); } else { delete dlg; dlg = NULL; } } }