1 // DasherInterfaceBase.cpp
3 // Copyright (c) 2002 Iain Murray
5 #include "../Common/Common.h"
7 #include "DasherInterfaceBase.h"
9 //#include "ActionButton.h"
10 #include "AlphabetManagerFactory.h"
11 #include "DasherViewSquare.h"
12 #include "ControlManager.h"
13 #include "DasherScreen.h"
14 #include "DasherView.h"
15 #include "DasherInput.h"
16 #include "DasherModel.h"
17 #include "EventHandler.h"
19 #include "NodeCreationManager.h"
22 #include "WrapperFactory.h"
25 #include "ClickFilter.h"
26 #include "DefaultFilter.h"
27 #include "DasherButtons.h"
28 #include "DynamicFilter.h"
29 #include "EyetrackerFilter.h"
30 #include "OneDimensionalFilter.h"
31 #include "StylusFilter.h"
32 #include "TwoButtonDynamicFilter.h"
38 // Legacy C library headers
43 // Declare our global file logging object
44 #include "../DasherCore/FileLogger.h"
46 const eLogLevel g_iLogLevel
= logDEBUG
;
47 const int g_iLogOptions
= logTimeStamp
| logDateStamp
| logDeleteOldFile
;
49 const eLogLevel g_iLogLevel
= logNORMAL
;
50 const int g_iLogOptions
= logTimeStamp
| logDateStamp
;
52 CFileLogger
* g_pLogger
= NULL
;
54 using namespace Dasher
;
57 // Track memory leaks on Windows to the line that new'd the memory
60 #define DEBUG_NEW new( _NORMAL_BLOCK, THIS_FILE, __LINE__ )
63 static char THIS_FILE
[] = __FILE__
;
67 CDasherInterfaceBase::CDasherInterfaceBase()
68 :m_Alphabet(0), m_pDasherModel(0), m_DasherScreen(0),
69 m_pDasherView(0), m_pInput(0), m_AlphIO(0), m_ColourIO(0), m_pUserLog(NULL
),
70 m_pInputFilter(NULL
) {
72 m_iCurrentState
= ST_START
;
77 m_bGlobalLock
= false;
79 m_bRedrawScheduled
= false;
81 m_pEventHandler
= new CEventHandler(this);
83 strCurrentContext
= ". ";
85 strTrainfileBuffer
= "";
87 // Global logging object we can use from anywhere
88 g_pLogger
= new CFileLogger("dasher.log",
94 void CDasherInterfaceBase::Realize() {
96 // TODO: What exactly needs to have happened by the time we call Realize()?
97 CreateSettingsStore();
101 std::vector
<std::string
> vAlphabetFiles
;
102 ScanAlphabetFiles(vAlphabetFiles
);
103 m_AlphIO
= new CAlphIO(GetStringParameter(SP_SYSTEM_LOC
), GetStringParameter(SP_USER_LOC
), vAlphabetFiles
);
105 std::vector
<std::string
> vColourFiles
;
106 ScanColourFiles(vColourFiles
);
107 m_ColourIO
= new CColourIO(GetStringParameter(SP_SYSTEM_LOC
), GetStringParameter(SP_USER_LOC
), vColourFiles
);
112 // Create the user logging object if we are suppose to. We wait
113 // until now so we have the real value of the parameter and not
116 // TODO: Sort out log type selection
118 int iUserLogLevel
= GetLongParameter(LP_USER_LOG_LEVEL_MASK
);
120 if(iUserLogLevel
== 10)
121 m_pUserLog
= new CBasicLog(m_pEventHandler
, m_pSettingsStore
);
122 else if (iUserLogLevel
> 0)
123 m_pUserLog
= new CUserLog(m_pEventHandler
, m_pSettingsStore
, iUserLogLevel
, m_Alphabet
);
126 CreateLocalFactories();
130 SetupActionButtons();
132 // FIXME - need to rationalise this sort of thing.
133 InvalidateContext(true);
136 // All the setup is done by now, so let the user log object know
137 // that future parameter changes should be logged.
138 if (m_pUserLog
!= NULL
)
139 m_pUserLog
->InitIsDone();
141 ChangeState(TR_MODEL_INIT
);
144 CDasherInterfaceBase::~CDasherInterfaceBase() {
146 DASHER_ASSERT(m_iCurrentState
== ST_SHUTDOWN
);
148 delete m_pDasherModel
; // The order of some of these deletions matters
150 delete m_pDasherView
;
153 delete m_pInputFilter
;
155 // Do NOT delete Edit box or Screen. This class did not create them.
157 // When we destruct on shutdown, we'll output any detailed log file
158 if (m_pUserLog
!= NULL
)
160 m_pUserLog
->OutputFile();
165 if (g_pLogger
!= NULL
) {
170 // Must delete event handler after all CDasherComponent derived classes
172 delete m_pEventHandler
;
175 void CDasherInterfaceBase::PreSetNotify(int iParameter
, const std::string
&sNewValue
) {
177 // FIXME - make this a more general 'pre-set' event in the message
182 // Cycle the alphabet history
183 if(GetStringParameter(SP_ALPHABET_ID
) != sNewValue
) {
184 if(GetStringParameter(SP_ALPHABET_1
) != sNewValue
) {
185 if(GetStringParameter(SP_ALPHABET_2
) != sNewValue
) {
186 if(GetStringParameter(SP_ALPHABET_3
) != sNewValue
)
187 SetStringParameter(SP_ALPHABET_4
, GetStringParameter(SP_ALPHABET_3
));
189 SetStringParameter(SP_ALPHABET_3
, GetStringParameter(SP_ALPHABET_2
));
192 SetStringParameter(SP_ALPHABET_2
, GetStringParameter(SP_ALPHABET_1
));
195 SetStringParameter(SP_ALPHABET_1
, GetStringParameter(SP_ALPHABET_ID
));
202 void CDasherInterfaceBase::InterfaceEventHandler(Dasher::CEvent
*pEvent
) {
204 if(pEvent
->m_iEventType
== 1) {
205 Dasher::CParameterNotificationEvent
* pEvt(static_cast < Dasher::CParameterNotificationEvent
* >(pEvent
));
207 switch (pEvt
->m_iParameter
) {
209 case BP_OUTLINE_MODE
:
215 case BP_CONTROL_MODE
:
218 case BP_DRAW_MOUSE_LINE
:
222 if(GetLongParameter(LP_ORIENTATION
) == Dasher::Opts::AlphabetDefault
)
223 // TODO: See comment in DasherModel.cpp about prefered values
224 SetLongParameter(LP_REAL_ORIENTATION
, m_Alphabet
->GetOrientation());
226 SetLongParameter(LP_REAL_ORIENTATION
, GetLongParameter(LP_ORIENTATION
));
237 case SP_DEFAULT_COLOUR_ID
: // Delibarate fallthrough
238 case BP_PALETTE_CHANGE
:
239 if(GetBoolParameter(BP_PALETTE_CHANGE
))
240 SetStringParameter(SP_COLOUR_ID
, GetStringParameter(SP_DEFAULT_COLOUR_ID
));
242 case LP_LANGUAGE_MODEL_ID
:
248 case LP_DASHER_FONTSIZE
:
251 case SP_INPUT_DEVICE
:
254 case SP_INPUT_FILTER
:
262 else if(pEvent
->m_iEventType
== 2) {
263 CEditEvent
*pEditEvent(static_cast < CEditEvent
* >(pEvent
));
265 if(pEditEvent
->m_iEditType
== 1) {
266 strCurrentContext
+= pEditEvent
->m_sText
;
267 if( strCurrentContext
.size() > 20 )
268 strCurrentContext
= strCurrentContext
.substr( strCurrentContext
.size() - 20 );
270 strTrainfileBuffer
+= pEditEvent
->m_sText
;
272 else if(pEditEvent
->m_iEditType
== 2) {
273 strCurrentContext
= strCurrentContext
.substr( 0, strCurrentContext
.size() - pEditEvent
->m_sText
.size());
275 strTrainfileBuffer
= strTrainfileBuffer
.substr( 0, strTrainfileBuffer
.size() - pEditEvent
->m_sText
.size());
278 else if(pEvent
->m_iEventType
== EV_CONTROL
) {
279 CControlEvent
*pControlEvent(static_cast <CControlEvent
*>(pEvent
));
281 switch(pControlEvent
->m_iID
) {
282 case CControlManager::CTL_STOP
:
285 case CControlManager::CTL_PAUSE
:
290 else if(pEvent
->m_iEventType
== EV_LOCK
) {
291 CLockEvent
*pLockEvent(static_cast<CLockEvent
*>(pEvent
));
293 // TODO: Sort this out - at the moment these don't occur in pairs, so the old boolean variable is still needed
294 if(pLockEvent
->m_bLock
) {
303 m_bGlobalLock
= pLockEvent
->m_bLock
;
307 void CDasherInterfaceBase::WriteTrainFileFull() {
308 WriteTrainFile(strTrainfileBuffer
);
309 strTrainfileBuffer
= "";
312 void CDasherInterfaceBase::WriteTrainFilePartial() {
313 // TODO: what if we're midway through a unicode character?
314 WriteTrainFile(strTrainfileBuffer
.substr(0,100));
315 strTrainfileBuffer
= strTrainfileBuffer
.substr(100);
318 void CDasherInterfaceBase::CreateDasherModel()
323 // TODO: Move training into model?
324 // TODO: Do we really need to check for a valid language model?
325 int lmID
= GetLongParameter(LP_LANGUAGE_MODEL_ID
);
328 // Train the new language model
331 pEvent
= new CLockEvent("Training Dasher", true, 0);
332 m_pEventHandler
->InsertEvent(pEvent
);
337 // Delete the old model and create a new one
339 delete m_pDasherModel
;
348 if(m_deGameModeStrings
.size() == 0) {
349 m_pNCManager
= new CNodeCreationManager(m_pEventHandler
, m_pSettingsStore
, false, "", m_AlphIO
);
350 m_pDasherModel
= new CDasherModel(m_pEventHandler
, m_pSettingsStore
, m_pNCManager
, this);
353 m_pNCManager
= new CNodeCreationManager(m_pEventHandler
, m_pSettingsStore
, true, m_deGameModeStrings
[0], m_AlphIO
);
354 m_pDasherModel
= new CDasherModel(m_pEventHandler
, m_pSettingsStore
, m_pNCManager
, this, true, m_deGameModeStrings
[0]);
355 // m_deGameModeStrings.pop_front();
358 m_Alphabet
= m_pNCManager
->GetAlphabet();
360 string T
= m_Alphabet
->GetTrainingFile();
363 iTotalBytes
+= GetFileSize(GetStringParameter(SP_SYSTEM_LOC
) + T
);
364 iTotalBytes
+= GetFileSize(GetStringParameter(SP_USER_LOC
) + T
);
366 if(iTotalBytes
> 0) {
368 iOffset
= TrainFile(GetStringParameter(SP_SYSTEM_LOC
) + T
, iTotalBytes
, 0);
369 TrainFile(GetStringParameter(SP_USER_LOC
) + T
, iTotalBytes
, iOffset
);
372 CMessageEvent
oEvent("No training text is avilable for the selected alphabet. Dasher will function, but it may be difficult to enter text.\nPlease see http://www.dasher.org.uk/alphabets/ for more information.", 0, 0);
373 m_pEventHandler
->InsertEvent(&oEvent
);
376 pEvent
= new CLockEvent("Training Dasher", false, 0);
377 m_pEventHandler
->InsertEvent(pEvent
);
387 void CDasherInterfaceBase::Start() {
388 // TODO: Clarify the relationship between Start() and
389 // InvalidateContext() - I believe that they essentially do the same
392 if(m_pDasherModel
!= 0) {
393 m_pDasherModel
->Start();
395 if(m_pDasherView
!= 0) {
396 // m_pDasherView->ResetSum();
397 // m_pDasherView->ResetSumCounter();
398 // m_pDasherView->ResetYAutoOffset();
403 if(m_pInputFilter
&& m_pInputFilter
->GetMinWidth(iMinWidth
)) {
404 m_pDasherModel
->LimitRoot(iMinWidth
);
408 void CDasherInterfaceBase::PauseAt(int MouseX
, int MouseY
) {
409 SetBoolParameter(BP_DASHER_PAUSED
, true);
411 // Request a full redraw at the next time step.
412 SetBoolParameter(BP_REDRAW
, true);
414 Dasher::CStopEvent oEvent
;
415 m_pEventHandler
->InsertEvent(&oEvent
);
417 if (m_pUserLog
!= NULL
)
418 m_pUserLog
->StopWriting((float) GetNats());
421 void CDasherInterfaceBase::Halt() {
422 SetBoolParameter(BP_DASHER_PAUSED
, true);
425 if(GetBoolParameter(BP_MOUSEPOS_MODE
)) {
426 SetLongParameter(LP_MOUSE_POS_BOX
, 1);
430 // This will cause us to reinitialise the frame rate counter - ie we start off slowly
431 if(m_pDasherModel
!= 0)
432 m_pDasherModel
->Halt();
435 void CDasherInterfaceBase::Unpause(unsigned long Time
) {
436 SetBoolParameter(BP_DASHER_PAUSED
, false);
438 if(m_pDasherModel
!= 0) {
439 m_pDasherModel
->Reset_framerate(Time
);
440 //m_pDasherModel->Set_paused(m_Paused);
442 if(m_pDasherView
!= 0) {
443 // m_pDasherView->ResetSum();
444 // m_pDasherView->ResetSumCounter();
447 Dasher::CStartEvent oEvent
;
448 m_pEventHandler
->InsertEvent(&oEvent
);
451 if (m_pUserLog
!= NULL
)
452 m_pUserLog
->StartWriting();
455 void CDasherInterfaceBase::CreateInput() {
457 m_pInput
->Deactivate();
461 m_pInput
= (CDasherInput
*)GetModuleByName(GetStringParameter(SP_INPUT_DEVICE
));
465 m_pInput
->Activate();
468 if(m_pDasherView
!= 0)
469 m_pDasherView
->SetInput(m_pInput
);
472 void CDasherInterfaceBase::NewFrame(unsigned long iTime
, bool bForceRedraw
) {
473 // Fail if Dasher is locked
474 if(m_iCurrentState
!= ST_NORMAL
)
477 bool bChanged(false);
479 if(m_pDasherView
!= 0) {
480 if(!GetBoolParameter(BP_TRAINING
)) {
481 if (m_pUserLog
!= NULL
) {
483 Dasher::VECTOR_SYMBOL_PROB vAdded
;
487 bChanged
= m_pInputFilter
->Timer(iTime
, m_pDasherView
, m_pDasherModel
, &vAdded
, &iNumDeleted
);
491 m_pUserLog
->DeleteSymbols(iNumDeleted
);
492 if (vAdded
.size() > 0)
493 m_pUserLog
->AddSymbols(&vAdded
);
498 bChanged
= m_pInputFilter
->Timer(iTime
, m_pDasherView
, m_pDasherModel
, 0, 0);
502 m_pDasherModel
->CheckForNewRoot(m_pDasherView
);
506 Redraw(bChanged
|| m_bRedrawScheduled
|| bForceRedraw
);
507 m_bRedrawScheduled
= false;
509 // This just passes the time through to the framerate tracker, so we
510 // know how often new frames are being drawn.
511 if(m_pDasherModel
!= 0)
512 m_pDasherModel
->NewFrame(iTime
);
515 void CDasherInterfaceBase::CheckRedraw() {
516 if(m_bRedrawScheduled
)
519 m_bRedrawScheduled
= false;
522 /// Full redraw - renders model, decorations and blits onto display
523 /// buffer. Not recommended if nothing has changed with the model,
524 /// otherwise we're wasting effort.
526 void CDasherInterfaceBase::Redraw(bool bRedrawNodes
) {
527 if(!m_pDasherView
|| !m_pDasherModel
)
530 // TODO: More generic notion of 'layers'?
533 m_pDasherView
->Screen()->SendMarker(0);
534 m_pDasherModel
->RenderToView(m_pDasherView
, true);
537 m_pDasherView
->Screen()->SendMarker(1);
539 bool bDecorationsChanged(false);
542 bDecorationsChanged
= m_pInputFilter
->DecorateView(m_pDasherView
);
545 bool bActionButtonsChanged(false);
546 #ifdef EXPERIMENTAL_FEATURES
547 bActionButtonsChanged
= DrawActionButtons();
550 if(bRedrawNodes
|| bDecorationsChanged
|| bActionButtonsChanged
)
551 m_pDasherView
->Display();
554 void CDasherInterfaceBase::ChangeAlphabet() {
556 if(GetStringParameter(SP_ALPHABET_ID
) == "") {
557 SetStringParameter(SP_ALPHABET_ID
, m_AlphIO
->GetDefault());
558 // This will result in ChangeAlphabet() being called again, so
559 // exit from the first recursion
565 WriteTrainFileFull();
567 // Lock Dasher to prevent changes from happening while we're training.
569 SetBoolParameter( BP_TRAINING
, true );
571 // m_AlphInfo = m_AlphIO->GetInfo(NewAlphabetID);
573 // //AlphabetID = m_AlphInfo.AlphID.c_str();
575 // // std::auto_ptr < CAlphabet > ptrOld(m_Alphabet); // So we can delete the old alphabet later
577 // m_Alphabet = new CAlphabet(m_AlphInfo);
579 delete m_pDasherModel
;
583 // Let our user log object know about the new alphabet since
584 // it needs to convert symbols into text for the log file.
585 if (m_pUserLog
!= NULL
)
586 m_pUserLog
->SetAlphabetPtr(m_Alphabet
);
588 // Apply options from alphabet
590 SetBoolParameter( BP_TRAINING
, false );
595 void CDasherInterfaceBase::ChangeColours() {
596 if(!m_ColourIO
|| !m_DasherScreen
)
599 // TODO: Make fuction return a pointer directly
600 m_DasherScreen
->SetColourScheme(&(m_ColourIO
->GetInfo(GetStringParameter(SP_COLOUR_ID
))));
603 void CDasherInterfaceBase::ChangeScreen(CDasherScreen
*NewScreen
) {
604 m_DasherScreen
= NewScreen
;
607 if(m_pDasherView
!= 0) {
608 m_pDasherView
->ChangeScreen(m_DasherScreen
);
610 if(GetLongParameter(LP_VIEW_ID
) != -1)
614 PositionActionButtons();
618 void CDasherInterfaceBase::ChangeView() {
619 // TODO: Actually respond to LP_VIEW_ID parameter (although there is only one view at the moment)
621 if(m_DasherScreen
!= 0 && m_pDasherModel
!= 0) {
622 delete m_pDasherView
;
624 m_pDasherView
= new CDasherViewSquare(m_pEventHandler
, m_pSettingsStore
, m_DasherScreen
);
627 m_pDasherView
->SetInput(m_pInput
);
631 void CDasherInterfaceBase::GetAlphabets(std::vector
<std::string
>*AlphabetList
) {
632 m_AlphIO
->GetAlphabets(AlphabetList
);
635 const CAlphIO::AlphInfo
& CDasherInterfaceBase::GetInfo(const std::string
&AlphID
) {
636 return m_AlphIO
->GetInfo(AlphID
);
639 void CDasherInterfaceBase::SetInfo(const CAlphIO::AlphInfo
&NewInfo
) {
640 m_AlphIO
->SetInfo(NewInfo
);
643 void CDasherInterfaceBase::DeleteAlphabet(const std::string
&AlphID
) {
644 m_AlphIO
->Delete(AlphID
);
647 void CDasherInterfaceBase::GetColours(std::vector
<std::string
>*ColourList
) {
648 m_ColourIO
->GetColours(ColourList
);
652 I've used C style I/O because I found that C++ style I/O bloated
653 the Win32 code enormously. The overhead of loading the buffer into
654 the string instead of reading straight into a string seems to be
655 negligible compared to huge requirements elsewhere.
657 int CDasherInterfaceBase::TrainFile(string Filename
, int iTotalBytes
, int iOffset
) {
662 if((InputFile
= fopen(Filename
.c_str(), "r")) == (FILE *) 0)
665 const int BufferSize
= 1024;
666 char InputBuffer
[BufferSize
];
671 vector
< symbol
> Symbols
;
673 CAlphabetManagerFactory::CTrainer
* pTrainer
= m_pDasherModel
->GetTrainer();
675 NumberRead
= fread(InputBuffer
, 1, BufferSize
- 1, InputFile
);
676 InputBuffer
[NumberRead
] = '\0';
677 StringBuffer
+= InputBuffer
;
678 bool bIsMore
= false;
679 if(NumberRead
== (BufferSize
- 1))
683 m_Alphabet
->GetSymbols(&Symbols
, &StringBuffer
, bIsMore
);
685 pTrainer
->Train(Symbols
);
686 iTotalRead
+= NumberRead
;
688 // TODO: No reason for this to be a pointer (other than cut/paste laziness!)
690 pEvent
= new CLockEvent("Training Dasher", true, static_cast<int>((100.0 * (iTotalRead
+ iOffset
))/iTotalBytes
));
691 m_pEventHandler
->InsertEvent(pEvent
);
694 } while(NumberRead
== BufferSize
- 1);
703 void CDasherInterfaceBase::GetFontSizes(std::vector
<int >*FontSizes
) const {
704 FontSizes
->push_back(20);
705 FontSizes
->push_back(14);
706 FontSizes
->push_back(11);
707 FontSizes
->push_back(40);
708 FontSizes
->push_back(28);
709 FontSizes
->push_back(22);
710 FontSizes
->push_back(80);
711 FontSizes
->push_back(56);
712 FontSizes
->push_back(44);
715 double CDasherInterfaceBase::GetCurCPM() {
720 double CDasherInterfaceBase::GetCurFPS() {
725 // int CDasherInterfaceBase::GetAutoOffset() {
726 // if(m_pDasherView != 0) {
727 // return m_pDasherView->GetAutoOffset();
732 double CDasherInterfaceBase::GetNats() const {
734 return m_pDasherModel
->GetNats();
739 void CDasherInterfaceBase::ResetNats() {
741 m_pDasherModel
->ResetNats();
745 void CDasherInterfaceBase::InvalidateContext(bool bForceStart
) {
746 m_pDasherModel
->m_strContextBuffer
= "";
748 Dasher::CEditContextEvent
oEvent(10);
749 m_pEventHandler
->InsertEvent(&oEvent
);
751 std::string
strNewContext(m_pDasherModel
->m_strContextBuffer
);
753 // We keep track of an internal context and compare that to what
754 // we are given - don't restart Dasher if nothing has changed.
755 // This should really be integrated with DasherModel, which
756 // probably will be the case when we start to deal with being able
757 // to back off indefinitely. For now though we'll keep it in a
760 int iContextLength( 6 ); // The 'important' context length - should really get from language model
762 // FIXME - use unicode lengths
764 if(bForceStart
|| (strNewContext
.substr( std::max(static_cast<int>(strNewContext
.size()) - iContextLength
, 0)) != strCurrentContext
.substr( std::max(static_cast<int>(strCurrentContext
.size()) - iContextLength
, 0)))) {
766 if(m_pDasherModel
!= NULL
) {
767 // TODO: Reimplement this
768 // if(m_pDasherModel->m_bContextSensitive || bForceStart) {
770 m_pDasherModel
->SetContext(strNewContext
);
775 strCurrentContext
= strNewContext
;
776 WriteTrainFileFull();
782 if(m_pInputFilter
&& m_pInputFilter
->GetMinWidth(iMinWidth
)) {
783 m_pDasherModel
->LimitRoot(iMinWidth
);
788 while( m_pDasherModel
->CheckForNewRoot(m_pDasherView
) ) {
795 void CDasherInterfaceBase::SetContext(std::string strNewContext
) {
796 m_pDasherModel
->m_strContextBuffer
= strNewContext
;
799 // Control mode stuff
801 void CDasherInterfaceBase::RegisterNode( int iID
, const std::string
&strLabel
, int iColour
) {
802 m_pNCManager
->RegisterNode(iID
, strLabel
, iColour
);
805 void CDasherInterfaceBase::ConnectNode(int iChild
, int iParent
, int iAfter
) {
806 m_pNCManager
->ConnectNode(iChild
, iParent
, iAfter
);
809 void CDasherInterfaceBase::DisconnectNode(int iChild
, int iParent
) {
810 m_pNCManager
->DisconnectNode(iChild
, iParent
);
813 void CDasherInterfaceBase::SetBoolParameter(int iParameter
, bool bValue
) {
814 m_pSettingsStore
->SetBoolParameter(iParameter
, bValue
);
817 void CDasherInterfaceBase::SetLongParameter(int iParameter
, long lValue
) {
818 m_pSettingsStore
->SetLongParameter(iParameter
, lValue
);
821 void CDasherInterfaceBase::SetStringParameter(int iParameter
, const std::string
& sValue
) {
822 PreSetNotify(iParameter
, sValue
);
823 m_pSettingsStore
->SetStringParameter(iParameter
, sValue
);
826 bool CDasherInterfaceBase::GetBoolParameter(int iParameter
) {
827 return m_pSettingsStore
->GetBoolParameter(iParameter
);
830 long CDasherInterfaceBase::GetLongParameter(int iParameter
) {
831 return m_pSettingsStore
->GetLongParameter(iParameter
);
834 std::string
CDasherInterfaceBase::GetStringParameter(int iParameter
) {
835 return m_pSettingsStore
->GetStringParameter(iParameter
);
838 void CDasherInterfaceBase::ResetParameter(int iParameter
) {
839 m_pSettingsStore
->ResetParameter(iParameter
);
842 // We need to be able to get at the UserLog object from outside the interface
843 CUserLogBase
* CDasherInterfaceBase::GetUserLogPtr() {
847 void CDasherInterfaceBase::KeyDown(int iTime
, int iId
) {
848 if(m_iCurrentState
!= ST_NORMAL
)
851 if(m_pInputFilter
&& !GetBoolParameter(BP_TRAINING
)) {
852 m_pInputFilter
->KeyDown(iTime
, iId
, m_pDasherModel
, m_pUserLog
);
855 if(m_pInput
&& !GetBoolParameter(BP_TRAINING
)) {
856 m_pInput
->KeyDown(iTime
, iId
);
860 void CDasherInterfaceBase::KeyUp(int iTime
, int iId
) {
861 if(m_iCurrentState
!= ST_NORMAL
)
864 if(m_pInputFilter
&& !GetBoolParameter(BP_TRAINING
)) {
865 m_pInputFilter
->KeyUp(iTime
, iId
, m_pDasherModel
);
868 if(m_pInput
&& !GetBoolParameter(BP_TRAINING
)) {
869 m_pInput
->KeyUp(iTime
, iId
);
873 void CDasherInterfaceBase::CreateInputFilter()
876 m_pInputFilter
->Deactivate();
877 m_pInputFilter
->Unref();
878 m_pInputFilter
= NULL
;
881 m_pInputFilter
= (CInputFilter
*)GetModuleByName(GetStringParameter(SP_INPUT_FILTER
));
884 m_pInputFilter
->Ref();
885 m_pInputFilter
->Activate();
888 // Fall back to a sensible alternative if for some reason the
889 // current choice isn't valid.
890 if(GetStringParameter(SP_INPUT_FILTER
) != "Normal Control")
891 SetStringParameter(SP_INPUT_FILTER
, "Normal Control");
895 void CDasherInterfaceBase::RegisterFactory(CModuleFactory
*pFactory
) {
896 m_oModuleManager
.RegisterFactory(pFactory
);
899 CDasherModule
*CDasherInterfaceBase::GetModule(long long int iID
) {
900 return m_oModuleManager
.GetModule(iID
);
903 CDasherModule
*CDasherInterfaceBase::GetModuleByName(const std::string
&strName
) {
904 return m_oModuleManager
.GetModuleByName(strName
);
907 void CDasherInterfaceBase::CreateFactories() {
908 RegisterFactory(new CWrapperFactory(m_pEventHandler
, m_pSettingsStore
, new CDefaultFilter(m_pEventHandler
, m_pSettingsStore
, this, m_pDasherModel
,3, "Normal Control")));
909 RegisterFactory(new CWrapperFactory(m_pEventHandler
, m_pSettingsStore
, new COneDimensionalFilter(m_pEventHandler
, m_pSettingsStore
, this, m_pDasherModel
)));
910 RegisterFactory(new CWrapperFactory(m_pEventHandler
, m_pSettingsStore
, new CEyetrackerFilter(m_pEventHandler
, m_pSettingsStore
, this, m_pDasherModel
)));
911 RegisterFactory(new CWrapperFactory(m_pEventHandler
, m_pSettingsStore
, new CClickFilter(m_pEventHandler
, m_pSettingsStore
, this)));
912 RegisterFactory(new CWrapperFactory(m_pEventHandler
, m_pSettingsStore
, new CDynamicFilter(m_pEventHandler
, m_pSettingsStore
, this)));
913 RegisterFactory(new CWrapperFactory(m_pEventHandler
, m_pSettingsStore
, new CTwoButtonDynamicFilter(m_pEventHandler
, m_pSettingsStore
, this, 14, 1, "Two Button Dynamic Mode")));
914 // TODO: specialist factory for button mode
915 RegisterFactory(new CWrapperFactory(m_pEventHandler
, m_pSettingsStore
, new CDasherButtons(m_pEventHandler
, m_pSettingsStore
, this, 5, 1, true,8, "Menu Mode")));
916 RegisterFactory(new CWrapperFactory(m_pEventHandler
, m_pSettingsStore
, new CDasherButtons(m_pEventHandler
, m_pSettingsStore
, this, 3, 0, false,10, "Direct Mode")));
917 // RegisterFactory(new CWrapperFactory(m_pEventHandler, m_pSettingsStore, new CDasherButtons(m_pEventHandler, m_pSettingsStore, this, 4, 0, false,11, "Buttons 3")));
918 RegisterFactory(new CWrapperFactory(m_pEventHandler
, m_pSettingsStore
, new CDasherButtons(m_pEventHandler
, m_pSettingsStore
, this, 3, 3, false,12, "Alternating Direct Mode")));
919 RegisterFactory(new CWrapperFactory(m_pEventHandler
, m_pSettingsStore
, new CDasherButtons(m_pEventHandler
, m_pSettingsStore
, this, 4, 2, false,13, "Compass Mode")));
920 RegisterFactory(new CWrapperFactory(m_pEventHandler
, m_pSettingsStore
, new CStylusFilter(m_pEventHandler
, m_pSettingsStore
, this, m_pDasherModel
,15, "Stylus Control")));
924 void CDasherInterfaceBase::GetPermittedValues(int iParameter
, std::vector
<std::string
> &vList
) {
925 // TODO: Deprecate direct calls to these functions
926 switch (iParameter
) {
928 GetAlphabets(&vList
);
933 case SP_INPUT_FILTER
:
934 m_oModuleManager
.ListModules(1, vList
);
936 case SP_INPUT_DEVICE
:
937 m_oModuleManager
.ListModules(0, vList
);
942 void CDasherInterfaceBase::StartShutdown() {
943 ChangeState(TR_SHUTDOWN
);
946 bool CDasherInterfaceBase::GetModuleSettings(const std::string
&strName
, SModuleSettings
**pSettings
, int *iCount
) {
947 return GetModuleByName(strName
)->GetSettings(pSettings
, iCount
);
950 void CDasherInterfaceBase::SetupActionButtons() {
951 m_vLeftButtons
.push_back(new CActionButton(this, "Exit", true));
952 m_vLeftButtons
.push_back(new CActionButton(this, "Preferences", false));
953 m_vLeftButtons
.push_back(new CActionButton(this, "Help", false));
954 m_vLeftButtons
.push_back(new CActionButton(this, "About", false));
957 void CDasherInterfaceBase::DestroyActionButtons() {
958 // TODO: implement and call this
961 void CDasherInterfaceBase::PositionActionButtons() {
965 int iCurrentOffset(16);
967 for(std::vector
<CActionButton
*>::iterator
it(m_vLeftButtons
.begin()); it
!= m_vLeftButtons
.end(); ++it
) {
968 (*it
)->SetPosition(16, iCurrentOffset
, 32, 32);
969 iCurrentOffset
+= 48;
974 for(std::vector
<CActionButton
*>::iterator
it(m_vRightButtons
.begin()); it
!= m_vRightButtons
.end(); ++it
) {
975 (*it
)->SetPosition(m_DasherScreen
->GetWidth() - 144, iCurrentOffset
, 128, 32);
976 iCurrentOffset
+= 48;
980 bool CDasherInterfaceBase::DrawActionButtons() {
984 bool bVisible(GetBoolParameter(BP_DASHER_PAUSED
));
986 bool bRV(bVisible
!= m_bOldVisible
);
987 m_bOldVisible
= bVisible
;
989 for(std::vector
<CActionButton
*>::iterator
it(m_vLeftButtons
.begin()); it
!= m_vLeftButtons
.end(); ++it
)
990 (*it
)->Draw(m_DasherScreen
, bVisible
);
992 for(std::vector
<CActionButton
*>::iterator
it(m_vRightButtons
.begin()); it
!= m_vRightButtons
.end(); ++it
)
993 (*it
)->Draw(m_DasherScreen
, bVisible
);
999 void CDasherInterfaceBase::HandleClickUp(int iTime
, int iX
, int iY
) {
1000 #ifdef EXPERIMENTAL_FEATURES
1001 bool bVisible(GetBoolParameter(BP_DASHER_PAUSED
));
1003 for(std::vector
<CActionButton
*>::iterator
it(m_vLeftButtons
.begin()); it
!= m_vLeftButtons
.end(); ++it
) {
1004 if((*it
)->HandleClickUp(iTime
, iX
, iY
, bVisible
))
1008 for(std::vector
<CActionButton
*>::iterator
it(m_vRightButtons
.begin()); it
!= m_vRightButtons
.end(); ++it
) {
1009 if((*it
)->HandleClickUp(iTime
, iX
, iY
, bVisible
))
1017 void CDasherInterfaceBase::HandleClickDown(int iTime
, int iX
, int iY
) {
1018 #ifdef EXPERIMENTAL_FEATURES
1019 bool bVisible(GetBoolParameter(BP_DASHER_PAUSED
));
1021 for(std::vector
<CActionButton
*>::iterator
it(m_vLeftButtons
.begin()); it
!= m_vLeftButtons
.end(); ++it
) {
1022 if((*it
)->HandleClickDown(iTime
, iX
, iY
, bVisible
))
1026 for(std::vector
<CActionButton
*>::iterator
it(m_vRightButtons
.begin()); it
!= m_vRightButtons
.end(); ++it
) {
1027 if((*it
)->HandleClickDown(iTime
, iX
, iY
, bVisible
))
1032 KeyDown(iTime
, 100);
1036 void CDasherInterfaceBase::ExecuteCommand(const std::string
&strName
) {
1037 // TODO: Pointless - just insert event directly
1039 CCommandEvent
*pEvent
= new CCommandEvent(strName
);
1040 m_pEventHandler
->InsertEvent(pEvent
);
1044 double CDasherInterfaceBase::GetFramerate() {
1046 return(m_pDasherModel
->Framerate());
1051 int CDasherInterfaceBase::GetRenderCount() {
1053 return(m_pDasherView
->GetRenderCount());
1058 void CDasherInterfaceBase::AddActionButton(const std::string
&strName
) {
1059 m_vRightButtons
.push_back(new CActionButton(this, strName
, false));
1063 void CDasherInterfaceBase::OnUIRealised() {
1065 ChangeState(TR_UI_INIT
);
1069 void CDasherInterfaceBase::ChangeState(ETransition iTransition
) {
1070 static EState iTransitionTable
[ST_NUM
][TR_NUM
] = {
1071 {ST_MODEL
, ST_UI
, ST_FORBIDDEN
, ST_FORBIDDEN
, ST_FORBIDDEN
},
1072 {ST_FORBIDDEN
, ST_NORMAL
, ST_FORBIDDEN
, ST_FORBIDDEN
, ST_FORBIDDEN
},
1073 {ST_NORMAL
, ST_FORBIDDEN
, ST_FORBIDDEN
, ST_FORBIDDEN
, ST_FORBIDDEN
},
1074 {ST_FORBIDDEN
, ST_FORBIDDEN
, ST_LOCKED
, ST_FORBIDDEN
, ST_SHUTDOWN
},
1075 {ST_FORBIDDEN
, ST_FORBIDDEN
, ST_FORBIDDEN
, ST_NORMAL
, ST_FORBIDDEN
},
1076 {ST_FORBIDDEN
, ST_FORBIDDEN
, ST_FORBIDDEN
, ST_FORBIDDEN
, ST_FORBIDDEN
}
1079 EState
iNewState(iTransitionTable
[m_iCurrentState
][iTransition
]);
1081 if(iNewState
!= ST_FORBIDDEN
) {
1082 LeaveState(m_iCurrentState
);
1083 EnterState(iNewState
);
1085 m_iCurrentState
= iNewState
;
1089 void CDasherInterfaceBase::LeaveState(EState iState
) {
1093 void CDasherInterfaceBase::EnterState(EState iState
) {
1104 void CDasherInterfaceBase::AddLock(int iLockFlags
) {
1105 if(m_iLockCount
== 0)
1106 ChangeState(TR_LOCK
);
1111 void CDasherInterfaceBase::ReleaseLock(int iLockFlags
) {
1112 if(m_iLockCount
> 0)
1115 if(m_iLockCount
== 0)
1116 ChangeState(TR_UNLOCK
);