00001 #ifndef Impala_Visualization_RotorBrowser_RotorBrowser_h
00002 #define Impala_Visualization_RotorBrowser_RotorBrowser_h
00004 //345678901234567890123456789012345678901234567890123456789012345678901234567890
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 
00037 
00038 
00039 
00040 
00041 
00042 
00043 
00044 
00045 
00046 
00047 
00048 
00049 
00050 
00051 
00052 
00053 
00054 
00055 
00056 
00057 
00058 
00059 
00060 
00061 
00062 
00063 
00064 
00065 
00066 
00067 
00068 
00069 
00070 
00071 
00072 
00073 
00074 
00075 
00076 
00077 
00078 
00079 
00080 
00081 
00082 
00083 
00084 
00085 
00086 
00087 
00088 
00089 
00090 
00091 
00092 
00093 
00094 
00095 
00096 
00097 
00098 
00099 
00100 
00101 
00102 
00103 
00104 
00105 
00106 
00107 
00108 
00109 
00110 
00111 
00112 
00113 
00114 
00115 
00116 
00117 
00118 
00119 
00120 
00121 
00122 
00123 
00124 
00125 
00126 
00127 
00128 
00129 
00130 
00131 
00132 
00133 
00134 
00135 
00136 
00137 
00138 
00139 
00140 
00141 
00142 
00143 
00144 
00145 
00146 
00147 
00148 
00149 
00150 
00151 
00152 
00153 
00154 
00155 
00156 
00157 
00158 
00159 
00160 
00161 
00162 
00163 
00164 
00165 
00166 
00167 
00168 
00169 
00170 
00171 
00172 
00173 
00174 
00175 
00176 
00177 
00178 
00179 
00180 
00181 
00182 
00183 
00184 
00185 
00186 
00187 
00188 #include <list>
00189 
00190 
00191 #include "RotorBrowserListener.h"
00192 #include "RotorView.h"
00193 #include "RotorBrowserContext.h"
00194 #include "ThreadClusterSelector.h"
00195 
00196 #include "Visualization/KeyBindingsMap.h"
00197 #include "Visualization/GUI/HelpViewer.h"
00198 #include "Visualization/StatusOverlayWindow.h"
00199 #include "Visualization/FontHandler.h"
00200 #include "Visualization/VideoMinimap.h"
00201 
00202 #include "Core/VideoSet/SegmentationDocument.h"
00203 #include "Core/Trec/VisualQueryEngine.h"
00204 #include "Core/Trec/ThreadSet.h"
00205 #include "Core/Table/TableTem.h"
00206 #include "Core/Table/Sort.h"
00207 
00208 #include "Sandbox/ork/ProgramNameReader.h"
00209 #include "Basis/CmdOptions.h"
00210 
00211 namespace Impala {
00212 namespace Visualization {
00213 namespace RotorBrowser {
00214 
00215 typedef Core::Table::TableTem
00216         <Core::Column::ColumnTem<Int32>,
00217         Core::Column::ColumnTem<Core::Trec::Thread*> >     TableThreadWidthId;
00218 
00219 class RotorBrowser : public OglGui::Window, public RotorViewListener
00220 {
00221 public:
00222     typedef std::list<RotorBrowserContext*>         RotorBrowserContextList;
00223     typedef std::list<RotorView*>                   RotorViewList;
00224     typedef Core::Array::Element::Vec3Int32         Vec3Int32;
00225     typedef Core::Trec::VisualQueryEngine           VisualQueryEngine;
00226     typedef Core::Trec::ThreadSet                   ThreadSet;
00227     typedef Core::Trec::Thread                      Thread;
00228     typedef Core::Trec::ThreadBookmarked            ThreadBookmarked;
00229     typedef Core::Trec::ThreadHistory               ThreadHistory;
00230     typedef Core::Trec::ThreadVirtual               ThreadVirtual;
00231     typedef Core::Trec::ThreadVisualSimilarity      ThreadVisualSimilarity;
00232     typedef Core::Trec::KeyframeResult              KeyframeResult;
00233     typedef Core::VideoSet::SegmentationDocument    SegmentationDocument;
00234     typedef Core::VideoSet::Stills                  Stills;
00235     typedef Core::ImageSet::ImageSet                ImageSet;
00236 
00237     RotorBrowser(OglGui::Window *parent, int w, int h, ThreadSet *threadset,
00238                  SegmentationDocument *document, String preFix = "") :
00239         OglGui::Window(parent, w, h, false)
00240     {
00241         Init(threadset, document, preFix);
00242     }
00243 
00244     RotorBrowser(OglGui::Window *parent, int x, int y, int w, int h,
00245                  ThreadSet *threadset, SegmentationDocument *document,
00246                  String preFix = "") :
00247         OglGui::Window(parent, x, y, w, h, false)
00248     {
00249         Init(threadset, document, preFix);
00250     }
00251 
00252     ~RotorBrowser()
00253     {
00254         ILOG_DEBUG("~RotorBrowser()");
00255         delete mActiveContext;
00256     }
00257 
00258     void SetRotorBrowserListener(RotorBrowserListener *listener)
00259     {
00260         mRotorBrowserListener = listener;
00261     }
00262 
00263     bool CheckKBN(String keyStr, int c, int state, int n=6)
00264     {
00265         keyStr = mPreFix + keyStr;
00266         return CheckKeyBindingExt(mKeyBindings, keyStr, c, state, n);
00267     }
00268 
00269     RotorBrowserContext*    GetActiveContext() { return mActiveContext; }
00270     RotorBrowserContextList GetOtherContexts() { return mContexts; }
00271 
00272     int  GetBrowseMode()                { return mBrowseMode; }
00273     bool GetKeepCenterCentered()        { return mKeepCenterCentered; }
00274     void SetShowDirection(bool sd)      { mShowDirection = sd; }
00275     bool GetShowDirection()             { return mShowDirection; }
00276     void SetActiveHorizontal(bool ah)   { mActiveHorizontal = ah; }
00277     bool GetActiveHorizontal()          { return mActiveHorizontal; }
00278     void SetManageContexts(bool mc)     { mManageContexts = mc; }
00279     bool GetManageContexts()            { return mManageContexts; }
00280     void SetTopNRelevant(int topn)      { mTopN = topn; }
00281     int  GetTopNRelevant()              { return mTopN; }
00282     void SetMinimapEnabled(bool val)    { mMinimapEnabled = val; }
00283     bool GetMinimapEnabled()            { return mMinimapEnabled; }
00284     int  GetNrActiveContexts()          { return mContexts.size() + 1; }
00285     bool GetEnableShotSwallow()         { return mEnableShotSwallow; }
00286 
00287     void SetProgramNames(Samples::ProgramNameReader *programs)
00288     {
00289         mPrograms = programs;
00290     }
00291 
00292     void SetBrowseMode(int mode)
00293     {
00294         ILOG_SYSTEM("RotorBrowser SetBrowseMode to " << mode);
00295         mBrowseMode = mode;
00296         CheckFocus(true);
00297 
00298         if (mBrowseMode == MODE_CROSSBROWSER)
00299         {
00300             InitCrossBrowser();
00301             ShowStatusStr("Current Browser", "CrossBrowser", oglDARKGREY);
00302         }
00303         if (mBrowseMode == MODE_ROTORBROWSER)
00304         {
00305             InitRotorBrowser();
00306             ShowStatusStr("Current Browser", "RotorBrowser", 0xffcccc22);
00307         }
00308         if (mBrowseMode == MODE_FORKBROWSER)
00309         {
00310             InitForkBrowser();
00311             ShowStatusStr("Current Browser", "ForkBrowser", 0xff2222cc);
00312         }
00313         UpdateViewsToContext();
00314     }
00315 
00316     
00317     RotorView* GetCenterRotorView()
00318     {
00319         if (!mActiveContext)
00320             return 0;
00321         return mCache->FindViewFor(mActiveContext->GetName(),
00322                                    mActiveContext->GetCenter());
00323     }
00324 
00325     void EnableCenterVideoStills(bool mode)
00326     {
00327         if (mAutoStills==STILLS_NONE)
00328             mode = false;
00329         RotorView* rotorView = GetCenterRotorView();
00330         if (!rotorView)
00331             return;
00332         if (mode)
00333         {
00334             const int curFileId = mDocument->CurFileId();
00335             if (curFileId != mDisabledCenterVideo)
00336             {
00337                 mDisabledCenterVideo = 
00338                     rotorView->EnableVideoStills(mDocument) ? -1 : curFileId;
00339                 if (mDisabledCenterVideo == -1)
00340                     return;
00341             }
00342         }
00343         rotorView->DisableVideoStills();
00344     }
00345 
00346     virtual void InitFunc()
00347     {
00348         OglGui::Window::InitFunc();
00349         view3DSys.SetCamera(GetOGLWND(),0.0f,0.0f,+4.0f,0.0f,0.0f,0.0f);
00350     }
00351 
00352     virtual void DisplayFunc()
00353     {
00354 
00355 #ifndef AS_TODS_BROWSER
00356         CheckFocus();
00357 #endif
00358         view3DSys.View3DCameraTransform(GetOGLWND());
00359 
00360         
00361         if (mBrowseMode==MODE_CROSSBROWSER || mBrowseMode==MODE_FORKBROWSER)
00362         {
00363             RotorBrowserContext *time = GetContext("time");
00364             float w = 1.0 + time->GetDepth() * 2.0;
00365             Printf3D(w/3,-1.05f,-9.1f,0.4f,0.4f,0.1f,time->GetNiceName());
00366         }
00367 
00368         if (mBrowseMode == MODE_ROTORBROWSER)
00369         {
00370             RotorBrowserContextList::iterator ctx;
00371             for (ctx = mContexts.begin(); ctx != mContexts.end(); ctx++)
00372             {
00373                 glPushMatrix();
00374                 float w = 1.0 + (*ctx)->GetDepth() * 3.0;
00375                 glRotatef((*ctx)->GetDirection()/M_PI*180.0f,0.f,0.f,1.f);
00376                 Printf3D(w/3,-1.05f,-9.1f,0.4f,0.4f,0.1f,(*ctx)->GetNiceName());
00377                 glPopMatrix();
00378             }
00379         }
00380         
00381         if (mBrowseMode == MODE_ROTORBROWSER && mShowDirection)
00382         {
00383             glPushMatrix();
00384             float w = 1.0 + mActiveContext->GetDepth() * 3.0;
00385             OGC   oldOGC;
00386             INT   oldBlendInfo[3];
00387             OGCSave(&oldOGC);
00388             oglSys.StartBlend(&oldBlendInfo[0]);
00389             glRotatef(mActiveContext->GetDirection()/M_PI*180.f, 0.f, 0.f, 1.f);
00390             ULONG colL = 0x22ff0000, colR = 0x2200ff00;
00391             SetFillColors(colL,colR,colR,colL,0xee000000);
00392             FillRoundRectExt3D(-w/2, -1.f, -10.1f, w, 2.f, 5.f, 5.f, 5.f, 5.f);
00393             glColor3f(0.5f, 0.f, 0.f);
00394             Printf3D(w/4, -1.f, -8.1f, 0.5f, 0.5f, 0.1f,
00395                      mActiveContext->GetNiceName());
00396             oglSys.EndBlend(&oldBlendInfo[0]);
00397             OGCRestore(&oldOGC);
00398             glPopMatrix();
00399         }
00400 
00401         if (mBrowseMode == MODE_FORKBROWSER)
00402         {
00403             
00404         }
00405 
00406         
00407         RotorViewList views = mCache->GetViews();
00408 
00409         
00410         bool updateNeeded = false;
00411         RotorViewList::const_iterator i;
00412         for (i = views.begin(); i != views.end(); i++)
00413             updateNeeded |= (*i)->DrawView();
00414 
00415         if (updateNeeded)
00416             UpdateScene();
00417     }
00418 
00419 
00420     virtual void KeyboardFunc(int c, int state)
00421     {
00422         bool keySwallowed = false;
00423         StopStills();
00424 
00425 
00426 
00427         if (!keySwallowed && mClusterSelector->IsActive())
00428             keySwallowed = KeyboardClusterSelectionFunc(c, state);
00429 
00430         if (!keySwallowed)
00431             keySwallowed = StdKeyboardFunc(c,state);
00432 
00433         if (!keySwallowed)
00434         {
00435             if (mBrowseMode == MODE_ROTORBROWSER)
00436                 keySwallowed = KeyboardRotorFunc(c, state);
00437             if (mBrowseMode == MODE_CROSSBROWSER)
00438                 keySwallowed = KeyboardCrossFunc(c, state);
00439             if (mBrowseMode == MODE_FORKBROWSER)
00440                 keySwallowed = KeyboardForkFunc(c, state);
00441         }
00442 
00443         if (!keySwallowed)
00444         {
00445             ILOG_DEBUG("key "<<c<<" state "<<state<<" still unswallowed." );
00446             Window::KeyboardFunc(c, state);
00447         }
00448         StartStills();
00449         UpdateScene(true);
00450     }
00451 
00452     bool StdKeyboardFunc(int c, int state)
00453     {
00454         bool keyHandled = true;
00455         bool book;
00456 
00457         if (CheckKBN("StdToggleShowBookmarks", c, state))
00458         {
00459             ILOG_USER("KB: show/hide bookmarks thread");
00460             DoShowBookmarksThread();
00461         }
00462         else if (CheckKBN("StdStopAutoStills", c, state))
00463         {
00464             ILOG_USER("KB: Stop autostill feature");
00465             StopAutoStills();
00466             ShowStatusStr("Shot still player", false);
00467         }
00468         else if (CheckKBN("StdToggleAutoStills", c, state))
00469         {
00470             ILOG_USER("KB: Toggle autostill feature");
00471             ToggleAutoStills();
00472         }
00473         else if (CheckKBN("StdToggleVideoStream", c, state))
00474         {
00475             ILOG_USER( "KB: toggling video stream for center shot" );
00476             ToggleEnableVideoStream();
00477         }
00478         else if (CheckKBN("StdTogglePlayUntilEnd", c, state))
00479         {
00480             ILOG_USER("KB: toggling video continuous to end for center shot");
00481             TogglePlayUntilEnd();
00482         }
00483         else if (CheckKBN("StdIncrAutoStillSpeed", c, state))
00484         {
00485             int va = RotorView::GetStillFrameWait();
00486             va -= 2;
00487             if (va < 1) va = 1;
00488             mStatusOverlay->ShowStatus("Stills animation delay", va, 1, 40);
00489             ILOG_USER( "KB: autostills faster, now " << va );
00490             RotorView::SetStillFrameWait(va);
00491         }
00492         else if (CheckKBN("StdDecrAutoStillSpeed", c, state))
00493         {
00494             int va = RotorView::GetStillFrameWait();
00495             va += 2;
00496             if (va > 40) va = 40;
00497             mStatusOverlay->ShowStatus("Stills animation delay", va, 1, 40);
00498             ILOG_USER( "KB: autostills slower, now " << va );
00499             RotorView::SetStillFrameWait(va);
00500         }
00501         else if (CheckKBN("StdIncrAnimationSpeed", c, state))
00502         {
00503             ILOG_USER( "KB: DEBUG: increase sFactor" );
00504             RotorView::SetSpeedFactor( RotorView::GetSpeedFactor() + 0.8 );
00505             mStatusOverlay->ShowStatus("Animation delay",
00506                                        RotorView::GetSpeedFactor(), 1, 20);
00507         }
00508         else if (CheckKBN("StdDecrAnimationSpeed", c, state))
00509         {
00510             ILOG_USER( "KB: DEBUG: decrease sFactor" );
00511             RotorView::SetSpeedFactor( RotorView::GetSpeedFactor() - 0.8 );
00512             mStatusOverlay->ShowStatus("Animation delay",
00513                                        RotorView::GetSpeedFactor(), 1, 20);
00514         }
00515         else if (CheckKBN("StdToggleShowHelp", c, state))
00516         {
00517             ILOG_USER( "KB: Toggle display inline help viewer" );
00518             mHelpViewer->SetVisible(!mHelpViewer->GetVisible());
00519         }
00520         else if (CheckKBN("StdCrossBrowserMode", c, state))
00521         {
00522             ILOG_USER( "KB: switch browser to CrossBrowser" );
00523             SetBrowseMode(RotorBrowser::MODE_CROSSBROWSER);
00524         }
00525 #ifndef AS_TODS_BROWSER
00526         else if (CheckKBN("StdRotorBrowserMode", c, state))
00527         {
00528             ILOG_USER( "KB: switch browser to RotorBrowser" );
00529             SetBrowseMode(RotorBrowser::MODE_ROTORBROWSER);
00530         }
00531         else if (CheckKBN("StdForkBrowserMode", c, state))
00532         {
00533             ILOG_USER("KB: switch browser to ForkBrowser");
00534             SetBrowseMode(RotorBrowser::MODE_FORKBROWSER);
00535         }
00536 #endif
00537         else if (CheckKBN("StdToggleShotSwallow", c, state))
00538         {
00539             SetEnableShotSwallow(!GetEnableShotSwallow());
00540             ILOG_USER("KB: toggle enable shot swallow. Now " <<
00541                       GetEnableShotSwallow());
00542             UpdateViewsToContext();
00543         }
00544         else if (CheckKBN("StdToggleShotSwallowThread", c, state))
00545         {
00546             ToggleShotSwallowThread();
00547             ILOG_USER("KB: toggle shot swallow thread.");
00548             UpdateViewsToContext();
00549         }
00550         else if (CheckKBN("StdToggleKeepCenterCentered", c, state))
00551         {
00552             SetKeepCenterCentered(!GetKeepCenterCentered());
00553             ILOG_USER("KB: toggle keep center shot centered. Now " <<
00554                       GetKeepCenterCentered() );
00555             UpdateViewsToContext();
00556         }            
00557         else if ((book=CheckKBN("StdBookmarkCenterPositive", c, state)) ||
00558                  CheckKBN("StdBookmarkCenterNegative", c, state))
00559         {
00560             ILOG_USER("KB: " << (book ? "bookmark" : "remove") << " center " <<
00561                       mActiveContext->GetCenter() << " from " <<
00562                       mActiveContext->GetName());
00563             BookmarkActiveCenterEx(c==' ');
00564             UpdateViewsToContext();
00565         }
00566 #ifndef AS_TODS_BROWSER
00567         else if (CheckKBN("StdClusterSelect", c, state))
00568         {
00569             ILOG_USER("KB: cluster select in active thread direction");
00570             ClusterSelect();
00571             UpdateViewsToContext();
00572         }
00573 #endif
00574         else if (CheckKBN("StdClearViewedCache", c, state))
00575         {
00576             ILOG_USER("KB: (debug code) reset viewed shots");
00577             ClearViewedCache();
00578             UpdateViewsToContext();
00579         }
00580         else if (CheckKBN("StdJudgeBrowseMode", c, state))
00581         {
00582             ILOG_USER("KB: (debug code) activating judge-browse mode.");
00583             RotorBrowserContext::SetAutoNegatives(false);
00584             RotorView::SetShowNegativeBookmarks(true);
00585             RotorView::SetShowProbabilityFeedback(false);
00586             ClearViewedCache();
00587             UpdateViewsToContext();
00588         }
00589         else if (CheckKBN("StdToggleAutoSelectNegatives", c, state))
00590         {
00591             bool nstate = !RotorBrowserContext::GetAutoNegatives();
00592             ILOG_USER("KB: (debug code) toggle auto-select negatives. " <<
00593                       "Now " << nstate);
00594             RotorBrowserContext::SetAutoNegatives(nstate);
00595             RotorView::SetShowNegativeBookmarks(nstate);
00596             RotorView::SetShowProbabilityFeedback(nstate);
00597             if (!nstate)
00598                 ClearViewedCache();
00599             UpdateViewsToContext();
00600         }
00601         else
00602             keyHandled = false;
00603         return keyHandled;
00604     }
00605 
00606     
00607     
00608     bool KeyboardClusterSelectionFunc(int c, int state)
00609     {
00610         if (mClusterSelector->ClusterKeyboardFunc(c,state))
00611             return true;
00612 
00613         bool force    = false;
00614         bool positive = false;
00615 
00616         if ((positive = CheckKBN("CsBookPositive", c, state)) ||
00617             (force = positive = CheckKBN("CsBookPositiveForce", c, state)) ||
00618             (CheckKBN("CsBookNegative", c, state)) ||
00619             (force = CheckKBN("CsBookNegativeForce", c, state)))
00620         {
00621             ILOG_USER("KB: " << (force ? "force" : "") <<
00622                       "bookmark cluster viewer selection " <<
00623                       (positive ? "" : "as negative"));
00624             DoBookmarkCluster(positive, force);
00625             return true;
00626         }
00627         return false;
00628     }
00629 
00630     bool CrossBrowserNavigateKey(int c, int state, bool keepCenter)
00631     {
00632         int up=0, down=0, left=0, right=0;
00633 
00634         if ((up    = CheckKBN("CbGoUp",    c, state)) ||
00635             (down  = CheckKBN("CbGoDown",  c, state)) ||
00636             (left  = CheckKBN("CbGoLeft",  c, state)) ||
00637             (right = CheckKBN("CbGoRight", c, state)))
00638         {
00639             state = 0; 
00640         }
00641         else if ((up   = CheckKBN("CbBookmarkUpNegative",   c, state)) ||
00642                  (down = CheckKBN("CbBookmarkDownNegative", c, state)) ||
00643                  (left = CheckKBN("CbBookmarkPrevNegative", c, state)) ||
00644                  (right= CheckKBN("CbBookmarkNextNegative", c, state)))
00645         {
00646             state = oglControl; 
00647         }
00648         else if ((up   = CheckKBN("CbBookmarkUpPositive",   c, state)) ||
00649                  (down = CheckKBN("CbBookmarkDownPositive", c, state)) ||
00650                  (left = CheckKBN("CbBookmarkPrevPositive", c, state)) ||
00651                  (right= CheckKBN("CbBookmarkNextPositive", c, state)))
00652         {
00653             state = oglShift; 
00654         }
00655         if (up)    c = oglUP;
00656         if (down)  c = oglDOWN;
00657         if (left)  c = oglLEFT;
00658         if (right) c = oglRIGHT;
00659 
00660         if (!(left || right || up || down))
00661             return false;
00662 
00663         char*  dirStr[] = {"UP (forward)", "DOWN (backward)", "LEFT", "RIGHT"};
00664         String action   = (state==oglControl) ? " removing " : " bookmarking ";
00665 
00666         if (!keepCenter && (state==oglShift || state==oglControl))
00667         {
00668             BookmarkActiveCenterEx(state==oglShift);
00669             ILOG_USER("KB: " << action << " center "  <<
00670                       mActiveContext->GetCenter() << " from " <<
00671                       mActiveContext->GetName() << " and....");
00672         }
00673 
00674         SwitchToContext((left||right) ? "time" : "shots_initialquery");
00675 
00676         if (keepCenter && (state == oglControl || state == oglShift))
00677         {
00678             int dir     = (left || up) ? -1 : 1;
00679             int target  = mActiveContext->GetRelative(dir);
00680 
00681             BookmarkSpecificEx(target, state==oglShift);
00682             ILOG_USER("KB: " << action << dirStr[c-oglUP] << target);
00683             UpdateViewsToContext();
00684         }
00685 
00686         if (!keepCenter)
00687         {
00688             ILOG_USER("KB: crossbrowser " << dirStr[c-oglUP]);
00689             if (left || down)
00690                 mActiveContext->GoLeft();
00691             if (right || up)
00692                 mActiveContext->GoRight();
00693             UpdateViewsToContext();
00694             PublishContextMoved((left || down) ? -1 : 1);
00695         }
00696         return true;
00697     }
00698 
00699     bool VisualQueryKey(int c, int state)
00700     {
00701         String visStr = "";
00702         if (CheckKBN("VisualQuery_vissemgabor", c, state))
00703             visStr = "vissemgabor";
00704         if (CheckKBN("VisualQuery_vissem", c, state))
00705             visStr = "vissem";
00706         if (CheckKBN("VisualQuery_fusionvissemgabor", c, state))
00707             visStr = "fusionvissemgabor";
00708         if (CheckKBN("VisualQuery_labhistogram", c, state))
00709             visStr = "labhistogram";
00710 
00711         if (!visStr.empty())
00712         {
00713             int center = mActiveContext->GetCenter();
00714             if (mBrowseMode==MODE_CROSSBROWSER)
00715                 ILOG_USER("KB: CrossBrowser switching initialquery to " <<
00716                           visStr << " for active " << center);
00717             if (mBrowseMode==MODE_ROTORBROWSER)
00718                 ILOG_USER("KB: RotorBrowser generate visual " << visStr <<
00719                           " thread for active " << center);
00720             DoVisualQuery(visStr);
00721             return true;
00722         }
00723         return false;
00724     }
00725 
00726     bool KeyboardCrossFunc(int c, int state)
00727     {
00728         if (CrossBrowserNavigateKey(c,state,mKeepCenterCentered))
00729             return true;
00730 
00731         if (VisualQueryKey(c,state))
00732             return true;
00733 
00734         
00735         bool    keyHandled  = true;
00736 
00737         if (CheckKBN("CbGoFirst", c, state))
00738         {
00739             ILOG_USER( "KB: CrossBrowser moving to FIRST" );
00740             ResetRanking();
00741         }
00742         if (CheckKBN("CbGoLast", c, state))
00743         {
00744             ILOG_USER( "KB: CrossBrowser moving to LAST" );
00745             SwitchToContext("shots_initialquery");
00746             mActiveContext->GoLast();
00747             UpdateViewsToContext();
00748             PublishContextMoved(1);
00749         }
00750         if (CheckKBN("CbGoInitialQuery", c, state))
00751         {
00752             ILOG_USER("KB: Return to original search query");
00753             DoReturnToFirstQuery();
00754         }
00755         else
00756             keyHandled = false;
00757 
00758         return keyHandled;
00759     }
00760 
00761     bool RotorBrowserNavigateKey(int k, int state, bool keepCenter)
00762     {
00763         int c = 0;
00764         if ( CheckKBN("RbGoForward", k, state))
00765             c = 'd';
00766         else if (CheckKBN("RbGoBackward", k, state))
00767             c = 'a';
00768         else if (CheckKBN("RbGoFirst", k, state))
00769             c = 'q';
00770         else if (CheckKBN("RbGoLast", k, state))
00771             c = 'e';
00772         else if (CheckKBN("RbBookmarkNext", k, state))
00773             c = 'D';
00774         else if (CheckKBN("RbBookmarkPrev", k, state))
00775             c = 'A';
00776 
00777         if (!c)
00778             return false;
00779 
00780         if (c=='a') mActiveContext->GoLeft();
00781         if (c=='d') mActiveContext->GoRight();
00782         if (c=='q') mActiveContext->GoFirst();
00783         if (c=='e') mActiveContext->GoLast();
00784 
00785         if (c=='q' || c=='e')
00786             ILOG_USER("KB: RotorBrowser moving active " <<
00787                       mActiveContext->GetName() << " to " <<
00788                       (c=='q' ? "FIRST" : "LAST"));
00789 
00790 
00791         if (c=='A' || c=='D')
00792         {
00793             if (!mKeepCenterCentered) {
00794                 ILOG_USER("KB: bookmark center " <<
00795                            mActiveContext->GetCenter()  << " from " <<
00796                            mActiveContext->GetName() << " and go " <<
00797                            (c=='A' ? "LEFT" : "RIGHT") << " in "<<
00798                            mActiveContext->GetName());
00799                 int nextshot = mActiveContext->GetRelative(c=='A'? -1 : 1);
00800                 BookmarkActiveCenter();
00801                 mActiveContext->GoTo(nextshot);
00802             }
00803             else
00804             {
00805                 int target = mActiveContext->GetRelative(c=='A' ? -1 : 1);
00806                 ILOG_USER("KB: RotorBrowser bookmark " << target <<
00807                           (c=='A'? "left" : "right") << " of center from " <<
00808                           mActiveContext->GetName() );
00809                 BookmarkSpecific(target);
00810             }
00811         }
00812         UpdateViewsToContext();
00813         if ( !(keepCenter && (c=='A' || c=='D')))
00814             PublishContextMoved((c=='A' || c=='a' || c=='q') ? -1 : 1);
00815 
00816         return true;
00817     }
00818 
00819     bool KeyboardRotorFunc(int c, int state)
00820     {
00821         if (VisualQueryKey(c,state))
00822             return true;
00823 
00824         if (RotorBrowserNavigateKey(c,state,mKeepCenterCentered))
00825             return true;
00826 
00827         bool keySwallowed = true;
00828         if (CheckKBN("RbSwitchToContextNext", c, state))
00829         {
00830             ILOG_USER( "KB: RotorBrowser switch to NEXT context" );
00831             SwitchToNextContext();
00832             UpdateViewsToContext();
00833         }
00834         else if (CheckKBN("RbSwitchToContextPrev", c, state))
00835         {
00836             ILOG_USER( "KB: RotorBrowser switch to PREVIOUS context" );
00837             SwitchToPreviousContext();
00838             UpdateViewsToContext();
00839         }
00840         else if (CheckKBN("RbSwitchToContextTime", c, state))
00841         {
00842             ILOG_USER( "KB: RotorBrowser switch to context 'time'" );
00843             SwitchToContext("time");
00844             UpdateViewsToContext();
00845         }
00846         else if (CheckKBN("RbSwitchToContextBookmark", c, state))
00847         {
00848             ILOG_USER( "KB: RotorBrowser switch to context 'bookmarked'" );
00849             if (!HasContext("bookmarked"))
00850             {
00851                 Thread* t = GetThreadByName("bookmarked");
00852                 mContexts.push_back(new RotorBrowserContext(mCache,t,0,0.0f,4));
00853             }
00854             SwitchToContext("bookmarked");
00855             UpdateViewsToContext();
00856         }
00857         else if (CheckKBN("RbReturnLastInitialQuery", c, state))
00858         {
00859             ILOG_USER("KB: return to last known initialquery position " <<
00860                       mInitialQueryPosition );
00861             SwitchToContext("shots_initialquery");
00862             if (mActiveContext->GetName() == "shots_initialquery")
00863             {
00864                 ILOG_DEBUG("current context = initialquery" );
00865                 mActiveContext->GoTo(mInitialQueryPosition);
00866                 ILOG_DEBUG("current context = " << mActiveContext->GetCenter());
00867                 UpdateViewsToContext();
00868             }
00869             else
00870                 ILOG_DEBUG("return to context failed, current context=" <<
00871                            mActiveContext->GetName() );
00872         }
00873         else if (CheckKBN("RbToggleShowRankThreads", c, state))
00874         {
00875             ILOG_USER( "KB: toggling show rank threads" );
00876             mShowRankThreads = !mShowRankThreads;
00877             ShowStatusStr("Show extra threads", mShowRankThreads);
00878             UpdateViewsToContext();
00879         }
00880         else
00881             keySwallowed = false;
00882 
00883         return keySwallowed;
00884     }
00885 
00886     void KbBookmarkActiveCenter(bool positive)
00887     {
00888         ILOG_USER("KB: bookmarking center " << mActiveContext->GetCenter() <<
00889                   " from " << mActiveContext->GetName() << " and....");
00890         if (positive)
00891             BookmarkActiveCenter();
00892         else
00893             BookmarkActiveCenterNegative();
00894     }
00895 
00896     void KbNavigateFork(char* str, int dir, char* logStr )
00897     {
00898         ILOG_USER("KB: ForkBrowser " << logStr);
00899         SwitchToContext(str);
00900         if (dir == -1)
00901             mActiveContext->GoLeft();
00902         if (dir == 1)
00903             mActiveContext->GoRight();
00904         AddCenterToHistory();
00905         if (!strcmp(str,"shots_initialquery"))
00906             mForkLastQueryShot = mActiveContext->GetCenter();
00907         UpdateViewsToContext();
00908         PublishContextMoved(dir);
00909     }
00910 
00911     bool KeyboardForkFunc(int c, int state)
00912     {
00913         int l = 0, r = 0, v = 0, g = 0, q = 0, h = 0;
00914 
00915         if (
00916             (l = CheckKBN("FbBookmarkPositiveTimeBackward",  c, state)) ||
00917             (r = CheckKBN("FbBookmarkPositiveTimeForward",   c, state)) ||
00918             (v = CheckKBN("FbBookmarkPositiveVissemForward", c, state)) ||
00919             (g = CheckKBN("FbBookmarkPositiveGaborForward",  c, state)) ||
00920             (q = CheckKBN("FbBookmarkPositiveQueryForward",  c, state)) ||
00921             (h = CheckKBN("FbBookmarkPositiveHistoryGoLast", c, state)))
00922         {
00923             KbBookmarkActiveCenter(true);
00924         }
00925         else if (
00926             (l = CheckKBN("FbBookmarkNegativeTimeBackward",  c, state)) ||
00927             (r = CheckKBN("FbBookmarkNegativeTimeForward",   c, state)) ||
00928             (v = CheckKBN("FbBookmarkNegativeVissemForward", c, state)) ||
00929             (g = CheckKBN("FbBookmarkNegativeGaborForward",  c, state)) ||
00930             (q = CheckKBN("FbBookmarkNegativeQueryForward",  c, state)) ||
00931             (h = CheckKBN("FbBookmarkNegativeHistoryGoLast", c, state)))
00932         {
00933             KbBookmarkActiveCenter(false);
00934         }
00935         else if (
00936             (l = CheckKBN("FbTimeBackward",  c, state)) ||
00937             (r = CheckKBN("FbTimeForward",   c, state)) ||
00938             (v = CheckKBN("FbVissemForward", c, state)) ||
00939             (g = CheckKBN("FbGaborForward",  c, state)) ||
00940             (q = CheckKBN("FbQueryForward",  c, state)) ||
00941             (h = CheckKBN("FbLastHistory",   c, state)))
00942         {}
00943     
00944         bool keySwallowed = true;
00945         if (l)
00946             KbNavigateFork("time",-1,"LEFT in TIME");
00947         else if (r)
00948             KbNavigateFork("time",1,"RIGHT in TIME");
00949         else if (g)
00950             KbNavigateFork("visual_vissemgabor",1,"NEXT in visually similar");
00951         else if (v)
00952             KbNavigateFork("visual_vissem",1,"NEXT in conceptually similar");
00953         else if (q)
00954             KbNavigateFork("shots_initialquery",1,"NEXT in QUERY");
00955         else if (h)
00956         {
00957             ILOG_USER( "KB: ForkBrowser LAST in HISTORY" );
00958             SwitchToContext("history");
00959             mActiveContext->GoLeft();
00960             UpdateViewsToContext();
00961             PublishContextMoved(-1);
00962         }
00963         else if (CheckKBN("FbLastQueryShot", c, state))
00964         {
00965             ILOG_USER("KB: ForkBrowser return to last shot selected from QUERY "
00966                       << mForkLastQueryShot);
00967             
00968             if (mForkLastQueryShot > -1)
00969             {
00970                 SwitchToContext("shots_initialquery");
00971                 mActiveContext->GoTo(mForkLastQueryShot);
00972                 AddCenterToHistory();
00973                 UpdateViewsToContext();
00974             }
00975         }
00976         else
00977             keySwallowed = false;
00978         return keySwallowed;
00979     }
00980 
00981     void PublishContextMoved(int dir)
00982     {
00983         if (!mRotorBrowserListener || !mActiveContext)
00984             return;
00985         int center = mActiveContext->GetCenter();
00986         mRotorBrowserListener->ContextMoveEvent(this, dir, center);
00987     }
00988 
00989     void AddCenterToHistory()
00990     {
00991         if (mActiveContext != 0)
00992             AddToHistory(mActiveContext->GetCenter());
00993     }
00994 
00995     void AddToHistory(int shot)
00996     {
00997         ThreadHistory *history = (ThreadHistory*)GetThreadByName("history");
00998         if (history != 0)
00999         {
01000             history->Remove(shot);
01001             history->Push(shot);
01002             if (mTrailHistory)
01003                 mTrailHistory->Push(shot);
01004         }
01005     }
01006 
01007     virtual void MouseFunc(int msg, int but, int state, int x, int y)
01008     {
01009         if (msg == oglMouseWheelUp)
01010         {
01011             KeyboardFunc('s', state);
01012             return;
01013         }
01014 
01015         if (msg == oglMouseWheelDown)
01016         {
01017             KeyboardFunc('w', state);
01018             return;
01019         }
01020 
01021         if ((state & oglAlt) || (msg != oglMouseDown))
01022         {
01023 #ifndef AS_TODS_BROWSER
01024             Window::MouseFunc(msg, but, state, x, y);
01025 #endif
01026             return;
01027         }
01028         OGLVIEW3D *v = view3DSys.FindView(mOglWnd, x, y);
01029         if (v == NULL) return;
01030         RotorView *view = RotorViewCache::OGLVIEW3DToRotorView(v);
01031         if (view == NULL) return;
01032 
01033         if (but == oglLeftButton)
01034         {
01035             if (state & oglShift)
01036             {
01037                 
01038                 int vNr = view->GetNR();
01039                 RotorBrowserContext *c = FindContextForPosition(vNr);
01040                 if (!c) return;
01041 
01042                 ILOG_USER("MOUSE: move to shot " << vNr <<
01043                           " from context " << c->GetName() );
01044                 if (SwitchToContext(c->GetName()))
01045                 {
01046                     mActiveContext->GoTo(vNr);
01047                     UpdateViewsToContext();
01048                     PublishContextMoved(0);
01049                 }
01050             }
01051             else
01052             {
01053                 ILOG_USER("MOUSE: click on shot " << view->GetNR() <<
01054                           " at " << view->GetName());
01055                 BookmarkSpecific(view->GetNR());
01056                 view->UpdateBookmarkState();
01057                 if (mBrowseMode == MODE_FORKBROWSER)
01058                 {
01059                     AddToHistory(view->GetNR());
01060                     UpdateViewsToContext();
01061                 }
01062             }
01063         }
01064         if (but == oglRightButton)
01065         {
01066             ILOG_USER("MOUSE: rightclick on shot " << view->GetNR() <<
01067                       " at " << view->GetName() );
01068             BookmarkSpecificNegative(view->GetNR());
01069             view->UpdateBookmarkState();
01070         }
01071     }
01072 
01073     void AddContext(Thread *thread, int initialpos, float direction=0.0f,
01074                     int depth=3)
01075     {
01076         if (HasContext(thread->GetName()))
01077         {
01078             ILOG_DEBUG("RotorBrowser::AddContext(" << thread->GetName() <<
01079                        "): already exists. not added." );
01080             return;
01081         }
01082         ILOG_DEBUG("RotorBrowser::AddContext(" << thread->GetName() <<
01083                    ", " << initialpos <<")" );
01084 
01085         if (thread->GetName() == "shots_initialquery")
01086             mInitialQueryPosition = -1;
01087 
01088         RotorBrowserContext *add =
01089             new RotorBrowserContext(mCache,thread,initialpos,direction,depth);
01090         add->SetSwallowThread(GetThreadByName("virtual_hidden"));
01091         add->SetSwallowMode(RotorBrowserContext::SWALLOW_ALL);
01092         mContexts.push_back(add);
01093 
01094         RepositionContexts();
01095         UpdateViewsToContext();
01096     }
01097 
01098     void ReloadCrossBrowser(int position = -1)
01099     {
01100         ILOG_DEBUG( "ReloadCrossBrowser()" );
01101         SwitchToContext("shots_initialquery");
01102         if (mActiveContext->GetName() != "shots_initialquery")
01103         {
01104             ILOG_WARN("active context is not initialquery. " << 
01105                       "Aborting ReloadCrossBrowser." );
01106             return;
01107         }
01108         delete mActiveContext;
01109         mActiveContext = NULL;
01110         InitCrossBrowser(position);
01111         UpdateViewsToContext();
01112     }
01113 
01114     
01115     void ReloadForkBrowser()
01116     {
01117         ILOG_DEBUG("ReloadForkBrowser()");
01118         SwitchToContext("shots_initialquery");
01119         if (mActiveContext->GetName() != "shots_initialquery")
01120         {
01121             ILOG_WARN("active context is not initialquery. " << 
01122                       "Aborting ReloadForkBrowser." );
01123             return;
01124         }
01125         delete mActiveContext;
01126         mActiveContext = NULL;
01127         InitForkBrowser();
01128         UpdateViewsToContext();
01129         
01130         
01131     }
01132 
01133     void ReloadInitial()
01134     {
01135         if (mClusterSelector->IsActive())
01136         {
01137             ILOG_DEBUG("hiding cluster selector");
01138             mClusterSelector->Hide();
01139         }
01140 
01141         ClearTrails();
01142 
01143         if (mBrowseMode==MODE_CROSSBROWSER || mBrowseMode==MODE_FORKBROWSER)
01144         {
01145             UpdateViewsToContext();
01146             return;
01147         }
01148 
01149         ILOG_SYSTEM( "reloading initial query" );
01150         if (!mActiveContext || mActiveContext->GetName()!="shots_initalquery")
01151         {
01152             ILOG_DEBUG( "initialquery was not active, activating..." );
01153             SwitchToContext("shots_initialquery");
01154         }
01155         if (mActiveContext && mActiveContext->GetName()=="shots_initialquery")
01156         {
01157             delete mActiveContext;
01158             mActiveContext = NULL;
01159             SwitchToContext("time");
01160             UpdateViewsToContext();
01161             SwitchToContext("shots_initialquery");
01162         }
01163     }
01164 
01165     void ResetRanking()
01166     {
01167         SwitchToContext("shots_initialquery");
01168         mActiveContext->GoFirst();
01169         UpdateViewsToContext();
01170         PublishContextMoved(-1);
01171     }
01172 
01173     void RemoveContext(String name)
01174     {
01175         if (mActiveContext->GetName() == name)
01176         {
01177             if (mContexts.size() < 1)
01178             {
01179                 ILOG_DEBUG("RotorBrowser::RemoveContext(" << name <<
01180                            "): is active and alone. Not removed.");
01181                 return;
01182             }
01183             SwitchToNextContext();
01184         }
01185         RotorBrowserContextList::iterator context;
01186         for (context=mContexts.begin(); context!=mContexts.end(); context++)
01187             if ((*context)->GetName() == name)
01188                 break;
01189         
01190         if (context != mContexts.end())
01191         {
01192             delete *context;
01193             mContexts.erase(context);
01194             ILOG_DEBUG("RotorBrowser::RemoveContext(" << name <<
01195                        "): erased. " << mContexts.size() <<
01196                        " contexts remaining.");
01197         }
01198         else
01199             ILOG_DEBUG("RotorBrowser::RemoveContext(" << name <<
01200                        "): was not in active contexts. " );
01201 
01202         RepositionContexts();
01203         UpdateViewsToContext();
01204     }
01205 
01206     void SetEnableShotSwallow(bool swallow)
01207     {
01208         if (mKeepCenterCentered)
01209         {
01210             ShowStatusStr("Bookmarked shots", "hidden, keep center enabled",
01211                           0xffdddd22);
01212             return;
01213         }
01214         mEnableShotSwallow = swallow;
01215         RotorBrowserContext::SetGlobalShotSwallow(swallow);
01216         if (swallow)
01217             ShowStatusStr("Bookmarked shots", "hidden", oglDARKRED);
01218         else
01219             ShowStatusStr("Bookmarked shots", "shown", oglDARKGREEN);
01220     }
01221 
01222     void ToggleShotSwallowThread()
01223     {
01224         ThreadVirtual *v = (ThreadVirtual*)GetThreadByName("virtual_hidden");
01225         Thread *positive = GetThreadByName("bookmarked");
01226         Thread *negative = GetThreadByName("bookmarked_negative");
01227 
01228         SetEnableShotSwallow(true);
01229         
01230         if (!v)
01231             return;
01232         if (v->HasThread(positive) && v->HasThread(negative))
01233         {
01234             v->RemoveThread(positive);
01235             ShowStatusStr("Hide shots", "only negative", oglDARKRED);
01236             return;
01237         }
01238         if (v->HasThread(negative))
01239         {
01240             v->RemoveThread(negative); 
01241             v->AddThread(positive);
01242             ShowStatusStr("Hide shots", "only positive", oglDARKGREEN);
01243             return;
01244         }
01245         if (v->HasThread(positive)) {
01246             v->AddThread(negative);
01247             ShowStatusStr("Hide shots","both positive and negative",0xffdddd22);
01248             return;
01249         }
01250     }
01251 
01252     void SetKeepCenterCentered(bool centercentered)
01253     {
01254         if (mBrowseMode==MODE_FORKBROWSER)
01255         {
01256             ShowStatusStr("Center shot stays in center",
01257                           "N/A in ForkBrowser mode", 0xffdddd22);
01258             return;
01259         }
01260         mKeepCenterCentered = centercentered;
01261         ShowStatusStr("Center Shot stays in center", mKeepCenterCentered);
01262 
01263         
01264         if (mKeepCenterCentered)
01265         {
01266             RotorBrowserContext::SetGlobalShotSwallow(true);
01267             if (mActiveContext) 
01268                 mActiveContext->SetSwallowMode(RotorBrowserContext::SWALLOW_ALL);
01269         }
01270         else
01271             RotorBrowserContext::SetGlobalShotSwallow(mEnableShotSwallow);
01272     }
01273 
01274     
01275 
01276 
01277 
01278 
01279     void UpdateViewsToContext()
01280     {
01281         if (mBusyManaging)
01282             return;
01283 
01284         if (mClusterSelector->IsActive())
01285         {
01286             
01287             
01288             return;
01289         }
01290         if (mManageContexts)
01291             ManageContexts();
01292 
01293         RotorBrowserContext* time;
01294         if (mPrograms && (time = GetContext("time")))
01295         {
01296             String shotTitle = mPrograms->GetTitleForShot(time->GetCenter());
01297             time->SetNiceName("time: " + shotTitle);
01298         }
01299 
01300         int cPos = mActiveContext->GetCenter();
01301         if (mActiveContext->GetName() == "shots_initialquery")
01302             mInitialQueryPosition = cPos;
01303         mCache->DoHide(mCache->GetViews());
01304         mActiveContext->UpdateViewsToContext();
01305         if (cPos >= 0)
01306         {
01307             
01308             mDocument->GotoKeyfr(mThreadSet->GetKeyframes()->GetShotRKF(cPos));
01309             UpdateTrails(); 
01310             if (mTrailVisited)
01311                 mTrailVisited->Push(cPos);
01312         }
01313 
01314         RotorBrowserContextList::const_iterator context;
01315 
01316         RotorBrowserContext *matchcontext;
01317 
01318         
01319         if (mBrowseMode == MODE_ROTORBROWSER)
01320         {
01321             matchcontext = mActiveContext;
01322             for (context=mContexts.begin(); context!=mContexts.end(); context++)
01323                 (*context)->UpdateViewsToContext(matchcontext);
01324         }
01325         else if (mBrowseMode == MODE_CROSSBROWSER)
01326         {
01327             matchcontext = GetContext("shots_initialquery");
01328             for (context=mContexts.begin(); context!=mContexts.end(); context++)
01329                 (*context)->UpdateViewsToContext(matchcontext);
01330         }
01331         else if (mBrowseMode == MODE_FORKBROWSER)
01332             UpdateForkContexts();
01333 
01334         mCache->DoCleanup(mCache->GetViews());
01335 
01336         UpdateViewedShotBookmarks();
01337     }
01338 
01339     void UpdateForkContexts()
01340     {
01341 
01342         
01343         Thread* visual = GetThreadByName("visual_vissemgabor");
01344         ((ThreadVisualSimilarity*)visual)->SetMaxReturned(100);
01345 
01346         Thread* conceptual = GetThreadByName("visual_vissem");
01347         ((ThreadVisualSimilarity*)conceptual)->SetMaxReturned(100);
01348 
01349         if (mTrailVisibleVisualA && mTrailVisibleVisualB)
01350         {
01351             mTrailVisibleVisualA->AddThread(visual, 9);
01352             mTrailVisibleVisualB->AddThread(conceptual, 9);
01353         }
01354 
01355         
01356         RotorBrowserContextList::const_iterator context;
01357         for (context = mContexts.begin(); context != mContexts.end(); context++)
01358         {
01359             if ((*context)->GetName() == "shots_initialquery")
01360                 (*context)->UpdateViewsToContext(*context);
01361             else if ((*context)->GetName() == "history")
01362             {
01363                 
01364                 (*context)->GoLast();
01365                 (*context)->UpdateViewsToContext(*context);
01366             }
01367             else
01368                 (*context)->UpdateViewsToContext(mActiveContext);
01369         }
01370     }
01371 
01372     void Redraw()
01373     {
01374         UpdateViewsToContext();
01375     }
01376 
01377     
01378 
01379 
01380     void RegisterShotTrails(VideoMinimap *map)
01381     {
01382         mTrailBookmarks =
01383             new ShotTrail("bookmarks", 1000, Vec3Int32(0,128,0), 0.0);
01384         mTrailVisibleTime =
01385             new ShotTrail("visible_time", 20, Vec3Int32(0,255,0), 0.05);
01386         mTrailVisibleQuery =
01387             new ShotTrail("visible_query", 100, Vec3Int32(255,0,255), 0.01);
01388         mTrailVisibleVisualA =
01389             new ShotTrail("visible_visualA", 10, Vec3Int32(255,255,0), 0.1);
01390         mTrailVisibleVisualB =
01391             new ShotTrail("visible_visualB", 10, Vec3Int32(255,255,0), 0.1);
01392         mTrailVisited =
01393             new ShotTrail("visited", 80000, Vec3Int32(64,64,64), 0.001);
01394         mTrailHistory =
01395             new ShotTrail("history", 100, Vec3Int32(255, 0, 0), 0.01);
01396         map->RegisterTrail(mTrailVisited);
01397         map->RegisterTrail(mTrailVisibleTime);
01398         map->RegisterTrail(mTrailVisibleVisualA);
01399         map->RegisterTrail(mTrailVisibleVisualB);
01400         map->RegisterTrail(mTrailVisibleQuery);
01401         map->RegisterTrail(mTrailHistory);
01402         map->RegisterTrail(mTrailBookmarks);
01403         mMinimapEnabled = true;
01404     }
01405 
01406     void ClearTrails()
01407     {
01408         ClearVisibleTrails();
01409         if (mTrailBookmarks)
01410             mTrailBookmarks->Clear();
01411         if (mTrailHistory)
01412             mTrailHistory->Clear();
01413         if (mTrailVisited)
01414             mTrailVisited->Clear();
01415     }
01416 
01417     void ClearVisibleTrails()
01418     {
01419         if (mTrailVisibleVisualA)
01420             mTrailVisibleVisualA->Clear();
01421         if (mTrailVisibleVisualB)
01422             mTrailVisibleVisualB->Clear();
01423         if (mTrailVisibleTime)
01424             mTrailVisibleTime->Clear();
01425         if (mTrailVisibleQuery)
01426             mTrailVisibleQuery->Clear();
01427     }
01428 
01429     void UpdateTrails()
01430     {
01431         if (!mMinimapEnabled)
01432             return;
01433 
01434         
01435         ClearVisibleTrails();
01436 
01437         String cName = mActiveContext->GetName();
01438         
01439         if (mTrailVisibleQuery && cName == "shots_initialquery")
01440             mTrailVisibleQuery->AddBrowserContext(mActiveContext, 100);
01441 
01442         if (mTrailVisibleTime && cName == "time")
01443             mTrailVisibleTime->AddBrowserContext(mActiveContext, 20, true);
01444 
01445         
01446         RotorBrowserContextList::iterator context;
01447         for (context = mContexts.begin(); context != mContexts.end(); context++)
01448         {
01449             if ((*context)->GetName() == "shots_initialquery")
01450             {
01451                 if (mTrailVisibleQuery)
01452                     mTrailVisibleQuery->AddBrowserContext(*context, 100);
01453             }
01454             else if ((*context)->GetName() == "time")
01455             {
01456                 if (mTrailVisibleTime)
01457                     mTrailVisibleTime->AddBrowserContext(*context, 20, true);
01458             }
01459         }
01460     }
01461 
01462     void ClearViewedCache()
01463     {
01464         mCache->ClearShotViewed();
01465     }
01466 
01467     bool ShotHasBeenDumpedByTrecvidAtTheLastMinute(int shotid)
01468     {
01469     switch (mThreadSet->GetSegmentation()->GetVideoId(shotid))
01470         {
01471             case 22:  
01472             case 158: 
01473             case 187: 
01474             case 198: 
01475             case 407: 
01476             case 514: 
01477             case 543: 
01478                 return true;
01479         default:
01480             return false;
01481         }
01482     }
01483 
01484     void BookmarkActiveCenter()
01485     {
01486         if (ShotHasBeenDumpedByTrecvidAtTheLastMinute(mActiveContext->GetCenter()))
01487         {
01488             ILOG_WARN("Shot " << mActiveContext->GetCenter() << " has been dumped by trecvid, not bookmarked.");
01489             return;
01490         }
01491         if (mDocument->AddCursorToBookmarked())
01492         {
01493             int shot = mActiveContext->GetCenter();
01494             if (mRotorBrowserListener)
01495                 mRotorBrowserListener->BookmarkEvent(this,shot,true);
01496             RemoveSpecificNegative(shot);
01497             ILOG_DEBUG( "Bookmarked active center " << shot << " POSITIVE." );
01498             RotorView* bookmarked =
01499                 mCache->GetViewFor(mActiveContext->GetName(),shot);
01500             bookmarked->Rename("bookmarked");
01501             bookmarked->MoveTo(1.0f, -1.0f, -2.0f, 1.0f, 1.0f);
01502             bookmarked->UpdateBookmarkState();
01503 
01504             if (mTrailBookmarks)
01505                 mTrailBookmarks->Push(shot);
01506         }
01507     }
01508 
01509     void BookmarkActiveCenterNegative()
01510     {
01511         BookmarkSpecificNegative(mActiveContext->GetCenter());
01512     }
01513 
01514     void BookmarkActiveCenterEx(bool positive)
01515     {
01516         if (positive)
01517             BookmarkActiveCenter();
01518         else
01519             BookmarkActiveCenterNegative();
01520     }
01521 
01522     void BookmarkSpecific(int shotID)
01523     {
01524         if (ShotHasBeenDumpedByTrecvidAtTheLastMinute(shotID))
01525         {
01526             ILOG_WARN("Shot " << shotID << " has been dumped by trecvid, not bookmarked.");
01527             return;
01528         }
01529 
01530         if (shotID < 0)
01531             return;
01532         int active = mDocument->CurKeyfr();
01533         mDocument->GotoKeyfr(mThreadSet->GetKeyframes()->GetShotRKF(shotID));
01534         if (mDocument->AddCursorToBookmarked())
01535         {
01536             if (mRotorBrowserListener)
01537                 mRotorBrowserListener->BookmarkEvent(this, shotID, true);
01538             RemoveSpecificNegative(shotID);
01539             ILOG_DEBUG("Bookmarked specific shot " << shotID << " POSITIVE.");
01540 
01541             if (mTrailBookmarks)
01542                 mTrailBookmarks->Push(shotID);
01543         }
01544         mDocument->GotoKeyfr(active);
01545     }
01546 
01547     void BookmarkSpecificNegative(int shotID)
01548     {
01549         if (shotID < 0)
01550             return;
01551         ThreadBookmarked *b;
01552         if (b = (ThreadBookmarked*)GetThreadByName("bookmarked_negative"))
01553         {
01554             int keyframe = mThreadSet->GetKeyframes()->GetShotRKF(shotID);
01555             b->AddShot(shotID, keyframe);
01556             ILOG_DEBUG( "Bookmarked specific shot " << shotID << " NEGATIVE." );
01557         }
01558         RemoveSpecific(shotID);
01559     }
01560 
01561     void BookmarkSpecificEx(int shotID, bool positive=true)
01562     {
01563         if (positive)
01564             BookmarkSpecific(shotID);
01565         else
01566             BookmarkSpecificNegative(shotID);
01567     }
01568 
01569     void RemoveSpecificNegative(int shotid)
01570     {
01571         ThreadBookmarked *b;
01572         if (b = (ThreadBookmarked*)GetThreadByName("bookmarked_negative"))
01573             b->RemoveShot(shotid);
01574     }
01575 
01576     void RemoveSpecific(int shotid)
01577     {
01578         ThreadBookmarked *b = (ThreadBookmarked*)GetThreadByName("bookmarked");
01579         if (b)
01580             b->RemoveShot(shotid);
01581         if (mRotorBrowserListener)
01582             mRotorBrowserListener->BookmarkEvent(this, shotid, false);
01583     }
01584 
01585     
01586 
01587 
01588     void DoBookmarkCluster(bool markPositive, bool force)
01589     {
01590         if (!mClusterSelector->IsActive()) return;
01591 
01592         ThreadBookmarked *positive =
01593             (ThreadBookmarked*)GetThreadByName("bookmarked");
01594         ThreadBookmarked *negative =
01595             (ThreadBookmarked*)GetThreadByName("bookmarked_negative");
01596 
01597         std::vector<int> shots = mClusterSelector->GetSelectedShots();
01598         ILOG_SYSTEM("cluster bookmarking " << shots.size() <<
01599                     " shots as " << (markPositive ? "POSITIVE" : "NEGATIVE"));
01600         for (int i=0; i<shots.size(); i++)
01601         {
01602             if (markPositive  && (force || !negative->Contains(shots[i])))
01603                     BookmarkSpecific(shots[i]);
01604             if (!markPositive && (force || !positive->Contains(shots[i])))
01605                     BookmarkSpecificNegative(shots[i]);
01606         }
01607         mClusterSelector->Show(mActiveContext);
01608     }
01609 
01610     void UpdateViewedShotBookmarks()
01611     {
01612         Impala::Core::Table::AnnotationTable *t = mCache->GetViewedShots();
01613         ThreadBookmarked *positive =
01614             (ThreadBookmarked*)GetThreadByName("bookmarked");
01615         ThreadBookmarked *negative =
01616             (ThreadBookmarked*)GetThreadByName("bookmarked_negative");
01617         if (!positive || !negative) return;
01618 
01619         int ctr = 0, booked = 0;
01620         for (int i=0; i < t->Size(); i++)
01621         {
01622             if (!t->IsPositive(i))
01623                 continue;
01624             ctr++;
01625             int shot = mThreadSet->GetSegmentation()->GetShotId(t->Get1(i));
01626 
01627             if (!positive->Contains(shot) && !negative->Contains(shot))
01628             {
01629                 int keyframe = mThreadSet->GetKeyframes()->GetShotRKF(shot);
01630                 negative->AddShot(shot, keyframe);
01631                 booked ++;
01632             }
01633         }
01634         if (booked)
01635             ILOG_DEBUG("GetViewedShots(): " << ctr << " shots viewed, " <<
01636                        booked << " new bookmarks.");
01637     }
01638 
01639     void ShowHideStill(RotorView* v, bool show)
01640     {
01641         if (show)
01642             v->SetShowStills(mStills,mDocument->GetImSetStills());
01643         else
01644             v->SetHideStills();
01645     }
01646 
01647     void StartStopStills(bool start)
01648     {
01649         if (mAutoStills == STILLS_NONE)
01650             return;
01651 
01652         RotorView*  v;
01653         String      cName = mActiveContext->GetName();
01654         if (mClusterSelector->IsActive())
01655         {
01656             std::vector<int> shots = mClusterSelector->GetVisibleShots();
01657             for (int i=0; i<shots.size(); i++)
01658                 if (v = mCache->FindViewFor(cName,shots[i]))
01659                     ShowHideStill(v,start);
01660             return;
01661         }
01662 
01663         if (mAutoStills == STILLS_CENTER)
01664         {
01665             if (v = mCache->FindViewFor(cName,mActiveContext->GetCenter()))
01666                 ShowHideStill(v,start);
01667         }
01668         if (mAutoStills == STILLS_NEARCENTER)
01669         {
01670             for (int i=-2; i<=+2; i++)
01671                 if(v=mCache->FindViewFor(cName,mActiveContext->GetRelative(i)))
01672                     ShowHideStill(v,start);
01673         }
01674         if (mAutoStills == STILLS_ACTIVE)
01675         {
01676             int depth = mActiveContext->GetDepth();
01677             for (int i = -depth; i<= depth; i++)
01678                 if(v=mCache->FindViewFor(cName,mActiveContext->GetRelative(i)))
01679                     ShowHideStill(v,start);
01680         }
01681         if (mAutoStills == STILLS_ALL)
01682         {
01683             RotorViewList views = mCache->GetViews();
01684             RotorViewList::const_iterator i;
01685             for (i=views.begin(); i != views.end(); i++)
01686                 if ((*i)->IsCurrentlyShown())
01687                     ShowHideStill(*i,start);
01688         }
01689     }
01690 
01691     void StartStills()
01692     {
01693         StartStopStills(true);
01694     }
01695     void StopStills()
01696     {
01697         StartStopStills(false);
01698     }
01699 
01700     int AutoStills()
01701     {
01702         return mAutoStills;
01703     }
01704 
01705     void AutoStills(int mode)
01706     {
01707         StopStills();
01708         mAutoStills = mode;
01709         if (mAutoStills > STILLS_ALL)
01710             mAutoStills = STILLS_NONE;
01711         StartStills();
01712         String title = "Shot still player";
01713         switch (mAutoStills)
01714         {
01715             case STILLS_NONE:
01716                 ShowStatusStr(title,false); break;
01717             case STILLS_CENTER:
01718                 ShowStatusStr(title,"center shot only",oglDARKGREEN); break;
01719             case STILLS_NEARCENTER:
01720                 ShowStatusStr(title,"local area",oglDARKGREEN); break;
01721             case STILLS_ACTIVE:
01722                 ShowStatusStr(title,"active thread",oglDARKGREEN); break;
01723             case STILLS_ALL:
01724                 ShowStatusStr(title,"all shots",oglDARKGREEN); break;
01725         }
01726     }
01727 
01728 
01729     void ToggleAutoStills()
01730     {
01731         AutoStills(++mAutoStills);
01732     }
01733 
01734     void ToggleEnableVideoStream()
01735     {
01736         RotorView*  v;
01737         String      cName = mActiveContext->GetName();
01738         if (mClusterSelector->IsActive())
01739         {   
01740             std::vector<int> shots = mClusterSelector->GetVisibleShots();
01741             for (int i=0; i<shots.size(); i++)
01742             {
01743                 if (!(v = mCache->FindViewFor(cName,shots[i])))
01744                     continue;
01745                 if (v->GetVideoStillsEnabled())
01746                     v->DisableVideoStills();
01747                 else
01748                     v->EnableVideoStills(mDocument);
01749             }
01750             return;
01751         }
01752 
01753         if (v = mCache->FindViewFor(cName,mActiveContext->GetCenter()))
01754         {
01755             bool enabled = v->GetVideoStillsEnabled();
01756             if (enabled)
01757                 v->DisableVideoStills();
01758             else
01759                 v->EnableVideoStills(mDocument);
01760             ShowStatusStr("Center shot video player",!enabled);
01761         }
01762     }
01763 
01764     void TogglePlayUntilEnd()
01765     {
01766         if (mClusterSelector->IsActive())
01767             return;
01768 
01769         RotorView* center = mCache->FindViewFor(mActiveContext->GetName(), 
01770                                                 mActiveContext->GetCenter());
01771         if (center)
01772             center->SetPlayUntilEnd(!center->GetPlayUntilEnd());
01773         ShowStatusStr("Center shot plays until end of video",
01774                                    center->GetPlayUntilEnd());
01775     }
01776 
01777     void StopAutoStills()
01778     {
01779         StopStills();
01780         mAutoStills = STILLS_NONE;
01781         StartStills();
01782     }
01783 
01784     void TakeFocus()
01785     {
01786         oglFocusWnd = GetOGLWND();
01787         CheckFocus();
01788     }
01789 
01790     void ClusterSelect()
01791     {
01792         
01793         if (!mClusterSelector->IsActive())
01794         {
01795             ILOG_DEBUG("ClusterSelect(): showing...");
01796             mClusterSelector->Show(mActiveContext);
01797             if (mActiveContext->GetThread()->GetType() == Thread::VISUAL)
01798                 mClusterSelector->SetPagemode(false);
01799             else
01800                 mClusterSelector->SetPagemode(true);
01801         }
01802         else
01803         {
01804             ILOG_DEBUG("ClusterSelect(): hiding...");
01805             mClusterSelector->Hide();
01806         }
01807     }
01808 
01809     Thread* GetThreadByName(CString name)
01810     {
01811         return mThreadSet->GetThreadByName(name);
01812     }
01813 
01814     virtual void
01815     OnRectangleSelect(int shotID, float x, float y, float w, float h)
01816     {
01817         ILOG_DEBUG("OnRectangleSelect: shot ID="<<shotID<<" x=" << x <<
01818                    " y=" << y << " w=" << w << " h=" << h);
01819         int keyframe = mThreadSet->GetKeyframes()->GetShotRKF(shotID);
01820         DoQueryByRegion(keyframe, x, y, w, h);
01821     }
01822 
01823     virtual void OnRectangleSelectByKeyframe(int keyframeID, float x, float y,
01824                                              float w, float h)
01825     {
01826         ILOG_DEBUG("OnRectangleSelect: keyframe ID="<<keyframeID<<" x=" <<
01827                    x << " y=" << y << " w=" << w << " h=" << h);
01828         DoQueryByRegion(keyframeID, x, y, w, h);
01829     }
01830 
01831     bool ValidateContext(CString name)
01832     {
01833         RotorBrowserContext* ctx = GetContextByName(name);
01834         if (!ctx || !ctx->ThreadValid())
01835             return false;
01836         return true;
01837     }
01838 
01839 private:
01840     void InitHelp()
01841     {
01842         int w = WndWidth(), h = WndHeight();
01843         if (w < 600 || h < 200)
01844             mHelpViewer = new GUI::HelpViewer(this,0,0,w,h);
01845         else
01846             mHelpViewer = new GUI::HelpViewer(this,(w-600)/2,60,600,h-120);
01847         mHelpViewer->ConnectTo(this);
01848         mHelpViewer->SetVisible(false);
01849     }
01850 
01851     void ShowStatusStr(String s1, String s2, ULONG col=0)
01852     {
01853         if (!mStatusOverlay) return;
01854 
01855         mStatusOverlay->ShowStatus(s1,s2,col);
01856     }
01857 
01858     void ShowStatusStr(String s1, bool mode)
01859     {
01860         if (!mStatusOverlay) return;
01861 
01862         mStatusOverlay->ShowStatus(s1,mode);
01863     }
01864 
01865     void Printf3D(float x, float y, float z,
01866                   float scaleX, float scaleY, float scaleZ, String str)
01867     {
01868         glPushMatrix();
01869         int fBase = mFontHandler->GetFontBase(this);
01870         oglSys.Printf3D(fBase,x,y,z,scaleX,scaleY,scaleZ,str.c_str());
01871         glPopMatrix();
01872     }
01873 
01874     void DoReturnToFirstQuery()
01875     {
01876         if (!mHasReturnQuery) return;
01877 
01878         mThreadSet->RemoveThread("shots_initialquery");
01879         Thread* t = GetThreadByName("shots_returnquery");
01880         mThreadSet->CopyToShotsThread(t,"initialquery");
01881         ILOG_DEBUG("Returning to previous query, position = "<<mReturnPosition);
01882         mHasReturnQuery = false;
01883         UpdateViewsToContext();
01884         ReloadCrossBrowser(mReturnPosition);
01885     }
01886 
01887     void DoShowBookmarksThread()
01888     {
01889         
01890         if (mHasReturnQuery)
01891         {
01892             DoReturnToFirstQuery();
01893             return;
01894         }
01895         
01896         Thread* t = GetThreadByName("bookmarked");
01897         if (t->GetLength()<1) return;
01898 
01899         ClearReturnQuery();
01900         if (!mHasReturnQuery)
01901         {
01902             t = GetThreadByName("shots_initialquery");
01903             mThreadSet->CopyToShotsThread(t,"returnquery");
01904             mHasReturnQuery = true;
01905             mReturnPosition = GetContext("shots_initialquery")->GetCenter();
01906             ILOG_DEBUG("Stored return query with position " << mReturnPosition);
01907         }
01908         mThreadSet->RemoveThread("shots_initialquery");
01909         mThreadSet->CopyToShotsThread(GetThreadByName("bookmarked"), 
01910                                       "initialquery");
01911         ILOG_DEBUG("Showing bookmark thread");
01912         UpdateViewsToContext();
01913         mActiveContext->GoFirst();
01914         UpdateViewsToContext();
01915     }
01916 
01917     void ClearReturnQuery()
01918     {
01919         mThreadSet->RemoveThread("shots_returnquery");
01920         mHasReturnQuery = false;
01921         mReturnPosition = 0;
01922     }
01923 
01924     void DoVisualQuery(String type)
01925     {
01926         if (mBrowseMode == MODE_FORKBROWSER)
01927         {
01928             ILOG_WARN("DoVisualQuery redundant in ForkBrowser, not executing.");
01929             return;
01930         }
01931 
01932         int active = mActiveContext->GetCenter();
01933 
01934         String tname = "vis_" + type + "_" + MakeString(active);
01935         if (mBrowseMode==MODE_ROTORBROWSER && GetThreadByName("shots_"+tname))
01936         {
01937             ILOG_WARN("DoVisualQuery: thread " << tname << " already exists." );
01938             return;
01939         }
01940 
01941         active = mThreadSet->GetKeyframes()->GetShotRKF(active);
01942         std::list<KeyframeResult> visual =
01943             mVisualQueryEngine->QueryVisual(type, active);
01944         if (visual.empty())
01945         {
01946             ILOG_WARN("DoVisualQuery: " << type << " no results");
01947             return;
01948         }
01949 
01950         if (mBrowseMode == MODE_CROSSBROWSER)
01951         {
01952             ClearReturnQuery();
01953             if (!mHasReturnQuery)
01954             {
01955                 Thread* t = GetThreadByName("shots_initialquery");
01956                 mThreadSet->CopyToShotsThread(t,"returnquery");
01957                 mHasReturnQuery = true;
01958                 mReturnPosition = GetContext("shots_initialquery")->GetCenter();
01959                 ILOG_DEBUG("Stored return query with position " <<
01960                            mReturnPosition);
01961             }
01962             mThreadSet->RemoveThread("shots_initialquery");
01963             mThreadSet->AddThreadShots("initialquery", visual);
01964             ReloadCrossBrowser();
01965             UpdateViewsToContext();
01966             return;
01967         }
01968 
01969         
01970         mThreadSet->AddThreadShots(tname, visual);
01971         UpdateViewsToContext();
01972         SwitchToContext("shots_" + tname);
01973         UpdateViewsToContext();
01974     }
01975 
01976 
01977 
01978 
01979 
01980 
01981 
01982 
01983 
01984 
01985 
01986 
01987 
01988 
01989 
01990 
01991 
01992 
01993 
01994 
01995 
01996 
01997 
01998 
01999 
02000 
02001 
02002 
02003 
02004 
02005 
02006 
02007 
02008 
02009 
02010 
02011 
02012 
02013 
02014 
02015 
02016 
02017 
02018 
02019 
02020 
02021 
02022 
02023 
02024 
02025 
02026 
02027     void
02028     DoQueryByRegion(int keyframeID, float x, float y, float w, float h)
02029     {
02030         ILOG_DEBUG("DoQueryByRegion: keyframe ID="<<keyframeID<<" x=" << x
02031                    << " y=" << y << " w=" << w << " h=" << h);
02032 
02033         if (mBrowseMode == MODE_FORKBROWSER) {
02034             ILOG_ERROR("Handling of Query By Region queries in ForkBrowser " <<
02035                        "not yet implemented.");
02036             return;
02037         }
02038 
02039         if (mBrowseMode == MODE_CROSSBROWSER)
02040         {
02041             std::list<KeyframeResult> qbyr =
02042                 mVisualQueryEngine->QueryByRegion(keyframeID,x,y,x+w,y+h);
02043             if (qbyr.size() > 1)
02044             {
02045                 ILOG_DEBUG("Got "<<qbyr.size()<<" results from webservice.");
02046                 std::ostringstream bla;
02047                 bla << "Found " << qbyr.size() << " query by region results.";
02048                 ShowStatusStr("Query by Region",bla.str(),oglGREEN);
02049                 mThreadSet->RemoveThread("shots_initialquery");
02050                 mThreadSet->AddThreadShots("initialquery", qbyr);
02051                 UpdateViewsToContext();
02052                 ReloadCrossBrowser();
02053             }
02054             else
02055             {
02056                 ILOG_DEBUG("Got no results from webservice.");
02057                 char *t = "No query by region result found for this selection.";
02058                 ShowStatusStr("Error",t,oglRED);
02059             }
02060             return;
02061         }
02062         String tname = "qbyr_" + MakeString(keyframeID);
02063         if (GetThreadByName("shots_" + tname) != NULL)
02064             ILOG_WARN( "thread " << tname << " already exists." );
02065 
02066         std::list<KeyframeResult> qbyr =
02067             mVisualQueryEngine->QueryByRegion(keyframeID,x,y,x+w,y+h);
02068 
02069         mThreadSet->AddThreadShots(tname, qbyr);
02070         UpdateViewsToContext();
02071         SwitchToContext("shots_" + tname);
02072         UpdateViewsToContext();
02073     }
02074 
02075     void AddRelevantContexts()
02076     {
02077         int active = mActiveContext->GetCenter();
02078         ILOG_DEBUG("Searching for relevant contexts for " <<
02079                     mActiveContext->GetName());
02080         TableThreadWidthId *queue =
02081             new TableThreadWidthId(mThreadSet->GetNrThreads());
02082         for (int i=0; i < mThreadSet->GetNrThreads(); i++)
02083         {
02084             Thread *t = mThreadSet->GetThread(i);
02085             if (t->GetName() == "shots_videos")
02086                 continue;
02087             if (t->GetType() == Thread::RANK && !mShowRankThreads)
02088                 continue;
02089             int relevancy = IsRelevant(t, active);
02090             if (relevancy > 0)
02091                 queue->Add(relevancy, t);
02092         }
02093         
02094         Impala::Core::Table::Sort(queue, 1, true); 
02095 
02096         for (int i=0; i < queue->Size(); i++)
02097         {
02098             if (i > 4 && queue->Get1(i) > 3)
02099                 break;
02100             if (i > 6)
02101                 break;
02102             AddContext(queue->Get2(i), active);
02103         }
02104         
02105         delete queue;
02106         ILOG_DEBUG( " end of relevant context search." );
02107     }
02108 
02109     
02110 
02111 
02112 
02113 
02114 
02115 
02116 
02117     int IsRelevant(Thread *t, int position)
02118     {
02119         switch (t->GetType())
02120         {
02121             case Thread::VISUAL:
02122             case Thread::BOOKMARK:
02123             case Thread::HISTORY:
02124                 return 0;
02125             case Thread::TIME:
02126                 return 1;
02127             case Thread::SHOTS:
02128                 if (t->GetName() == "shots_initialquery") return 1;
02129                 if (t->GetName() == "shots_supplement")   return 0;
02130                 if (t->GetName().find("vis_") != String::npos)
02131                 {
02132                     if (t->GetShotPosition(position) < mTopN &&
02133                         t->GetShotPosition(position) >= 0)
02134                         return 2;
02135                     return 0;
02136                 }
02137                 return 3;
02138             default:
02139                 int pos = t->GetShotPosition(position);
02140                 if (pos >=0 && pos < mTopN)
02141                     return pos+4;
02142                 
02143                 if (pos > 0 && pos < 79484 &&
02144                     t->GetName().find("rank_thread_all") != String::npos)
02145                     return 3;
02146         }
02147         return 0;
02148     }
02149 
02150     void ManageContexts()
02151     {
02152         if (mBrowseMode == MODE_ROTORBROWSER)
02153             return ManageRotorContexts();
02154     }
02155 
02156     void ManageRotorContexts()
02157     {
02158         mBusyManaging = true;
02159 
02160         
02161         RotorBrowserContextList newposition;
02162 
02163         
02164         RotorBrowserContextList::iterator context;
02165         for (context=mContexts.begin(); context!=mContexts.end(); context++)
02166         {
02167             if ((*context)->GetName() == "time" ||
02168                 IsRelevant((*context)->GetThread(),mActiveContext->GetCenter()))
02169             {
02170                 
02171                 newposition.push_back(*context);
02172                 if (mManageDepth)
02173                     (*context)->SetDepth(4);
02174                 continue;
02175             }
02176             delete (*context);
02177         }
02178         mContexts.clear();
02179         mContexts = newposition; 
02180         AddRelevantContexts();
02181 
02182         if (mManageDepth)
02183             mActiveContext->SetDepth(6);
02184         mBusyManaging = false;
02185         RepositionContexts();
02186     }
02187 
02188     Thread* GetInitBrowserThread(char* str)
02189     {
02190         ILOG_SYSTEM("Init " << str);
02191         Thread *query = GetThreadByName("shots_initialquery");
02192         if (query == NULL || query->GetLength() == 0)
02193         {
02194             ILOG_WARN("tried to inialize " << str << " but no initial " <<
02195                       "query present. Aborting." );
02196             SetBrowseMode(MODE_ROTORBROWSER);
02197         }
02198         return query;
02199     }
02200 
02201     int CheckInitBrowserFirstShot(Thread* query, char* str)
02202     {
02203         int pos;
02204         if ((pos = query->GetFirstShot()) < 0)
02205         {
02206             ILOG_WARN("tried to inialize " << str << " but initial " <<
02207                       "query has no first shot. Switching to RotorBrowser." );
02208             SetBrowseMode(MODE_ROTORBROWSER);
02209         }
02210         return pos;
02211     }
02212 
02213     void InitCrossBrowser(int startposition = -1)
02214     {
02215         Thread* query = GetInitBrowserThread("CrossBrowser");
02216         if (!query) return;
02217 
02218         int pos = mActiveContext ? mActiveContext->GetCenter() : 0;
02219         if (pos == 0)
02220         {
02221             if ((pos = CheckInitBrowserFirstShot(query,"CrossBrowser")) < 0)
02222                 return;
02223             if (startposition >= 0)
02224                 pos = startposition;
02225             ILOG_DEBUG("setting up CrossBrowser start position at " << pos);
02226         }
02227 
02228         if (mActiveContext != NULL)
02229             delete mActiveContext;
02230 
02231         RotorBrowserContextList::iterator context;
02232         for (context=mContexts.begin(); context!=mContexts.end(); context++)
02233             delete (*context);
02234         mContexts.clear();
02235 
02236         mActiveContext = new RotorBrowserContext(mCache,query,pos,M_PI/2,6);
02237         mActiveContext->SetSwallowThread(GetThreadByName("virtual_hidden"));
02238         mActiveContext->SetSwallowMode(RotorBrowserContext::SWALLOW_ALL);
02239 
02240         RotorBrowserContext *time =
02241             new RotorBrowserContext(mCache,GetThreadByName("time"),pos,0.0,6);
02242         time->SetSwallowThread(GetThreadByName("virtual_hidden"));
02243         time->SetSwallowMode(RotorBrowserContext::SWALLOW_ALL);
02244         mContexts.push_back(time);
02245     }
02246 
02247     void InitForkBrowser()
02248     {
02249         Thread* query = GetInitBrowserThread("ForkBrowser");
02250         if (!query) return;
02251 
02252         RotorBrowserContext::SetGlobalShotSwallow(true);
02253         
02254         mForkLastQueryShot = -1;
02255 
02256         int position = mActiveContext ? mActiveContext->GetCenter() : 0;        
02257         if (position == 0)
02258         {
02259             if ((position = CheckInitBrowserFirstShot(query,"ForkBrowser")) < 0)
02260                 return;
02261             ILOG_DEBUG("setting up ForkBrowser start position at " << position);
02262         }
02263 
02264         
02265         if (mActiveContext != NULL)
02266             delete mActiveContext;
02267 
02268         RotorBrowserContextList::iterator context;
02269         for (context = mContexts.begin(); context != mContexts.end(); context++)
02270             delete (*context);
02271         mContexts.clear();
02272 
02273         Thread* threadHidden = GetThreadByName("virtual_hidden");
02274 
02275         
02276         mActiveContext =
02277             new RotorBrowserContext(mCache, query, position, M_PI/2, 6);
02278         mActiveContext->SetDrawDirection(RotorBrowserContext::DIRECTION_UP);
02279         mActiveContext->SetSwallowThread(threadHidden);
02280         mActiveContext->SetSwallowMode(RotorBrowserContext::SWALLOW_ALL);
02281 
02282         
02283         Thread* threadHistory = GetThreadByName("history");
02284         RotorBrowserContext *history =
02285             new RotorBrowserContext(mCache,threadHistory,position,M_PI/2,6);
02286         history->SetDrawDirection(RotorBrowserContext::DIRECTION_DOWN);
02287         history->SetSwallowThread(threadHidden);
02288         history->SetSwallowMode(RotorBrowserContext::SWALLOW_NONE);
02289         mContexts.push_back(history);
02290 
02291         
02292         RotorBrowserContext *time =
02293            new RotorBrowserContext(mCache,GetThreadByName("time"),position,0,6);
02294         time->SetSwallowThread(threadHidden);
02295         time->SetSwallowMode(RotorBrowserContext::SWALLOW_ALL);
02296         mContexts.push_back(time);
02297 
02298         Thread* visSemGabor = GetThreadByName("visual_vissemgabor");
02299         RotorBrowserContext *visual =
02300             new RotorBrowserContext(mCache,visSemGabor,position,M_PI/4,6);
02301         visual->SetDrawDirection(RotorBrowserContext::DIRECTION_UP);
02302         visual->SetSwallowThread(threadHidden);
02303         visual->SetSwallowMode(RotorBrowserContext::SWALLOW_ALL);
02304         mContexts.push_back(visual);
02305 
02306         Thread* visSem = GetThreadByName("visual_vissem");
02307         RotorBrowserContext *contextual =
02308             new RotorBrowserContext(mCache,visSem,position,M_PI/4+M_PI/2,6);
02309         contextual->SetDrawDirection(RotorBrowserContext::DIRECTION_UP);
02310         contextual->SetSwallowThread(threadHidden);
02311         contextual->SetSwallowMode(RotorBrowserContext::SWALLOW_ALL);
02312         mContexts.push_back(contextual);
02313     }
02314 
02315     void InitRotorBrowser()
02316     {
02317         RotorBrowserContext *query = GetContext("shots_initialquery");
02318         ILOG_SYSTEM( "Init RotorBrowser" );
02319         mInitialQueryPosition = -1;
02320         if (query)
02321             query->SetSwallowMode(RotorBrowserContext::SWALLOW_ALL);
02322         if (mActiveContext)
02323             mActiveContext->SetSwallowMode(RotorBrowserContext::SWALLOW_ALL);
02324     }
02325 
02326     RotorBrowserContext* GetContextByName(String name) 
02327     {
02328         if (mActiveContext->GetName() == name)
02329             return mActiveContext;
02330 
02331         RotorBrowserContextList::iterator context;
02332         for (context=mContexts.begin(); context!=mContexts.end(); context++)
02333         {
02334             if ((*context)->GetName() == name)
02335                 return *context;
02336         }
02337         return NULL;
02338     }
02339 
02340     RotorBrowserContext* FindContextForPosition(int ID)
02341     {
02342         if (mActiveContext->ShowsPosition(ID))
02343             return mActiveContext;
02344 
02345         RotorBrowserContextList::iterator context;
02346         for (context=mContexts.begin(); context!=mContexts.end(); context++)
02347         {
02348             if ((*context)->ShowsPosition(ID))
02349                 return *context;
02350         }
02351         return NULL;
02352     }
02353 
02354     bool HasContext(String name)
02355     {
02356         return GetContextByName(name) != NULL;
02357     }
02358 
02359     bool SwitchToPreviousContext()
02360     {
02361         return SwitchToNextContext(-1);
02362     }
02363 
02364     bool SwitchToNextContext(int direction = +1) 
02365     {
02366         if (mBrowseMode != MODE_ROTORBROWSER)
02367             return false;
02368         if (mContexts.size() == 0)
02369         {
02370             ILOG_DEBUG( "RotorBrowser::SwitchToNextContext: no other contexts");
02371             return false;
02372         }
02373         RotorBrowserContext *next;
02374         if (direction < 0)
02375         {
02376             next = mContexts.back();
02377             mContexts.pop_back();
02378             mContexts.push_front(mActiveContext);
02379         }
02380         else
02381         {
02382             next = mContexts.front();
02383             mContexts.pop_front();
02384             mContexts.push_back(mActiveContext);
02385         }
02386         if (mManageDepth)
02387         {
02388             next->SetDepth(5);
02389             mActiveContext->SetDepth(3);
02390         }
02391         mActiveContext = next;
02392         ILOG_DEBUG("RotorBrowser::SwitchToNextContext: active context now: " <<
02393                    mActiveContext->GetName() );
02394         if (mRotorBrowserListener)
02395             mRotorBrowserListener->ContextChangeEvent(this, mActiveContext);
02396         RepositionContexts();
02397         return true;
02398     }
02399 
02400     bool SwitchToContext(String name)
02401     {
02402         if (mActiveContext && mActiveContext->GetName() == name)
02403             return true;
02404         if (mContexts.size() == 0) {
02405             ILOG_DEBUG( "SwitchToContext: no other contexts found." );
02406             return false;
02407         }
02408         if (mActiveContext == NULL)
02409         {
02410             mActiveContext = mContexts.front();
02411             mContexts.pop_front();
02412             ILOG_WARN("no active context found. Active context set to "
02413                       << mActiveContext->GetName() );
02414         }
02415 
02416         String scontext = mActiveContext->GetName();
02417         int maxr = 0;
02418         while (mActiveContext->GetName() != name)
02419         {
02420             RotorBrowserContext *next = mContexts.front();
02421             mContexts.pop_front();
02422             if (mBrowseMode == MODE_ROTORBROWSER && mManageDepth)
02423             {
02424                 next->SetDepth(5);
02425                 mActiveContext->SetDepth(3);
02426             }
02427             mContexts.push_back(mActiveContext);
02428             mActiveContext = next;
02429             if (mActiveContext->GetName() == scontext && ++maxr==2)
02430                 return false; 
02431         }
02432         ILOG_DEBUG("RotorBrowser::SwitchToContext: active context now: "
02433                    << mActiveContext->GetName() );
02434         if (mRotorBrowserListener)
02435             mRotorBrowserListener->ContextChangeEvent(this, mActiveContext);
02436         RepositionContexts();
02437         return true;
02438     }
02439 
02440     RotorBrowserContext* GetContext(String name)
02441     {
02442         if (mActiveContext->GetName() == name)
02443             return mActiveContext;
02444 
02445         RotorBrowserContextList::iterator context;
02446         for (context=mContexts.begin(); context != mContexts.end(); context++)
02447         {
02448             if ((*context)->GetName() == name)
02449                 return *context;
02450         }
02451         return NULL;
02452     }
02453 
02454     void RepositionContexts()
02455     {
02456         if (mBusyManaging || mBrowseMode != MODE_ROTORBROWSER)
02457             return;
02458 
02459                 if (mActiveHorizontal)
02460                         mActiveContext->SetDirection(0.0);
02461 
02462         double cDi = M_PI / ((double)mContexts.size()+1);
02463                 double cD  = mActiveContext->GetDirection() + cDi;
02464         RotorBrowserContextList::const_iterator context;
02465         for (context=mContexts.begin(); context!=mContexts.end(); context++)
02466         {
02467             (*context)->SetDirection(cD);
02468             cD += cDi;
02469         }
02470     }
02471 
02472     void CheckFocus(bool force=false)
02473     {
02474         bool hasFocus = (GetOGLWND() == oglFocusWnd);
02475         if ((hasFocus && !mHadFocus) || (force && mHadFocus))
02476         {
02477             mHadFocus = true;
02478             if (!force)
02479                 mBackNormal = GetBorderBackground();
02480             if (mBrowseMode == MODE_ROTORBROWSER)
02481                 SetBorderBackground(0x80802020);
02482             else if (mBrowseMode == MODE_FORKBROWSER)
02483                 SetBorderBackground(0x802020A0);
02484             else
02485                 SetBorderBackground(0x80206020);
02486         }
02487         if (!hasFocus && mHadFocus)
02488         {
02489             mHadFocus = false;
02490             SetBorderBackground(mBackNormal);
02491         }
02492     }
02493 
02494     void InitKB(String keyStr, String dfltStr0,
02495                 String dfltStr1="", String dfltStr2="",
02496                 String dfltStr3="", String dfltStr4="",
02497                 String dfltStr5="", String dfltStr6="")
02498     {
02499         KeyBindingsMap& kb = mKeyBindings;
02500         keyStr = mPreFix + keyStr;
02501         InitKeyBinding(kb, keyStr, dfltStr0, dfltStr1, dfltStr2, dfltStr3,
02502                        dfltStr4, dfltStr5, dfltStr6);
02503     }
02504 
02505     void InitKeyBindings()
02506     {
02507         KeyBindingsMap& kb = mKeyBindings;
02508 
02509         InitKB("CsBookPositive",                  "space");
02510         InitKB("CsBookPositiveForce",             "shift#space");
02511         InitKB("CsBookNegative",                  "x");
02512         InitKB("CsBookNegativeForce",             "X");
02513 
02514         InitKB("StdToggleShowBookmarks",          "b");
02515         InitKB("StdStopAutoStills",               "esc");
02516         InitKB("StdToggleAutoStills",             "\t");
02517         InitKB("StdToggleVideoStream",            "1");
02518         InitKB("StdTogglePlayUntilEnd",           "2");
02519         InitKB("StdIncrAutoStillSpeed",           "=");
02520         InitKB("StdDecrAutoStillSpeed",           "-");
02521         InitKB("StdIncrAnimationSpeed",           "]");
02522         InitKB("StdDecrAnimationSpeed",           "[");
02523         InitKB("StdToggleShowHelp",               "h", "H");
02524         InitKB("StdCrossBrowserMode",             "fn5");
02525         InitKB("StdRotorBrowserMode",             "fn6");
02526         InitKB("StdForkBrowserMode",              "fn7");
02527         InitKB("StdToggleShotSwallow",            "`");
02528         InitKB("StdToggleShotSwallowThread",      "~");
02529         InitKB("StdToggleKeepCenterCentered",     ".", "l");
02530         InitKB("StdBookmarkCenterPositive",       "space");
02531         InitKB("StdBookmarkCenterNegative",       "x", "X");
02532         InitKB("StdClusterSelect",                "f", "F");
02533         InitKB("StdClearViewedCache",             "O");
02534         InitKB("StdJudgeBrowseMode",              "ctrl-shift#l");
02535         InitKB("StdToggleAutoSelectNegatives",    "L");
02536 
02537         InitKB("VisualQuery_vissemgabor",         "V");
02538         InitKB("VisualQuery_vissem",              "B");
02539         InitKB("VisualQuery_fusionvissemgabor",   "N");
02540         InitKB("VisualQuery_labhistogram",        "M");
02541 
02542         InitKB("RbGoForward",                     "d");
02543         InitKB("RbGoBackward",                    "a");
02544         InitKB("RbGoFirst",                       "q");
02545         InitKB("RbGoLast",                        "e");
02546         InitKB("RbBookmarkNext",                  "D");
02547         InitKB("RbBookmarkPrev",                  "A");
02548         InitKB("RbSwitchToContextNext",           "w");
02549         InitKB("RbSwitchToContextPrev",           "W");
02550         InitKB("RbSwitchToContextTime",           "t");
02551         InitKB("RbSwitchToContextBookmark",       "T");
02552         InitKB("RbReturnLastInitialQuery",        "r", "R");
02553         InitKB("RbToggleShowRankThreads",         "o");
02554 
02555         InitKB("CbGoFirst",                       "q");
02556         InitKB("CbGoLast",                        "e");
02557         InitKB("CbGoInitialQuery",                "r", "R");
02558         InitKB("CbGoUp",                          "w", "up");
02559         InitKB("CbGoDown",                        "s", "down");
02560         InitKB("CbGoLeft",                        "a", "left");
02561         InitKB("CbGoRight",                       "d", "right");
02562         InitKB("CbBookmarkPrevNegative",          "ctrl#a", "ctrl#left");
02563         InitKB("CbBookmarkNextNegative",          "ctrl#d", "ctrl#right");
02564         InitKB("CbBookmarkPrevPositive",          "A","shift#left");
02565         InitKB("CbBookmarkNextPositive",          "D", "shift#right");
02566         InitKB("CbBookmarkUpNegative",            "ctrl#w", "ctrl#up");
02567         InitKB("CbBookmarkDownNegative",          "ctrl#s", "ctrl#down");
02568         InitKB("CbBookmarkUpPositive",            "W", "shift#up");
02569         InitKB("CbBookmarkDownPositive",          "s", "shift#down");
02570 
02571         InitKB("FbTimeBackward",                  "a", "left");
02572         InitKB("FbTimeForward",                   "d", "right");
02573         InitKB("FbBookmarkPositiveTimeBackward",  "A", "shift#left");
02574         InitKB("FbBookmarkPositiveTimeForward",   "D", "shift#right");
02575         InitKB("FbBookmarkNegativeTimeBackward",  "ctrl#a", "ctrl#left");
02576         InitKB("FbBookmarkNegativeTimeForward",   "ctrl#d", "ctrl#right");
02577         InitKB("FbLastHistory",                   "s", "down");
02578         InitKB("FbBookmarkPositiveHistoryGoLast", "S", "shift#down");
02579         InitKB("FbBookmarkNegativeHistoryGoLast", "ctrl#s","ctrl#down");
02580         InitKB("FbLastQueryShot",                 "r");
02581         InitKB("FbQueryForward",                  "w", "up");
02582         InitKB("FbBookmarkPositiveQueryForward",  "W", "shift#up");
02583         InitKB("FbBookmarkNegativeQueryForward",  "ctrl#w","ctrl#up");
02584         InitKB("FbGaborForward",                  "e");
02585         InitKB("FbBookmarkPositiveGaborForward",  "E");
02586         InitKB("FbBookmarkNegativeGaborForward",  "ctrl#e");
02587         InitKB("FbVissemForward",                 "q");
02588         InitKB("FbBookmarkPositiveVissemForward", "Q");
02589         InitKB("FbBookmarkNegativeVissemForward", "ctrl#q");
02590     }
02591 
02592     void
02593     Init(ThreadSet *threadset, SegmentationDocument *document, String preFix)
02594     {
02595         ILOG_DEBUG("RotorBrowser::init()");
02596         oglSys.SetAllowCameraMove(GetOGLWND(), CamMove_Keys | CamMove_Mouse);
02597 
02598         CmdOptions &options   = CmdOptions::GetInstance();
02599 
02600         mRotorBrowserListener = NULL;
02601         mThreadSet            = threadset;
02602         mDocument             = document;
02603         mPreFix               = options.GetString("RbKeybindingPrefix", preFix);
02604         mPrograms             = 0;
02605 
02606         mBrowseMode           = MODE_ROTORBROWSER;
02607         mAutoStills           = STILLS_NONE;
02608         mBackNormal           = GetBackground();
02609         mTopN                 = 30;
02610         mInitialQueryPosition = -1;
02611         mReturnPosition       = 0;
02612         mDisabledCenterVideo  = -1;
02613 
02614         
02615         mTrailBookmarks       = 0;
02616         mTrailVisited         = 0;
02617         mTrailHistory         = 0;
02618         mTrailVisibleTime     = 0;
02619         mTrailVisibleQuery    = 0;
02620         mTrailVisibleVisualA  = 0;
02621         mTrailVisibleVisualB  = 0;
02622 
02623         mHadFocus             = false;
02624         mShowRankThreads      = false;
02625         mEnableShotSwallow    = false;
02626         mKeepCenterCentered   = false;
02627         mBusyManaging         = false;
02628         mHasReturnQuery       = false;
02629         mActiveHorizontal     = true;
02630         mShowDirection        = true;
02631         mManageContexts       = true;
02632         mManageDepth          = true;
02633 
02634         Thread* timeThr       = GetThreadByName("time");
02635         Thread* hiddenThr     = GetThreadByName("virtual_hidden");
02636 
02637         mFontHandler          = new FontHandler();
02638         mStatusOverlay        = new StatusOverlayWindow(this);
02639         mCache                = new RotorViewCache(this, threadset, this);
02640         mClusterSelector      = new ThreadClusterSelector(mCache);
02641         mVisualQueryEngine    = new VisualQueryEngine(mThreadSet,mTopN*2);
02642         mStills               = new Stills(mDocument->GetVideoSet(),"stills");
02643         mActiveContext        = new RotorBrowserContext(mCache,timeThr,0,0.0,5);
02644 
02645         mActiveContext->SetSwallowThread(hiddenThr);
02646         mActiveContext->SetSwallowMode(RotorBrowserContext::SWALLOW_ALL);
02647 
02648         SetEnableShotSwallow(false);
02649         RotorView::SetStillFrameWait(15);
02650 
02651         InitHelp();
02652         InitKeyBindings();
02653 
02654         
02655         
02656         
02657         SetDisableOGLViewKeys(false);
02658         SetBorderBackground(0x80202020);
02659         
02660     }
02661 
02662     KeyBindingsMap                  mKeyBindings;
02663     String                          mPreFix;
02664 
02665     ThreadSet*                      mThreadSet;
02666     SegmentationDocument*           mDocument;
02667     VisualQueryEngine*              mVisualQueryEngine;
02668     ThreadClusterSelector*          mClusterSelector;
02669     Samples::ProgramNameReader*     mPrograms;
02670     Stills*                         mStills;
02671 
02672     RotorBrowserContextList         mContexts;
02673     RotorBrowserContext*            mActiveContext;
02674     RotorBrowserListener*           mRotorBrowserListener;
02675     RotorViewCache*                 mCache;
02676 
02677     
02678     ShotTrail*                      mTrailVisited;
02679     ShotTrail*                      mTrailBookmarks;
02680     ShotTrail*                      mTrailHistory;
02681     ShotTrail*                      mTrailVisibleTime;
02682     ShotTrail*                      mTrailVisibleQuery;
02683     ShotTrail*                      mTrailVisibleVisualA;
02684     ShotTrail*                      mTrailVisibleVisualB;
02685 
02686     Visualization::GUI::HelpViewer* mHelpViewer;
02687     FontHandler*                    mFontHandler;
02688     StatusOverlayWindow*            mStatusOverlay;
02689 
02690     int                             mTopN;
02691     int                             mBrowseMode;
02692     int                             mForkLastQueryShot;
02693     int                             mInitialQueryPosition;
02694     int                             mReturnPosition;
02695     int                             mAutoStills;
02696 
02697     
02698     
02699     int                             mDisabledCenterVideo;
02700 
02701     bool                            mHadFocus;
02702     bool                            mShowDirection;
02703     bool                            mActiveHorizontal;
02704     bool                            mManageContexts;
02705     bool                            mBusyManaging;
02706     bool                            mManageDepth;
02707     bool                            mEnableShotSwallow;
02708     bool                            mKeepCenterCentered;
02709     bool                            mShowRankThreads;
02710     bool                            mMinimapEnabled;
02711     bool                            mHasReturnQuery;
02712 
02713     ULONG                           mBackNormal;
02714 
02715 public:
02716     static const int MODE_CROSSBROWSER  = 1;
02717     static const int MODE_ROTORBROWSER  = 2;
02718     static const int MODE_FORKBROWSER   = 3;
02719 
02720     static const int STILLS_NONE        = 1;
02721     static const int STILLS_CENTER      = 2;
02722     static const int STILLS_NEARCENTER  = 3;
02723     static const int STILLS_ACTIVE      = 4;
02724     static const int STILLS_ALL         = 5;
02725 
02726     ILOG_VAR_DEC;
02727 
02728 }; 
02729 
02730 ILOG_VAR_INIT(RotorBrowser, Visualization.RotorBrowser);
02731 
02732 } 
02733 } 
02734 } 
02735 #endif
02736