3 // Copyright (c) 2007 The Dasher Team
5 // This file is part of Dasher.
7 // Dasher is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 2 of the License, or
10 // (at your option) any later version.
12 // Dasher is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with Dasher; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 #include "Common/WinMenus.h"
23 // TODO: Put this in DasherInterfaceBase header?
24 #include "../DasherCore/ControlManager.h"
25 #include "DasherWindow.h"
26 #include "Widgets/AboutBox.h"
28 #include "Widgets/Prefs.h"
31 #include "Widgets/Slidebar.h"
32 #include "Widgets/Toolbar.h"
33 #include "Widgets/GameGroup.h"
34 #include "WinCommon.h"
39 //#include <guiddef.h>
42 using namespace Dasher
;
45 #define IDT_TIMER1 200
47 // NOTE: There were previously various bits and pieces in this class from
48 // text services framework stuff, which were never really finished. If
49 // required, look in version control history (prior to May 2007).
51 CDasherWindow::CDasherWindow() {
54 m_pSpeedAlphabetBar
= 0;
59 m_hIconSm
= (HICON
) LoadImage(WinHelper::hInstApp
, (LPCTSTR
) IDI_DASHER
, IMAGE_ICON
, GetSystemMetrics(SM_CXSMICON
), GetSystemMetrics(SM_CYSMICON
), LR_DEFAULTCOLOR
);
61 ATL::CWndClassInfo
& wc
= CDasherWindow::GetWndClassInfo();
62 wc
.m_wc
.hIcon
= LoadIcon(WinHelper::hInstApp
, (LPCTSTR
) IDI_DASHER
);
63 wc
.m_wc
.hCursor
= LoadCursor(NULL
, IDC_ARROW
);
64 wc
.m_wc
.hbrBackground
= (HBRUSH
) (COLOR_WINDOW
);
66 // wc.m_wc.lpszMenuName = (LPCTSTR) IDC_DASHER;
67 wc
.m_wc
.hIconSm
= m_hIconSm
;
70 m_hMenu
= LoadMenu(WinHelper::hInstApp
, (LPCTSTR
) IDC_DASHER
);
73 HWND
CDasherWindow::Create() {
74 hAccelTable
= LoadAccelerators(WinHelper::hInstApp
, (LPCTSTR
) IDC_DASHER
);
76 // Get window title from resource script
78 WinLocalisation::GetResourceString(IDS_APP_TITLE
, &WindowTitle
);
80 m_pAppSettings
= new CAppSettings(0, 0);
81 int iStyle(m_pAppSettings
->GetLongParameter(APP_LP_STYLE
));
86 if((iStyle
== APP_STYLE_COMPOSE
) || (iStyle
== APP_STYLE_DIRECT
)) {
87 hWnd
= CWindowImpl
<CDasherWindow
>::Create(NULL
, NULL
, WindowTitle
.c_str(), WS_OVERLAPPEDWINDOW
| WS_CLIPCHILDREN
, WS_EX_NOACTIVATE
| WS_EX_APPWINDOW
| WS_EX_TOPMOST
);
88 ::SetMenu(hWnd
, NULL
);
91 hWnd
= CWindowImpl
<CDasherWindow
>::Create(NULL
, NULL
, WindowTitle
.c_str(), WS_OVERLAPPEDWINDOW
| WS_CLIPCHILDREN
);
92 ::SetMenu(hWnd
, m_hMenu
);
95 hWnd
= CWindowImpl
<CDasherWindow
, CWindow
, CWinTraits
<WS_CLIPCHILDREN
| WS_CLIPSIBLINGS
> >::Create(NULL
);
101 m_pDasher
= new CDasher(hWnd
);
103 // Create a CAppSettings
104 m_pAppSettings
->SetHwnd(hWnd
);
105 m_pAppSettings
->SetDasher(m_pDasher
);
107 m_pEdit
= new CEdit(m_pAppSettings
);
108 m_pEdit
->Create(hWnd
, m_pAppSettings
->GetBoolParameter(APP_BP_TIME_STAMP
));
109 m_pEdit
->SetFont(m_pAppSettings
->GetStringParameter(APP_SP_EDIT_FONT
), m_pAppSettings
->GetLongParameter(APP_LP_EDIT_FONT_SIZE
));
111 #ifdef PJC_EXPERIMENTAL
112 g_hWnd
= m_pEdit
->GetHwnd();
115 m_pToolbar
= new CToolbar(hWnd
, m_pAppSettings
->GetBoolParameter(APP_BP_SHOW_TOOLBAR
));
118 m_pToolbar
->ShowToolbar(false);
121 // FIXME - the edit box really shouldn't need access to the interface,
122 // but at the moment it does, for training, blanking the display etc
124 m_pEdit
->SetInterface(m_pDasher
);
126 m_pSpeedAlphabetBar
= new CStatusControl(m_pDasher
);
127 m_pSpeedAlphabetBar
->Create(hWnd
);
129 m_pGameGroup
= new CGameGroup(m_pDasher
, m_pEdit
);
130 m_pGameGroup
->Create(hWnd
);
131 m_pGameGroup
->ShowWindow(SW_HIDE
);
132 m_pGameGroup
->SetEditFont(m_pAppSettings
->GetStringParameter(APP_SP_EDIT_FONT
), m_pAppSettings
->GetLongParameter(APP_LP_EDIT_FONT_SIZE
));
134 m_pSplitter
= new CSplitter(this,100);
135 HWND hSplitter
= m_pSplitter
->Create(hWnd
);
140 // Add extra control nodes
142 m_pDasher
->RegisterNode( Dasher::CControlManager::CTL_USER
, "Speak", -1 );
143 m_pDasher
->RegisterNode( Dasher::CControlManager::CTL_USER
+1, "All", -1 );
144 m_pDasher
->RegisterNode( Dasher::CControlManager::CTL_USER
+2, "New", -1 );
145 m_pDasher
->RegisterNode( Dasher::CControlManager::CTL_USER
+3, "Repeat", -1 );
147 m_pDasher
->ConnectNode(Dasher::CControlManager::CTL_USER
, Dasher::CControlManager::CTL_ROOT
, -2);
149 m_pDasher
->ConnectNode(Dasher::CControlManager::CTL_USER
+1, Dasher::CControlManager::CTL_USER
, -2);
150 m_pDasher
->ConnectNode(Dasher::CControlManager::CTL_USER
+2, Dasher::CControlManager::CTL_USER
, -2);
151 m_pDasher
->ConnectNode(Dasher::CControlManager::CTL_USER
+3, Dasher::CControlManager::CTL_USER
, -2);
153 m_pDasher
->ConnectNode(-1, Dasher::CControlManager::CTL_USER
+1, -2);
154 m_pDasher
->ConnectNode(Dasher::CControlManager::CTL_ROOT
, Dasher::CControlManager::CTL_USER
+1, -2);
156 m_pDasher
->ConnectNode(-1, Dasher::CControlManager::CTL_USER
+2, -2);
157 m_pDasher
->ConnectNode(Dasher::CControlManager::CTL_ROOT
, Dasher::CControlManager::CTL_USER
+2, -2);
159 m_pDasher
->ConnectNode(-1, Dasher::CControlManager::CTL_USER
+3, -2);
160 m_pDasher
->ConnectNode(Dasher::CControlManager::CTL_ROOT
, Dasher::CControlManager::CTL_USER
+3, -2);
162 m_pGameModeHelper
= 0;
167 CDasherWindow::~CDasherWindow() {
172 delete m_pAppSettings
;
174 DestroyIcon(m_hIconSm
);
179 void CDasherWindow::Main() {
180 // TODO: Sort this sort ofthing out, figure out how it fits into ATL etc.
181 // This function is not called by anybody...
183 DASHER_ASSERT_VALIDPTR_RW(m_pDasher
);
187 Sleep(50); // limits framerate to 20fps
190 int CDasherWindow::MessageLoop() {
191 // See previous function's comments
194 while(GetMessage(&msg
, NULL
, 0, 0)) {
195 if(!TranslateAccelerator(msg
.hwnd
, hAccelTable
, &msg
)) {
196 TranslateMessage(&msg
);
197 DispatchMessage(&msg
);
201 m_pDasher
->StartShutdown();
206 void CDasherWindow::Show(int nCmdShow
) {
207 InvalidateRect(NULL
, FALSE
);
209 if(!LoadWindowState())
210 ShowWindow(nCmdShow
);
213 void CDasherWindow::SaveWindowState() const {
216 wp
.length
= sizeof(WINDOWPLACEMENT
);
218 if(GetWindowPlacement(&wp
)) {//function call succeeds
219 m_pAppSettings
->SaveSetting("WindowState", &wp
);
224 bool CDasherWindow::LoadWindowState() {
228 if(m_pAppSettings
->LoadSetting("WindowState", &wp
)) {
229 if(SetWindowPlacement(&wp
))
236 void CDasherWindow::HandleParameterChange(int iParameter
) {
239 case APP_BP_SHOW_TOOLBAR
:
240 m_pToolbar
->ShowToolbar(m_pAppSettings
->GetBoolParameter(APP_BP_SHOW_TOOLBAR
));
244 // TODO: No longer handled after startup?
247 case APP_BP_TIME_STAMP
:
249 // m_pEdit->TimeStampNewFiles(m_pAppSettings->GetBoolParameter(APP_BP_TIME_STAMP));
259 void CDasherWindow::HandleControlEvent(int iID
) {
260 // TODO: Some kind of automatic translation here? Or at least a table
263 case Dasher::CControlManager::CTL_MOVE_FORWARD_CHAR
:
265 m_pEdit
->Move(EDIT_FORWARDS
, EDIT_CHAR
);
267 case Dasher::CControlManager::CTL_MOVE_FORWARD_WORD
:
269 m_pEdit
->Move(EDIT_FORWARDS
, EDIT_WORD
);
271 case Dasher::CControlManager::CTL_MOVE_FORWARD_LINE
:
273 m_pEdit
->Move(EDIT_FORWARDS
, EDIT_LINE
);
275 case Dasher::CControlManager::CTL_MOVE_FORWARD_FILE
:
277 m_pEdit
->Move(EDIT_FORWARDS
, EDIT_FILE
);
279 case Dasher::CControlManager::CTL_MOVE_BACKWARD_CHAR
:
281 m_pEdit
->Move(EDIT_BACKWARDS
, EDIT_CHAR
);
283 case Dasher::CControlManager::CTL_MOVE_BACKWARD_WORD
:
285 m_pEdit
->Move(EDIT_BACKWARDS
, EDIT_WORD
);
287 case Dasher::CControlManager::CTL_MOVE_BACKWARD_LINE
:
289 m_pEdit
->Move(EDIT_BACKWARDS
, EDIT_LINE
);
291 case Dasher::CControlManager::CTL_MOVE_BACKWARD_FILE
:
293 m_pEdit
->Move(EDIT_BACKWARDS
, EDIT_FILE
);
295 case Dasher::CControlManager::CTL_DELETE_FORWARD_CHAR
:
297 m_pEdit
->Delete(EDIT_FORWARDS
, EDIT_CHAR
);
299 case Dasher::CControlManager::CTL_DELETE_FORWARD_WORD
:
301 m_pEdit
->Delete(EDIT_FORWARDS
, EDIT_WORD
);
303 case Dasher::CControlManager::CTL_DELETE_FORWARD_LINE
:
305 m_pEdit
->Delete(EDIT_FORWARDS
, EDIT_LINE
);
307 case Dasher::CControlManager::CTL_DELETE_FORWARD_FILE
:
309 m_pEdit
->Delete(EDIT_FORWARDS
, EDIT_FILE
);
311 case Dasher::CControlManager::CTL_DELETE_BACKWARD_CHAR
:
313 m_pEdit
->Delete(EDIT_BACKWARDS
, EDIT_CHAR
);
315 case Dasher::CControlManager::CTL_DELETE_BACKWARD_WORD
:
317 m_pEdit
->Delete(EDIT_BACKWARDS
, EDIT_WORD
);
319 case Dasher::CControlManager::CTL_DELETE_BACKWARD_LINE
:
321 m_pEdit
->Delete(EDIT_BACKWARDS
, EDIT_LINE
);
323 case Dasher::CControlManager::CTL_DELETE_BACKWARD_FILE
:
325 m_pEdit
->Delete(EDIT_BACKWARDS
, EDIT_FILE
);
327 case Dasher::CControlManager::CTL_USER
+1: // Speak all
331 case Dasher::CControlManager::CTL_USER
+2: // Speak new
335 case Dasher::CControlManager::CTL_USER
+3: // Repeat speech
342 LRESULT
CDasherWindow::OnCommand(UINT message
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
) {
343 const int wmId
= LOWORD(wParam
);
344 const int wmEvent
= HIWORD(wParam
);
346 // Tell edit box if it has changed. It should know itself really, but this is easier
347 // This shouldn't be here - it should be in the edit box class
348 if( m_pEdit
&& ((HWND
) lParam
== m_pEdit
->GetHwnd()) && (HIWORD(wParam
) == EN_CHANGE
)) {
353 // Parse the menu selections:
354 // TODO: Put these into separate functions
358 Aboutbox
.DoModal(m_hWnd
);
362 case ID_OPTIONS_PREFS
: {
363 CPrefs
Prefs(m_hWnd
, m_pDasher
, m_pAppSettings
);
368 case ID_HELP_CONTENTS
:
369 HtmlHelp(m_hWnd
, L
"Dasher.chm", HH_DISPLAY_INDEX
, NULL
);
372 case ID_HELP_DASHERTUTORIAL
:
373 m_pGameModeHelper
= new CGameModeHelper(m_pDasher
);
376 m_pDasher
->GameMessageIn(m_pGameGroup
->IsWindowVisible()?
377 (GameMode::GAME_MESSAGE_GAME_OFF
) : (GameMode::GAME_MESSAGE_GAME_ON
),
379 m_pGameGroup
->ShowWindow(m_pGameGroup
->IsWindowVisible()?SW_HIDE
:SW_SHOW
);
386 case ID_EDIT_SELECTALL
:
388 m_pEdit
->SelectAll();
398 case ID_EDIT_COPY_ALL
:
409 // Selecting file->new indicates a new trial to our user logging object
410 if (m_pDasher
!= NULL
) {
411 CUserLogBase
* pUserLog
= m_pDasher
->GetUserLogPtr();
412 if (pUserLog
!= NULL
)
413 pUserLog
->NewTrial();
415 m_pDasher
->SetBuffer(0);
427 case ID_FILE_SAVE_AS
:
431 case ID_IMPORT_TRAINFILE
:
432 m_pDasher
->ImportTrainingText(m_pEdit
->Import());
435 return DefWindowProc(message
, wParam
, lParam
);
442 LRESULT
CDasherWindow::OnDasherEvent(UINT message
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
) {
443 // Apparently putting the typecast directly in the switch doesn't work
444 CEvent
*pEvent( (CEvent
*)lParam
);
446 // TODO: return if handled?
447 switch(pEvent
->m_iEventType
) {
448 case EV_PARAM_NOTIFY
:
449 HandleParameterChange(((CParameterNotificationEvent
*)pEvent
)->m_iParameter
);
452 HandleControlEvent(((CControlEvent
*)pEvent
)->m_iID
);
455 if(m_pGameModeHelper
) {
456 Dasher::CEditEvent
* pEvt(static_cast< Dasher::CEditEvent
* >(pEvent
));
458 switch (pEvt
->m_iEditType
) {
460 m_pGameModeHelper
->Output(pEvt
->m_sText
);
463 m_pGameModeHelper
->Delete(pEvt
->m_sText
.size());
468 case EV_EDIT_CONTEXT
:
470 Dasher::CEditContextEvent
*pEvt
= static_cast< Dasher::CEditContextEvent
* >(pEvent
);
471 m_pDasher
->SetContext(m_pEdit
->get_context(pEvt
->m_iOffset
, pEvt
->m_iLength
));
479 m_pEdit
->HandleEvent(pEvent
);
484 LRESULT
CDasherWindow::OnGameMessage(UINT message
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
) {
485 m_pGameGroup
->Message(static_cast<int>(wParam
), reinterpret_cast<const void*>(lParam
));
490 LRESULT
CDasherWindow::OnDasherFocus(UINT message
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
) {
491 ::SetFocus(m_pEdit
->GetHwnd());
493 // TODO: Is this obsolete?
494 HWND
*pHwnd((HWND
*)lParam
);
495 m_pEdit
->SetKeyboardTarget(*pHwnd
);
499 LRESULT
CDasherWindow::OnDestroy(UINT message
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
) {
505 LRESULT
CDasherWindow::OnGetMinMaxInfo(UINT message
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
) {
507 if (m_pToolbar
== 0 || m_pSplitter
== 0 || m_pSpeedAlphabetBar
== 0)
512 lppt
= (LPPOINT
) lParam
; // lParam points to array of POINTs
513 lppt
[3].x
= 100; // Set minimum width (arbitrary)
514 // Set minimum height:
515 if(m_pAppSettings
->GetBoolParameter(APP_BP_SHOW_TOOLBAR
))
516 lppt
[3].y
= m_pToolbar
->GetHeight() + m_pSplitter
->GetPos()
517 + m_pSplitter
->GetHeight() + m_pSpeedAlphabetBar
->GetHeight() + GetSystemMetrics(SM_CYEDGE
) * 10;
519 lppt
[3].y
= m_pSplitter
->GetPos()
520 + m_pSplitter
->GetHeight() + m_pSpeedAlphabetBar
->GetHeight() + GetSystemMetrics(SM_CYEDGE
) * 10;
526 LRESULT
CDasherWindow::OnInitMenuPopup(UINT message
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
) {
527 WinMenu
.SortOut((HMENU
) wParam
);
531 LRESULT
CDasherWindow::OnClose(UINT message
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
) {
532 // TODO: Prompt for confirmation here
538 LRESULT
CDasherWindow::OnSize(UINT message
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
) {
539 if(wParam
== SIZE_MINIMIZED
)
543 m_pToolbar
->Resize();
551 LRESULT
CDasherWindow::OnSetFocus(UINT message
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
) {
552 m_pDasher
->TakeFocus();
556 LRESULT
CDasherWindow::OnOther(UINT message
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
) {
557 // A switch statement would be preferable, except the message ids are
558 // not constant-expressions since they are provided by the system at
560 if (message
== WM_DASHER_EVENT
)
561 return OnDasherEvent( message
, wParam
, lParam
, bHandled
);
562 else if (message
== WM_DASHER_FOCUS
)
563 return OnDasherFocus(message
, wParam
, lParam
, bHandled
);
564 else if (message
== WM_DASHER_GAME_MESSAGE
)
565 return OnGameMessage(message
, wParam
, lParam
, bHandled
);
566 else if (message
== DASHER_SHOW_PREFS
) {
568 CPrefs
Prefs(m_hWnd
, m_pDasher
, m_pAppSettings
);
575 void CDasherWindow::Layout() {
576 int iStyle(m_pAppSettings
->GetLongParameter(APP_LP_STYLE
));
578 // Set up the window properties
580 if((iStyle
== APP_STYLE_COMPOSE
) || (iStyle
== APP_STYLE_DIRECT
)) {
581 SetWindowLong(GWL_EXSTYLE
, GetWindowLong(GWL_EXSTYLE
) | WS_EX_NOACTIVATE
| WS_EX_APPWINDOW
);
582 SetWindowPos(HWND_TOPMOST
, 0, 0, 0, 0, SWP_NOMOVE
| SWP_NOSIZE
);
586 SetWindowLong(GWL_EXSTYLE
, GetWindowLong(GWL_EXSTYLE
) & !WS_EX_NOACTIVATE
);
587 SetWindowPos(HWND_NOTOPMOST
, 0, 0, 0, 0, SWP_NOMOVE
| SWP_NOSIZE
);
592 // Now do the actual layout
594 bool bHorizontal(iStyle
== APP_STYLE_COMPOSE
);
595 bool bShowEdit(iStyle
!= APP_STYLE_DIRECT
);
597 // Get the width of the window
599 GetClientRect( &ClientRect
);
600 const int Width
= ClientRect
.right
;
601 const int Height
= ClientRect
.bottom
;
603 // Get the height of the toolbar widget
605 if(m_pToolbar
&& m_pAppSettings
->GetBoolParameter(APP_BP_SHOW_TOOLBAR
))
606 ToolbarHeight
= m_pToolbar
->GetHeight();
610 // Get the height of the control bar at the bottom of the screen
611 int SpeedAlphabetHeight
;
612 if(m_pSpeedAlphabetBar
!= 0)
613 SpeedAlphabetHeight
= m_pSpeedAlphabetBar
->GetHeight();
615 SpeedAlphabetHeight
= 0;
617 int GameGroupHeight
= 0;
618 int GameGroupWidth
= 0;
619 int GameLabelHeight
= 0;
622 GameGroupHeight
= m_pGameGroup
->GetHeight();
623 GameGroupWidth
= m_pGameGroup
->GetWidth();
624 GameLabelHeight
= m_pGameGroup
->GetLabelHeight();
627 int MaxCanvas
= Height
- SpeedAlphabetHeight
*2;
628 int CurY
= ToolbarHeight
;
631 int SplitterPos
= m_pSplitter
->GetPos();
632 int SplitterHeight
= m_pSplitter
->GetHeight();
633 //SplitterPos = max(CurY + 2 * SplitterHeight, SplitterPos);
634 SplitterPos
= max(CurY
+ GameGroupHeight
, SplitterPos
);
635 SplitterPos
= min(SplitterPos
, MaxCanvas
- 3 * SplitterHeight
);
636 m_pSplitter
->Move(SplitterPos
, Width
);
640 m_pDasher
->Move(0, CurY
, Width
/ 2, MaxCanvas
- CurY
);
643 m_pEdit
->Move(Width
/ 2, CurY
, Width
/ 2, MaxCanvas
- CurY
);
647 m_pEdit
->ShowWindow(SW_SHOW
);
648 m_pSplitter
->ShowWindow(SW_SHOW
);
649 m_pGameGroup
->MoveWindow(0,CurY
,Width
,GameGroupHeight
);
653 //m_pEdit->Move(2, CurY+2, Width, SplitterPos - CurY-2);
654 m_pEdit
->Move(0, CurY
+GameLabelHeight
, Width
-GameGroupWidth
, SplitterPos
- CurY
-GameLabelHeight
);
657 CurY
= SplitterPos
+ SplitterHeight
;
660 m_pEdit
->ShowWindow(SW_HIDE
);
661 m_pSplitter
->ShowWindow(SW_HIDE
);
664 int CanvasHeight
= Height
- CurY
- SpeedAlphabetHeight
;
665 //- GetSystemMetrics(SM_CYEDGE);
667 // Put the DasherControl in the correct place...
669 m_pDasher
->Move(0, CurY
, Width
, CanvasHeight
-5);
670 //m_pDasher->Move(2, CurY+2, Width-4, CanvasHeight-2);
672 // ...with the bottom bar just below it.
673 if(m_pSpeedAlphabetBar
)
674 m_pSpeedAlphabetBar
->MoveWindow(0, Height
- SpeedAlphabetHeight
, Width
, SpeedAlphabetHeight
);
675 // m_pSlidebar->MoveWindow(2, Height - SlidebarHeight, Width-4, SlidebarHeight);
682 void CDasherWindow::HandleWinEvent(HWINEVENTHOOK hWinEventHook
, DWORD event
, HWND hwnd
, LONG idObject
, LONG idChild
, DWORD dwEventThread
, DWORD dwmsEventTime
) {
683 // Ignore events if not in direct mode
684 if(m_pAppSettings
&& (m_pAppSettings
->GetLongParameter(APP_LP_STYLE
) != APP_STYLE_DIRECT
))
687 // For now assume all events are focus changes, so reset the buffer
689 m_pDasher
->SetBuffer(0);