1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547
|
// DasherInterfaceBase.h
//
// Copyright (c) 2008 The Dasher Team
//
// This file is part of Dasher.
//
// Dasher is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Dasher is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Dasher; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#ifndef __DasherInterfaceBase_h__
#define __DasherInterfaceBase_h__
///
/// \mainpage
///
/// This is the Dasher source code documentation. Please try to keep
/// it up to date!
///
// TODO - there is a list of things to be configurable in my notes
// Check that everything that is not self-contained within the GUI is covered.
#include "Messages.h"
#include "../Common/NoClones.h"
#include "../Common/ModuleSettings.h"
#include "Alphabet/AlphIO.h"
#include "AutoSpeedControl.h"
#include "ColourIO.h"
#include "InputFilter.h"
#include "ModuleManager.h"
#include "ControlManager.h"
#include "FrameRate.h"
#include <set>
#include <algorithm>
namespace Dasher {
class CDasherScreen;
class CDasherView;
class CDasherInput;
class CInputFilter;
class CDasherModel;
class CSettingsStore;
class CGameModule;
class CDasherInterfaceBase;
}
class CUserLogBase;
class CNodeCreationManager;
/// \defgroup Core Core Dasher classes
/// @{
/// The central class in the core of Dasher. Ties together the rest of
/// the platform independent stuff and provides a single interface for
/// the UI to use. Note: CMessageDisplay unimplemented; platforms should
/// provide their own methods using appropriate GUI components, or subclass
/// CDashIntfScreenMsgs instead.
class Dasher::CDasherInterfaceBase : public CMessageDisplay, public Observable<const CEditEvent *>, protected Observer<int>, protected CSettingsUser, private NoClones {
public:
///Create a new interface by providing the only-and-only settings store that will be used throughout.
CDasherInterfaceBase(CSettingsStore *pSettingsStore);
virtual ~CDasherInterfaceBase();
/// @name Access to internal member classes
/// Access various classes contained within the interface. These
/// should be considered dangerous and use minimised. Eventually to
/// be replaced by properly encapsulated equivalents.
/// @{
CUserLogBase* GetUserLogPtr();
// @}
///
/// @name Parameter manipulation
/// Members for manipulating the parameters of the core Dasher object.
///
//@{
///
/// Reset a parameter to the default value
///
void ResetParameter(int iParmater);
///
/// Obtain the permitted values for a string parameter - used to
/// geneate preferences dialogues etc.
///
void GetPermittedValues(int iParameter, std::vector<std::string> &vList);
///
/// Get a list of settings which apply to a particular module
///
bool GetModuleSettings(const std::string &strName, SModuleSettings **pSettings, int *iCount);
//@}
/// Called when a parameter changes - but *after* components have been notified.
/// Subsumes previous Interface level event handler, for example, responsible for
/// restarting the Dasher model whenever parameter changes make it
/// invalid. Subclasses should override to forward events to SettingsUI, editbox,
/// etc., as appropriate, but should _call_through_to_superclass_method_ first.
/// \param iParameter The parameter that's just changed.
/// \todo Should be protected (??)
virtual void HandleEvent(int iParameter);
void PreSetNotify(int iParameter, const std::string &sValue);
///Locks/unlocks Dasher. The default here stores the lock message and percentage
/// in m_strLockMessage, such that NewFrame renders this instead of the canvas
/// if we are locked. Subclasses may override to implement better (GUI)
/// notifications/dialogues, but should call through to this method to ensure
/// isLocked() returns the correct value.
/// Note that we do not support multiple/concurrent locks; each call to SetLockStatus
/// overrides any/all previous ones.
/// \param strText text of message to display, excluding %age, _if_ locked;
/// ignored, if unlocked.
/// \param iPercent -1 unlocks Dasher; anything else locks it, and indicates
/// %progress.
virtual void SetLockStatus(const std::string &strText, int iPercent);
/// Tells us whether Dasher is locked (i.e. for training).
/// TODO This just replaces the old BP_TRAINING; however, I'd think that _if_ we
/// do actually need a global function to tell whether Dasher's locked, it probably
/// needs to be threadsafe, which neither this nor BP_TRAINING is (I don't think!)...
inline bool isLocked() {return !m_strLockMessage.empty();}
///Does this subclass support speech (i.e. the speak(string) method?)
/// Default is just to return false.
virtual bool SupportsSpeech() {return false;}
///Does this subclass support clipboard copying (i.e. the copyToClipboard(string) method?)
/// Default is just to return false.
virtual bool SupportsClipboard() {return false;}
///Subclasses supporting speech should override to speak the supplied text
/// (Default implementation does nothing)
virtual void Speak(const std::string &text, bool bInterrupt) {}
///Subclasses supporting clipboard operations should override to copy
/// the specified text to the clipboard. (Default implementation does nothing).
virtual void CopyToClipboard(const std::string &text) {}
///Called to execute a control-mode "move" command.
///\param bForwards true to move forwards (right), false for backwards
///\param dist how far to move: character, word, line, file. (Usually defined
/// by OS, e.g. for non-european languages)
///\return the offset, into the edit buffer of the cursor *after* the move.
virtual unsigned int ctrlMove(bool bForwards, CControlManager::EditDistance dist)=0;
///Called to execute a control-mode "delete" command.
///\param bForwards true to delete forwards (right), false for backwards
///\param dist how much to delete: character, word, line, file. (Usually defined
/// by OS, e.g. for non-european languages)
///\return the offset, into the edit buffer, of the cursor *after* the delete
/// (for forwards deletion, this will be the same as the offset *before*)
virtual unsigned int ctrlDelete(bool bForwards, CControlManager::EditDistance dist)=0;
virtual void editOutput(const std::string &strText, CDasherNode *pCause);
virtual void editDelete(const std::string &strText, CDasherNode *pCause);
virtual void editConvert(CDasherNode *pCause);
virtual void editProtect(CDasherNode *pCause);
class TextAction {
public:
TextAction(CDasherInterfaceBase *pMgr);
void executeOnAll();
void executeOnNew();
void executeLast();
void NotifyOffset(int iOffset);
virtual ~TextAction();
protected:
virtual void operator()(const std::string &strText)=0;
CDasherInterfaceBase *m_pIntf;
private:
int m_iStartOffset;
std::string strLast;
};
/// @name Starting and stopping
/// Methods used to instruct dynamic motion of Dasher to start or stop
/// @{
/// Call when the user has finished writing a piece of text, to execute
/// any "on-stop" actions: the default implements speak on stop (if
/// BP_SPEAK_ON_STOP is set) and copy-on-stop (if BP_COPY_ALL_ON_STOP) is set;
/// subclasses may override to do more.
virtual void Done();
///Whether the Done() method does anything (and so should be presented
/// to the user) - default deals with speak/copy-on-stop, and subclasses
/// which override Done() to add additional on-stop actions must/should
/// override this to match.
virtual bool hasDone();
/// @}
///
/// Append text to the user training file - used to store state between sessions
/// \param filename name of training file, without path (e.g. "training_english_GB.txt")
/// \param strNewText text to append
///
virtual void WriteTrainFile(const std::string &filename, const std::string &strNewText) {
};
// App Interface
// -----------------------------------------------------
// std::map<int, std::string>& GetAlphabets(); // map<key, value> int is a UID string can change. Store UID in preferences. Display string to user.
// std::vector<std::string>& GetAlphabets();
// std::vector<std::string>& GetLangModels();
// std::vector<std::string>& GetViews();
/// Supply a new CDasherScreen object onto which to render. Note this should
/// only be called (a) at startup, and (b) when the new screen is _significantly_
/// different from the old, rather than just a window resize: specifically, this means
/// the tree of nodes will be rebuilt with new Labels for the new screen; and in the future,
/// maybe also if things like colour depth, alpha transparency support, etc., change.
/// If the existing rendering setup should just scale to the new screen dimensions,
/// call ScreenResized() instead (we expect this to be the case most/all of the time,
/// and this method subsumes a call to ScreenResized.) Note, at startup, ChangeScreen
/// and Realize may occur in either order; if ChangeScreen comes after, Resize will create a
/// tree with null Labels, which will have to be rebuilt in the call to ChangeScreen.
/// \param NewScreen Pointer to the new CDasherScreen.
virtual void ChangeScreen(CDasherScreen * NewScreen);
///Call when the screen dimensions have been changed, to recalculate scaling factors etc.
/// \param pScreen the screen whose dimensions have changed. TODO we expect this to be
/// the same one-and-only screen that we are using anyway, so remove parameter?
void ScreenResized(CDasherScreen *pScreen);
/// Train Dasher from a file
/// All traing data must be in UTF-8
/// \param Filename File to load.
/// \param iTotalBytes documentme
/// \param iOffset Document me
// int TrainFile(std::string Filename, int iTotalBytes, int iOffset);
/// New control mechanisms:
///Equivalent to SetOffset(iOffset, true)
void SetBuffer(int iOffset) {SetOffset(iOffset, true);}
/// Rebuilds the model at the specified location, potentially reusing nodes if !bForce
/// @param iOffset Cursor position in attached buffer from which to obtain context
/// @param bForce if true, model should be completely rebuilt (even for
/// same offset) - characters at old offsets may have changed, or we have
/// a new AlphabetManager. If false, assume buffer and alphabet unchanged,
/// so no need to rebuild the model if an existing node covers this point.
/// @param bForce true meaning the entire context may have changed,
/// false if we've just moved around within it.
void SetOffset(int iOffset, bool bForce=false);
/// @name Status reporting
/// Get information about the runtime status of Dasher which might
/// be of interest for debugging purposes etc.
/// @{
/// Get the current rate of text entry.
/// \retval The rate in characters per minute.
/// TODO: Check that this is still used
double GetCurCPM();
/// Get current refresh rate.
/// \retval The rate in frames per second
/// TODO: Check that this is still used
double GetCurFPS();
/// Get the total number of nats (base-e bits) entered.
/// \retval The current total
/// \todo Obsolete since new logging code?
double GetNats() const;
/// Reset the count of nats entered.
/// \todo Obsolete since new logging code?
void ResetNats();
/// @}
/// @name User input
/// Deals with forwarding user input to the core
/// @{
/// Called from outside to indicate a key or mouse button has just been pushed down
/// \param iTime time at which button pressed
/// \param iId integer identifying button. TODO we need a better system here.
/// At present 1-4 are keys on the keyboard (or external), after mapping from e.g.
/// qwerty layout, such that for a user who can press 2 buttons, 1 is the primary, 2
/// secondary (maybe harder for them), etc. Direct mode can use an arbitrary number.
/// 100 is left mouse button, 101 right, 102 middle (if there is one), and so on.
/// (Note we do not specify the location at which mouse presses occur: the current
/// pointer location can be obtained from the input device if necessary)
void KeyDown(unsigned long iTime, int iId);
/// Called from outside to indicate a key or mouse button has just been released
/// \param iTime time at which button released
/// \param iId integer identifying button. See comments for KeyDown.
void KeyUp(unsigned long iTime, int iId);
/// @}
// Module management functions
CDasherModule *RegisterModule(CDasherModule *pModule);
CDasherModule *GetModule(ModuleID_t iID);
CDasherModule *GetModuleByName(const std::string &strName);
CDasherInput *GetActiveInputDevice() {return m_pInput;}
CInputFilter *GetActiveInputMethod() {return m_pInputFilter;}
const CAlphInfo *GetActiveAlphabet();
void SetDefaultInputDevice(CDasherInput *);
void SetDefaultInputMethod(CInputFilter *);
void StartShutdown();
void ScheduleRedraw() {
m_bRedrawScheduled = true;
};
///Subclasses should return the contents of (the specified subrange of) the edit buffer
virtual std::string GetContext(unsigned int iStart, unsigned int iLength)=0;
///Clears all written text from edit buffer and rebuilds the model. The default
/// implementation does this using the control mode editDelete mechanism
/// (one call forward, one back), followed by a call to SetBuffer(0). Subclasses
/// may (optionally) override with more efficient / easier implementations, but
/// should make the same call to SetBuffer.
virtual void ClearAllContext();
virtual std::string GetAllContext()=0;
/// Set a key value pair by name - designed to allow operation from
/// the command line. Returns 0 on success, an error string on failure.
///
const char* ClSet(const std::string &strKey, const std::string &strValue);
void ImportTrainingText(const std::string &strPath);
/// Flush the/all currently-written text to the user's training file(s).
/// Just calls through to WriteTrainFileFull(this) on the AlphabetManager;
/// public so e.g. iPhone can flush the buffer when app is backgrounded.
void WriteTrainFileFull();
/// @name Platform dependent utility functions
/// These functions provide various platform dependent functions
/// required by the core. A derived class is created for each
/// supported platform which implements these.
// @{
///
/// Obtain the size in bytes of a file - the way to do this is
/// dependent on the OS (TODO: Check this - any posix on Windows?)
///
virtual int GetFileSize(const std::string &strFileName) = 0;
///Look for files, matching a filename pattern, in whatever system and/or user
/// locations as may exist - e.g. on disk, in app package, on web, whatever.
/// TODO, can we add a default implementation that looks on the Dasher website?
/// \param pattern string matching just filename (not path), potentially
/// including '*'s (as per glob)
virtual void ScanFiles(AbstractParser *parser, const std::string &strPattern) = 0;
// @}
///Gets a pointer to the game module. This is the correct way to determine
/// whether game mode is currently on or off.
/// \return pointer to current game module, if game mode on; or null, if off.
CGameModule *GetGameModule() {
return m_pGameModule;
}
///Call to enter game mode. The correct procedure for UI activation of game
/// mode, is to first create a game module (the method CreateGameModule is
/// provided for this purpose), and then prompt the user to change any
/// ModuleSettings for that GameModule (hence needing to create it first in
/// order to determine what settings it has); if the user clicks ok,
/// then the created module can be passed to this method. (If the user instead
/// clicks cancel, then the module should be deleted.)
/// Note method is virtual, so subclasses can override e.g. to detect entering
/// game mode (they should call this method, then check GetGameModule()).
/// \param pGameModule concrete instance of GameModule to use. This can be null,
/// in which case we will use the module returned by CreateGameModule (e.g.
/// this is done for demo filter). However
/// \param pGameModule newly-constructed GameModule to use, or NULL to use one
/// returned from CreateGameModule; in either case, will be deleted when we
/// leave game mode.
virtual void EnterGameMode(CGameModule *pGameModule);
///Exits game mode, including deleting the game module that was in use.
/// virtual so subclasses can override to detect leaving game mode.
void LeaveGameMode();
protected:
/// @name Startup
/// Interaction with the derived class during core startup
/// @{
///
/// Finish initializing the DasherInterface; we can't do everything in the constructor,
/// because some initialization depends on virtual methods provided by subclasses.
/// Both Realize and ChangeScreen must be called after construction before other functions
/// will work, but they can be called in either order (as the SettingsStore is passed into
/// the c'tor).
/// \param ulTime timestamp, much as per NewFrame, used for initializing the RNG (i.e. srand).
/// (Is that too hacky?)
///
void Realize(unsigned long ulTime);
///
/// Creates a default set of modules. Override in subclasses to create any
/// extra/different modules specific to the platform (eg input device drivers)
///
virtual void CreateModules();
/// @}
///Creates the game module. Subclasses must implement to return a concrete
/// subclass of CGameModule, perhaps by using platform-specific widgets (e.g.
/// the edit box?). Note the view and model can be obtained by calling GetView()
/// and reading m_pDasherModel, respectively
virtual CGameModule *CreateGameModule() = 0;
/// Draw a new Dasher frame, regardless of whether we're paused etc.
/// \param iTime Current time in ms.
/// \param bForceRedraw Passing in true is equivalent to calling ScheduleRedraw() first,
/// and forces the nodes/canvas to be re-rendered (even if we haven't moved).
void NewFrame(unsigned long iTime, bool bForceRedraw);
///Renders the current state of the nodes (optionally), decorations, etc. (Does not move around the nodes.)
/// \param ulTime Time of rendering, for time-dependent decorations (e.g. messages)
/// \param bRedrawNodes whether to re-render the nodes (expensive!)
/// \param policy if redrawing nodes, use this to expand/collapse nodes, and set m_bLastChanged if any were.
bool Redraw(unsigned long ulTime, bool bRedrawNodes, CExpansionPolicy &policy);
///Called at the end of each frame, after lock-message / nodes+decorations have been rendered.
/// Default does nothing, but subclasses can override if they need to do anything else.
/// \return true if anything has been rendered to the Screen such that it needs to be blitted
/// (i.e. Display() called) - the default just returns false.
virtual bool FinishRender(unsigned long ulTime) {return false;}
/// @}
///Called (from NewFrame) if this frame moved and the previous didn't
/// (moved = was scheduled in the model, even if no actual change to
/// co-ordinates - the latter might occur if e.g. running default filter
/// but with the mouse precisely over the crosshair)
virtual void onUnpause(unsigned long lTime);
CDasherView *GetView() {return m_pDasherView;}
CDasherModel * const m_pDasherModel;
///Framerate monitor; created in constructor, req'd for DynamicFilter subclasses
CFrameRate * const m_pFramerate;
private:
///We keep a reference to the (currently unique/global) SettingsStore with which
/// this interface was created, as ClSet and ResetParameter need to access it.
/// (TODO _could_ move these into CSettingsUser, but that seems uglier given so few clients?)
CSettingsStore * const m_pSettingsStore;
//The default expansion policy to use - an amortized policy depending on the LP_NODE_BUDGET parameter.
CExpansionPolicy *m_defaultPolicy;
/// Provide a new CDasherInput input device object.
void CreateInput();
void CreateInputFilter();
void CreateModel(int iOffset);
void CreateNCManager();
void ChangeAlphabet();
void ChangeColours();
void ChangeView();
//Compute the screen orientation to use - i.e. combining the user's
// preference with the alphabet.
Opts::ScreenOrientations ComputeOrientation();
class WordSpeaker : public TransientObserver<const CEditEvent *> {
public:
WordSpeaker(CDasherInterfaceBase *pIntf);
void HandleEvent(const CEditEvent *);
private:
///builds up the word currently being entered
std::string m_strCurrentWord;
} *m_pWordSpeaker;
/// @name Child components
/// Various objects which are 'owned' by the core.
/// @{
CDasherScreen *m_DasherScreen;
CDasherView *m_pDasherView;
CDasherInput *m_pInput;
CInputFilter* m_pInputFilter;
CModuleManager m_oModuleManager;
CAlphIO *m_AlphIO;
CColourIO *m_ColourIO;
CNodeCreationManager *m_pNCManager;
CUserLogBase *m_pUserLog;
// the game mode module - only
// initialized if game mode is enabled
CGameModule *m_pGameModule;
/// @}
///If non-empty, Dasher is locked, and this is the message that should be displayed.
std::string m_strLockMessage;
/// (Cache) renderable version of previous; created only to render
/// (so may still be NULL even if locked)
CDasherScreen::Label *m_pLockLabel;
///Whether a full redraw (inc of nodes) has been requested externally,
/// via ScheduleRedraw, for the next frame
bool m_bRedrawScheduled;
///Whether we moved anywhere in the last call to NewFrame.
bool m_bLastMoved;
/// @}
std::set<TextAction *> m_vTextActions;
};
/// @}
#endif /* #ifndef __DasherInterfaceBase_h__ */
|