1 // DasherInterfaceBase.cpp
3 // Copyright (c) 2007 The Dasher Team
5 // This file is part of Dasher.
7 // Dasher is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 2 of the License, or
10 // (at your option) any later version.
12 // Dasher is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with Dasher; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 #include "../Common/Common.h"
23 #include "DasherInterfaceBase.h"
25 //#include "ActionButton.h"
26 #include "AlphabetManagerFactory.h"
27 #include "DasherViewSquare.h"
28 #include "ControlManager.h"
29 #include "DasherScreen.h"
30 #include "DasherView.h"
31 #include "DasherInput.h"
32 #include "DasherModel.h"
33 #include "EventHandler.h"
35 #include "NodeCreationManager.h"
38 #include "WrapperFactory.h"
41 #include "ClickFilter.h"
42 #include "DefaultFilter.h"
43 #include "DasherButtons.h"
44 #include "DynamicFilter.h"
45 #include "EyetrackerFilter.h"
46 #include "OneDimensionalFilter.h"
47 #include "StylusFilter.h"
48 #include "TwoButtonDynamicFilter.h"
54 // Legacy C library headers
59 // Declare our global file logging object
60 #include "../DasherCore/FileLogger.h"
62 const eLogLevel g_iLogLevel
= logDEBUG
;
63 const int g_iLogOptions
= logTimeStamp
| logDateStamp
| logDeleteOldFile
;
65 const eLogLevel g_iLogLevel
= logNORMAL
;
66 const int g_iLogOptions
= logTimeStamp
| logDateStamp
;
68 CFileLogger
* g_pLogger
= NULL
;
70 using namespace Dasher
;
73 // Track memory leaks on Windows to the line that new'd the memory
76 #define DEBUG_NEW new( _NORMAL_BLOCK, THIS_FILE, __LINE__ )
79 static char THIS_FILE
[] = __FILE__
;
83 CDasherInterfaceBase::CDasherInterfaceBase() {
85 // Ensure that pointers to 'owned' objects are set to NULL.
87 m_pDasherModel
= NULL
;
88 m_DasherScreen
= NULL
;
94 m_pInputFilter
= NULL
;
97 // Various state variables
98 m_bRedrawScheduled
= false;
100 m_iCurrentState
= ST_START
;
103 m_bGlobalLock
= false;
105 // TODO: Are these actually needed?
106 strCurrentContext
= ". ";
107 strTrainfileBuffer
= "";
109 // Create an event handler.
110 m_pEventHandler
= new CEventHandler(this);
112 m_bLastChanged
= true;
114 // Global logging object we can use from anywhere
115 g_pLogger
= new CFileLogger("dasher.log",
121 void CDasherInterfaceBase::Realize() {
123 // TODO: What exactly needs to have happened by the time we call Realize()?
124 CreateSettingsStore();
128 std::vector
<std::string
> vAlphabetFiles
;
129 ScanAlphabetFiles(vAlphabetFiles
);
130 m_AlphIO
= new CAlphIO(GetStringParameter(SP_SYSTEM_LOC
), GetStringParameter(SP_USER_LOC
), vAlphabetFiles
);
132 std::vector
<std::string
> vColourFiles
;
133 ScanColourFiles(vColourFiles
);
134 m_ColourIO
= new CColourIO(GetStringParameter(SP_SYSTEM_LOC
), GetStringParameter(SP_USER_LOC
), vColourFiles
);
139 // Create the user logging object if we are suppose to. We wait
140 // until now so we have the real value of the parameter and not
143 // TODO: Sort out log type selection
145 int iUserLogLevel
= GetLongParameter(LP_USER_LOG_LEVEL_MASK
);
147 if(iUserLogLevel
== 10)
148 m_pUserLog
= new CBasicLog(m_pEventHandler
, m_pSettingsStore
);
149 else if (iUserLogLevel
> 0)
150 m_pUserLog
= new CUserLog(m_pEventHandler
, m_pSettingsStore
, iUserLogLevel
, m_Alphabet
);
153 CreateLocalFactories();
157 SetupActionButtons();
159 // FIXME - need to rationalise this sort of thing.
160 // InvalidateContext(true);
163 // All the setup is done by now, so let the user log object know
164 // that future parameter changes should be logged.
165 if (m_pUserLog
!= NULL
)
166 m_pUserLog
->InitIsDone();
168 // TODO: Make things work when model is created latet
169 ChangeState(TR_MODEL_INIT
);
172 CDasherInterfaceBase::~CDasherInterfaceBase() {
173 DASHER_ASSERT(m_iCurrentState
== ST_SHUTDOWN
);
175 delete m_pDasherModel
; // The order of some of these deletions matters
177 delete m_pDasherView
;
180 delete m_pInputFilter
;
182 // Do NOT delete Edit box or Screen. This class did not create them.
184 // When we destruct on shutdown, we'll output any detailed log file
185 if (m_pUserLog
!= NULL
)
187 m_pUserLog
->OutputFile();
192 if (g_pLogger
!= NULL
) {
197 // Must delete event handler after all CDasherComponent derived classes
199 delete m_pEventHandler
;
202 void CDasherInterfaceBase::PreSetNotify(int iParameter
, const std::string
&sNewValue
) {
204 // FIXME - make this a more general 'pre-set' event in the message
209 // Cycle the alphabet history
210 if(GetStringParameter(SP_ALPHABET_ID
) != sNewValue
) {
211 if(GetStringParameter(SP_ALPHABET_1
) != sNewValue
) {
212 if(GetStringParameter(SP_ALPHABET_2
) != sNewValue
) {
213 if(GetStringParameter(SP_ALPHABET_3
) != sNewValue
)
214 SetStringParameter(SP_ALPHABET_4
, GetStringParameter(SP_ALPHABET_3
));
216 SetStringParameter(SP_ALPHABET_3
, GetStringParameter(SP_ALPHABET_2
));
219 SetStringParameter(SP_ALPHABET_2
, GetStringParameter(SP_ALPHABET_1
));
222 SetStringParameter(SP_ALPHABET_1
, GetStringParameter(SP_ALPHABET_ID
));
229 void CDasherInterfaceBase::InterfaceEventHandler(Dasher::CEvent
*pEvent
) {
231 if(pEvent
->m_iEventType
== 1) {
232 Dasher::CParameterNotificationEvent
* pEvt(static_cast < Dasher::CParameterNotificationEvent
* >(pEvent
));
234 switch (pEvt
->m_iParameter
) {
236 case BP_OUTLINE_MODE
:
242 case BP_CONTROL_MODE
:
245 case BP_DRAW_MOUSE_LINE
:
249 if(GetLongParameter(LP_ORIENTATION
) == Dasher::Opts::AlphabetDefault
)
250 // TODO: See comment in DasherModel.cpp about prefered values
251 SetLongParameter(LP_REAL_ORIENTATION
, m_Alphabet
->GetOrientation());
253 SetLongParameter(LP_REAL_ORIENTATION
, GetLongParameter(LP_ORIENTATION
));
264 case SP_DEFAULT_COLOUR_ID
: // Delibarate fallthrough
265 case BP_PALETTE_CHANGE
:
266 if(GetBoolParameter(BP_PALETTE_CHANGE
))
267 SetStringParameter(SP_COLOUR_ID
, GetStringParameter(SP_DEFAULT_COLOUR_ID
));
269 case LP_LANGUAGE_MODEL_ID
:
275 case LP_DASHER_FONTSIZE
:
278 case SP_INPUT_DEVICE
:
281 case SP_INPUT_FILTER
:
285 case BP_DASHER_PAUSED
:
292 else if(pEvent
->m_iEventType
== 2) {
293 CEditEvent
*pEditEvent(static_cast < CEditEvent
* >(pEvent
));
295 if(pEditEvent
->m_iEditType
== 1) {
296 strCurrentContext
+= pEditEvent
->m_sText
;
297 if( strCurrentContext
.size() > 20 )
298 strCurrentContext
= strCurrentContext
.substr( strCurrentContext
.size() - 20 );
300 strTrainfileBuffer
+= pEditEvent
->m_sText
;
302 else if(pEditEvent
->m_iEditType
== 2) {
303 strCurrentContext
= strCurrentContext
.substr( 0, strCurrentContext
.size() - pEditEvent
->m_sText
.size());
305 strTrainfileBuffer
= strTrainfileBuffer
.substr( 0, strTrainfileBuffer
.size() - pEditEvent
->m_sText
.size());
308 else if(pEvent
->m_iEventType
== EV_CONTROL
) {
309 CControlEvent
*pControlEvent(static_cast <CControlEvent
*>(pEvent
));
311 switch(pControlEvent
->m_iID
) {
312 case CControlManager::CTL_STOP
:
315 case CControlManager::CTL_PAUSE
:
320 else if(pEvent
->m_iEventType
== EV_LOCK
) {
321 CLockEvent
*pLockEvent(static_cast<CLockEvent
*>(pEvent
));
323 // // TODO: Sort this out - at the moment these don't occur in pairs, so the old boolean variable is still needed
324 // if(pLockEvent->m_bLock) {
329 // if(!m_bGlobalLock)
333 m_bGlobalLock
= pLockEvent
->m_bLock
;
337 void CDasherInterfaceBase::WriteTrainFileFull() {
338 WriteTrainFile(strTrainfileBuffer
);
339 strTrainfileBuffer
= "";
342 void CDasherInterfaceBase::WriteTrainFilePartial() {
343 // TODO: what if we're midway through a unicode character?
344 WriteTrainFile(strTrainfileBuffer
.substr(0,100));
345 strTrainfileBuffer
= strTrainfileBuffer
.substr(100);
348 void CDasherInterfaceBase::CreateModel(int iOffset
) {
349 // Creating a model without a node creation manager is a bad plan
354 delete m_pDasherModel
;
358 if(m_deGameModeStrings
.size() == 0) {
359 m_pDasherModel
= new CDasherModel(m_pEventHandler
, m_pSettingsStore
, m_pNCManager
, this, m_pDasherView
, iOffset
);
362 m_pDasherModel
= new CDasherModel(m_pEventHandler
, m_pSettingsStore
, m_pNCManager
, this, m_pDasherView
, iOffset
, true, m_deGameModeStrings
[0]);
366 void CDasherInterfaceBase::CreateNCManager() {
367 // TODO: Try and make this work without necessarilty rebuilding the model
372 int lmID
= GetLongParameter(LP_LANGUAGE_MODEL_ID
);
377 // Train the new language model
380 pEvent
= new CLockEvent("Training Dasher", true, 0);
381 m_pEventHandler
->InsertEvent(pEvent
);
389 iOffset
= m_pDasherModel
->GetOffset();
391 iOffset
= 0; // TODO: Is this right?
393 // Delete the old model and create a new one
395 delete m_pDasherModel
;
404 if(m_deGameModeStrings
.size() == 0) {
405 m_pNCManager
= new CNodeCreationManager(this, m_pEventHandler
, m_pSettingsStore
, false, "", m_AlphIO
);
408 m_pNCManager
= new CNodeCreationManager(this, m_pEventHandler
, m_pSettingsStore
, true, m_deGameModeStrings
[0], m_AlphIO
);
411 m_Alphabet
= m_pNCManager
->GetAlphabet();
413 string T
= m_Alphabet
->GetTrainingFile();
416 iTotalBytes
+= GetFileSize(GetStringParameter(SP_SYSTEM_LOC
) + T
);
417 iTotalBytes
+= GetFileSize(GetStringParameter(SP_USER_LOC
) + T
);
419 if(iTotalBytes
> 0) {
421 iOffset
= TrainFile(GetStringParameter(SP_SYSTEM_LOC
) + T
, iTotalBytes
, 0);
422 TrainFile(GetStringParameter(SP_USER_LOC
) + T
, iTotalBytes
, iOffset
);
425 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);
426 m_pEventHandler
->InsertEvent(&oEvent
);
429 pEvent
= new CLockEvent("Training Dasher", false, 0);
430 m_pEventHandler
->InsertEvent(pEvent
);
435 // TODO: Eventually we'll not have to pass the NC manager to the model...
436 CreateModel(iOffset
);
439 // void CDasherInterfaceBase::Start() {
440 // // TODO: Clarify the relationship between Start() and
441 // // InvalidateContext() - I believe that they essentially do the same
444 // if(m_pDasherModel != 0) {
445 // m_pDasherModel->Start();
447 // if(m_pDasherView != 0) {
448 // // m_pDasherView->ResetSum();
449 // // m_pDasherView->ResetSumCounter();
450 // // m_pDasherView->ResetYAutoOffset();
453 // TODO: Reimplement this sometime
457 // if(m_pInputFilter && m_pInputFilter->GetMinWidth(iMinWidth)) {
458 // m_pDasherModel->LimitRoot(iMinWidth);
462 void CDasherInterfaceBase::PauseAt(int MouseX
, int MouseY
) {
463 SetBoolParameter(BP_DASHER_PAUSED
, true);
465 // Request a full redraw at the next time step.
466 SetBoolParameter(BP_REDRAW
, true);
468 Dasher::CStopEvent oEvent
;
469 m_pEventHandler
->InsertEvent(&oEvent
);
471 if (m_pUserLog
!= NULL
)
472 m_pUserLog
->StopWriting((float) GetNats());
475 void CDasherInterfaceBase::Halt() {
476 SetBoolParameter(BP_DASHER_PAUSED
, true);
478 // This will cause us to reinitialise the frame rate counter - ie we start off slowly
479 if(m_pDasherModel
!= 0)
480 m_pDasherModel
->Halt();
483 void CDasherInterfaceBase::Unpause(unsigned long Time
) {
484 SetBoolParameter(BP_DASHER_PAUSED
, false);
486 if(m_pDasherModel
!= 0)
487 m_pDasherModel
->Reset_framerate(Time
);
489 Dasher::CStartEvent oEvent
;
490 m_pEventHandler
->InsertEvent(&oEvent
);
493 if (m_pUserLog
!= NULL
)
494 m_pUserLog
->StartWriting();
497 void CDasherInterfaceBase::CreateInput() {
499 m_pInput
->Deactivate();
503 m_pInput
= (CDasherInput
*)GetModuleByName(GetStringParameter(SP_INPUT_DEVICE
));
507 m_pInput
->Activate();
510 if(m_pDasherView
!= 0)
511 m_pDasherView
->SetInput(m_pInput
);
514 void CDasherInterfaceBase::NewFrame(unsigned long iTime
, bool bForceRedraw
) {
515 // Fail if Dasher is locked
516 if(m_iCurrentState
!= ST_NORMAL
)
519 bool bChanged(false);
521 if(m_pDasherView
!= 0) {
522 if(!GetBoolParameter(BP_TRAINING
)) {
523 if (m_pUserLog
!= NULL
) {
525 Dasher::VECTOR_SYMBOL_PROB vAdded
;
529 bChanged
= m_pInputFilter
->Timer(iTime
, m_pDasherView
, m_pDasherModel
, &vAdded
, &iNumDeleted
);
533 m_pUserLog
->DeleteSymbols(iNumDeleted
);
534 if (vAdded
.size() > 0)
535 m_pUserLog
->AddSymbols(&vAdded
);
540 bChanged
= m_pInputFilter
->Timer(iTime
, m_pDasherView
, m_pDasherModel
, 0, 0);
544 m_pDasherModel
->CheckForNewRoot(m_pDasherView
);
548 // TODO: This is a bit hacky - we really need to sort out the redraw logic
549 if((!bChanged
&& m_bLastChanged
) || m_bRedrawScheduled
|| bForceRedraw
) {
550 m_pDasherView
->Screen()->SetCaptureBackground(true);
551 m_pDasherView
->Screen()->SetLoadBackground(true);
554 Redraw((bChanged
|| m_bLastChanged
) || m_bRedrawScheduled
|| bForceRedraw
);
556 m_bLastChanged
= bChanged
;
557 m_bRedrawScheduled
= false;
559 // This just passes the time through to the framerate tracker, so we
560 // know how often new frames are being drawn.
561 if(m_pDasherModel
!= 0)
562 m_pDasherModel
->NewFrame(iTime
);
565 void CDasherInterfaceBase::CheckRedraw() {
566 if(m_bRedrawScheduled
)
569 m_bRedrawScheduled
= false;
572 /// Full redraw - renders model, decorations and blits onto display
573 /// buffer. Not recommended if nothing has changed with the model,
574 /// otherwise we're wasting effort.
576 void CDasherInterfaceBase::Redraw(bool bRedrawNodes
) {
578 if(!m_pDasherView
|| !m_pDasherModel
)
581 // TODO: More generic notion of 'layers'?
584 m_pDasherView
->Screen()->SendMarker(0);
585 m_pDasherModel
->RenderToView(m_pDasherView
, true);
588 m_pDasherView
->Screen()->SendMarker(1);
590 bool bDecorationsChanged(false);
593 bDecorationsChanged
= m_pInputFilter
->DecorateView(m_pDasherView
);
596 bool bActionButtonsChanged(false);
597 #ifdef EXPERIMENTAL_FEATURES
598 bActionButtonsChanged
= DrawActionButtons();
601 if(bRedrawNodes
|| bDecorationsChanged
|| bActionButtonsChanged
)
602 m_pDasherView
->Display();
605 void CDasherInterfaceBase::ChangeAlphabet() {
607 if(GetStringParameter(SP_ALPHABET_ID
) == "") {
608 SetStringParameter(SP_ALPHABET_ID
, m_AlphIO
->GetDefault());
609 // This will result in ChangeAlphabet() being called again, so
610 // exit from the first recursion
616 WriteTrainFileFull();
618 // Lock Dasher to prevent changes from happening while we're training.
620 SetBoolParameter( BP_TRAINING
, true );
624 // Let our user log object know about the new alphabet since
625 // it needs to convert symbols into text for the log file.
626 if (m_pUserLog
!= NULL
)
627 m_pUserLog
->SetAlphabetPtr(m_Alphabet
);
629 // Apply options from alphabet
631 SetBoolParameter( BP_TRAINING
, false );
636 void CDasherInterfaceBase::ChangeColours() {
637 if(!m_ColourIO
|| !m_DasherScreen
)
640 // TODO: Make fuction return a pointer directly
641 m_DasherScreen
->SetColourScheme(&(m_ColourIO
->GetInfo(GetStringParameter(SP_COLOUR_ID
))));
644 void CDasherInterfaceBase::ChangeScreen(CDasherScreen
*NewScreen
) {
645 m_DasherScreen
= NewScreen
;
648 if(m_pDasherView
!= 0) {
649 m_pDasherView
->ChangeScreen(m_DasherScreen
);
651 if(GetLongParameter(LP_VIEW_ID
) != -1)
655 PositionActionButtons();
659 void CDasherInterfaceBase::ChangeView() {
660 // TODO: Actually respond to LP_VIEW_ID parameter (although there is only one view at the moment)
662 if(m_DasherScreen
!= 0 && m_pDasherModel
!= 0) {
663 delete m_pDasherView
;
665 m_pDasherView
= new CDasherViewSquare(m_pEventHandler
, m_pSettingsStore
, m_DasherScreen
);
668 m_pDasherView
->SetInput(m_pInput
);
672 const CAlphIO::AlphInfo
& CDasherInterfaceBase::GetInfo(const std::string
&AlphID
) {
673 return m_AlphIO
->GetInfo(AlphID
);
676 void CDasherInterfaceBase::SetInfo(const CAlphIO::AlphInfo
&NewInfo
) {
677 m_AlphIO
->SetInfo(NewInfo
);
680 void CDasherInterfaceBase::DeleteAlphabet(const std::string
&AlphID
) {
681 m_AlphIO
->Delete(AlphID
);
685 I've used C style I/O because I found that C++ style I/O bloated
686 the Win32 code enormously. The overhead of loading the buffer into
687 the string instead of reading straight into a string seems to be
688 negligible compared to huge requirements elsewhere.
690 int CDasherInterfaceBase::TrainFile(std::string Filename
, int iTotalBytes
, int iOffset
) {
695 if((InputFile
= fopen(Filename
.c_str(), "r")) == (FILE *) 0)
700 const int BufferSize
= 1024;
701 char InputBuffer
[BufferSize
];
706 vector
< symbol
> Symbols
;
708 CAlphabetManagerFactory::CTrainer
* pTrainer
= m_pNCManager
->GetTrainer();
710 NumberRead
= fread(InputBuffer
, 1, BufferSize
- 1, InputFile
);
711 InputBuffer
[NumberRead
] = '\0';
712 StringBuffer
+= InputBuffer
;
713 bool bIsMore
= false;
714 if(NumberRead
== (BufferSize
- 1))
718 m_Alphabet
->GetSymbols(&Symbols
, &StringBuffer
, bIsMore
);
720 pTrainer
->Train(Symbols
);
721 iTotalRead
+= NumberRead
;
723 // TODO: No reason for this to be a pointer (other than cut/paste laziness!)
725 pEvent
= new CLockEvent("Training Dasher", true, static_cast<int>((100.0 * (iTotalRead
+ iOffset
))/iTotalBytes
));
726 m_pEventHandler
->InsertEvent(pEvent
);
729 } while(NumberRead
== BufferSize
- 1);
740 void CDasherInterfaceBase::GetFontSizes(std::vector
<int >*FontSizes
) const {
741 FontSizes
->push_back(20);
742 FontSizes
->push_back(14);
743 FontSizes
->push_back(11);
744 FontSizes
->push_back(40);
745 FontSizes
->push_back(28);
746 FontSizes
->push_back(22);
747 FontSizes
->push_back(80);
748 FontSizes
->push_back(56);
749 FontSizes
->push_back(44);
752 double CDasherInterfaceBase::GetCurCPM() {
757 double CDasherInterfaceBase::GetCurFPS() {
762 // int CDasherInterfaceBase::GetAutoOffset() {
763 // if(m_pDasherView != 0) {
764 // return m_pDasherView->GetAutoOffset();
769 double CDasherInterfaceBase::GetNats() const {
771 return m_pDasherModel
->GetNats();
776 void CDasherInterfaceBase::ResetNats() {
778 m_pDasherModel
->ResetNats();
782 // TODO: Check that none of this needs to be reimplemented
784 // void CDasherInterfaceBase::InvalidateContext(bool bForceStart) {
785 // m_pDasherModel->m_strContextBuffer = "";
787 // Dasher::CEditContextEvent oEvent(10);
788 // m_pEventHandler->InsertEvent(&oEvent);
790 // std::string strNewContext(m_pDasherModel->m_strContextBuffer);
792 // // We keep track of an internal context and compare that to what
793 // // we are given - don't restart Dasher if nothing has changed.
794 // // This should really be integrated with DasherModel, which
795 // // probably will be the case when we start to deal with being able
796 // // to back off indefinitely. For now though we'll keep it in a
797 // // separate string.
799 // int iContextLength( 6 ); // The 'important' context length - should really get from language model
801 // // FIXME - use unicode lengths
803 // if(bForceStart || (strNewContext.substr( std::max(static_cast<int>(strNewContext.size()) - iContextLength, 0)) != strCurrentContext.substr( std::max(static_cast<int>(strCurrentContext.size()) - iContextLength, 0)))) {
805 // if(m_pDasherModel != NULL) {
806 // // TODO: Reimplement this
807 // // if(m_pDasherModel->m_bContextSensitive || bForceStart) {
809 // m_pDasherModel->SetContext(strNewContext);
814 // strCurrentContext = strNewContext;
815 // WriteTrainFileFull();
821 // if(m_pInputFilter && m_pInputFilter->GetMinWidth(iMinWidth)) {
822 // m_pDasherModel->LimitRoot(iMinWidth);
827 // while( m_pDasherModel->CheckForNewRoot(m_pDasherView) ) {
836 std::string
CDasherInterfaceBase::GetContext(int iStart
, int iLength
) {
839 CEditContextEvent
oEvent(iStart
, iLength
);
840 m_pEventHandler
->InsertEvent(&oEvent
);
845 void CDasherInterfaceBase::SetContext(std::string strNewContext
) {
846 m_strContext
= strNewContext
;
849 // Control mode stuff
851 void CDasherInterfaceBase::RegisterNode( int iID
, const std::string
&strLabel
, int iColour
) {
852 m_pNCManager
->RegisterNode(iID
, strLabel
, iColour
);
855 void CDasherInterfaceBase::ConnectNode(int iChild
, int iParent
, int iAfter
) {
856 m_pNCManager
->ConnectNode(iChild
, iParent
, iAfter
);
859 void CDasherInterfaceBase::DisconnectNode(int iChild
, int iParent
) {
860 m_pNCManager
->DisconnectNode(iChild
, iParent
);
863 void CDasherInterfaceBase::SetBoolParameter(int iParameter
, bool bValue
) {
864 m_pSettingsStore
->SetBoolParameter(iParameter
, bValue
);
867 void CDasherInterfaceBase::SetLongParameter(int iParameter
, long lValue
) {
868 m_pSettingsStore
->SetLongParameter(iParameter
, lValue
);
871 void CDasherInterfaceBase::SetStringParameter(int iParameter
, const std::string
& sValue
) {
872 PreSetNotify(iParameter
, sValue
);
873 m_pSettingsStore
->SetStringParameter(iParameter
, sValue
);
876 bool CDasherInterfaceBase::GetBoolParameter(int iParameter
) {
877 return m_pSettingsStore
->GetBoolParameter(iParameter
);
880 long CDasherInterfaceBase::GetLongParameter(int iParameter
) {
881 return m_pSettingsStore
->GetLongParameter(iParameter
);
884 std::string
CDasherInterfaceBase::GetStringParameter(int iParameter
) {
885 return m_pSettingsStore
->GetStringParameter(iParameter
);
888 void CDasherInterfaceBase::ResetParameter(int iParameter
) {
889 m_pSettingsStore
->ResetParameter(iParameter
);
892 // We need to be able to get at the UserLog object from outside the interface
893 CUserLogBase
* CDasherInterfaceBase::GetUserLogPtr() {
897 void CDasherInterfaceBase::KeyDown(int iTime
, int iId
) {
898 if(m_iCurrentState
!= ST_NORMAL
)
901 if(m_pInputFilter
&& !GetBoolParameter(BP_TRAINING
)) {
902 m_pInputFilter
->KeyDown(iTime
, iId
, m_pDasherModel
, m_pUserLog
);
905 if(m_pInput
&& !GetBoolParameter(BP_TRAINING
)) {
906 m_pInput
->KeyDown(iTime
, iId
);
910 void CDasherInterfaceBase::KeyUp(int iTime
, int iId
) {
911 if(m_iCurrentState
!= ST_NORMAL
)
914 if(m_pInputFilter
&& !GetBoolParameter(BP_TRAINING
)) {
915 m_pInputFilter
->KeyUp(iTime
, iId
, m_pDasherModel
);
918 if(m_pInput
&& !GetBoolParameter(BP_TRAINING
)) {
919 m_pInput
->KeyUp(iTime
, iId
);
923 void CDasherInterfaceBase::CreateInputFilter()
926 m_pInputFilter
->Deactivate();
927 m_pInputFilter
->Unref();
928 m_pInputFilter
= NULL
;
931 m_pInputFilter
= (CInputFilter
*)GetModuleByName(GetStringParameter(SP_INPUT_FILTER
));
934 m_pInputFilter
->Ref();
935 m_pInputFilter
->Activate();
938 // Fall back to a sensible alternative if for some reason the
939 // current choice isn't valid.
940 if(GetStringParameter(SP_INPUT_FILTER
) != "Normal Control")
941 SetStringParameter(SP_INPUT_FILTER
, "Normal Control");
945 void CDasherInterfaceBase::RegisterFactory(CModuleFactory
*pFactory
) {
946 m_oModuleManager
.RegisterFactory(pFactory
);
949 CDasherModule
*CDasherInterfaceBase::GetModule(ModuleID_t iID
) {
950 return m_oModuleManager
.GetModule(iID
);
953 CDasherModule
*CDasherInterfaceBase::GetModuleByName(const std::string
&strName
) {
954 return m_oModuleManager
.GetModuleByName(strName
);
957 void CDasherInterfaceBase::CreateFactories() {
958 RegisterFactory(new CWrapperFactory(m_pEventHandler
, m_pSettingsStore
, new CDefaultFilter(m_pEventHandler
, m_pSettingsStore
, this, m_pDasherModel
,3, _("Normal Control"))));
959 RegisterFactory(new CWrapperFactory(m_pEventHandler
, m_pSettingsStore
, new COneDimensionalFilter(m_pEventHandler
, m_pSettingsStore
, this, m_pDasherModel
)));
960 RegisterFactory(new CWrapperFactory(m_pEventHandler
, m_pSettingsStore
, new CEyetrackerFilter(m_pEventHandler
, m_pSettingsStore
, this, m_pDasherModel
)));
961 RegisterFactory(new CWrapperFactory(m_pEventHandler
, m_pSettingsStore
, new CClickFilter(m_pEventHandler
, m_pSettingsStore
, this)));
962 RegisterFactory(new CWrapperFactory(m_pEventHandler
, m_pSettingsStore
, new CDynamicFilter(m_pEventHandler
, m_pSettingsStore
, this)));
963 RegisterFactory(new CWrapperFactory(m_pEventHandler
, m_pSettingsStore
, new CTwoButtonDynamicFilter(m_pEventHandler
, m_pSettingsStore
, this, 14, 1, _("Two Button Dynamic Mode"))));
964 // TODO: specialist factory for button mode
965 RegisterFactory(new CWrapperFactory(m_pEventHandler
, m_pSettingsStore
, new CDasherButtons(m_pEventHandler
, m_pSettingsStore
, this, 5, 1, true,8, _("Menu Mode"))));
966 RegisterFactory(new CWrapperFactory(m_pEventHandler
, m_pSettingsStore
, new CDasherButtons(m_pEventHandler
, m_pSettingsStore
, this, 3, 0, false,10, _("Direct Mode"))));
967 // RegisterFactory(new CWrapperFactory(m_pEventHandler, m_pSettingsStore, new CDasherButtons(m_pEventHandler, m_pSettingsStore, this, 4, 0, false,11, "Buttons 3")));
968 RegisterFactory(new CWrapperFactory(m_pEventHandler
, m_pSettingsStore
, new CDasherButtons(m_pEventHandler
, m_pSettingsStore
, this, 3, 3, false,12, _("Alternating Direct Mode"))));
969 RegisterFactory(new CWrapperFactory(m_pEventHandler
, m_pSettingsStore
, new CDasherButtons(m_pEventHandler
, m_pSettingsStore
, this, 4, 2, false,13, _("Compass Mode"))));
970 RegisterFactory(new CWrapperFactory(m_pEventHandler
, m_pSettingsStore
, new CStylusFilter(m_pEventHandler
, m_pSettingsStore
, this, m_pDasherModel
,15, _("Stylus Control"))));
974 void CDasherInterfaceBase::GetPermittedValues(int iParameter
, std::vector
<std::string
> &vList
) {
975 // TODO: Deprecate direct calls to these functions
976 switch (iParameter
) {
979 m_AlphIO
->GetAlphabets(&vList
);
983 m_ColourIO
->GetColours(&vList
);
985 case SP_INPUT_FILTER
:
986 m_oModuleManager
.ListModules(1, vList
);
988 case SP_INPUT_DEVICE
:
989 m_oModuleManager
.ListModules(0, vList
);
994 void CDasherInterfaceBase::StartShutdown() {
995 ChangeState(TR_SHUTDOWN
);
998 bool CDasherInterfaceBase::GetModuleSettings(const std::string
&strName
, SModuleSettings
**pSettings
, int *iCount
) {
999 return GetModuleByName(strName
)->GetSettings(pSettings
, iCount
);
1002 void CDasherInterfaceBase::SetupActionButtons() {
1003 m_vLeftButtons
.push_back(new CActionButton(this, "Exit", true));
1004 m_vLeftButtons
.push_back(new CActionButton(this, "Preferences", false));
1005 m_vLeftButtons
.push_back(new CActionButton(this, "Help", false));
1006 m_vLeftButtons
.push_back(new CActionButton(this, "About", false));
1009 void CDasherInterfaceBase::DestroyActionButtons() {
1010 // TODO: implement and call this
1013 void CDasherInterfaceBase::PositionActionButtons() {
1017 int iCurrentOffset(16);
1019 for(std::vector
<CActionButton
*>::iterator
it(m_vLeftButtons
.begin()); it
!= m_vLeftButtons
.end(); ++it
) {
1020 (*it
)->SetPosition(16, iCurrentOffset
, 32, 32);
1021 iCurrentOffset
+= 48;
1024 iCurrentOffset
= 16;
1026 for(std::vector
<CActionButton
*>::iterator
it(m_vRightButtons
.begin()); it
!= m_vRightButtons
.end(); ++it
) {
1027 (*it
)->SetPosition(m_DasherScreen
->GetWidth() - 144, iCurrentOffset
, 128, 32);
1028 iCurrentOffset
+= 48;
1032 bool CDasherInterfaceBase::DrawActionButtons() {
1036 bool bVisible(GetBoolParameter(BP_DASHER_PAUSED
));
1038 bool bRV(bVisible
!= m_bOldVisible
);
1039 m_bOldVisible
= bVisible
;
1041 for(std::vector
<CActionButton
*>::iterator
it(m_vLeftButtons
.begin()); it
!= m_vLeftButtons
.end(); ++it
)
1042 (*it
)->Draw(m_DasherScreen
, bVisible
);
1044 for(std::vector
<CActionButton
*>::iterator
it(m_vRightButtons
.begin()); it
!= m_vRightButtons
.end(); ++it
)
1045 (*it
)->Draw(m_DasherScreen
, bVisible
);
1051 void CDasherInterfaceBase::HandleClickUp(int iTime
, int iX
, int iY
) {
1052 #ifdef EXPERIMENTAL_FEATURES
1053 bool bVisible(GetBoolParameter(BP_DASHER_PAUSED
));
1055 for(std::vector
<CActionButton
*>::iterator
it(m_vLeftButtons
.begin()); it
!= m_vLeftButtons
.end(); ++it
) {
1056 if((*it
)->HandleClickUp(iTime
, iX
, iY
, bVisible
))
1060 for(std::vector
<CActionButton
*>::iterator
it(m_vRightButtons
.begin()); it
!= m_vRightButtons
.end(); ++it
) {
1061 if((*it
)->HandleClickUp(iTime
, iX
, iY
, bVisible
))
1069 void CDasherInterfaceBase::HandleClickDown(int iTime
, int iX
, int iY
) {
1070 #ifdef EXPERIMENTAL_FEATURES
1071 bool bVisible(GetBoolParameter(BP_DASHER_PAUSED
));
1073 for(std::vector
<CActionButton
*>::iterator
it(m_vLeftButtons
.begin()); it
!= m_vLeftButtons
.end(); ++it
) {
1074 if((*it
)->HandleClickDown(iTime
, iX
, iY
, bVisible
))
1078 for(std::vector
<CActionButton
*>::iterator
it(m_vRightButtons
.begin()); it
!= m_vRightButtons
.end(); ++it
) {
1079 if((*it
)->HandleClickDown(iTime
, iX
, iY
, bVisible
))
1084 KeyDown(iTime
, 100);
1088 void CDasherInterfaceBase::ExecuteCommand(const std::string
&strName
) {
1089 // TODO: Pointless - just insert event directly
1091 CCommandEvent
*pEvent
= new CCommandEvent(strName
);
1092 m_pEventHandler
->InsertEvent(pEvent
);
1096 double CDasherInterfaceBase::GetFramerate() {
1098 return(m_pDasherModel
->Framerate());
1103 int CDasherInterfaceBase::GetRenderCount() {
1105 return(m_pDasherView
->GetRenderCount());
1110 void CDasherInterfaceBase::AddActionButton(const std::string
&strName
) {
1111 m_vRightButtons
.push_back(new CActionButton(this, strName
, false));
1115 void CDasherInterfaceBase::OnUIRealised() {
1117 ChangeState(TR_UI_INIT
);
1121 void CDasherInterfaceBase::ChangeState(ETransition iTransition
) {
1122 static EState iTransitionTable
[ST_NUM
][TR_NUM
] = {
1123 {ST_MODEL
, ST_UI
, ST_FORBIDDEN
, ST_FORBIDDEN
, ST_FORBIDDEN
},
1124 {ST_FORBIDDEN
, ST_NORMAL
, ST_FORBIDDEN
, ST_FORBIDDEN
, ST_FORBIDDEN
},
1125 {ST_NORMAL
, ST_FORBIDDEN
, ST_FORBIDDEN
, ST_FORBIDDEN
, ST_FORBIDDEN
},
1126 {ST_FORBIDDEN
, ST_FORBIDDEN
, ST_LOCKED
, ST_FORBIDDEN
, ST_SHUTDOWN
},
1127 {ST_FORBIDDEN
, ST_FORBIDDEN
, ST_FORBIDDEN
, ST_NORMAL
, ST_FORBIDDEN
},
1128 {ST_FORBIDDEN
, ST_FORBIDDEN
, ST_FORBIDDEN
, ST_FORBIDDEN
, ST_FORBIDDEN
}
1131 EState
iNewState(iTransitionTable
[m_iCurrentState
][iTransition
]);
1133 if(iNewState
!= ST_FORBIDDEN
) {
1134 LeaveState(m_iCurrentState
);
1135 EnterState(iNewState
);
1137 m_iCurrentState
= iNewState
;
1141 void CDasherInterfaceBase::LeaveState(EState iState
) {
1145 void CDasherInterfaceBase::EnterState(EState iState
) {
1149 WriteTrainFileFull();
1157 void CDasherInterfaceBase::AddLock(int iLockFlags
) {
1158 if(m_iLockCount
== 0)
1159 ChangeState(TR_LOCK
);
1164 void CDasherInterfaceBase::ReleaseLock(int iLockFlags
) {
1165 if(m_iLockCount
> 0)
1168 if(m_iLockCount
== 0)
1169 ChangeState(TR_UNLOCK
);
1172 void CDasherInterfaceBase::SetBuffer(int iOffset
) {
1173 CreateModel(iOffset
);
1176 void CDasherInterfaceBase::UnsetBuffer() {
1177 // TODO: Write training file?
1179 delete m_pDasherModel
;
1184 void CDasherInterfaceBase::SetOffset(int iOffset
) {
1186 m_pDasherModel
->SetOffset(iOffset
, m_pDasherView
);
1189 void CDasherInterfaceBase::SetControlOffset(int iOffset
) {
1191 m_pDasherModel
->SetControlOffset(iOffset
);