#if 0 /********************************************************************** *< FILE: boolctrl.cpp DESCRIPTION: A boolean controller CREATED BY: Rolf Berteig HISTORY: 11/18/96 *> Copyright (c) 1996, All Rights Reserved. **********************************************************************/ #include "ctrl.h" #include "units.h" #include "exprlib.h" #define BOOL_CONTROL_CLASS_ID Class_ID(0x984b8d27,0x938f3e43) #define BOOL_CONTROL_CNAME GetString(IDS_RB_BOOLCONTROL) #define KEY_SELECTED (1<<0) #define KEY_FLAGGED (1<<1) #define MAKEBOOL(fl) ( (fl)<=0.0f ? FALSE : TRUE ) class BKey { public: TimeValue time; DWORD flags; BKey() {flags=0;} BKey(TimeValue t) {time=t; flags=0;} }; class BoolControl : public StdControl { public: Tab keys; Interval range, valid; BOOL onOff, startOnOff, rangeLinked; BoolControl(); // Animatable methods void DeleteThis() {delete this;} int IsKeyable() {return 1;} BOOL IsAnimated() {return keys.Count?TRUE:FALSE;} Class_ID ClassID() {return BOOL_CONTROL_CLASS_ID;} SClass_ID SuperClassID() {return CTRL_FLOAT_CLASS_ID;} void GetClassName(TSTR& s) {s = BOOL_CONTROL_CNAME;} // Reference methods RefResult NotifyRefChanged(Interval, RefTargetHandle, PartID&, RefMessage) {return REF_SUCCEED;} IOResult Save(ISave *isave); IOResult Load(ILoad *iload); RefTargetHandle Clone(RemapDir &remap = NoRemap()); // Control methods void Copy(Control *from); BOOL IsLeaf() {return TRUE;} void CommitValue(TimeValue t) {} void RestoreValue(TimeValue t) {} void HoldTrack(); Interval GetTimeRange(DWORD flags); void EditTimeRange(Interval range,DWORD flags); void MapKeys(TimeMap *map,DWORD flags ); int NumKeys() {return keys.Count();} TimeValue GetKeyTime(int index) {return keys[index].time;} int GetKeyIndex(TimeValue t); void DeleteKeyAtTime(TimeValue t); BOOL IsKeyAtTime(TimeValue t,DWORD flags); void DeleteTime(Interval iv, DWORD flags); void ReverseTime(Interval iv, DWORD flags); void ScaleTime(Interval iv, float s); void InsertTime(TimeValue ins, TimeValue amount); BOOL SupportTimeOperations() {return TRUE;} void DeleteKeys(DWORD flags); void DeleteKeyByIndex(int index); void SelectKeys(TrackHitTab& sel, DWORD flags); void SelectKeyByIndex(int i,BOOL sel); void FlagKey(TrackHitRecord hit); int GetFlagKeyIndex(); int NumSelKeys(); void CloneSelectedKeys(BOOL offset=FALSE); void AddNewKey(TimeValue t,DWORD flags); BOOL IsKeySelected(int index); BOOL CanCopyTrack(Interval iv, DWORD flags) {return TRUE;} BOOL CanPasteTrack(TrackClipObject *cobj,Interval iv, DWORD flags) {return cobj->ClassID()==ClassID();} TrackClipObject *CopyTrack(Interval iv, DWORD flags); void PasteTrack(TrackClipObject *cobj,Interval iv, DWORD flags); int GetSelKeyCoords(TimeValue &t, float &val,DWORD flags); void SetSelKeyCoords(TimeValue t, float val,DWORD flags); int SetSelKeyCoordsExpr(ParamDimension *dim,TCHAR *timeExpr, TCHAR *valExpr, DWORD flags); int HitTestTrack( TrackHitTab& hits, Rect& rcHit, Rect& rcTrack, float zoom, int scroll, DWORD flags); int PaintTrack( ParamDimensionBase *dim, HDC hdc, Rect& rcTrack, Rect& rcPaint, float zoom, int scroll, DWORD flags); // StdControl methods void GetValueLocalTime(TimeValue t, void *val, Interval &valid, GetSetMethod method=CTRL_ABSOLUTE) {GetValue(t,val,valid,method);} void GetValue(TimeValue t, void *val, Interval &valid, GetSetMethod method=CTRL_ABSOLUTE); void SetValueLocalTime(TimeValue t, void *val, int commit, GetSetMethod method); void Extrapolate(Interval range,TimeValue t,void *val,Interval &valid,int type); void *CreateTempValue() {return new float;} void DeleteTempValue(void *val) {delete (float*)val;} void ApplyValue(void *val, void *delta) {*((float*)val) += *((float*)delta);} void MultiplyValue(void *val, float m) {*((float*)val) *= m;} void SortKeys(); }; class BoolClassDesc:public ClassDesc { public: int IsPublic() {return 1;} void * Create(BOOL loading) {return new BoolControl();} const TCHAR * ClassName() {return BOOL_CONTROL_CNAME;} SClass_ID SuperClassID() {return CTRL_FLOAT_CLASS_ID; } Class_ID ClassID() {return BOOL_CONTROL_CLASS_ID;} const TCHAR* Category() {return _T("");} }; static BoolClassDesc boolCD; ClassDesc* GetBoolControlDesc() {return &boolCD;} class BoolControlRestore : public RestoreObj { public: Tab undo; Tab redo; Interval urange, rrange; BoolControl *cont; BoolControlRestore(BoolControl *c) { cont = c; undo = c->keys; urange = c->range; } void Restore(int isUndo) { if (isUndo) { redo = cont->keys; rrange = cont->range; } cont->keys = undo; cont->range = urange; cont->NotifyDependents(FOREVER,0,REFMSG_CHANGE); } void Redo() { cont->keys = redo; cont->range = rrange; cont->NotifyDependents(FOREVER,0,REFMSG_CHANGE); } int Size() {return 1;} void EndHold() {cont->ClearAFlag(A_HELD);} }; class BoolClipObject : public TrackClipObject { public: Tab tab; Class_ID ClassID() {return BOOL_CONTROL_CLASS_ID;} SClass_ID SuperClassID() { return CTRL_FLOAT_CLASS_ID; } void DeleteThis() {delete this;} BoolClipObject(Interval iv) : TrackClipObject(iv) {} }; //----------------------------------------------------------------------------- BoolControl::BoolControl() { //SPEW(("jerryeds","WHY THE FUCK IS BOOL BEING CALLED??? IT SHOULD NEVER BE CALLLED!")); //MessageBox(NULL, "WHY THE FUCK IS BOOL BEING CALLED??? IT SHOULD NEVER BE CALLLED!", "WTF?", MB_OK); startOnOff = TRUE; rangeLinked = TRUE; } RefTargetHandle BoolControl::Clone(RemapDir &remap) { //SPEW(("jerryeds","WHY THE FUCK IS BOOL BEING CALLED??? IT SHOULD NEVER BE CALLLED!")); //MessageBox(NULL, "WHY THE FUCK IS BOOL BEING CALLED??? IT SHOULD NEVER BE CALLLED!", "WTF?", MB_OK); BoolControl *bc = new BoolControl; bc->range = range; bc->valid = valid; bc->keys = keys; bc->onOff = onOff; bc->startOnOff = startOnOff; CloneControl(bc,remap); return bc; } #define KEYTIME_CHUNKID 0x0100 #define KEYFLAGS_CHUNKID 0x0110 #define NUMKEYS_CHUNKID 0x0130 IOResult BoolControl::Save(ISave *isave) { //MessageBox(NULL, "WHY THE FUCK IS BOOL BEING CALLED??? IT SHOULD NEVER BE CALLLED!", "WTF?", MB_OK); //SPEW(("jerryeds","WHY THE FUCK IS BOOL BEING CALLED??? IT SHOULD NEVER BE CALLLED!")); ULONG nb; int ct = keys.Count(); // Save the number of keys isave->BeginChunk(NUMKEYS_CHUNKID); isave->Write(&ct,sizeof(ct),&nb); isave->EndChunk(); // Write each key for (int i=0; iBeginChunk(KEYTIME_CHUNKID); isave->Write(&keys[i].time,sizeof(keys[i].time),&nb); isave->EndChunk(); isave->BeginChunk(KEYFLAGS_CHUNKID); isave->Write(&keys[i].flags,sizeof(keys[i].flags),&nb); isave->EndChunk(); } return IO_OK; } IOResult BoolControl::Load(ILoad *iload) { //MessageBox(NULL, "WHY THE FUCK IS BOOL BEING CALLED??? IT SHOULD NEVER BE CALLLED!", "WTF?", MB_OK); //SPEW(("jerryeds","WHY THE FUCK IS BOOL BEING CALLED??? IT SHOULD NEVER BE CALLLED!")); ULONG nb; int ct; IOResult res; if (IO_OK!=(res=iload->OpenChunk())) return res; assert(iload->CurChunkID()==NUMKEYS_CHUNKID); iload->Read(&ct,sizeof(ct),&nb); iload->CloseChunk(); keys.SetCount(ct); for (int i=0; iOpenChunk(); assert(iload->CurChunkID()==KEYTIME_CHUNKID); iload->Read(&keys[i].time,sizeof(keys[i].time),&nb); iload->CloseChunk(); iload->OpenChunk(); assert(iload->CurChunkID()==KEYFLAGS_CHUNKID); iload->Read(&keys[i].flags,sizeof(keys[i].flags),&nb); iload->CloseChunk(); } return IO_OK; } void BoolControl::Copy(Control *from) { //MessageBox(NULL, "WHY THE FUCK IS BOOL BEING CALLED??? IT SHOULD NEVER BE CALLLED!", "WTF?", MB_OK); //SPEW(("jerryeds","WHY THE FUCK IS BOOL BEING CALLED??? IT SHOULD NEVER BE CALLLED!")); if (from) { if (from->SuperClassID()!=CTRL_FLOAT_CLASS_ID) return; TimeValue t; float s; Interval iv; TimeValue tpf = GetTicksPerFrame(); Interval v = from->GetTimeRange(TIMERANGE_ALL); BOOL state = 1; TimeValue astart = GetAnimStart(); if (v.Start()>astart) { from->GetValue(astart, &s, iv); if (s<=0.0f) { state = 0; AddNewKey(astart, 0); } } for (t = v.Start(); t<=v.End(); t+=tpf) { from->GetValue(t, &s, iv); if (state) { if (s<=0.0f) { state = 0; AddNewKey(t, 0); } } else { if (s>0.0f) { state = 1; AddNewKey(t, 0); } } } } } void BoolControl::HoldTrack() { if (theHold.Holding()&&!TestAFlag(A_HELD)) { theHold.Put(new BoolControlRestore(this)); SetAFlag(A_HELD); } } void BoolControl::EditTimeRange(Interval range,DWORD flags) { HoldTrack(); if (flags&EDITRANGE_LINKTOKEYS && keys.Count()) { this->range.Set(keys[0].time,keys[keys.Count()-1].time); rangeLinked = TRUE; } else { rangeLinked = FALSE; this->range = range; } valid.SetEmpty(); NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE); } Interval BoolControl::GetTimeRange(DWORD flags) { if (rangeLinked && keys.Count()) return Interval(keys[0].time,keys[keys.Count()-1].time); else return range; } int BoolControl::GetSelKeyCoords(TimeValue &t, float &val,DWORD flags) { BOOL tfound=FALSE, tuncommon = FALSE; int n = keys.Count(), res; TimeValue atime; for (int i = 0; i < n; i++ ) { if (keys[i].flags & KEY_SELECTED) { if (tfound) { if (keys[i].time!=atime) { return KEYS_MULTISELECTED; } } else { tfound = TRUE; atime = keys[i].time; } } if (tuncommon) return KEYS_MULTISELECTED; } t = atime; res = 0; if (tfound && !tuncommon) { res |= KEYS_COMMONTIME; } if (!tfound) { res = KEYS_NONESELECTED; } return res; } int BoolControl::SetSelKeyCoordsExpr( ParamDimension *dim, TCHAR *timeExpr, TCHAR *valExpr, DWORD flags) { Expr texpr; float tfin, tfout=0.0f; if (timeExpr) { texpr.defVar(SCALAR_VAR,KEYCOORDS_TIMEVAR); if (texpr.load(timeExpr)!=EXPR_NORMAL) return KEYCOORDS_EXPR_ERROR; } int n = keys.Count(); if (!n) return KEYCOORDS_EXPR_OK; HoldTrack(); for (int i=0; imap(range.Start()); TimeValue t1 = map->map(range.End()); range.Set(t0,t1); changed = TRUE; } if (flags&TRACK_DOALL) { for (int i=0; imap(keys[i].time); changed = TRUE; } } else if (flags&TRACK_DOSEL) { BOOL slide = flags&TRACK_SLIDEUNSEL; TimeValue delta = 0, prev; int start, end, inc; if (flags&TRACK_RIGHTTOLEFT) { start = n-1; end = -1; inc = -1; } else { start = 0; end = n; inc = 1; } for (int i=start; i!=end; i+=inc) { if (keys[i].flags & KEY_SELECTED) { prev = keys[i].time; keys[i].time = map->map(keys[i].time); delta = keys[i].time - prev; changed = TRUE; } else if (slide) { keys[i].time += delta; } } } if (changed) { valid.SetEmpty(); SortKeys(); NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE); } } int BoolControl::GetKeyIndex(TimeValue t) { for (int i=0; i=0) { HoldTrack(); keys.Delete(index,1); valid.SetEmpty(); NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE); } } BOOL BoolControl::IsKeyAtTime(TimeValue t,DWORD flags) { for (int i=0; it) return FALSE; if (keys[i].time==t) return TRUE; } return FALSE; } void BoolControl::DeleteTime(Interval iv, DWORD flags) { Interval test = TestInterval(iv,flags); int n = keys.Count(); int d = iv.Duration()-1; if (d<0) d = 0; HoldTrack(); for (int i = n-1; i >= 0; i--) { if (test.InInterval(keys[i].time)) { keys.Delete(i,1); } else if (!(flags&TIME_NOSLIDE)) { if (keys[i].time > test.End()) { keys[i].time -= d; } } } valid.SetEmpty(); SortKeys(); NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE); } void BoolControl::ReverseTime(Interval iv, DWORD flags) { Interval test = TestInterval(iv,flags); int n = keys.Count(); HoldTrack(); for (int i = 0; i < n; i++) { if (test.InInterval(keys[i].time)) { TimeValue delta = keys[i].time - iv.Start(); keys[i].time = iv.End()-delta; } } valid.SetEmpty(); SortKeys(); NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE); } void BoolControl::ScaleTime(Interval iv, float s) { int n = keys.Count(); TimeValue delta = int(s*float(iv.End()-iv.Start())) + iv.Start()-iv.End(); HoldTrack(); for (int i = 0; i < n; i++) { if (iv.InInterval(keys[i].time)) { keys[i].time = int(s*float(keys[i].time - iv.Start())) + iv.Start(); } else if (keys[i].time > iv.End()) { keys[i].time += delta; } } valid.SetEmpty(); SortKeys(); NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE); } void BoolControl::InsertTime(TimeValue ins, TimeValue amount) { int n = keys.Count(); HoldTrack(); for (int i = 0; i < n; i++) { if (keys[i].time >= ins) { keys[i].time += amount; } } valid.SetEmpty(); SortKeys(); NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE); } void BoolControl::DeleteKeys(DWORD flags) { int n = keys.Count(); HoldTrack(); for (int i = n-1; i >= 0; i--) { if (flags&TRACK_DOALL || keys[i].flags&KEY_SELECTED) { keys.Delete(i,1); } } valid.SetEmpty(); NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE); } void BoolControl::DeleteKeyByIndex(int index) { HoldTrack(); keys.Delete(index,1); NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE); } void BoolControl::SelectKeyByIndex(int i,BOOL sel) { HoldTrack(); if (sel) keys[i].flags |= KEY_SELECTED; else keys[i].flags &= ~KEY_SELECTED; NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE); } void BoolControl::SelectKeys(TrackHitTab& sel, DWORD flags) { HoldTrack(); if (flags&SELKEYS_CLEARKEYS) { int n = keys.Count(); for (int i = 0; i < n; i++ ) { keys[i].flags &= ~KEY_SELECTED; } } if (flags&SELKEYS_DESELECT) { for (int i = 0; i < sel.Count(); i++ ) { keys[sel[i].hit].flags &= ~KEY_SELECTED; } } if (flags&SELKEYS_SELECT) { for (int i = 0; i < sel.Count(); i++ ) { keys[sel[i].hit].flags |= KEY_SELECTED; } } NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE); } void BoolControl::FlagKey(TrackHitRecord hit) { int n = keys.Count(); for (int i = 0; i < n; i++) { keys[i].flags &= ~KEY_FLAGGED; } assert(hit.hit>=0&&hit.hit<(DWORD)n); keys[hit.hit].flags |= KEY_FLAGGED; } int BoolControl::GetFlagKeyIndex() { int n = keys.Count(); for (int i = 0; i < n; i++) { if (keys[i].flags & KEY_FLAGGED) { return i; } } return -1; } int BoolControl::NumSelKeys() { int n = keys.Count(); int c = 0; for ( int i = 0; i < n; i++ ) { if (keys[i].flags & KEY_SELECTED) { c++; } } return c; } void BoolControl::CloneSelectedKeys(BOOL offset) { int n = keys.Count(); HoldTrack(); BOOL changed = FALSE; for (int i = 0; i < n; i++) { if (keys[i].flags & KEY_SELECTED) { BKey key(keys[i].time); key.flags |= KEY_SELECTED; keys.Append(1,&key,5); keys[i].flags &= ~KEY_SELECTED; changed = TRUE; } } if (changed) { keys.Shrink(); valid.SetEmpty(); SortKeys(); } } void BoolControl::AddNewKey(TimeValue t,DWORD flags) { HoldTrack(); BKey key(t); if (flags&ADDKEY_SELECT) { key.flags |= KEY_SELECTED; } if (flags&ADDKEY_FLAGGED) { int n = keys.Count(); for (int i = 0; i < n; i++) { keys[i].flags &= ~KEY_FLAGGED; } key.flags |= KEY_FLAGGED; } keys.Append(1,&key); valid.SetEmpty(); SortKeys(); NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE); } BOOL BoolControl::IsKeySelected(int index) { return keys[index].flags & KEY_SELECTED; } TrackClipObject *BoolControl::CopyTrack(Interval iv, DWORD flags) { BoolClipObject *cobj = new BoolClipObject(iv); Interval test = TestInterval(iv,flags); for (int i = 0; i < keys.Count(); i++) { if (test.InInterval(keys[i].time)) { BKey nk(keys[i].time); cobj->tab.Append(1,&nk,10); } } cobj->tab.Shrink(); return cobj; } void BoolControl::PasteTrack(TrackClipObject *cobj,Interval iv, DWORD flags) { BoolClipObject *cob = (BoolClipObject*)cobj; HoldTrack(); DeleteTime(iv,flags); InsertTime(iv.Start(),cob->clip.Duration()-1); for (int i = 0; i < cob->tab.Count(); i++) { BKey key(cob->tab[i].time); key.time -= cob->clip.Start() - iv.Start(); keys.Append(1,&key); } valid.SetEmpty(); SortKeys(); NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE); } int BoolControl::HitTestTrack( TrackHitTab& hits, Rect& rcHit, Rect& rcTrack, float zoom, int scroll, DWORD flags) { int left = ScreenToTime(rcTrack.left,zoom,scroll) - 4; int right = ScreenToTime(rcTrack.right,zoom,scroll) + 4; int n = keys.Count(); int y = (rcTrack.top+rcTrack.bottom)/2; for ( int i = 0; i < n; i++ ) { if (flags&HITTRACK_SELONLY && !(keys[i].flags & KEY_SELECTED)) continue; if (flags&HITTRACK_UNSELONLY && (keys[i].flags & KEY_SELECTED)) continue; if (keys[i].time > right) { break; } if (keys[i].time > left) { int x = TimeToScreen(keys[i].time,zoom,scroll); if (rcHit.Contains(IPoint2(x,y))) { TrackHitRecord rec(i,0); hits.Append(1,&rec); if (flags&HITTRACK_ABORTONHIT) return TRACK_DONE; } } } return TRACK_DONE; } int BoolControl::PaintTrack( ParamDimensionBase *dim, HDC hdc, Rect& rcTrack, Rect& rcPaint, float zoom, int scroll, DWORD flags) { int left = ScreenToTime(rcPaint.left-8,zoom,scroll); int right = ScreenToTime(rcPaint.right+8,zoom,scroll); int n = keys.Count(); int y = (rcTrack.top+rcTrack.bottom)/2, lx, x = rcPaint.left-2; HBRUSH selBrush = CreateSolidBrush(RGB(255,255,255)); HBRUSH barBrush = CreateSolidBrush(RGB(113,160,231)); //RGB(80,100,180) HBRUSH unselBrush = (HBRUSH)GetStockObject(GRAY_BRUSH); BOOL state = startOnOff; SelectObject(hdc,GetStockObject(BLACK_PEN)); SelectObject(hdc,barBrush); for (int i = 0; i < n; i++) { lx = x; x = TimeToScreen(keys[i].time,zoom,scroll); if (keys[i].time > left) { if (state) { Rectangle(hdc,lx,y-4,x,y+4); } } state = !state; if (keys[i].time > right) { break; } } if (state) { Rectangle(hdc,x,y-4,rcPaint.right,y+4); } for (i = 0; i < n; i++) { if (keys[i].time > right) { break; } if (keys[i].time > left) { x = TimeToScreen(keys[i].time,zoom,scroll); if ((flags&PAINTTRACK_SHOWSEL) && (keys[i].flags&KEY_SELECTED)) { SelectObject(hdc,selBrush); } else { SelectObject(hdc,unselBrush); } Ellipse(hdc,x-4,y-5,x+4,y+5); } } DeleteObject(selBrush); DeleteObject(barBrush); return TRACK_DONE; } void BoolControl::GetValue( TimeValue t, void *val, Interval &valid, GetSetMethod method) { Interval wvalid = FOREVER; float *v = (float*)val; t = ApplyEase(t,wvalid); if (!this->valid.InInterval(t)) { onOff = startOnOff; for (int i=0; it) break; onOff = !onOff; } if (keys.Count()) { if (t < keys[0].time) { this->valid.Set(TIME_NegInfinity,keys[0].time-1); } else if (t > keys[keys.Count()-1].time) { this->valid.Set(keys[keys.Count()-1].time,TIME_PosInfinity); } else this->valid.SetInstant(t); } else { this->valid = FOREVER; } } valid &= this->valid; *v = onOff ? 1.0f : -1.0f; } void BoolControl::SetValueLocalTime( TimeValue t, void *val, int commit, GetSetMethod method) { float *v = (float*)val; float tv; GetValue(t,&tv,FOREVER); if (MAKEBOOL(tv) == MAKEBOOL(*v)) { return; } if (Animating()) { int index = GetKeyIndex(t); if (index>=0) { keys.Delete(index,1); keys.Shrink(); } else { BKey k(t); keys.Append(1,&k); SortKeys(); } } else { if (keys.Count()) { startOnOff = !startOnOff; } else { onOff = startOnOff = MAKEBOOL(*v); } } valid.SetEmpty(); NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE); } void BoolControl::Extrapolate( Interval range,TimeValue t,void *val,Interval &valid,int type) { GetValue(t,val,valid); } static int __cdecl CompareBKeys(const BKey *k1, const BKey *k2) { if (k1->time < k2->time) return -1; if (k1->time > k2->time) return 1; return 0; } void BoolControl::SortKeys() { keys.Sort((CompareFnc)CompareBKeys); } #endif