Various small changes
[dasher.git] / Src / DasherCore / DasherViewSquare.cpp
blobc247bca671eeeac20fbe17d73b1dbdeb969ebc43
1 // DasherViewSquare.cpp
2 //
3 // Copyright (c) 2001-2004 David Ward
5 // TODO - there's no real reason to distinguish between groups and nodes here - they're all just boxes to be rendered, with the distinction being at the level of the alphabet manager
7 #include "../Common/Common.h"
9 #include "DasherViewSquare.h"
10 #include "DasherModel.h"
11 #include "DasherView.h"
12 #include "DasherTypes.h"
13 #include "Event.h"
14 #include "EventHandler.h"
15 #include "View/DelayedDraw.h"
17 #include <algorithm>
18 #include <limits>
20 #include <iostream>
22 using namespace Dasher;
24 // Track memory leaks on Windows to the line that new'd the memory
25 #ifdef _WIN32
26 #ifdef _DEBUG
27 #define DEBUG_NEW new( _NORMAL_BLOCK, THIS_FILE, __LINE__ )
28 #define new DEBUG_NEW
29 #undef THIS_FILE
30 static char THIS_FILE[] = __FILE__;
31 #endif
32 #endif
34 // FIXME - quite a lot of the code here probably should be moved to
35 // the parent class (DasherView). I think we really should make the
36 // parent class less general - we're probably not going to implement
37 // anything which uses radically different co-ordinate transforms, and
38 // we can always override if necessary.
40 // FIXME - duplicated 'mode' code throught - needs to be fixed (actually, mode related stuff, Input2Dasher etc should probably be at least partially in some other class)
42 CDasherViewSquare::CDasherViewSquare(CEventHandler *pEventHandler, CSettingsStore *pSettingsStore, CDasherScreen *DasherScreen)
43 : CDasherView(pEventHandler, pSettingsStore, DasherScreen) {
45 // TODO - AutoOffset should be part of the eyetracker input filter
46 // Make sure that the auto calibration is set to zero berfore we start
47 m_yAutoOffset = 0;
49 m_pDelayDraw = new CDelayedDraw();
50 ChangeScreen(DasherScreen);
52 // TODO - Make these parameters
53 // tweak these if you know what you are doing
54 m_dXmpa = 0.2; // these are for the x non-linearity
55 m_dXmpb = 0.5;
56 m_dXmpc = 0.9;
57 m_dXmpd = 0.5; // slow X movement when accelerating Y
59 m_ymap = Cymap((myint)GetLongParameter(LP_MAX_Y));
61 m_bVisibleRegionValid = false;
64 CDasherViewSquare::~CDasherViewSquare() {
65 if (m_pDelayDraw != NULL) {
66 delete m_pDelayDraw;
67 m_pDelayDraw = NULL;
71 void CDasherViewSquare::HandleEvent(Dasher::CEvent *pEvent) {
72 // Let the parent class do its stuff
73 CDasherView::HandleEvent(pEvent);
75 // And then interpret events for ourself
76 if(pEvent->m_iEventType == 1) {
77 Dasher::CParameterNotificationEvent * pEvt(static_cast < Dasher::CParameterNotificationEvent * >(pEvent));
78 switch (pEvt->m_iParameter) {
79 case LP_REAL_ORIENTATION:
80 m_bVisibleRegionValid = false;
81 break;
82 default:
83 break;
88 void CDasherViewSquare::RenderNodes(CDasherNode *pRoot, myint iRootMin, myint iRootMax, std::vector<CDasherNode *> &vNodeList, std::vector<CDasherNode *> &vDeleteList) {
90 DASHER_ASSERT(pRoot != 0);
92 Screen()->Blank();
94 myint iDasherMinX;
95 myint iDasherMinY;
96 myint iDasherMaxX;
97 myint iDasherMaxY;
98 VisibleRegion(iDasherMinX, iDasherMinY, iDasherMaxX, iDasherMaxY);
100 RecursiveRender(pRoot, iRootMin, iRootMax, iDasherMaxX, vNodeList, vDeleteList);
102 // DelayDraw the text nodes
103 m_pDelayDraw->Draw(Screen());
105 Crosshair((myint)GetLongParameter(LP_OX)); // add crosshair
109 int CDasherViewSquare::RecursiveRender(CDasherNode *pRender, myint y1, myint y2, int mostleft, std::vector<CDasherNode *> &vNodeList, std::vector<CDasherNode *> &vDeleteList) {
110 DASHER_ASSERT_VALIDPTR_RW(pRender);
112 if(!RenderNode(pRender->Colour(), pRender->ColorScheme(), y1, y2, mostleft, pRender->m_strDisplayText, pRender->m_bShove)) {
113 vDeleteList.push_back(pRender);
114 pRender->Kill();
115 return 0;
118 if(pRender->ChildCount() == 0) {
119 vNodeList.push_back(pRender);
120 return 0;
123 // Render groups
124 RenderGroups(pRender, y1, y2, mostleft);
126 // Render children
127 int norm = (myint)GetLongParameter(LP_NORMALIZATION);
129 CDasherNode::ChildMap::const_iterator i;
130 for(i = pRender->GetChildren().begin(); i != pRender->GetChildren().end(); i++) {
131 CDasherNode *pChild = *i;
133 myint Range = y2 - y1;
134 myint newy1 = y1 + (Range * pChild->Lbnd()) / norm;
135 myint newy2 = y1 + (Range * pChild->Hbnd()) / norm;
137 // FIXME - make the threshold a parameter
139 if((newy2 - newy1 > 50) || (pChild->Alive())) {
140 pChild->Alive(true);
141 RecursiveRender(pChild, newy1, newy2, mostleft, vNodeList, vDeleteList);
145 return 1;
148 void CDasherViewSquare::RenderGroups(CDasherNode *Render, myint y1, myint y2, int mostleft) {
149 SGroupInfo *pCurrentGroup(Render->m_pBaseGroup);
151 while(pCurrentGroup) {
152 RecursiveRenderGroups(pCurrentGroup, Render, y1, y2, mostleft);
153 pCurrentGroup = pCurrentGroup->pNext;
157 void CDasherViewSquare::RecursiveRenderGroups(SGroupInfo *pCurrentGroup, CDasherNode *pNode, myint y1, myint y2, int mostleft) {
159 if(pCurrentGroup->bVisible) {
160 myint range = y2 - y1;
162 int lower(pCurrentGroup->iStart);
163 int upper(pCurrentGroup->iEnd);
165 myint lbnd = pNode->Children()[lower]->Lbnd();
166 myint hbnd = pNode->Children()[upper - 1]->Hbnd();
168 myint newy1 = y1 + (range * lbnd) / (int)GetLongParameter(LP_NORMALIZATION);
169 myint newy2 = y1 + (range * hbnd) / (int)GetLongParameter(LP_NORMALIZATION);
171 RenderNode(pCurrentGroup->iColour, Opts::Groups, newy1, newy2, mostleft, pCurrentGroup->strLabel, true);
174 // Iterate through child groups
175 SGroupInfo *pCurrentChild(pCurrentGroup->pChild);
177 while(pCurrentChild) {
178 RecursiveRenderGroups(pCurrentChild, pNode, y1, y2, mostleft);
179 pCurrentChild = pCurrentChild->pNext;
184 CDasherViewSquare::Cymap::Cymap(myint iScale) {
185 double dY1 = 0.25; // Amount of acceleration
186 double dY2 = 0.95; // Accelerate Y movement below this point
187 double dY3 = 0.05; // Accelerate Y movement above this point
189 m_Y2 = myint(dY2 * iScale);
190 m_Y3 = myint(dY3 * iScale);
191 m_Y1 = myint(1.0 / dY1);
196 int CDasherViewSquare::RenderNode(const int Color, Opts::ColorSchemes ColorScheme, myint y1, myint y2, int &mostleft, const std::string &sDisplayText, bool bShove) {
198 // Commenting because click mode occasionally fails this assert.
199 // I don't know why. -- cjb.
200 if (!(y2 >= y1)) { return 1; }
202 // TODO - Get sensibel limits here (to allow for non-linearities)
203 myint iDasherMinX;
204 myint iDasherMinY;
205 myint iDasherMaxX;
206 myint iDasherMaxY;
207 VisibleRegion(iDasherMinX, iDasherMinY, iDasherMaxX, iDasherMaxY);
209 screenint s1, s2;
210 // TODO - use new versions of functions
211 Cint32 iSize = dashery2screen(y1, y2, s1, s2);
213 // Actual height in pixels
214 Cint32 iHeight = Cint32((Cint32) (iSize * CanvasY) / (Cint32) GetLongParameter(LP_MAX_Y));
216 if(iHeight <= 1)
217 return 0; // We're too small to render
219 if((y1 > iDasherMaxY) || (y2 < iDasherMinY)){
220 return 0; // We're entirely off screen, so don't render.
223 myint iDasherSize(y2 - y1);
225 // FIXME - get rid of pointless assignment below
227 int iTruncation(GetLongParameter(LP_TRUNCATION)); // Trucation farction times 100;
228 int iTruncationType(GetLongParameter(LP_TRUNCATIONTYPE));
230 if(iTruncation == 0) { // Regular squares
231 DasherDrawRectangle(std::min(iDasherSize,iDasherMaxX), std::min(y2,iDasherMaxY), 0, std::max(y1,iDasherMinY), Color, -1, ColorScheme, GetBoolParameter(BP_OUTLINE_MODE), true, 1);
233 else {
234 int iDasherY((myint)GetLongParameter(LP_MAX_Y));
236 int iSpacing(iDasherY / 128); // FIXME - assuming that this is an integer below
238 int iXStart = 0;
240 switch (iTruncationType) {
241 case 1:
242 iXStart = iSize - iSize * iTruncation / 200;
243 break;
244 case 2:
245 iXStart = iSize - iSize * iTruncation / 100;
246 break;
249 int iTipMin((y2 - y1) * iTruncation / (200) + y1);
250 int iTipMax(y2 - (y2 - y1) * iTruncation / (200));
252 int iLowerMin(((y1 + 1) / iSpacing) * iSpacing);
253 int iLowerMax(((iTipMin - 1) / iSpacing) * iSpacing);
255 int iUpperMin(((iTipMax + 1) / iSpacing) * iSpacing);
256 int iUpperMax(((y2 - 1) / iSpacing) * iSpacing);
258 if(iLowerMin < 0)
259 iLowerMin = 0;
261 if(iLowerMax < 0)
262 iLowerMax = 0;
264 if(iUpperMin < 0)
265 iUpperMin = 0;
267 if(iUpperMax < 0)
268 iUpperMax = 0;
270 if(iLowerMin > iDasherY)
271 iLowerMin = iDasherY;
273 if(iLowerMax > iDasherY)
274 iLowerMax = iDasherY;
276 if(iUpperMin > iDasherY)
277 iUpperMin = iDasherY;
279 if(iUpperMax > iDasherY)
280 iUpperMax = iDasherY;
282 while(iLowerMin < y1)
283 iLowerMin += iSpacing;
285 while(iLowerMax > iTipMin)
286 iLowerMax -= iSpacing;
288 while(iUpperMin < iTipMax)
289 iUpperMin += iSpacing;
291 while(iUpperMax > y2)
292 iUpperMax -= iSpacing;
294 int iLowerCount((iLowerMax - iLowerMin) / iSpacing + 1);
295 int iUpperCount((iUpperMax - iUpperMin) / iSpacing + 1);
297 if(iLowerCount < 0)
298 iLowerCount = 0;
300 if(iUpperCount < 0)
301 iUpperCount = 0;
303 int iTotalCount(iLowerCount + iUpperCount + 6);
305 myint *x = new myint[iTotalCount];
306 myint *y = new myint[iTotalCount];
308 // Weird duplication here is to make truncated squares possible too
310 x[0] = 0;
311 y[0] = y1;
312 x[1] = iXStart;
313 y[1] = y1;
315 x[iLowerCount + 2] = iDasherSize;
316 y[iLowerCount + 2] = iTipMin;
317 x[iLowerCount + 3] = iDasherSize;
318 y[iLowerCount + 3] = iTipMax;
320 x[iTotalCount - 2] = iXStart;
321 y[iTotalCount - 2] = y2;
322 x[iTotalCount - 1] = 0;
323 y[iTotalCount - 1] = y2;
325 for(int i(0); i < iLowerCount; ++i) {
326 x[i + 2] = (iLowerMin + i * iSpacing - y1) * (iDasherSize - iXStart) / (iTipMin - y1) + iXStart;
327 y[i + 2] = iLowerMin + i * iSpacing;
330 for(int j(0); j < iUpperCount; ++j) {
331 x[j + iLowerCount + 4] = (y2 - (iUpperMin + j * iSpacing)) * (iDasherSize - iXStart) / (y2 - iTipMax) + iXStart;
332 y[j + iLowerCount + 4] = iUpperMin + j * iSpacing;
335 DasherPolygon(x, y, iTotalCount, Color);
337 delete x;
338 delete y;
342 myint iDasherAnchorX(iDasherSize);
344 if( sDisplayText.size() > 0 )
345 DasherDrawText(iDasherAnchorX, y1, iDasherAnchorX, y2, sDisplayText, mostleft, bShove);
347 return 1;
350 bool CDasherViewSquare::IsNodeVisible(myint y1, myint y2) {
352 myint iDasherMinX;
353 myint iDasherMinY;
354 myint iDasherMaxX;
355 myint iDasherMaxY;
357 VisibleRegion(iDasherMinX, iDasherMinY, iDasherMaxX, iDasherMaxY);
359 return (y1 > iDasherMinY) || (y2 < iDasherMaxY ) || (y2-y1 < iDasherMaxX);
362 /// Convert screen co-ordinates to dasher co-ordinates. This doesn't
363 /// include the nonlinear mapping for eyetracking mode etc - it is
364 /// just the inverse of the mapping used to calculate the screen
365 /// positions of boxes etc.
367 void CDasherViewSquare::Screen2Dasher(screenint iInputX, screenint iInputY, myint &iDasherX, myint &iDasherY, bool b1D, bool bNonlinearity) {
369 // Things we're likely to need:
371 myint iDasherWidth = (myint)GetLongParameter(LP_MAX_Y);
372 myint iDasherHeight = (myint)GetLongParameter(LP_MAX_Y);
374 screenint iScreenWidth = Screen()->GetWidth();
375 screenint iScreenHeight = Screen()->GetHeight();
377 if( b1D ) { // Special case for 1D mode...
378 iDasherX = iInputX * iDasherWidth / iScreenWidth;
379 iDasherY = iInputY * iDasherHeight / iScreenHeight;
380 return;
383 int eOrientation(GetLongParameter(LP_REAL_ORIENTATION));
385 myint iScaleFactorX;
386 myint iScaleFactorY;
388 GetScaleFactor(eOrientation, &iScaleFactorX, &iScaleFactorY);
390 switch(eOrientation) {
391 case Dasher::Opts::LeftToRight:
392 iDasherX = iDasherWidth / 2 - ( iInputX - iScreenWidth / 2 ) * m_iScalingFactor / iScaleFactorX;
393 iDasherY = iDasherHeight / 2 + ( iInputY - iScreenHeight / 2 ) * m_iScalingFactor / iScaleFactorY;
394 break;
395 case Dasher::Opts::RightToLeft:
396 iDasherX = myint(iDasherWidth / 2 + ( iInputX - iScreenWidth / 2 ) * m_iScalingFactor/ iScaleFactorX);
397 iDasherY = myint(iDasherHeight / 2 + ( iInputY - iScreenHeight / 2 ) * m_iScalingFactor/ iScaleFactorY);
398 break;
399 case Dasher::Opts::TopToBottom:
400 iDasherX = myint(iDasherWidth / 2 - ( iInputY - iScreenHeight / 2 ) * m_iScalingFactor/ iScaleFactorY);
401 iDasherY = myint(iDasherHeight / 2 + ( iInputX - iScreenWidth / 2 ) * m_iScalingFactor/ iScaleFactorX);
402 break;
403 case Dasher::Opts::BottomToTop:
404 iDasherX = myint(iDasherWidth / 2 + ( iInputY - iScreenHeight / 2 ) * m_iScalingFactor/ iScaleFactorY);
405 iDasherY = myint(iDasherHeight / 2 + ( iInputX - iScreenWidth / 2 ) * m_iScalingFactor/ iScaleFactorX);
406 break;
409 #ifndef WITH_MAEMO
410 // FIXME - disabled to avoid floating point
411 if( bNonlinearity ) {
412 iDasherX = myint(ixmap(iDasherX / static_cast < double >(GetLongParameter(LP_MAX_Y))) * (myint)GetLongParameter(LP_MAX_Y));
413 iDasherY = m_ymap.unmap(iDasherY);
415 #endif
418 void CDasherViewSquare::SetScaleFactor( void )
420 myint iDasherWidth = (myint)GetLongParameter(LP_MAX_Y);
421 myint iDasherHeight = iDasherWidth;
423 screenint iScreenWidth = Screen()->GetWidth();
424 screenint iScreenHeight = Screen()->GetHeight();
426 // Try doing this a different way:
428 myint iDasherMargin( 300 ); // Make this a parameter
430 myint iMinX( 0-iDasherMargin );
431 myint iMaxX( iDasherWidth + iDasherMargin );
432 myint iMinY( 0 );
433 myint iMaxY( iDasherHeight );
435 double dLRHScaleFactor;
436 double dLRVScaleFactor;
437 double dTBHScaleFactor;
438 double dTBVScaleFactor;
440 dLRHScaleFactor = iScreenWidth / static_cast<double>( iMaxX - iMinX );
441 dLRVScaleFactor = iScreenHeight / static_cast<double>( iMaxY - iMinY );
442 dTBHScaleFactor = iScreenWidth / static_cast<double>( iMaxY - iMinY );
443 dTBVScaleFactor = iScreenHeight / static_cast<double>( iMaxX - iMinX );
445 iLRScaleFactorX = myint(std::max(std::min(dLRHScaleFactor, dLRVScaleFactor), dLRHScaleFactor / 4.0) * m_iScalingFactor);
446 iLRScaleFactorY = myint(std::max(std::min(dLRHScaleFactor, dLRVScaleFactor), dLRVScaleFactor / 4.0) * m_iScalingFactor);
447 iTBScaleFactorX = myint(std::max(std::min(dTBHScaleFactor, dTBVScaleFactor), dTBVScaleFactor / 4.0) * m_iScalingFactor);
448 iTBScaleFactorY = myint(std::max(std::min(dTBHScaleFactor, dTBVScaleFactor), dTBHScaleFactor / 4.0) * m_iScalingFactor);
451 void CDasherViewSquare::GetScaleFactor( int eOrientation, myint *iScaleFactorX, myint *iScaleFactorY ) {
452 if(( eOrientation == Dasher::Opts::LeftToRight ) || ( eOrientation == Dasher::Opts::RightToLeft )) {
453 *iScaleFactorX = iLRScaleFactorX;
454 *iScaleFactorY = iLRScaleFactorY;
455 } else {
456 *iScaleFactorX = iTBScaleFactorX;
457 *iScaleFactorY = iTBScaleFactorY;
461 /// Convert dasher co-ordinates to screen co-ordinates
463 void CDasherViewSquare::Dasher2Screen(myint iDasherX, myint iDasherY, screenint &iScreenX, screenint &iScreenY) {
465 // Apply the nonlinearities
467 #ifndef WITH_MAEMO
468 // FIXME
469 iDasherX = myint(xmap(iDasherX / static_cast < double >(GetLongParameter(LP_MAX_Y))) * (myint)GetLongParameter(LP_MAX_Y));
470 iDasherY = m_ymap.map(iDasherY);
471 #endif
473 // Things we're likely to need:
475 myint iDasherWidth = (myint)GetLongParameter(LP_MAX_Y);
476 myint iDasherHeight = (myint)GetLongParameter(LP_MAX_Y);
478 screenint iScreenWidth = Screen()->GetWidth();
479 screenint iScreenHeight = Screen()->GetHeight();
481 int eOrientation( GetLongParameter(LP_REAL_ORIENTATION) );
483 myint iScaleFactorX;
484 myint iScaleFactorY;
486 GetScaleFactor( eOrientation, &iScaleFactorX, &iScaleFactorY);
488 switch( eOrientation ) {
489 case Dasher::Opts::LeftToRight:
490 iScreenX = screenint(iScreenWidth / 2 - ( iDasherX - iDasherWidth / 2 ) * iScaleFactorX / m_iScalingFactor);
491 iScreenY = screenint(iScreenHeight / 2 + ( iDasherY - iDasherHeight / 2 ) * iScaleFactorY / m_iScalingFactor);
492 break;
493 case Dasher::Opts::RightToLeft:
494 iScreenX = screenint(iScreenWidth / 2 + ( iDasherX - iDasherWidth / 2 ) * iScaleFactorX / m_iScalingFactor);
495 iScreenY = screenint(iScreenHeight / 2 + ( iDasherY - iDasherHeight / 2 ) * iScaleFactorY / m_iScalingFactor);
496 break;
497 case Dasher::Opts::TopToBottom:
498 iScreenX = screenint(iScreenWidth / 2 + ( iDasherY - iDasherHeight / 2 ) * iScaleFactorX / m_iScalingFactor);
499 iScreenY = screenint(iScreenHeight / 2 - ( iDasherX - iDasherWidth / 2 ) * iScaleFactorY / m_iScalingFactor);
500 break;
501 case Dasher::Opts::BottomToTop:
502 iScreenX = screenint(iScreenWidth / 2 + ( iDasherY - iDasherHeight / 2 ) * iScaleFactorX / m_iScalingFactor);
503 iScreenY = screenint(iScreenHeight / 2 + ( iDasherX - iDasherWidth / 2 ) * iScaleFactorY / m_iScalingFactor);
504 break;
508 void CDasherViewSquare::VisibleRegion( myint &iDasherMinX, myint &iDasherMinY, myint &iDasherMaxX, myint &iDasherMaxY ) {
510 if(!m_bVisibleRegionValid) {
511 int eOrientation( GetLongParameter(LP_REAL_ORIENTATION) );
513 switch( eOrientation ) {
514 case Dasher::Opts::LeftToRight:
515 Screen2Dasher(Screen()->GetWidth(),0,m_iDasherMinX,m_iDasherMinY,false,true);
516 Screen2Dasher(0,Screen()->GetHeight(),m_iDasherMaxX,m_iDasherMaxY,false,true);
517 break;
518 case Dasher::Opts::RightToLeft:
519 Screen2Dasher(0,0,m_iDasherMinX,m_iDasherMinY,false,true);
520 Screen2Dasher(Screen()->GetWidth(),Screen()->GetHeight(),m_iDasherMaxX,m_iDasherMaxY,false,true);
521 break;
522 case Dasher::Opts::TopToBottom:
523 Screen2Dasher(0,Screen()->GetHeight(),m_iDasherMinX,m_iDasherMinY,false,true);
524 Screen2Dasher(Screen()->GetWidth(),0,m_iDasherMaxX,m_iDasherMaxY,false,true);
525 break;
526 case Dasher::Opts::BottomToTop:
527 Screen2Dasher(0,0,m_iDasherMinX,m_iDasherMinY,false,true);
528 Screen2Dasher(Screen()->GetWidth(),Screen()->GetHeight(),m_iDasherMaxX,m_iDasherMaxY,false,true);
529 break;
532 m_bVisibleRegionValid = true;
535 iDasherMinX = m_iDasherMinX;
536 iDasherMaxX = m_iDasherMaxX;
537 iDasherMinY = m_iDasherMinY;
538 iDasherMaxY = m_iDasherMaxY;
541 /// The minimum Dasher Y co-ordinate which will be visible
543 myint CDasherViewSquare::DasherVisibleMinY() {
545 // Todo - convert all these to a single 'get visible extent' function
547 myint iDasherX;
548 myint iDasherY;
550 int eOrientation( GetLongParameter(LP_REAL_ORIENTATION) );
552 switch( eOrientation ) {
553 case Dasher::Opts::LeftToRight:
554 Screen2Dasher(Screen()->GetWidth(),0,iDasherX,iDasherY,false,true);
555 break;
556 case Dasher::Opts::RightToLeft:
557 Screen2Dasher(0,0,iDasherX,iDasherY,false,true);
558 break;
559 case Dasher::Opts::TopToBottom:
560 Screen2Dasher(0,Screen()->GetHeight(),iDasherX,iDasherY,false,true);
561 break;
562 case Dasher::Opts::BottomToTop:
563 Screen2Dasher(0,0,iDasherX,iDasherY,false,true);
564 break;
567 return iDasherY;
570 /// The maximum Dasher Y co-ordinate which will be visible
572 myint CDasherViewSquare::DasherVisibleMaxY() {
573 // Todo - convert all these to a single 'get visible extent' function
575 myint iDasherX;
576 myint iDasherY;
578 int eOrientation( GetLongParameter(LP_REAL_ORIENTATION) );
580 switch( eOrientation ) {
581 case Dasher::Opts::LeftToRight:
582 Screen2Dasher(0,Screen()->GetHeight(),iDasherX,iDasherY,false,true);
583 break;
584 case Dasher::Opts::RightToLeft:
585 Screen2Dasher(Screen()->GetWidth(),Screen()->GetHeight(),iDasherX,iDasherY,false,true);
586 break;
587 case Dasher::Opts::TopToBottom:
588 Screen2Dasher(Screen()->GetWidth(),0,iDasherX,iDasherY,false,true);
589 break;
590 case Dasher::Opts::BottomToTop:
591 Screen2Dasher(Screen()->GetWidth(),Screen()->GetHeight(),iDasherX,iDasherY,false,true);
592 break;
595 return iDasherY;
598 /// The maximum Dasher X co-ordinate which will be visible
600 myint CDasherViewSquare::DasherVisibleMaxX() {
601 // Todo - convert all these to a single 'get visible extent' function
603 myint iDasherX;
604 myint iDasherY;
606 int eOrientation( GetLongParameter(LP_REAL_ORIENTATION) );
608 switch( eOrientation ) {
609 case Dasher::Opts::LeftToRight:
610 Screen2Dasher(0,Screen()->GetHeight(),iDasherX,iDasherY,false,true);
611 break;
612 case Dasher::Opts::RightToLeft:
613 Screen2Dasher(Screen()->GetWidth(),Screen()->GetHeight(),iDasherX,iDasherY,false,true);
614 break;
615 case Dasher::Opts::TopToBottom:
616 Screen2Dasher(Screen()->GetWidth(),0,iDasherX,iDasherY,false,true);
617 break;
618 case Dasher::Opts::BottomToTop:
619 Screen2Dasher(Screen()->GetWidth(),Screen()->GetHeight(),iDasherX,iDasherY,false,true);
620 break;
623 return iDasherX;
627 /// Convert abstract 'input coordinates', which may or may not
628 /// correspond to actual screen positions, depending on the settings,
629 /// into dasher co-ordinates. Modes are:
631 /// 0 = Direct (ie mouse)
632 /// 1 = 1D
633 /// 2 = Eyetracker
635 /// This should be done once initially, then we work in Dasher
636 /// co-ordinates for everything else. Input co-ordinates will be
637 /// assumed to range over the extent of the screen.
639 /// TODO: Abstract out modes into an enum
641 void CDasherViewSquare::Input2Dasher(screenint iInputX, screenint iInputY, myint &iDasherX, myint &iDasherY, int iType, int iMode) {
643 // FIXME - need to incorporate one-button mode?
645 // First convert the supplied co-ordinates to 'linear' Dasher co-ordinates
647 switch (iType) {
648 case 0:
649 // Raw secreen coordinates
651 // TODO - autocalibration should be at the level of the eyetracker filter
652 if(iMode == 2) {
653 // First apply the autocalibration offset
654 iInputY += int (m_yAutoOffset); // FIXME - we need more flexible autocalibration to work with orientations other than left-to-right
657 if( iMode == 0 )
658 Screen2Dasher( iInputX, iInputY, iDasherX, iDasherY, false, true );
659 else if( iMode == 1 )
660 Screen2Dasher( iInputX, iInputY, iDasherX, iDasherY, true, false );
661 else
662 Screen2Dasher( iInputX, iInputY, iDasherX, iDasherY, false, true );
663 break;
664 case 1:
665 // Raw dasher coordinates
667 iDasherX = iInputX;
668 iDasherY = iInputY;
669 break;
670 default:
671 // ERROR
672 break;
675 // Apply y scaling
677 if(iMode == 1 ) {
678 if( GetLongParameter(LP_YSCALE) > 0 ) {
680 double dYScale;
682 int eOrientation(GetLongParameter(LP_REAL_ORIENTATION));
684 if(( eOrientation == Dasher::Opts::LeftToRight ) || ( eOrientation == Dasher::Opts::RightToLeft ))
685 dYScale = Screen()->GetHeight() / static_cast<double>(GetLongParameter(LP_YSCALE));
686 else
687 dYScale = Screen()->GetWidth() / static_cast<double>(GetLongParameter(LP_YSCALE));
689 iDasherY = myint((iDasherY - (myint)GetLongParameter(LP_MAX_Y)/2) * dYScale + (myint)GetLongParameter(LP_MAX_Y)/2);
694 /// Truncate a set of co-ordinates so that they are on the screen
696 void CDasherViewSquare::TruncateToScreen(screenint &iX, screenint &iY) {
698 // I think that this function is now obsolete
700 if(iX < 0)
701 iX = 0;
702 if(iX > Screen()->GetWidth())
703 iX = Screen()->GetWidth();
705 if(iY < 0)
706 iY = 0;
707 if(iY > Screen()->GetHeight())
708 iY = Screen()->GetHeight();
711 // work out the next viewpoint
712 // move the rectangles accordingly
713 void CDasherViewSquare::TapOnDisplay(screenint mousex,
714 screenint mousey,
715 unsigned long Time,
716 myint &iDasherX, myint &iDasherY,
717 Dasher::VECTOR_SYMBOL_PROB* pAdded,
718 int* pNumDeleted) {
720 // FIXME - rename this something more appropriate (all this really should do is convert the coordinates)
722 // NOTE - we now ignore the values which are actually passed to the display
724 // FIXME - Actually turn autocalibration on and off!
725 // FIXME - AutoCalibrate should use Dasher co-ordinates, not raw mouse co-ordinates?
726 // FIXME - Have I broken this by moving it before the offset is applied?
727 // FIXME - put ymap stuff back in
729 // FIXME - optimise this
731 int iCoordinateCount(GetCoordinateCount());
733 myint *pCoordinates(new myint[iCoordinateCount]);
735 int iType(GetCoordinates(iCoordinateCount, pCoordinates));
737 if(iCoordinateCount == 1) {
738 mousex = 0;
739 mousey = pCoordinates[0];
741 else {
742 mousex = pCoordinates[0];
743 mousey = pCoordinates[1];
746 delete[]pCoordinates;
748 // bool autocalibrate = GetBoolParameter(BP_AUTOCALIBRATE);
749 if(GetBoolParameter(BP_AUTOCALIBRATE) && GetBoolParameter(BP_EYETRACKER_MODE)) {
750 AutoCalibrate(&mousex, &mousey);
754 // Convert the input co-ordinates to dasher co-ordinates
756 int mode;
758 if(GetBoolParameter(BP_NUMBER_DIMENSIONS))
759 mode = 1;
760 else if(GetBoolParameter(BP_EYETRACKER_MODE))
761 mode = 2;
762 else
763 mode = 0;
765 Input2Dasher(mousex, mousey, iDasherX, iDasherY, iType, mode);
766 m_iDasherXCache = iDasherX;
767 m_iDasherYCache = iDasherY;
769 // Request an update at the calculated co-ordinates
772 // Cache the Dasher Co-ordinates, so we can use them later for things like drawing the mouse position
773 #ifndef WITH_MAEMO
774 // FIXME
775 // iDasherX = myint(xmap(iDasherX / static_cast < double >(GetLongParameter(LP_MAX_Y))) * GetLongParameter(LP_MAX_Y));
776 // iDasherY = m_ymap.map(iDasherY);
777 #endif
780 void CDasherViewSquare::NewDrawGoTo(myint iDasherMin, myint iDasherMax, bool bActive) {
781 myint iHeight(iDasherMax - iDasherMin);
783 int iColour;
784 int iWidth;
786 if(bActive) {
787 iColour = 1;
788 iWidth = 3;
790 else {
791 iColour = 2;
792 iWidth = 1;
795 CDasherScreen::point p[4];
797 Dasher2Screen( 0, iDasherMin, p[0].x, p[0].y);
798 Dasher2Screen( iHeight, iDasherMin, p[1].x, p[1].y);
799 Dasher2Screen( iHeight, iDasherMax, p[2].x, p[2].y);
800 Dasher2Screen( 0, iDasherMax, p[3].x, p[3].y);
802 Screen()->Polyline(p, 4, iWidth, iColour);
805 void CDasherViewSquare::ResetSum() {
806 m_ySum = 0;
809 void CDasherViewSquare::ResetSumCounter() {
810 m_ySumCounter = 0;
813 void CDasherViewSquare::ResetYAutoOffset() {
814 m_yAutoOffset = 0;
817 void CDasherViewSquare::ChangeScreen(CDasherScreen *NewScreen) {
818 CDasherView::ChangeScreen(NewScreen);
819 screenint Width = Screen()->GetWidth();
820 screenint Height = Screen()->GetHeight();
821 CanvasX = 9 * Width / 10;
822 CanvasBorder = Width - CanvasX;
823 CanvasY = Height;
824 m_iScalingFactor = 100000000;
825 SetScaleFactor();
828 int CDasherViewSquare::GetAutoOffset() const {
829 return m_yAutoOffset;
832 void CDasherViewSquare::AutoCalibrate(screenint *mousex, screenint *mousey) {
833 double dashery = double (*mousey) * double ((myint)GetLongParameter(LP_MAX_Y)) / double (CanvasY);
834 myint dasherOY = (myint)GetLongParameter(LP_OY);
835 double disty = double (dasherOY) - dashery;
836 bool DasherRunning = GetBoolParameter(BP_DASHER_PAUSED);
838 if(!DasherRunning == true) {
839 m_yFilterTimescale = 20;
840 m_ySum += (int)disty;
841 m_ySumCounter++;
843 m_ySigBiasPercentage = 50;
844 m_ySigBiasPixels = m_ySigBiasPercentage * (myint)GetLongParameter(LP_MAX_Y) / 100;
846 //cout << "yAutoOffset: " << CDasherView::yAutoOffset << endl;
848 if(m_ySumCounter > m_yFilterTimescale) {
849 m_ySumCounter = 0;
851 // 'Conditions A', as specified by DJCM. Only make the auto-offset
852 // change if we're past the significance boundary.
854 if(m_ySum > m_ySigBiasPixels || m_ySum < -m_ySigBiasPixels) {
855 if(m_ySum > m_yFilterTimescale) {
856 m_yAutoOffset--;
858 else if(m_ySum < -m_yFilterTimescale)
859 m_yAutoOffset++;
861 m_ySum = 0;
865 //*mousey=int(dashery);
869 // TODO - should be elsewhere
871 void CDasherViewSquare::DrawGameModePointer() {
873 // FIXME - reimplement
875 // myint loc = DasherModel()->GetGameModePointerLoc();
877 // if(loc == myint(INT64_MIN))
878 // return;
880 // if(loc > GetLongParameter(LP_MAX_Y))
881 // DasherDrawCentredRectangle(-50, GetLongParameter(LP_MAX_Y), 5, 135, Opts::ColorSchemes(Objects), false);
883 // else if(loc < 0)
884 // DasherDrawCentredRectangle(-50, 0, 5, 135, Opts::ColorSchemes(Objects), false);
886 // else
887 // DasherDrawCentredRectangle(-50, loc, 7, 135, Opts::ColorSchemes(Objects), false);