1 // DasherInterfaceBase.h
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 #ifndef __DasherInterfaceBase_h__
22 #define __DasherInterfaceBase_h__
27 /// This is the Dasher source code documentation. Please try to keep
31 // TODO - there is a list of things to be configurable in my notes
32 // Check that everything that is not self-contained within the GUI is covered.
35 #include "../Common/NoClones.h"
36 #include "../Common/ModuleSettings.h"
37 #include "Alphabet/AlphIO.h"
38 #include "AutoSpeedControl.h"
40 #include "InputFilter.h"
41 #include "ModuleManager.h"
42 #include "ControlManager.h"
43 #include "FrameRate.h"
55 class CDasherInterfaceBase
;
59 class CNodeCreationManager
;
61 /// \defgroup Core Core Dasher classes
65 /// @name Platform dependent utility functions
66 /// These functions provide various platform dependent functions
67 /// required by the core. A derived class is created for each
68 /// supported platform which implements these.
72 virtual ~CFileUtils(){}
74 /// Obtain the size in bytes of a file - the way to do this is
75 /// dependent on the OS (TODO: Check this - any posix on Windows?)
77 virtual int GetFileSize(const std::string
&strFileName
) = 0;
79 ///Look for files, matching a filename pattern, in whatever system and/or user
80 /// locations as may exist - e.g. on disk, in app package, on web, whatever.
81 /// TODO, can we add a default implementation that looks on the Dasher website?
82 /// \param pattern string matching just filename (not path), potentially
83 /// including '*'s (as per glob)
84 virtual void ScanFiles(AbstractParser
*parser
, const std::string
&strPattern
) = 0;
86 // Writes file to user data directory.
87 virtual bool WriteUserDataFile(const std::string
&filename
, const std::string
&strNewText
, bool append
) = 0;
91 /// The central class in the core of Dasher. Ties together the rest of
92 /// the platform independent stuff and provides a single interface for
93 /// the UI to use. Note: CMessageDisplay unimplemented; platforms should
94 /// provide their own methods using appropriate GUI components, or subclass
95 /// CDashIntfScreenMsgs instead.
96 class Dasher::CDasherInterfaceBase
: public CMessageDisplay
, public Observable
<const CEditEvent
*>, protected Observer
<int>, protected CSettingsUser
, private NoClones
{
98 ///Create a new interface by providing the only-and-only settings store that will be used throughout.
99 CDasherInterfaceBase(CSettingsStore
*pSettingsStore
, CFileUtils
* fileUtils
);
100 virtual ~CDasherInterfaceBase();
102 /// @name Access to internal member classes
103 /// Access various classes contained within the interface. These
104 /// should be considered dangerous and use minimised. Eventually to
105 /// be replaced by properly encapsulated equivalents.
108 CUserLogBase
* GetUserLogPtr();
113 /// @name Parameter manipulation
114 /// Members for manipulating the parameters of the core Dasher object.
120 /// Reset a parameter to the default value
123 void ResetParameter(int iParmater
);
126 /// Obtain the permitted values for a string parameter - used to
127 /// geneate preferences dialogues etc.
130 void GetPermittedValues(int iParameter
, std::vector
<std::string
> &vList
);
133 /// Get a list of settings which apply to a particular module
136 bool GetModuleSettings(const std::string
&strName
, SModuleSettings
**pSettings
, int *iCount
);
140 /// Called when a parameter changes - but *after* components have been notified.
141 /// Subsumes previous Interface level event handler, for example, responsible for
142 /// restarting the Dasher model whenever parameter changes make it
143 /// invalid. Subclasses should override to forward events to SettingsUI, editbox,
144 /// etc., as appropriate, but should _call_through_to_superclass_method_ first.
145 /// \param iParameter The parameter that's just changed.
146 /// \todo Should be protected (??)
148 virtual void HandleEvent(int iParameter
);
150 ///Locks/unlocks Dasher. The default here stores the lock message and percentage
151 /// in m_strLockMessage, such that NewFrame renders this instead of the canvas
152 /// if we are locked. Subclasses may override to implement better (GUI)
153 /// notifications/dialogues, but should call through to this method to ensure
154 /// isLocked() returns the correct value.
155 /// Note that we do not support multiple/concurrent locks; each call to SetLockStatus
156 /// overrides any/all previous ones.
157 /// \param strText text of message to display, excluding %age, _if_ locked;
158 /// ignored, if unlocked.
159 /// \param iPercent -1 unlocks Dasher; anything else locks it, and indicates
161 virtual void SetLockStatus(const std::string
&strText
, int iPercent
);
163 /// Tells us whether Dasher is locked (i.e. for training).
164 /// TODO This just replaces the old BP_TRAINING; however, I'd think that _if_ we
165 /// do actually need a global function to tell whether Dasher's locked, it probably
166 /// needs to be threadsafe, which neither this nor BP_TRAINING is (I don't think!)...
167 inline bool isLocked() {return !m_strLockMessage
.empty();}
169 ///Does this subclass support speech (i.e. the speak(string) method?)
170 /// Default is just to return false.
171 virtual bool SupportsSpeech() {return false;}
172 ///Does this subclass support clipboard copying (i.e. the copyToClipboard(string) method?)
173 /// Default is just to return false.
174 virtual bool SupportsClipboard() {return false;}
176 ///Subclasses supporting speech should override to speak the supplied text
177 /// (Default implementation does nothing)
178 virtual void Speak(const std::string
&text
, bool bInterrupt
) {}
180 ///Subclasses supporting clipboard operations should override to copy
181 /// the specified text to the clipboard. (Default implementation does nothing).
182 virtual void CopyToClipboard(const std::string
&text
) {}
184 ///Called to calculate offset after control-mode "move" or delete commands.
185 ///\param bForwards true to move forwards (right), false for backwards
186 ///\param dist how far to move: character, word, line, ..., file. (Usually defined
187 /// by OS, e.g. for non-european languages)
188 ///\return the offset, into the edit buffer where the cursor would be *after* the move.
189 virtual unsigned int ctrlOffsetAfterMove(unsigned int offsetBefore
, bool bForwards
,
190 CControlManager::EditDistance iDist
) {
194 ///Called to execute a control-mode "move" command.
195 ///\param bForwards true to move forwards (right), false for backwards
196 ///\param dist how far to move: character, word, line, file. (Usually defined
197 /// by OS, e.g. for non-european languages)
198 ///\return the offset, into the edit buffer of the cursor *after* the move.
199 virtual unsigned int ctrlMove(bool bForwards
, CControlManager::EditDistance dist
)=0;
201 ///Called to execute a control-mode "delete" command.
202 ///\param bForwards true to delete forwards (right), false for backwards
203 ///\param dist how much to delete: character, word, line, file. (Usually defined
204 /// by OS, e.g. for non-european languages)
205 ///\return the offset, into the edit buffer, of the cursor *after* the delete
206 /// (for forwards deletion, this will be the same as the offset *before*)
207 virtual unsigned int ctrlDelete(bool bForwards
, CControlManager::EditDistance dist
)=0;
209 virtual void editOutput(const std::string
&strText
, CDasherNode
*pCause
);
210 virtual void editDelete(const std::string
&strText
, CDasherNode
*pCause
);
211 virtual void editConvert(CDasherNode
*pCause
);
212 virtual void editProtect(CDasherNode
*pCause
);
216 TextAction(CDasherInterfaceBase
*pMgr
);
217 void executeOnDistance(CControlManager::EditDistance dist
);
220 void NotifyOffset(int iOffset
);
221 virtual ~TextAction();
223 virtual void operator()(const std::string
&strText
)=0;
224 CDasherInterfaceBase
*m_pIntf
;
231 /// @name Starting and stopping
232 /// Methods used to instruct dynamic motion of Dasher to start or stop
235 /// Call when the user has finished writing a piece of text, to execute
236 /// any "on-stop" actions: the default implements speak on stop (if
237 /// BP_SPEAK_ON_STOP is set) and copy-on-stop (if BP_COPY_ALL_ON_STOP) is set;
238 /// subclasses may override to do more.
241 ///Whether the Done() method does anything (and so should be presented
242 /// to the user) - default deals with speak/copy-on-stop, and subclasses
243 /// which override Done() to add additional on-stop actions must/should
244 /// override this to match.
245 virtual bool hasDone();
249 /// Append text to the user training file - used to store state between sessions
250 /// \param filename name of training file, without path (e.g. "training_english_GB.txt")
251 /// \param strNewText text to append
253 void WriteTrainFile(const std::string
&filename
, const std::string
&strNewText
) {
254 m_fileUtils
->WriteUserDataFile(filename
, strNewText
, true);
258 // -----------------------------------------------------
260 // std::map<int, std::string>& GetAlphabets(); // map<key, value> int is a UID string can change. Store UID in preferences. Display string to user.
261 // std::vector<std::string>& GetAlphabets();
262 // std::vector<std::string>& GetLangModels();
263 // std::vector<std::string>& GetViews();
265 /// Supply a new CDasherScreen object onto which to render. Note this should
266 /// only be called (a) at startup, and (b) when the new screen is _significantly_
267 /// different from the old, rather than just a window resize: specifically, this means
268 /// the tree of nodes will be rebuilt with new Labels for the new screen; and in the future,
269 /// maybe also if things like colour depth, alpha transparency support, etc., change.
270 /// If the existing rendering setup should just scale to the new screen dimensions,
271 /// call ScreenResized() instead (we expect this to be the case most/all of the time,
272 /// and this method subsumes a call to ScreenResized.) Note, at startup, ChangeScreen
273 /// and Realize may occur in either order; if ChangeScreen comes after, Resize will create a
274 /// tree with null Labels, which will have to be rebuilt in the call to ChangeScreen.
275 /// \param NewScreen Pointer to the new CDasherScreen.
276 virtual void ChangeScreen(CDasherScreen
* NewScreen
);
278 ///Call when the screen dimensions have been changed, to recalculate scaling factors etc.
279 /// \param pScreen the screen whose dimensions have changed. TODO we expect this to be
280 /// the same one-and-only screen that we are using anyway, so remove parameter?
281 void ScreenResized(CDasherScreen
*pScreen
);
283 /// Train Dasher from a file
284 /// All traing data must be in UTF-8
285 /// \param Filename File to load.
286 /// \param iTotalBytes documentme
287 /// \param iOffset Document me
288 // int TrainFile(std::string Filename, int iTotalBytes, int iOffset);
290 /// New control mechanisms:
292 ///Equivalent to SetOffset(iOffset, true)
293 void SetBuffer(int iOffset
) {SetOffset(iOffset
, true);}
295 /// Rebuilds the model at the specified location, potentially reusing nodes if !bForce
296 /// @param iOffset Cursor position in attached buffer from which to obtain context
297 /// @param bForce if true, model should be completely rebuilt (even for
298 /// same offset) - characters at old offsets may have changed, or we have
299 /// a new AlphabetManager. If false, assume buffer and alphabet unchanged,
300 /// so no need to rebuild the model if an existing node covers this point.
302 /// @param bForce true meaning the entire context may have changed,
303 /// false if we've just moved around within it.
304 void SetOffset(int iOffset
, bool bForce
=false);
306 /// @name Status reporting
307 /// Get information about the runtime status of Dasher which might
308 /// be of interest for debugging purposes etc.
311 /// Get the current rate of text entry.
312 /// \retval The rate in characters per minute.
313 /// TODO: Check that this is still used
317 /// Get current refresh rate.
318 /// \retval The rate in frames per second
319 /// TODO: Check that this is still used
323 /// Get the total number of nats (base-e bits) entered.
324 /// \retval The current total
325 /// \todo Obsolete since new logging code?
327 double GetNats() const;
329 /// Reset the count of nats entered.
330 /// \todo Obsolete since new logging code?
337 /// Deals with forwarding user input to the core
339 /// Called from outside to indicate a key or mouse button has just been pushed down
340 /// \param iTime time at which button pressed
341 /// \param iId integer identifying button. TODO we need a better system here.
342 /// At present 1-4 are keys on the keyboard (or external), after mapping from e.g.
343 /// qwerty layout, such that for a user who can press 2 buttons, 1 is the primary, 2
344 /// secondary (maybe harder for them), etc. Direct mode can use an arbitrary number.
345 /// 100 is left mouse button, 101 right, 102 middle (if there is one), and so on.
346 /// (Note we do not specify the location at which mouse presses occur: the current
347 /// pointer location can be obtained from the input device if necessary)
348 void KeyDown(unsigned long iTime
, int iId
);
350 /// Called from outside to indicate a key or mouse button has just been released
351 /// \param iTime time at which button released
352 /// \param iId integer identifying button. See comments for KeyDown.
353 void KeyUp(unsigned long iTime
, int iId
);
357 // Module management functions
358 CDasherModule
*RegisterModule(CDasherModule
*pModule
);
359 CDasherModule
*GetModule(ModuleID_t iID
);
360 CDasherModule
*GetModuleByName(const std::string
&strName
);
361 CDasherInput
*GetActiveInputDevice() {return m_pInput
;}
362 CInputFilter
*GetActiveInputMethod() {return m_pInputFilter
;}
363 const CAlphInfo
*GetActiveAlphabet();
364 void SetDefaultInputDevice(CDasherInput
*);
365 void SetDefaultInputMethod(CInputFilter
*);
367 void StartShutdown();
369 void ScheduleRedraw() {
370 m_bRedrawScheduled
= true;
373 ///Subclasses should return the contents of (the specified subrange of) the edit buffer
374 virtual std::string
GetContext(unsigned int iStart
, unsigned int iLength
)=0;
376 ///Clears all written text from edit buffer and rebuilds the model. The default
377 /// implementation does this using the control mode editDelete mechanism
378 /// (one call forward, one back), followed by a call to SetBuffer(0). Subclasses
379 /// may (optionally) override with more efficient / easier implementations, but
380 /// should make the same call to SetBuffer.
381 virtual void ClearAllContext();
382 virtual std::string
GetAllContext()=0;
384 /// Subclasses should return the length of whole text. In letters, not bytes.
385 virtual int GetAllContextLenght() = 0;
387 /// Subclasses should return character, word, sentence, ... at current text cursor position.
388 /// For character around cursor decision is arbitrary. Let's settle for character before cursor.
389 /// TODO. Consistently name functions dealing with dasher context, versus functions dealing with editor text.
390 /// I.E. GetAllContext should be named GetAllTtext
391 virtual std::string
GetTextAroundCursor(CControlManager::EditDistance
) { // =0;
392 return std::string();
395 /// Set a key value pair by name - designed to allow operation from
396 /// the command line. Returns 0 on success, an error string on failure.
398 const char* ClSet(const std::string
&strKey
, const std::string
&strValue
);
400 void ImportTrainingText(const std::string
&strPath
);
402 /// Flush the/all currently-written text to the user's training file(s).
403 /// Just calls through to WriteTrainFileFull(this) on the AlphabetManager;
404 /// public so e.g. iPhone can flush the buffer when app is backgrounded.
405 void WriteTrainFileFull();
407 /// @name Platform dependent utility functions
408 /// These functions provide various platform dependent functions
409 /// required by the core. A derived class is created for each
410 /// supported platform which implements these.
414 /// Obtain the size in bytes of a file - the way to do this is
415 /// dependent on the OS (TODO: Check this - any posix on Windows?)
417 int GetFileSize(const std::string
&strFileName
) {
418 return m_fileUtils
->GetFileSize(strFileName
);
421 ///Look for files, matching a filename pattern, in whatever system and/or user
422 /// locations as may exist - e.g. on disk, in app package, on web, whatever.
423 /// TODO, can we add a default implementation that looks on the Dasher website?
424 /// \param pattern string matching just filename (not path), potentially
425 /// including '*'s (as per glob)
426 void ScanFiles(AbstractParser
*parser
, const std::string
&strPattern
) {
427 m_fileUtils
->ScanFiles(parser
, strPattern
);
432 ///Gets a pointer to the game module. This is the correct way to determine
433 /// whether game mode is currently on or off.
434 /// \return pointer to current game module, if game mode on; or null, if off.
435 CGameModule
*GetGameModule() {
436 return m_pGameModule
;
439 ///Call to enter game mode. The correct procedure for UI activation of game
440 /// mode, is to first create a game module (the method CreateGameModule is
441 /// provided for this purpose), and then prompt the user to change any
442 /// ModuleSettings for that GameModule (hence needing to create it first in
443 /// order to determine what settings it has); if the user clicks ok,
444 /// then the created module can be passed to this method. (If the user instead
445 /// clicks cancel, then the module should be deleted.)
446 /// Note method is virtual, so subclasses can override e.g. to detect entering
447 /// game mode (they should call this method, then check GetGameModule()).
448 /// \param pGameModule concrete instance of GameModule to use. This can be null,
449 /// in which case we will use the module returned by CreateGameModule (e.g.
450 /// this is done for demo filter). However
451 /// \param pGameModule newly-constructed GameModule to use, or NULL to use one
452 /// returned from CreateGameModule; in either case, will be deleted when we
454 virtual void EnterGameMode(CGameModule
*pGameModule
);
456 ///Exits game mode, including deleting the game module that was in use.
457 /// virtual so subclasses can override to detect leaving game mode.
458 void LeaveGameMode();
463 /// Interaction with the derived class during core startup
467 /// Finish initializing the DasherInterface; we can't do everything in the constructor,
468 /// because some initialization depends on virtual methods provided by subclasses.
469 /// Both Realize and ChangeScreen must be called after construction before other functions
470 /// will work, but they can be called in either order (as the SettingsStore is passed into
472 /// \param ulTime timestamp, much as per NewFrame, used for initializing the RNG (i.e. srand).
473 /// (Is that too hacky?)
475 void Realize(unsigned long ulTime
);
478 /// Creates a default set of modules. Override in subclasses to create any
479 /// extra/different modules specific to the platform (eg input device drivers)
481 virtual void CreateModules();
485 ///Creates the game module. Subclasses must implement to return a concrete
486 /// subclass of CGameModule, perhaps by using platform-specific widgets (e.g.
487 /// the edit box?). Note the view and model can be obtained by calling GetView()
488 /// and reading m_pDasherModel, respectively
489 virtual CGameModule
*CreateGameModule() = 0;
491 /// Draw a new Dasher frame, regardless of whether we're paused etc.
492 /// \param iTime Current time in ms.
493 /// \param bForceRedraw Passing in true is equivalent to calling ScheduleRedraw() first,
494 /// and forces the nodes/canvas to be re-rendered (even if we haven't moved).
495 void NewFrame(unsigned long iTime
, bool bForceRedraw
);
497 ///Renders the current state of the nodes (optionally), decorations, etc. (Does not move around the nodes.)
498 /// \param ulTime Time of rendering, for time-dependent decorations (e.g. messages)
499 /// \param bRedrawNodes whether to re-render the nodes (expensive!)
500 /// \param policy if redrawing nodes, use this to expand/collapse nodes, and set m_bLastChanged if any were.
501 bool Redraw(unsigned long ulTime
, bool bRedrawNodes
, CExpansionPolicy
&policy
);
503 ///Called at the end of each frame, after lock-message / nodes+decorations have been rendered.
504 /// Default does nothing, but subclasses can override if they need to do anything else.
505 /// \return true if anything has been rendered to the Screen such that it needs to be blitted
506 /// (i.e. Display() called) - the default just returns false.
507 virtual bool FinishRender(unsigned long ulTime
) {return false;}
511 ///Called (from NewFrame) if this frame moved and the previous didn't
512 /// (moved = was scheduled in the model, even if no actual change to
513 /// co-ordinates - the latter might occur if e.g. running default filter
514 /// but with the mouse precisely over the crosshair)
515 virtual void onUnpause(unsigned long lTime
);
517 CDasherView
*GetView() {return m_pDasherView
;}
519 CDasherModel
* const m_pDasherModel
;
520 ///Framerate monitor; created in constructor, req'd for DynamicFilter subclasses
521 CFrameRate
* const m_pFramerate
;
525 ///We keep a reference to the (currently unique/global) SettingsStore with which
526 /// this interface was created, as ClSet and ResetParameter need to access it.
527 /// (TODO _could_ move these into CSettingsUser, but that seems uglier given so few clients?)
528 CSettingsStore
* const m_pSettingsStore
;
530 class CPreSetObserver
: public Observer
<int> {
531 CSettingsStore
& m_settingsStore
;
533 CPreSetObserver(CSettingsStore
& settingsStore
) : m_settingsStore(settingsStore
) {};
534 void HandleEvent(int evt
) override
;
537 CPreSetObserver m_preSetObserver
;
538 CFileUtils
* m_fileUtils
;
540 //The default expansion policy to use - an amortized policy depending on the LP_NODE_BUDGET parameter.
541 CExpansionPolicy
*m_defaultPolicy
;
543 /// Provide a new CDasherInput input device object.
547 void CreateInputFilter();
549 void CreateModel(int iOffset
);
550 void CreateNCManager();
552 void ChangeAlphabet();
553 void ChangeColours();
556 //Compute the screen orientation to use - i.e. combining the user's
557 // preference with the alphabet.
558 Opts::ScreenOrientations
ComputeOrientation();
560 class WordSpeaker
: public TransientObserver
<const CEditEvent
*> {
562 WordSpeaker(CDasherInterfaceBase
*pIntf
);
563 void HandleEvent(const CEditEvent
*);
565 ///builds up the word currently being entered
566 std::string m_strCurrentWord
;
569 /// @name Child components
570 /// Various objects which are 'owned' by the core.
572 CDasherScreen
*m_DasherScreen
;
573 CDasherView
*m_pDasherView
;
574 CDasherInput
*m_pInput
;
575 CInputFilter
* m_pInputFilter
;
576 CModuleManager m_oModuleManager
;
578 CColourIO
*m_ColourIO
;
579 CControlBoxIO
*m_ControlBoxIO
;
580 CNodeCreationManager
*m_pNCManager
;
581 CUserLogBase
*m_pUserLog
;
583 // the game mode module - only
584 // initialized if game mode is enabled
585 CGameModule
*m_pGameModule
;
588 ///If non-empty, Dasher is locked, and this is the message that should be displayed.
589 std::string m_strLockMessage
;
590 /// (Cache) renderable version of previous; created only to render
591 /// (so may still be NULL even if locked)
592 CDasherScreen::Label
*m_pLockLabel
;
594 ///Whether a full redraw (inc of nodes) has been requested externally,
595 /// via ScheduleRedraw, for the next frame
596 bool m_bRedrawScheduled
;
598 ///Whether we moved anywhere in the last call to NewFrame.
603 std::set
<TextAction
*> m_vTextActions
;
607 #endif /* #ifndef __DasherInterfaceBase_h__ */