Updated German translation
[dasher.git] / Src / DasherCore / DasherInterfaceBase.cpp
blobd9bb86871a8eb165f2da4d1109d774e6362e8fd0
1 // DasherInterfaceBase.cpp
2 //
3 // Copyright (c) 2008 The Dasher Team
4 //
5 // This file is part of Dasher.
6 //
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"
32 #include "Event.h"
33 #include "NodeCreationManager.h"
34 #include "UserLog.h"
35 #include "BasicLog.h"
36 #include "GameModule.h"
37 #include "FileWordGenerator.h"
39 // Input filters
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"
53 // STL headers
54 #include <cstdio>
55 #include <iostream>
56 #include <memory>
57 #include <sstream>
59 // Declare our global file logging object
60 #include "../DasherCore/FileLogger.h"
61 #ifdef _DEBUG
62 const eLogLevel g_iLogLevel = logDEBUG;
63 const int g_iLogOptions = logTimeStamp | logDateStamp | logDeleteOldFile;
64 #else
65 const eLogLevel g_iLogLevel = logNORMAL;
66 const int g_iLogOptions = logTimeStamp | logDateStamp;
67 #endif
69 CFileLogger* g_pLogger = NULL;
71 using namespace Dasher;
72 using namespace std;
74 // Track memory leaks on Windows to the line that new'd the memory
75 #ifdef _WIN32
76 #ifdef _DEBUG_MEMLEAKS
77 #define DEBUG_NEW new( _NORMAL_BLOCK, THIS_FILE, __LINE__ )
78 #define new DEBUG_NEW
79 #undef THIS_FILE
80 static char THIS_FILE[] = __FILE__;
81 #endif
82 #endif
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),
89 m_pLockLabel(NULL),
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;
99 m_pDasherView = NULL;
100 m_pInput = NULL;
101 m_pInputFilter = NULL;
102 m_AlphIO = NULL;
103 m_ColourIO = NULL;
104 m_ControlBoxIO = NULL;
105 m_pUserLog = NULL;
106 m_pNCManager = 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",
118 g_iLogLevel,
119 g_iLogOptions);
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);
128 srand(ulTime);
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");
139 ChangeColours();
141 ChangeView();
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
144 // just the default.
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);
155 CreateModules();
157 ChangeAlphabet(); // This creates the NodeCreationManager, the Alphabet,
158 //and the tree of nodes in the model.
160 CreateInput();
161 CreateInputFilter();
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);
173 ScheduleRedraw();
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;
186 delete m_ColourIO;
187 delete m_AlphIO;
188 delete m_pNCManager;
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();
195 delete m_pUserLog;
196 m_pUserLog = NULL;
199 if (g_pLogger != NULL) {
200 delete g_pLogger;
201 g_pLogger = NULL;
204 delete m_pFramerate;
206 void CDasherInterfaceBase::CPreSetObserver::HandleEvent(int iParameter) {
207 switch(iParameter) {
208 case SP_ALPHABET_ID:
209 string value = m_settingsStore.GetStringParameter(SP_ALPHABET_ID);
210 // Cycle the alphabet history
211 vector<string> newHistory;
212 newHistory.push_back(value);
213 string v;
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);
223 // Fill empty slots.
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]);
231 break;
235 void CDasherInterfaceBase::HandleEvent(int iParameter) {
236 switch (iParameter) {
238 case LP_OUTLINE_WIDTH:
239 ScheduleRedraw();
240 break;
241 case BP_DRAW_MOUSE:
242 ScheduleRedraw();
243 break;
244 case BP_DRAW_MOUSE_LINE:
245 ScheduleRedraw();
246 break;
247 case LP_ORIENTATION:
248 m_pDasherView->SetOrientation(ComputeOrientation());
249 ScheduleRedraw();
250 break;
251 case SP_ALPHABET_ID:
252 ChangeAlphabet();
253 ScheduleRedraw();
254 break;
255 case SP_COLOUR_ID:
256 ChangeColours();
257 ScheduleRedraw();
258 break;
259 case BP_PALETTE_CHANGE:
260 if(GetBoolParameter(BP_PALETTE_CHANGE))
261 SetStringParameter(SP_COLOUR_ID, m_pNCManager->GetAlphabet()->GetPalette());
262 break;
263 case LP_LANGUAGE_MODEL_ID:
264 CreateNCManager();
265 break;
266 case LP_LINE_WIDTH:
267 ScheduleRedraw();
268 break;
269 case LP_DASHER_FONTSIZE:
270 ScheduleRedraw();
271 break;
272 case SP_INPUT_DEVICE:
273 CreateInput();
274 break;
275 case SP_INPUT_FILTER:
276 CreateInputFilter();
277 ScheduleRedraw();
278 break;
279 case LP_MARGIN_WIDTH:
280 case BP_NONLINEAR_Y:
281 case LP_NONLINEAR_X:
282 case LP_GEOMETRY:
283 case LP_SHAPE_TYPE: //for platforms which actually have this as a GUI pref!
284 ScheduleRedraw();
285 break;
286 case LP_NODE_BUDGET:
287 delete m_defaultPolicy;
288 m_defaultPolicy = new AmortizedPolicy(m_pDasherModel,GetLongParameter(LP_NODE_BUDGET));
289 break;
290 case BP_SPEAK_WORDS:
291 delete m_pWordSpeaker;
292 m_pWordSpeaker = GetBoolParameter(BP_SPEAK_WORDS) ? new WordSpeaker(this) : NULL;
293 break;
294 case BP_CONTROL_MODE:
295 case SP_CONTROL_BOX_ID:
296 // force rebuilding every node. If not control box is accessed after delete.
297 CreateNCManager();
298 break;
299 default:
300 break;
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);
311 } else {
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
324 delete pMod;
325 //m_pNCManager->updateControl();
326 SetBuffer(0);
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);
340 m_strCurrentWord="";
341 } else
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)
352 if (iPercent!=-1) {
353 ostringstream os;
354 os << (strText.empty() ? "Training Dasher" : strText);
355 if (iPercent) os << " " << iPercent << "%";
356 newMessage = os.str();
358 if (newMessage != m_strLockMessage) {
359 ScheduleRedraw();
360 if (m_pLockLabel) {
361 delete m_pLockLabel;
362 m_pLockLabel = NULL;
364 m_strLockMessage = newMessage;
368 void CDasherInterfaceBase::editOutput(const std::string &strText, CDasherNode *pCause) {
369 CEditEvent evt(CEditEvent::EDIT_OUTPUT, strText, pCause);
370 DispatchEvent(&evt);
373 void CDasherInterfaceBase::editDelete(const std::string &strText, CDasherNode *pCause) {
374 CEditEvent evt(CEditEvent::EDIT_DELETE, strText, pCause);
375 DispatchEvent(&evt);
378 void CDasherInterfaceBase::editConvert(CDasherNode *pCause) {
379 CEditEvent evt(CEditEvent::EDIT_CONVERT, "", pCause);
380 DispatchEvent(&evt);
383 void CDasherInterfaceBase::editProtect(CDasherNode *pCause) {
384 CEditEvent evt(CEditEvent::EDIT_PROTECT, "", pCause);
385 DispatchEvent(&evt);
388 void CDasherInterfaceBase::WriteTrainFileFull() {
389 m_pNCManager->GetAlphabetManager()->WriteTrainFileFull(this);
392 void CDasherInterfaceBase::CreateNCManager() {
394 if(!m_AlphIO || GetLongParameter(LP_LANGUAGE_MODEL_ID)==-1)
395 return;
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
414 delete pOldMgr;
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() {
437 (*this)(strLast);
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() {
451 ScheduleRedraw();
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() {
465 if(m_pInput) {
466 m_pInput->Deactivate();
469 m_pInput = (CDasherInput *)GetModuleByName(GetStringParameter(SP_INPUT_DEVICE));
471 if (m_pInput == NULL)
472 m_pInput = m_oModuleManager.GetDefaultInputDevice();
474 if(m_pInput) {
475 m_pInput->Activate();
479 void CDasherInterfaceBase::NewFrame(unsigned long iTime, bool bForceRedraw) {
480 // Prevent NewFrame from being reentered. This can happen occasionally and
481 // cause crashes.
482 static bool bReentered=false;
483 if (bReentered) {
484 #ifdef DEBUG
485 std::cout << "CDasherInterfaceBase::NewFrame was re-entered" << std::endl;
486 #endif
487 return;
489 bReentered=true;
491 if(m_DasherScreen) {
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
509 bBlit = true;
510 } else {
511 CExpansionPolicy *pol=m_defaultPolicy;
513 //1. Schedule any per-frame movement in the model...
514 if(m_pInputFilter) {
515 m_pInputFilter->Timer(iTime, m_pDasherView, m_pInput, m_pDasherModel, &pol);
517 //2. Render...
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()) {
526 //yes, we moved...
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;
532 } else {
533 //no movement
534 if (m_bLastMoved) bForceRedraw=true;//move into onPause() method if reqd
535 m_bLastMoved=false;
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();
551 bReentered=false;
554 void CDasherInterfaceBase::onUnpause(unsigned long lTime) {
555 //TODO When Game+UserLog modules are combined => reduce to just one call here
556 if (m_pGameModule)
557 m_pGameModule->StartWriting(lTime);
558 if (m_pUserLog)
559 m_pUserLog->StartWriting();
562 bool CDasherInterfaceBase::Redraw(unsigned long ulTime, bool bRedrawNodes, CExpansionPolicy &policy) {
563 DASHER_ASSERT(m_pDasherView);
565 // Draw the nodes
566 if(bRedrawNodes) {
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
571 // frame after this
572 if (policy.apply())
573 ScheduleRedraw();
575 if(m_pGameModule) {
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);
585 if(m_pInputFilter) {
586 if (m_pInputFilter->DecorateView(m_pDasherView, m_pInput)) bRedrawNodes=true;
589 return bRedrawNodes;
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
598 return;
601 if (m_pNCManager) WriteTrainFileFull(); //can't/don't before creating first NCManager
603 // Send a lock event
605 // Lock Dasher to prevent changes from happening while we're training.
607 CreateNCManager();
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)
626 return;
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;
635 ChangeColours();
637 if(m_pDasherView != 0) {
638 m_pDasherView->ChangeScreen(NewScreen);
639 ScreenResized(NewScreen);
640 } else {
641 //We can create the view as soon as we have a screen...
642 ChangeView();
645 if (m_pNCManager) {
646 m_pNCManager->ChangeScreen(m_DasherScreen);
647 if (m_pDasherModel)
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.
658 ScheduleRedraw();
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;
671 ScheduleRedraw();
674 double CDasherInterfaceBase::GetCurCPM() {
676 return 0;
679 double CDasherInterfaceBase::GetCurFPS() {
681 return 0;
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();
691 // }
692 // return -1;
693 // }
695 double CDasherInterfaceBase::GetNats() const {
696 if(m_pDasherModel)
697 return m_pDasherModel->GetNats();
698 else
699 return 0.0;
702 void CDasherInterfaceBase::ResetNats() {
703 if(m_pDasherModel)
704 m_pDasherModel->ResetNats();
707 void CDasherInterfaceBase::ClearAllContext() {
708 ctrlDelete(true, CControlManager::EDIT_FILE);
709 ctrlDelete(false, CControlManager::EDIT_FILE);
710 SetBuffer(0);
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() {
719 return m_pUserLog;
722 void CDasherInterfaceBase::KeyDown(unsigned long iTime, int iId) {
723 if(isLocked())
724 return;
726 if(m_pInputFilter) {
727 m_pInputFilter->KeyDown(iTime, iId, m_pDasherView, m_pInput, m_pDasherModel);
730 if(m_pInput) {
731 m_pInput->KeyDown(iTime, iId);
735 void CDasherInterfaceBase::KeyUp(unsigned long iTime, int iId) {
736 if(isLocked())
737 return;
739 if(m_pInputFilter) {
740 m_pInputFilter->KeyUp(iTime, iId, m_pDasherView, m_pInput, m_pDasherModel);
743 if(m_pInput) {
744 m_pInput->KeyUp(iTime, iId);
748 void CDasherInterfaceBase::CreateInputFilter() {
749 if(m_pInputFilter) {
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) {
806 case SP_ALPHABET_ID:
807 DASHER_ASSERT(m_AlphIO != NULL);
808 m_AlphIO->GetAlphabets(&vList);
809 break;
810 case SP_COLOUR_ID:
811 DASHER_ASSERT(m_ColourIO != NULL);
812 m_ColourIO->GetColours(&vList);
813 break;
814 case SP_CONTROL_BOX_ID:
815 DASHER_ASSERT(m_ControlBoxIO != NULL);
816 m_ControlBoxIO->GetControlBoxes(&vList);
817 break;
818 case SP_INPUT_FILTER:
819 m_oModuleManager.ListModules(1, vList);
820 break;
821 case SP_INPUT_DEVICE:
822 m_oModuleManager.ListModules(0, vList);
823 break;
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);
847 ScheduleRedraw();
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);
856 void
857 CDasherInterfaceBase::ImportTrainingText(const std::string &strPath) {
858 if(m_pNCManager)
859 m_pNCManager->ImportTrainingText(strPath);