1 // DasherInterfaceBase.cpp
3 // Copyright (c) 2008 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 "DasherViewSquare.h"
26 #include "ControlManager.h"
27 #include "DasherScreen.h"
28 #include "DasherView.h"
29 #include "DasherInput.h"
30 #include "DasherModel.h"
31 #include "Observable.h"
33 #include "NodeCreationManager.h"
36 #include "GameModule.h"
37 #include "FileWordGenerator.h"
40 #include "AlternatingDirectMode.h"
41 #include "ButtonMode.h"
42 #include "ClickFilter.h"
43 #include "CompassMode.h"
44 #include "DefaultFilter.h"
45 #include "DemoFilter.h"
46 #include "OneButtonFilter.h"
47 #include "OneButtonDynamicFilter.h"
48 #include "OneDimensionalFilter.h"
49 #include "StylusFilter.h"
50 #include "TwoButtonDynamicFilter.h"
51 #include "TwoPushDynamicFilter.h"
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
;
69 CFileLogger
* g_pLogger
= NULL
;
71 using namespace Dasher
;
74 // Track memory leaks on Windows to the line that new'd the memory
76 #ifdef _DEBUG_MEMLEAKS
77 #define DEBUG_NEW new( _NORMAL_BLOCK, THIS_FILE, __LINE__ )
80 static char THIS_FILE
[] = __FILE__
;
84 CDasherInterfaceBase::CDasherInterfaceBase(CSettingsStore
*pSettingsStore
, CFileUtils
* fileUtils
)
85 : CSettingsUser(pSettingsStore
),
86 m_pDasherModel(new CDasherModel()),
87 m_pFramerate(new CFrameRate(this)),
88 m_pSettingsStore(pSettingsStore
),
90 m_preSetObserver(*pSettingsStore
){
92 pSettingsStore
->Register(this);
93 pSettingsStore
->PreSetObservable().Register(&m_preSetObserver
);
95 m_fileUtils
= fileUtils
;
97 // Ensure that pointers to 'owned' objects are set to NULL.
98 m_DasherScreen
= NULL
;
101 m_pInputFilter
= NULL
;
104 m_ControlBoxIO
= NULL
;
107 m_defaultPolicy
= NULL
;
108 m_pWordSpeaker
= NULL
;
109 m_pGameModule
= NULL
;
111 // Various state variables
112 m_bRedrawScheduled
= false;
114 // m_bGlobalLock = false;
116 // Global logging object we can use from anywhere
117 g_pLogger
= new CFileLogger("dasher.log",
122 void CDasherInterfaceBase::Realize(unsigned long ulTime
) {
124 //if ChangeScreen has been called, we'll have created a view;
125 // otherwise, we still can't create a view, until we have a screen!
126 DASHER_ASSERT(m_DasherScreen
? m_pDasherView
!=NULL
: m_pDasherView
==NULL
);
130 m_AlphIO
= new CAlphIO(this);
131 ScanFiles(m_AlphIO
, "alphabet*.xml");
133 m_ColourIO
= new CColourIO(this);
134 ScanFiles(m_ColourIO
, "colour*.xml");
136 m_ControlBoxIO
= new CControlBoxIO(this);
137 ScanFiles(m_ControlBoxIO
, "control*.xml");
142 // Create the user logging object if we are suppose to. We wait
143 // until now so we have the real value of the parameter and not
146 // TODO: Sort out log type selection
148 int iUserLogLevel
= GetLongParameter(LP_USER_LOG_LEVEL_MASK
);
150 if(iUserLogLevel
== 10)
151 m_pUserLog
= new CBasicLog(this, this);
152 else if (iUserLogLevel
> 0)
153 m_pUserLog
= new CUserLog(this, this, iUserLogLevel
);
157 ChangeAlphabet(); // This creates the NodeCreationManager, the Alphabet,
158 //and the tree of nodes in the model.
162 //we may have created a control manager already; in which case, we need
163 // it to realize there's now an inputfilter (which may provide more actions).
164 // So tell it the setting has changed...
165 if (CControlManager
*pCon
= m_pNCManager
->GetControlManager())
166 pCon
->HandleEvent(SP_INPUT_FILTER
);
168 HandleEvent(LP_NODE_BUDGET
);
169 HandleEvent(BP_SPEAK_WORDS
);
171 // FIXME - need to rationalise this sort of thing.
172 // InvalidateContext(true);
175 // All the setup is done by now, so let the user log object know
176 // that future parameter changes should be logged.
177 if (m_pUserLog
!= NULL
)
178 m_pUserLog
->InitIsDone();
181 CDasherInterfaceBase::~CDasherInterfaceBase() {
182 //WriteTrainFileFull();???
183 delete m_pDasherModel
; // The order of some of these deletions matters
184 delete m_pDasherView
;
185 delete m_ControlBoxIO
;
189 // Do NOT delete Edit box or Screen. This class did not create them.
191 // When we destruct on shutdown, we'll output any detailed log file
192 if (m_pUserLog
!= NULL
)
194 m_pUserLog
->OutputFile();
199 if (g_pLogger
!= NULL
) {
206 void CDasherInterfaceBase::CPreSetObserver::HandleEvent(int iParameter
) {
209 string value
= m_settingsStore
.GetStringParameter(SP_ALPHABET_ID
);
210 // Cycle the alphabet history
211 vector
<string
> newHistory
;
212 newHistory
.push_back(value
);
214 if ((v
= m_settingsStore
.GetStringParameter(SP_ALPHABET_1
)) != value
)
215 newHistory
.push_back(v
);
216 if ((v
= m_settingsStore
.GetStringParameter(SP_ALPHABET_2
)) != value
)
217 newHistory
.push_back(v
);
218 if ((v
= m_settingsStore
.GetStringParameter(SP_ALPHABET_3
)) != value
)
219 newHistory
.push_back(v
);
220 if ((v
= m_settingsStore
.GetStringParameter(SP_ALPHABET_4
)) != value
)
221 newHistory
.push_back(v
);
224 while (newHistory
.size() < 4)
225 newHistory
.push_back("");
227 m_settingsStore
.SetStringParameter(SP_ALPHABET_1
, newHistory
[0]);
228 m_settingsStore
.SetStringParameter(SP_ALPHABET_2
, newHistory
[1]);
229 m_settingsStore
.SetStringParameter(SP_ALPHABET_3
, newHistory
[2]);
230 m_settingsStore
.SetStringParameter(SP_ALPHABET_4
, newHistory
[3]);
235 void CDasherInterfaceBase::HandleEvent(int iParameter
) {
236 switch (iParameter
) {
238 case LP_OUTLINE_WIDTH
:
244 case BP_DRAW_MOUSE_LINE
:
248 m_pDasherView
->SetOrientation(ComputeOrientation());
259 case BP_PALETTE_CHANGE
:
260 if(GetBoolParameter(BP_PALETTE_CHANGE
))
261 SetStringParameter(SP_COLOUR_ID
, m_pNCManager
->GetAlphabet()->GetPalette());
263 case LP_LANGUAGE_MODEL_ID
:
269 case LP_DASHER_FONTSIZE
:
272 case SP_INPUT_DEVICE
:
275 case SP_INPUT_FILTER
:
279 case LP_MARGIN_WIDTH
:
283 case LP_SHAPE_TYPE
: //for platforms which actually have this as a GUI pref!
287 delete m_defaultPolicy
;
288 m_defaultPolicy
= new AmortizedPolicy(m_pDasherModel
,GetLongParameter(LP_NODE_BUDGET
));
291 delete m_pWordSpeaker
;
292 m_pWordSpeaker
= GetBoolParameter(BP_SPEAK_WORDS
) ? new WordSpeaker(this) : NULL
;
294 case BP_CONTROL_MODE
:
295 case SP_CONTROL_BOX_ID
:
296 // force rebuilding every node. If not control box is accessed after delete.
304 void CDasherInterfaceBase::EnterGameMode(CGameModule
*pGameModule
) {
305 DASHER_ASSERT(m_pGameModule
== NULL
);
306 if (CWordGeneratorBase
*pWords
= m_pNCManager
->GetAlphabetManager()->GetGameWords()) {
307 if (!pGameModule
) pGameModule
=CreateGameModule();
308 m_pGameModule
=pGameModule
;
309 //m_pNCManager->updateControl();
310 m_pGameModule
->SetWordGenerator(m_pNCManager
->GetAlphabet(), pWords
);
312 ///TRANSLATORS: %s is the name of the alphabet; the string "GameTextFile"
313 /// refers to a setting name in gsettings or equivalent, and should not be translated.
314 FormatMessageWithString(_("Could not find game sentences file for %s - check alphabet definition, or override with GameTextFile setting"),
315 m_pNCManager
->GetAlphabet()->GetID().c_str());
316 delete pGameModule
; //does nothing if null.
320 void CDasherInterfaceBase::LeaveGameMode() {
321 DASHER_ASSERT(m_pGameModule
);
322 CGameModule
*pMod
= m_pGameModule
;
323 m_pGameModule
=NULL
; //point at which we officially exit game mode
325 //m_pNCManager->updateControl();
329 CDasherInterfaceBase::WordSpeaker::WordSpeaker(CDasherInterfaceBase
*pIntf
) : TransientObserver
<const CEditEvent
*>(pIntf
) {
332 void CDasherInterfaceBase::WordSpeaker::HandleEvent(const CEditEvent
*pEditEvent
) {
333 CDasherInterfaceBase
*pIntf(static_cast<CDasherInterfaceBase
*> (m_pEventHandler
));
334 if (pIntf
->GetGameModule()) return;
335 if(pEditEvent
->m_iEditType
== 1) {
336 if (pIntf
->SupportsSpeech()) {
337 const CAlphInfo
*pAlphabet
= pIntf
->m_pNCManager
->GetAlphabet();
338 if (pEditEvent
->m_sText
== pAlphabet
->GetText(pAlphabet
->GetSpaceSymbol())) {
339 pIntf
->Speak(m_strCurrentWord
, false);
342 m_strCurrentWord
+=pEditEvent
->m_sText
;
345 else if(pEditEvent
->m_iEditType
== 2) {
346 m_strCurrentWord
= m_strCurrentWord
.substr(0, max(static_cast<string::size_type
>(0), m_strCurrentWord
.size()-pEditEvent
->m_sText
.size()));
350 void CDasherInterfaceBase::SetLockStatus(const string
&strText
, int iPercent
) {
351 string newMessage
; //empty - what we want if iPercent==-1 (unlock)
354 os
<< (strText
.empty() ? "Training Dasher" : strText
);
355 if (iPercent
) os
<< " " << iPercent
<< "%";
356 newMessage
= os
.str();
358 if (newMessage
!= m_strLockMessage
) {
364 m_strLockMessage
= newMessage
;
368 void CDasherInterfaceBase::editOutput(const std::string
&strText
, CDasherNode
*pCause
) {
369 CEditEvent
evt(CEditEvent::EDIT_OUTPUT
, strText
, pCause
);
373 void CDasherInterfaceBase::editDelete(const std::string
&strText
, CDasherNode
*pCause
) {
374 CEditEvent
evt(CEditEvent::EDIT_DELETE
, strText
, pCause
);
378 void CDasherInterfaceBase::editConvert(CDasherNode
*pCause
) {
379 CEditEvent
evt(CEditEvent::EDIT_CONVERT
, "", pCause
);
383 void CDasherInterfaceBase::editProtect(CDasherNode
*pCause
) {
384 CEditEvent
evt(CEditEvent::EDIT_PROTECT
, "", pCause
);
388 void CDasherInterfaceBase::WriteTrainFileFull() {
389 m_pNCManager
->GetAlphabetManager()->WriteTrainFileFull(this);
392 void CDasherInterfaceBase::CreateNCManager() {
394 if(!m_AlphIO
|| GetLongParameter(LP_LANGUAGE_MODEL_ID
)==-1)
397 //can't delete the old manager yet until we've deleted all its nodes...
398 CNodeCreationManager
*pOldMgr
= m_pNCManager
;
400 //now create the new manager...
401 m_pNCManager
= new CNodeCreationManager(this, this, m_AlphIO
, m_ControlBoxIO
);
402 if (GetBoolParameter(BP_PALETTE_CHANGE
))
403 SetStringParameter(SP_COLOUR_ID
, m_pNCManager
->GetAlphabet()->GetPalette());
405 if (m_DasherScreen
) {
406 m_pNCManager
->ChangeScreen(m_DasherScreen
);
407 //and start a new tree of nodes from it (retaining old offset -
408 // this will be a sensible default of 0 if no nodes previously existed).
409 // This deletes the old tree of nodes...
410 SetOffset(m_pDasherModel
->GetOffset(), true);
411 } //else, if there is no screen, the model should not contain any nodes from the old NCManager. (Assert, somehow?)
413 //...so now we can delete the old manager
417 CDasherInterfaceBase::TextAction::TextAction(CDasherInterfaceBase
*pIntf
) : m_pIntf(pIntf
) {
418 m_iStartOffset
= pIntf
->GetAllContextLenght();
419 pIntf
->m_vTextActions
.insert(this);
422 CDasherInterfaceBase::TextAction::~TextAction() {
423 m_pIntf
->m_vTextActions
.erase(this);
426 void CDasherInterfaceBase::TextAction::executeOnDistance(CControlManager::EditDistance dist
) {
427 (*this)(strLast
= m_pIntf
->GetTextAroundCursor(dist
));
428 m_iStartOffset
= m_pIntf
->GetAllContextLenght();
431 void CDasherInterfaceBase::TextAction::executeOnNew() {
432 (*this)(strLast
= m_pIntf
->GetContext(m_iStartOffset
, m_pIntf
->GetAllContextLenght() - m_iStartOffset
));
433 m_iStartOffset
= m_pIntf
->GetAllContextLenght();
436 void CDasherInterfaceBase::TextAction::executeLast() {
440 void CDasherInterfaceBase::TextAction::NotifyOffset(int iOffset
) {
441 m_iStartOffset
= min(m_pIntf
->GetAllContextLenght(), m_iStartOffset
);
445 bool CDasherInterfaceBase::hasDone() {
446 return (GetBoolParameter(BP_COPY_ALL_ON_STOP
) && SupportsClipboard())
447 || (GetBoolParameter(BP_SPEAK_ALL_ON_STOP
) && SupportsSpeech());
450 void CDasherInterfaceBase::Done() {
453 if (m_pUserLog
!= NULL
)
454 m_pUserLog
->StopWriting((float) GetNats());
456 if (GetBoolParameter(BP_COPY_ALL_ON_STOP
) && SupportsClipboard()) {
457 CopyToClipboard(GetAllContext());
459 if (GetBoolParameter(BP_SPEAK_ALL_ON_STOP
) && SupportsSpeech()) {
460 Speak(GetAllContext(), true);
464 void CDasherInterfaceBase::CreateInput() {
466 m_pInput
->Deactivate();
469 m_pInput
= (CDasherInput
*)GetModuleByName(GetStringParameter(SP_INPUT_DEVICE
));
471 if (m_pInput
== NULL
)
472 m_pInput
= m_oModuleManager
.GetDefaultInputDevice();
475 m_pInput
->Activate();
479 void CDasherInterfaceBase::NewFrame(unsigned long iTime
, bool bForceRedraw
) {
480 // Prevent NewFrame from being reentered. This can happen occasionally and
482 static bool bReentered
=false;
485 std::cout
<< "CDasherInterfaceBase::NewFrame was re-entered" << std::endl
;
492 //ok, can draw _something_. Try and see what we can :).
494 bool bBlit
= false; //set to true if we actually render anything different i.e. that needs blitting to display
496 if (isLocked() || !m_pDasherView
) {
497 //Hmmm. If we're locked, NewFrame is never actually called - the thread
498 // that would be rendering frames, is the same one doing the training.
499 // So the following is never actually executed atm, but may be a simple
500 // template if/when we ever implement multithreading widely/properly...
501 m_DasherScreen
->SendMarker(0); //this replaces the nodes...
502 const screenint iSW
= m_DasherScreen
->GetWidth(), iSH
= m_DasherScreen
->GetHeight();
503 m_DasherScreen
->DrawRectangle(0,0,iSW
,iSH
,0,0,0); //fill in colour 0 = white
504 unsigned int iSize(GetLongParameter(LP_MESSAGE_FONTSIZE
));
505 if (!m_pLockLabel
) m_pLockLabel
= m_DasherScreen
->MakeLabel(m_strLockMessage
, iSize
);
506 pair
<screenint
,screenint
> dims
= m_DasherScreen
->TextSize(m_pLockLabel
, iSize
);
507 m_DasherScreen
->DrawString(m_pLockLabel
, (iSW
-dims
.first
)/2, (iSH
-dims
.second
)/2, iSize
, 4);
508 m_DasherScreen
->SendMarker(1); //decorations - don't draw any
511 CExpansionPolicy
*pol
=m_defaultPolicy
;
513 //1. Schedule any per-frame movement in the model...
515 m_pInputFilter
->Timer(iTime
, m_pDasherView
, m_pInput
, m_pDasherModel
, &pol
);
519 //If we've been told to render another frame via ScheduleRedraw,
520 // that's the same as passing in true to NewFrame.
521 if (m_bRedrawScheduled
) bForceRedraw
=true;
522 m_bRedrawScheduled
=false;
524 //Apply any movement that has been scheduled
525 if (m_pDasherModel
->NextScheduledStep()) {
527 if (!m_bLastMoved
) onUnpause(iTime
);
528 // ...so definitely need to render the nodes. We also make sure
529 // to render at least one more frame - think that's a bit of policy
530 // just to be on the safe side, and may not be strictly necessary...
531 bForceRedraw
=m_bRedrawScheduled
=m_bLastMoved
=true;
534 if (m_bLastMoved
) bForceRedraw
=true;//move into onPause() method if reqd
537 //2. Render nodes decorations, messages
538 bBlit
= Redraw(iTime
, bForceRedraw
, *pol
);
540 if (m_pUserLog
!= NULL
) {
541 //(any) UserLogBase will have been watching output events to gather information
542 // about symbols added/deleted; this tells it to apply that information at end-of-frame
543 // (previously DashIntf gathered the info, and then passed it to the logger here).
544 m_pUserLog
->FrameEnded();
547 if (FinishRender(iTime
)) bBlit
= true;
548 if (bBlit
) m_DasherScreen
->Display();
554 void CDasherInterfaceBase::onUnpause(unsigned long lTime
) {
555 //TODO When Game+UserLog modules are combined => reduce to just one call here
557 m_pGameModule
->StartWriting(lTime
);
559 m_pUserLog
->StartWriting();
562 bool CDasherInterfaceBase::Redraw(unsigned long ulTime
, bool bRedrawNodes
, CExpansionPolicy
&policy
) {
563 DASHER_ASSERT(m_pDasherView
);
567 m_pDasherView
->Screen()->SendMarker(0);
568 if (m_pDasherModel
) {
569 m_pDasherModel
->RenderToView(m_pDasherView
,policy
);
570 // if anything was expanded or collapsed render at least one more
576 m_pGameModule
->DecorateView(ulTime
, m_pDasherView
, m_pDasherModel
);
579 //From here on, we'll use bRedrawNodes just to denote whether we need to blit the display...
581 // Draw the decorations
582 m_pDasherView
->Screen()->SendMarker(1);
586 if (m_pInputFilter
->DecorateView(m_pDasherView
, m_pInput
)) bRedrawNodes
=true;
593 void CDasherInterfaceBase::ChangeAlphabet() {
594 if(GetStringParameter(SP_ALPHABET_ID
) == "") {
595 SetStringParameter(SP_ALPHABET_ID
, m_AlphIO
->GetDefault());
596 // This will result in ChangeAlphabet() being called again, so
597 // exit from the first recursion
601 if (m_pNCManager
) WriteTrainFileFull(); //can't/don't before creating first NCManager
605 // Lock Dasher to prevent changes from happening while we're training.
608 if (m_pDasherView
) m_pDasherView
->SetOrientation(ComputeOrientation());
609 // Apply options from alphabet
614 Opts::ScreenOrientations
CDasherInterfaceBase::ComputeOrientation() {
615 Opts::ScreenOrientations
pref(Opts::ScreenOrientations(GetLongParameter(LP_ORIENTATION
)));
616 if (pref
!=Opts::AlphabetDefault
) return pref
;
617 if (m_pNCManager
) return m_pNCManager
->GetAlphabet()->GetOrientation();
618 //haven't created the NCManager yet, so not yet reached Realize, but must
619 // have been given Screen (to make View). Use default LR for now, as when
620 // we ChangeAlphabet, we'll update the view.
621 return Opts::LeftToRight
;
624 void CDasherInterfaceBase::ChangeColours() {
625 if(!m_ColourIO
|| !m_DasherScreen
)
628 // TODO: Make fuction return a pointer directly
629 m_DasherScreen
->SetColourScheme(&(m_ColourIO
->GetInfo(GetStringParameter(SP_COLOUR_ID
))));
632 void CDasherInterfaceBase::ChangeScreen(CDasherScreen
*NewScreen
) {
634 m_DasherScreen
= NewScreen
;
637 if(m_pDasherView
!= 0) {
638 m_pDasherView
->ChangeScreen(NewScreen
);
639 ScreenResized(NewScreen
);
641 //We can create the view as soon as we have a screen...
646 m_pNCManager
->ChangeScreen(m_DasherScreen
);
648 SetOffset(m_pDasherModel
->GetOffset(), true);
652 void CDasherInterfaceBase::ScreenResized(CDasherScreen
*pScreen
) {
653 DASHER_ASSERT(pScreen
== m_DasherScreen
);
654 if (!m_pDasherView
) return;
655 m_pDasherView
->ScreenResized(m_DasherScreen
);
657 //Really, would like to do a Redraw _immediately_, but this will have to do.
661 void CDasherInterfaceBase::ChangeView() {
662 if(m_DasherScreen
!= 0 /*&& m_pDasherModel != 0*/) {
663 CDasherView
*pNewView
= new CDasherViewSquare(this, m_DasherScreen
, ComputeOrientation());
664 //the previous sends an event to all listeners registered with it, but there aren't any atm!
665 // so send an event to tell them of the new view object _and_ get them to recompute coords:
666 if (m_pDasherView
) m_pDasherView
->TransferObserversTo(pNewView
);
667 delete m_pDasherView
;
669 m_pDasherView
= pNewView
;
674 double CDasherInterfaceBase::GetCurCPM() {
679 double CDasherInterfaceBase::GetCurFPS() {
684 const CAlphInfo
*CDasherInterfaceBase::GetActiveAlphabet() {
685 return m_AlphIO
->GetInfo(GetStringParameter(SP_ALPHABET_ID
));
688 // int CDasherInterfaceBase::GetAutoOffset() {
689 // if(m_pDasherView != 0) {
690 // return m_pDasherView->GetAutoOffset();
695 double CDasherInterfaceBase::GetNats() const {
697 return m_pDasherModel
->GetNats();
702 void CDasherInterfaceBase::ResetNats() {
704 m_pDasherModel
->ResetNats();
707 void CDasherInterfaceBase::ClearAllContext() {
708 ctrlDelete(true, CControlManager::EDIT_FILE
);
709 ctrlDelete(false, CControlManager::EDIT_FILE
);
713 void CDasherInterfaceBase::ResetParameter(int iParameter
) {
714 m_pSettingsStore
->ResetParameter(iParameter
);
717 // We need to be able to get at the UserLog object from outside the interface
718 CUserLogBase
* CDasherInterfaceBase::GetUserLogPtr() {
722 void CDasherInterfaceBase::KeyDown(unsigned long iTime
, int iId
) {
727 m_pInputFilter
->KeyDown(iTime
, iId
, m_pDasherView
, m_pInput
, m_pDasherModel
);
731 m_pInput
->KeyDown(iTime
, iId
);
735 void CDasherInterfaceBase::KeyUp(unsigned long iTime
, int iId
) {
740 m_pInputFilter
->KeyUp(iTime
, iId
, m_pDasherView
, m_pInput
, m_pDasherModel
);
744 m_pInput
->KeyUp(iTime
, iId
);
748 void CDasherInterfaceBase::CreateInputFilter() {
750 m_pInputFilter
->pause();
751 m_pInputFilter
->Deactivate();
752 m_pInputFilter
= NULL
;
755 m_pInputFilter
= (CInputFilter
*)GetModuleByName(GetStringParameter(SP_INPUT_FILTER
));
757 if (m_pInputFilter
== NULL
)
758 m_pInputFilter
= m_oModuleManager
.GetDefaultInputMethod();
760 m_pInputFilter
->Activate();
763 CDasherModule
*CDasherInterfaceBase::RegisterModule(CDasherModule
*pModule
) {
764 return m_oModuleManager
.RegisterModule(pModule
);
767 CDasherModule
*CDasherInterfaceBase::GetModule(ModuleID_t iID
) {
768 return m_oModuleManager
.GetModule(iID
);
771 CDasherModule
*CDasherInterfaceBase::GetModuleByName(const std::string
&strName
) {
772 return m_oModuleManager
.GetModuleByName(strName
);
775 void CDasherInterfaceBase::SetDefaultInputDevice(CDasherInput
*pModule
) {
776 m_oModuleManager
.SetDefaultInputDevice(pModule
);
779 void CDasherInterfaceBase::SetDefaultInputMethod(CInputFilter
*pModule
) {
780 m_oModuleManager
.SetDefaultInputMethod(pModule
);
783 void CDasherInterfaceBase::CreateModules() {
784 CInputFilter
*defFil
= new CDefaultFilter(this, this, m_pFramerate
, 3, _("Normal Control"));
785 RegisterModule(defFil
);
786 SetDefaultInputMethod(defFil
);
787 RegisterModule(new COneDimensionalFilter(this, this, m_pFramerate
));
788 RegisterModule(new CClickFilter(this, this));
789 RegisterModule(new COneButtonFilter(this, this));
790 RegisterModule(new COneButtonDynamicFilter(this, this, m_pFramerate
));
791 RegisterModule(new CTwoButtonDynamicFilter(this, this, m_pFramerate
));
792 RegisterModule(new CTwoPushDynamicFilter(this, this, m_pFramerate
));
793 // TODO: specialist factory for button mode
794 RegisterModule(new CButtonMode(this, this, true, 8, _("Menu Mode")));
795 RegisterModule(new CButtonMode(this, this, false,10, _("Direct Mode")));
796 // RegisterModule(new CDasherButtons(this, this, 4, 0, false,11, "Buttons 3"));
797 RegisterModule(new CAlternatingDirectMode(this, this));
798 RegisterModule(new CCompassMode(this, this));
799 RegisterModule(new CStylusFilter(this, this, m_pFramerate
));
800 //WIP Temporary as too many segfaults! //RegisterModule(new CDemoFilter(this, this, m_pFramerate));
803 void CDasherInterfaceBase::GetPermittedValues(int iParameter
, std::vector
<std::string
> &vList
) {
804 // TODO: Deprecate direct calls to these functions
805 switch (iParameter
) {
807 DASHER_ASSERT(m_AlphIO
!= NULL
);
808 m_AlphIO
->GetAlphabets(&vList
);
811 DASHER_ASSERT(m_ColourIO
!= NULL
);
812 m_ColourIO
->GetColours(&vList
);
814 case SP_CONTROL_BOX_ID
:
815 DASHER_ASSERT(m_ControlBoxIO
!= NULL
);
816 m_ControlBoxIO
->GetControlBoxes(&vList
);
818 case SP_INPUT_FILTER
:
819 m_oModuleManager
.ListModules(1, vList
);
821 case SP_INPUT_DEVICE
:
822 m_oModuleManager
.ListModules(0, vList
);
827 bool CDasherInterfaceBase::GetModuleSettings(const std::string
&strName
, SModuleSettings
**pSettings
, int *iCount
) {
828 return GetModuleByName(strName
)->GetSettings(pSettings
, iCount
);
831 void CDasherInterfaceBase::SetOffset(int iOffset
, bool bForce
) {
832 if (iOffset
== m_pDasherModel
->GetOffset() && !bForce
) return;
834 CDasherNode
*pNode
= m_pNCManager
->GetAlphabetManager()->GetRoot(NULL
, iOffset
!=0, iOffset
);
835 if (GetGameModule()) pNode
->SetFlag(NF_GAME
, true);
836 m_pDasherModel
->SetNode(pNode
);
838 //ACL TODO note that CTL_MOVE, etc., do not come here (that would probably
839 // rebuild the model / violently repaint the screen every time!). But we
840 // still want to notifyOffset all text actions, so the "New" suboption sees
841 // all the editing the user's done...
843 for (set
<TextAction
*>::iterator it
= m_vTextActions
.begin(); it
!=m_vTextActions
.end(); it
++) {
844 (*it
)->NotifyOffset(iOffset
);
850 // Returns 0 on success, an error string on failure.
851 const char* CDasherInterfaceBase::ClSet(const std::string
&strKey
, const std::string
&strValue
) {
852 return m_pSettingsStore
->ClSet(strKey
, strValue
);
857 CDasherInterfaceBase::ImportTrainingText(const std::string
&strPath
) {
859 m_pNCManager
->ImportTrainingText(strPath
);