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 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867
|
// DasherInterfaceBase.cpp
//
// 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
#include "../Common/Common.h"
#include "DasherInterfaceBase.h"
#include "DasherViewSquare.h"
#include "ControlManager.h"
#include "DasherScreen.h"
#include "DasherView.h"
#include "DasherInput.h"
#include "DasherModel.h"
#include "Observable.h"
#include "Event.h"
#include "NodeCreationManager.h"
#ifndef _WIN32_WCE
#include "UserLog.h"
#include "BasicLog.h"
#endif
#include "GameModule.h"
#include "FileWordGenerator.h"
// Input filters
#include "AlternatingDirectMode.h"
#include "ButtonMode.h"
#include "ClickFilter.h"
#include "CompassMode.h"
#include "DefaultFilter.h"
#include "DemoFilter.h"
#include "OneButtonFilter.h"
#include "OneButtonDynamicFilter.h"
#include "OneDimensionalFilter.h"
#include "StylusFilter.h"
#include "TwoButtonDynamicFilter.h"
#include "TwoPushDynamicFilter.h"
// STL headers
#include <cstdio>
#include <iostream>
#include <memory>
#include <sstream>
// Declare our global file logging object
#include "../DasherCore/FileLogger.h"
#ifdef _DEBUG
const eLogLevel g_iLogLevel = logDEBUG;
const int g_iLogOptions = logTimeStamp | logDateStamp | logDeleteOldFile;
#else
const eLogLevel g_iLogLevel = logNORMAL;
const int g_iLogOptions = logTimeStamp | logDateStamp;
#endif
#ifndef _WIN32_WCE
CFileLogger* g_pLogger = NULL;
#endif
using namespace Dasher;
using namespace std;
// Track memory leaks on Windows to the line that new'd the memory
#ifdef _WIN32
#ifdef _DEBUG_MEMLEAKS
#define DEBUG_NEW new( _NORMAL_BLOCK, THIS_FILE, __LINE__ )
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#endif
CDasherInterfaceBase::CDasherInterfaceBase(CSettingsStore *pSettingsStore) : CSettingsUser(pSettingsStore), m_pSettingsStore(pSettingsStore), m_pDasherModel(new CDasherModel()), m_pFramerate(new CFrameRate(this)), m_pLockLabel(NULL) {
pSettingsStore->Register(this);
// Ensure that pointers to 'owned' objects are set to NULL.
m_DasherScreen = NULL;
m_pDasherView = NULL;
m_pInput = NULL;
m_pInputFilter = NULL;
m_AlphIO = NULL;
m_ColourIO = NULL;
m_pUserLog = NULL;
m_pNCManager = NULL;
m_defaultPolicy = NULL;
m_pWordSpeaker = NULL;
m_pGameModule = NULL;
// Various state variables
m_bRedrawScheduled = false;
// m_bGlobalLock = false;
#ifndef _WIN32_WCE
// Global logging object we can use from anywhere
g_pLogger = new CFileLogger("dasher.log",
g_iLogLevel,
g_iLogOptions);
#endif
}
void CDasherInterfaceBase::Realize(unsigned long ulTime) {
//if ChangeScreen has been called, we'll have created a view;
// otherwise, we still can't create a view, until we have a screen!
DASHER_ASSERT(m_DasherScreen ? m_pDasherView!=NULL : m_pDasherView==NULL);
srand(ulTime);
m_AlphIO = new CAlphIO(this);
ScanFiles(m_AlphIO, "alphabet*.xml");
m_ColourIO = new CColourIO(this);
ScanFiles(m_ColourIO, "colour*.xml");
ChangeColours();
ChangeView();
// Create the user logging object if we are suppose to. We wait
// until now so we have the real value of the parameter and not
// just the default.
// TODO: Sort out log type selection
#ifndef _WIN32_WCE
int iUserLogLevel = GetLongParameter(LP_USER_LOG_LEVEL_MASK);
if(iUserLogLevel == 10)
m_pUserLog = new CBasicLog(this, this);
else if (iUserLogLevel > 0)
m_pUserLog = new CUserLog(this, this, iUserLogLevel);
#else
m_pUserLog = NULL;
#endif
CreateModules();
ChangeAlphabet(); // This creates the NodeCreationManager, the Alphabet,
//and the tree of nodes in the model.
CreateInput();
CreateInputFilter();
//we may have created a control manager already; in which case, we need
// it to realize there's now an inputfilter (which may provide more actions).
// So tell it the setting has changed...
if (CControlManager *pCon = m_pNCManager->GetControlManager())
pCon->HandleEvent(SP_INPUT_FILTER);
HandleEvent(LP_NODE_BUDGET);
// FIXME - need to rationalise this sort of thing.
// InvalidateContext(true);
ScheduleRedraw();
#ifndef _WIN32_WCE
// All the setup is done by now, so let the user log object know
// that future parameter changes should be logged.
if (m_pUserLog != NULL)
m_pUserLog->InitIsDone();
#endif
}
CDasherInterfaceBase::~CDasherInterfaceBase() {
//WriteTrainFileFull();???
delete m_pDasherModel; // The order of some of these deletions matters
delete m_pDasherView;
delete m_ColourIO;
delete m_AlphIO;
delete m_pNCManager;
// Do NOT delete Edit box or Screen. This class did not create them.
#ifndef _WIN32_WCE
// When we destruct on shutdown, we'll output any detailed log file
if (m_pUserLog != NULL)
{
m_pUserLog->OutputFile();
delete m_pUserLog;
m_pUserLog = NULL;
}
if (g_pLogger != NULL) {
delete g_pLogger;
g_pLogger = NULL;
}
#endif
delete m_pFramerate;
}
void CDasherInterfaceBase::PreSetNotify(int iParameter, const std::string &sNewValue) {
// FIXME - make this a more general 'pre-set' event in the message
// infrastructure
switch(iParameter) {
case SP_ALPHABET_ID:
// Cycle the alphabet history
if(GetStringParameter(SP_ALPHABET_ID) != sNewValue) {
if(GetStringParameter(SP_ALPHABET_1) != sNewValue) {
if(GetStringParameter(SP_ALPHABET_2) != sNewValue) {
if(GetStringParameter(SP_ALPHABET_3) != sNewValue)
SetStringParameter(SP_ALPHABET_4, GetStringParameter(SP_ALPHABET_3));
SetStringParameter(SP_ALPHABET_3, GetStringParameter(SP_ALPHABET_2));
}
SetStringParameter(SP_ALPHABET_2, GetStringParameter(SP_ALPHABET_1));
}
SetStringParameter(SP_ALPHABET_1, GetStringParameter(SP_ALPHABET_ID));
}
break;
}
}
void CDasherInterfaceBase::HandleEvent(int iParameter) {
switch (iParameter) {
case LP_OUTLINE_WIDTH:
ScheduleRedraw();
break;
case BP_DRAW_MOUSE:
ScheduleRedraw();
break;
case BP_DRAW_MOUSE_LINE:
ScheduleRedraw();
break;
case LP_ORIENTATION:
m_pDasherView->SetOrientation(ComputeOrientation());
ScheduleRedraw();
break;
case SP_ALPHABET_ID:
ChangeAlphabet();
ScheduleRedraw();
break;
case SP_COLOUR_ID:
ChangeColours();
ScheduleRedraw();
break;
case BP_PALETTE_CHANGE:
if(GetBoolParameter(BP_PALETTE_CHANGE))
SetStringParameter(SP_COLOUR_ID, m_pNCManager->GetAlphabet()->GetPalette());
break;
case LP_LANGUAGE_MODEL_ID:
CreateNCManager();
break;
case LP_LINE_WIDTH:
ScheduleRedraw();
break;
case LP_DASHER_FONTSIZE:
ScheduleRedraw();
break;
case SP_INPUT_DEVICE:
CreateInput();
break;
case SP_INPUT_FILTER:
CreateInputFilter();
ScheduleRedraw();
break;
case LP_MARGIN_WIDTH:
case BP_NONLINEAR_Y:
case LP_NONLINEAR_X:
case LP_GEOMETRY:
case LP_SHAPE_TYPE: //for platforms which actually have this as a GUI pref!
ScheduleRedraw();
break;
case LP_NODE_BUDGET:
delete m_defaultPolicy;
m_defaultPolicy = new AmortizedPolicy(m_pDasherModel,GetLongParameter(LP_NODE_BUDGET));
break;
case BP_SPEAK_WORDS:
delete m_pWordSpeaker;
m_pWordSpeaker = GetBoolParameter(BP_SPEAK_WORDS) ? new WordSpeaker(this) : NULL;
break;
case BP_CONTROL_MODE:
//force rebuilding tree/nodes, to get new probabilities (inc/exc control node).
// This may move the canvas around a bit, but at least manages to keep/reuse the
// existing AlphabetManager, NCManager, etc. objects...
SetOffset(m_pDasherModel->GetOffset(), true);
break;
default:
break;
}
}
void CDasherInterfaceBase::EnterGameMode(CGameModule *pGameModule) {
DASHER_ASSERT(m_pGameModule == NULL);
if (CWordGeneratorBase *pWords = m_pNCManager->GetAlphabetManager()->GetGameWords()) {
if (!pGameModule) pGameModule=CreateGameModule();
m_pGameModule=pGameModule;
m_pNCManager->updateControl();
m_pGameModule->SetWordGenerator(m_pNCManager->GetAlphabet(), pWords);
} else {
///TRANSLATORS: %s is the name of the alphabet; the string "GameTextFile"
/// refers to a setting name in gsettings or equivalent, and should not be translated.
FormatMessageWithString(_("Could not find game sentences file for %s - check alphabet definition, or override with GameTextFile setting"),
m_pNCManager->GetAlphabet()->GetID().c_str());
delete pGameModule; //does nothing if null.
}
}
void CDasherInterfaceBase::LeaveGameMode() {
DASHER_ASSERT(m_pGameModule);
CGameModule *pMod = m_pGameModule;
m_pGameModule=NULL; //point at which we officially exit game mode
delete pMod;
m_pNCManager->updateControl();
SetBuffer(0);
}
CDasherInterfaceBase::WordSpeaker::WordSpeaker(CDasherInterfaceBase *pIntf) : TransientObserver<const CEditEvent *>(pIntf) {
}
void CDasherInterfaceBase::WordSpeaker::HandleEvent(const CEditEvent *pEditEvent) {
CDasherInterfaceBase *pIntf(static_cast<CDasherInterfaceBase *> (m_pEventHandler));
if (pIntf->GetGameModule()) return;
if(pEditEvent->m_iEditType == 1) {
if (pIntf->SupportsSpeech()) {
const CAlphInfo *pAlphabet = pIntf->m_pNCManager->GetAlphabet();
if (pEditEvent->m_sText == pAlphabet->GetText(pAlphabet->GetSpaceSymbol())) {
pIntf->Speak(m_strCurrentWord, false);
m_strCurrentWord="";
} else
m_strCurrentWord+=pEditEvent->m_sText;
}
}
else if(pEditEvent->m_iEditType == 2) {
m_strCurrentWord = m_strCurrentWord.substr(0, max(static_cast<string::size_type>(0), m_strCurrentWord.size()-pEditEvent->m_sText.size()));
}
}
void CDasherInterfaceBase::SetLockStatus(const string &strText, int iPercent) {
string newMessage; //empty - what we want if iPercent==-1 (unlock)
if (iPercent!=-1) {
ostringstream os;
os << (strText.empty() ? "Training Dasher" : strText);
if (iPercent) os << " " << iPercent << "%";
newMessage = os.str();
}
if (newMessage != m_strLockMessage) {
ScheduleRedraw();
if (m_pLockLabel) {
delete m_pLockLabel;
m_pLockLabel = NULL;
}
m_strLockMessage = newMessage;
}
}
void CDasherInterfaceBase::editOutput(const std::string &strText, CDasherNode *pCause) {
CEditEvent evt(CEditEvent::EDIT_OUTPUT, strText, pCause);
DispatchEvent(&evt);
}
void CDasherInterfaceBase::editDelete(const std::string &strText, CDasherNode *pCause) {
CEditEvent evt(CEditEvent::EDIT_DELETE, strText, pCause);
DispatchEvent(&evt);
}
void CDasherInterfaceBase::editConvert(CDasherNode *pCause) {
CEditEvent evt(CEditEvent::EDIT_CONVERT, "", pCause);
DispatchEvent(&evt);
}
void CDasherInterfaceBase::editProtect(CDasherNode *pCause) {
CEditEvent evt(CEditEvent::EDIT_PROTECT, "", pCause);
DispatchEvent(&evt);
}
void CDasherInterfaceBase::WriteTrainFileFull() {
m_pNCManager->GetAlphabetManager()->WriteTrainFileFull(this);
}
void CDasherInterfaceBase::CreateNCManager() {
if(!m_AlphIO || GetLongParameter(LP_LANGUAGE_MODEL_ID)==-1)
return;
//can't delete the old manager yet until we've deleted all its nodes...
CNodeCreationManager *pOldMgr = m_pNCManager;
//now create the new manager...
m_pNCManager = new CNodeCreationManager(this, this, m_AlphIO);
if (GetBoolParameter(BP_PALETTE_CHANGE))
SetStringParameter(SP_COLOUR_ID, m_pNCManager->GetAlphabet()->GetPalette());
if (m_DasherScreen) {
m_pNCManager->ChangeScreen(m_DasherScreen);
//and start a new tree of nodes from it (retaining old offset -
// this will be a sensible default of 0 if no nodes previously existed).
// This deletes the old tree of nodes...
SetOffset(m_pDasherModel->GetOffset(), true);
} //else, if there is no screen, the model should not contain any nodes from the old NCManager. (Assert, somehow?)
//...so now we can delete the old manager
delete pOldMgr;
}
CDasherInterfaceBase::TextAction::TextAction(CDasherInterfaceBase *pIntf) : m_pIntf(pIntf) {
m_iStartOffset= (pIntf->m_pDasherModel) ? pIntf->m_pDasherModel->GetOffset() : 0;
pIntf->m_vTextActions.insert(this);
}
CDasherInterfaceBase::TextAction::~TextAction() {
m_pIntf->m_vTextActions.erase(this);
}
void CDasherInterfaceBase::TextAction::executeOnAll() {
(*this)(strLast = m_pIntf->GetAllContext());
m_iStartOffset = m_pIntf->m_pDasherModel->GetOffset();
}
void CDasherInterfaceBase::TextAction::executeOnNew() {
int iNewOffset(m_pIntf->m_pDasherModel->GetOffset());
(*this)(strLast = m_pIntf->GetContext(m_iStartOffset, iNewOffset-m_iStartOffset));
m_iStartOffset=iNewOffset;
}
void CDasherInterfaceBase::TextAction::executeLast() {
(*this)(strLast);
}
void CDasherInterfaceBase::TextAction::NotifyOffset(int iOffset) {
m_iStartOffset = min(iOffset, m_iStartOffset);
}
bool CDasherInterfaceBase::hasDone() {
return (GetBoolParameter(BP_COPY_ALL_ON_STOP) && SupportsClipboard())
|| (GetBoolParameter(BP_SPEAK_ALL_ON_STOP) && SupportsSpeech());
}
void CDasherInterfaceBase::Done() {
ScheduleRedraw();
#ifndef _WIN32_WCE
if (m_pUserLog != NULL)
m_pUserLog->StopWriting((float) GetNats());
#endif
if (GetBoolParameter(BP_COPY_ALL_ON_STOP) && SupportsClipboard()) {
CopyToClipboard(GetAllContext());
}
if (GetBoolParameter(BP_SPEAK_ALL_ON_STOP) && SupportsSpeech()) {
Speak(GetAllContext(), true);
}
}
void CDasherInterfaceBase::CreateInput() {
if(m_pInput) {
m_pInput->Deactivate();
}
m_pInput = (CDasherInput *)GetModuleByName(GetStringParameter(SP_INPUT_DEVICE));
if (m_pInput == NULL)
m_pInput = m_oModuleManager.GetDefaultInputDevice();
if(m_pInput) {
m_pInput->Activate();
}
}
void CDasherInterfaceBase::NewFrame(unsigned long iTime, bool bForceRedraw) {
// Prevent NewFrame from being reentered. This can happen occasionally and
// cause crashes.
static bool bReentered=false;
if (bReentered) {
#ifdef DEBUG
std::cout << "CDasherInterfaceBase::NewFrame was re-entered" << std::endl;
#endif
return;
}
bReentered=true;
if(m_DasherScreen) {
//ok, can draw _something_. Try and see what we can :).
bool bBlit = false; //set to true if we actually render anything different i.e. that needs blitting to display
if (isLocked() || !m_pDasherView) {
//Hmmm. If we're locked, NewFrame is never actually called - the thread
// that would be rendering frames, is the same one doing the training.
// So the following is never actually executed atm, but may be a simple
// template if/when we ever implement multithreading widely/properly...
m_DasherScreen->SendMarker(0); //this replaces the nodes...
const screenint iSW = m_DasherScreen->GetWidth(), iSH = m_DasherScreen->GetHeight();
m_DasherScreen->DrawRectangle(0,0,iSW,iSH,0,0,0); //fill in colour 0 = white
unsigned int iSize(GetLongParameter(LP_MESSAGE_FONTSIZE));
if (!m_pLockLabel) m_pLockLabel = m_DasherScreen->MakeLabel(m_strLockMessage, iSize);
pair<screenint,screenint> dims = m_DasherScreen->TextSize(m_pLockLabel, iSize);
m_DasherScreen->DrawString(m_pLockLabel, (iSW-dims.first)/2, (iSH-dims.second)/2, iSize, 4);
m_DasherScreen->SendMarker(1); //decorations - don't draw any
bBlit = true;
} else {
CExpansionPolicy *pol=m_defaultPolicy;
//1. Schedule any per-frame movement in the model...
if(m_pInputFilter) {
m_pInputFilter->Timer(iTime, m_pDasherView, m_pInput, m_pDasherModel, &pol);
}
//2. Render...
//If we've been told to render another frame via ScheduleRedraw,
// that's the same as passing in true to NewFrame.
if (m_bRedrawScheduled) bForceRedraw=true;
m_bRedrawScheduled=false;
//Apply any movement that has been scheduled
if (m_pDasherModel->NextScheduledStep()) {
//yes, we moved...
if (!m_bLastMoved) onUnpause(iTime);
// ...so definitely need to render the nodes. We also make sure
// to render at least one more frame - think that's a bit of policy
// just to be on the safe side, and may not be strictly necessary...
bForceRedraw=m_bRedrawScheduled=m_bLastMoved=true;
} else {
//no movement
if (m_bLastMoved) bForceRedraw=true;//move into onPause() method if reqd
m_bLastMoved=false;
}
//2. Render nodes decorations, messages
bBlit = Redraw(iTime, bForceRedraw, *pol);
if (m_pUserLog != NULL) {
//(any) UserLogBase will have been watching output events to gather information
// about symbols added/deleted; this tells it to apply that information at end-of-frame
// (previously DashIntf gathered the info, and then passed it to the logger here).
m_pUserLog->FrameEnded();
}
}
if (FinishRender(iTime)) bBlit = true;
if (bBlit) m_DasherScreen->Display();
}
bReentered=false;
}
void CDasherInterfaceBase::onUnpause(unsigned long lTime) {
//TODO When Game+UserLog modules are combined => reduce to just one call here
if (m_pGameModule)
m_pGameModule->StartWriting(lTime);
if (m_pUserLog)
m_pUserLog->StartWriting();
}
bool CDasherInterfaceBase::Redraw(unsigned long ulTime, bool bRedrawNodes, CExpansionPolicy &policy) {
DASHER_ASSERT(m_pDasherView);
// Draw the nodes
if(bRedrawNodes) {
m_pDasherView->Screen()->SendMarker(0);
if (m_pDasherModel) {
m_pDasherModel->RenderToView(m_pDasherView,policy);
// if anything was expanded or collapsed render at least one more
// frame after this
if (policy.apply())
ScheduleRedraw();
}
if(m_pGameModule) {
m_pGameModule->DecorateView(ulTime, m_pDasherView, m_pDasherModel);
}
}
//From here on, we'll use bRedrawNodes just to denote whether we need to blit the display...
// Draw the decorations
m_pDasherView->Screen()->SendMarker(1);
if(m_pInputFilter) {
if (m_pInputFilter->DecorateView(m_pDasherView, m_pInput)) bRedrawNodes=true;
}
return bRedrawNodes;
}
void CDasherInterfaceBase::ChangeAlphabet() {
if(GetStringParameter(SP_ALPHABET_ID) == "") {
SetStringParameter(SP_ALPHABET_ID, m_AlphIO->GetDefault());
// This will result in ChangeAlphabet() being called again, so
// exit from the first recursion
return;
}
if (m_pNCManager) WriteTrainFileFull(); //can't/don't before creating first NCManager
// Send a lock event
// Lock Dasher to prevent changes from happening while we're training.
CreateNCManager();
if (m_pDasherView) m_pDasherView->SetOrientation(ComputeOrientation());
// Apply options from alphabet
//}
}
Opts::ScreenOrientations CDasherInterfaceBase::ComputeOrientation() {
Opts::ScreenOrientations pref(Opts::ScreenOrientations(GetLongParameter(LP_ORIENTATION)));
if (pref!=Opts::Alphabet) return pref;
if (m_pNCManager) return m_pNCManager->GetAlphabet()->GetOrientation();
//haven't created the NCManager yet, so not yet reached Realize, but must
// have been given Screen (to make View). Use default LR for now, as when
// we ChangeAlphabet, we'll update the view.
return Opts::LeftToRight;
}
void CDasherInterfaceBase::ChangeColours() {
if(!m_ColourIO || !m_DasherScreen)
return;
// TODO: Make fuction return a pointer directly
m_DasherScreen->SetColourScheme(&(m_ColourIO->GetInfo(GetStringParameter(SP_COLOUR_ID))));
}
void CDasherInterfaceBase::ChangeScreen(CDasherScreen *NewScreen) {
m_DasherScreen = NewScreen;
ChangeColours();
if(m_pDasherView != 0) {
m_pDasherView->ChangeScreen(NewScreen);
ScreenResized(NewScreen);
} else {
//We can create the view as soon as we have a screen...
ChangeView();
}
if (m_pNCManager) {
m_pNCManager->ChangeScreen(m_DasherScreen);
if (m_pDasherModel)
SetOffset(m_pDasherModel->GetOffset(), true);
}
}
void CDasherInterfaceBase::ScreenResized(CDasherScreen *pScreen) {
DASHER_ASSERT(pScreen == m_DasherScreen);
if (!m_pDasherView) return;
m_pDasherView->ScreenResized(m_DasherScreen);
//Really, would like to do a Redraw _immediately_, but this will have to do.
ScheduleRedraw();
}
void CDasherInterfaceBase::ChangeView() {
// TODO: Actually respond to LP_VIEW_ID parameter (although there is only one view at the moment)
if(m_DasherScreen != 0 /*&& m_pDasherModel != 0*/) {
CDasherView *pNewView = new CDasherViewSquare(this, m_DasherScreen, ComputeOrientation());
//the previous sends an event to all listeners registered with it, but there aren't any atm!
// so send an event to tell them of the new view object _and_ get them to recompute coords:
if (m_pDasherView) m_pDasherView->TransferObserversTo(pNewView);
delete m_pDasherView;
m_pDasherView = pNewView;
}
ScheduleRedraw();
}
double CDasherInterfaceBase::GetCurCPM() {
//
return 0;
}
double CDasherInterfaceBase::GetCurFPS() {
//
return 0;
}
const CAlphInfo *CDasherInterfaceBase::GetActiveAlphabet() {
return m_AlphIO->GetInfo(GetStringParameter(SP_ALPHABET_ID));
}
// int CDasherInterfaceBase::GetAutoOffset() {
// if(m_pDasherView != 0) {
// return m_pDasherView->GetAutoOffset();
// }
// return -1;
// }
double CDasherInterfaceBase::GetNats() const {
if(m_pDasherModel)
return m_pDasherModel->GetNats();
else
return 0.0;
}
void CDasherInterfaceBase::ResetNats() {
if(m_pDasherModel)
m_pDasherModel->ResetNats();
}
void CDasherInterfaceBase::ClearAllContext() {
ctrlDelete(true, CControlManager::EDIT_FILE);
ctrlDelete(false, CControlManager::EDIT_FILE);
SetBuffer(0);
}
void CDasherInterfaceBase::ResetParameter(int iParameter) {
m_pSettingsStore->ResetParameter(iParameter);
}
// We need to be able to get at the UserLog object from outside the interface
CUserLogBase* CDasherInterfaceBase::GetUserLogPtr() {
return m_pUserLog;
}
void CDasherInterfaceBase::KeyDown(unsigned long iTime, int iId) {
if(isLocked())
return;
if(m_pInputFilter) {
m_pInputFilter->KeyDown(iTime, iId, m_pDasherView, m_pInput, m_pDasherModel);
}
if(m_pInput) {
m_pInput->KeyDown(iTime, iId);
}
}
void CDasherInterfaceBase::KeyUp(unsigned long iTime, int iId) {
if(isLocked())
return;
if(m_pInputFilter) {
m_pInputFilter->KeyUp(iTime, iId, m_pDasherView, m_pInput, m_pDasherModel);
}
if(m_pInput) {
m_pInput->KeyUp(iTime, iId);
}
}
void CDasherInterfaceBase::CreateInputFilter() {
if(m_pInputFilter) {
m_pInputFilter->pause();
m_pInputFilter->Deactivate();
m_pInputFilter = NULL;
}
#ifndef _WIN32_WCE
m_pInputFilter = (CInputFilter *)GetModuleByName(GetStringParameter(SP_INPUT_FILTER));
#endif
if (m_pInputFilter == NULL)
m_pInputFilter = m_oModuleManager.GetDefaultInputMethod();
m_pInputFilter->Activate();
}
CDasherModule *CDasherInterfaceBase::RegisterModule(CDasherModule *pModule) {
return m_oModuleManager.RegisterModule(pModule);
}
CDasherModule *CDasherInterfaceBase::GetModule(ModuleID_t iID) {
return m_oModuleManager.GetModule(iID);
}
CDasherModule *CDasherInterfaceBase::GetModuleByName(const std::string &strName) {
return m_oModuleManager.GetModuleByName(strName);
}
void CDasherInterfaceBase::SetDefaultInputDevice(CDasherInput *pModule) {
m_oModuleManager.SetDefaultInputDevice(pModule);
}
void CDasherInterfaceBase::SetDefaultInputMethod(CInputFilter *pModule) {
m_oModuleManager.SetDefaultInputMethod(pModule);
}
void CDasherInterfaceBase::CreateModules() {
CInputFilter *defFil = new CDefaultFilter(this, this, m_pFramerate, 3, _("Normal Control"));
RegisterModule(defFil);
SetDefaultInputMethod(defFil);
RegisterModule(new COneDimensionalFilter(this, this, m_pFramerate));
#ifndef _WIN32_WCE
RegisterModule(new CClickFilter(this, this));
#else
SetDefaultInputMethod(
RegisterModule(new CClickFilter(this, this));
);
#endif
RegisterModule(new COneButtonFilter(this, this));
RegisterModule(new COneButtonDynamicFilter(this, this, m_pFramerate));
RegisterModule(new CTwoButtonDynamicFilter(this, this, m_pFramerate));
RegisterModule(new CTwoPushDynamicFilter(this, this, m_pFramerate));
// TODO: specialist factory for button mode
RegisterModule(new CButtonMode(this, this, true, 8, _("Menu Mode")));
RegisterModule(new CButtonMode(this, this, false,10, _("Direct Mode")));
// RegisterModule(new CDasherButtons(this, this, 4, 0, false,11, "Buttons 3"));
RegisterModule(new CAlternatingDirectMode(this, this));
RegisterModule(new CCompassMode(this, this));
RegisterModule(new CStylusFilter(this, this, m_pFramerate));
//WIP Temporary as too many segfaults! //RegisterModule(new CDemoFilter(this, this, m_pFramerate));
}
void CDasherInterfaceBase::GetPermittedValues(int iParameter, std::vector<std::string> &vList) {
// TODO: Deprecate direct calls to these functions
switch (iParameter) {
case SP_ALPHABET_ID:
DASHER_ASSERT(m_AlphIO != NULL);
m_AlphIO->GetAlphabets(&vList);
break;
case SP_COLOUR_ID:
DASHER_ASSERT(m_ColourIO != NULL);
m_ColourIO->GetColours(&vList);
break;
case SP_INPUT_FILTER:
m_oModuleManager.ListModules(1, vList);
break;
case SP_INPUT_DEVICE:
m_oModuleManager.ListModules(0, vList);
break;
}
}
bool CDasherInterfaceBase::GetModuleSettings(const std::string &strName, SModuleSettings **pSettings, int *iCount) {
return GetModuleByName(strName)->GetSettings(pSettings, iCount);
}
void CDasherInterfaceBase::SetOffset(int iOffset, bool bForce) {
if (iOffset == m_pDasherModel->GetOffset() && !bForce) return;
CDasherNode *pNode = m_pNCManager->GetAlphabetManager()->GetRoot(NULL, iOffset!=0, iOffset);
if (GetGameModule()) pNode->SetFlag(NF_GAME, true);
m_pDasherModel->SetNode(pNode);
//ACL TODO note that CTL_MOVE, etc., do not come here (that would probably
// rebuild the model / violently repaint the screen every time!). But we
// still want to notifyOffset all text actions, so the "New" suboption sees
// all the editing the user's done...
for (set<TextAction *>::iterator it = m_vTextActions.begin(); it!=m_vTextActions.end(); it++) {
(*it)->NotifyOffset(iOffset);
}
ScheduleRedraw();
}
// Returns 0 on success, an error string on failure.
const char* CDasherInterfaceBase::ClSet(const std::string &strKey, const std::string &strValue) {
return m_pSettingsStore->ClSet(strKey, strValue);
}
void
CDasherInterfaceBase::ImportTrainingText(const std::string &strPath) {
if(m_pNCManager)
m_pNCManager->ImportTrainingText(strPath);
}
|