1 // DasherViewSquare.cpp
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"
14 #include "EventHandler.h"
15 #include "View/DelayedDraw.h"
22 using namespace Dasher
;
24 // Track memory leaks on Windows to the line that new'd the memory
27 #define DEBUG_NEW new( _NORMAL_BLOCK, THIS_FILE, __LINE__ )
30 static char THIS_FILE
[] = __FILE__
;
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
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
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
) {
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;
88 void CDasherViewSquare::RenderNodes(CDasherNode
*pRoot
, myint iRootMin
, myint iRootMax
, std::vector
<CDasherNode
*> &vNodeList
, std::vector
<CDasherNode
*> &vDeleteList
) {
90 DASHER_ASSERT(pRoot
!= 0);
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
);
118 if(pRender
->ChildCount() == 0) {
119 vNodeList
.push_back(pRender
);
124 RenderGroups(pRender
, y1
, y2
, mostleft
);
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())) {
141 RecursiveRender(pChild
, newy1
, newy2
, mostleft
, vNodeList
, vDeleteList
);
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)
207 VisibleRegion(iDasherMinX
, iDasherMinY
, iDasherMaxX
, iDasherMaxY
);
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
));
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);
234 int iDasherY((myint
)GetLongParameter(LP_MAX_Y
));
236 int iSpacing(iDasherY
/ 128); // FIXME - assuming that this is an integer below
240 switch (iTruncationType
) {
242 iXStart
= iSize
- iSize
* iTruncation
/ 200;
245 iXStart
= iSize
- iSize
* iTruncation
/ 100;
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
);
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);
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
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
);
342 myint
iDasherAnchorX(iDasherSize
);
344 if( sDisplayText
.size() > 0 )
345 DasherDrawText(iDasherAnchorX
, y1
, iDasherAnchorX
, y2
, sDisplayText
, mostleft
, bShove
);
350 bool CDasherViewSquare::IsNodeVisible(myint y1
, myint y2
) {
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
;
383 int eOrientation(GetLongParameter(LP_REAL_ORIENTATION
));
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
;
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
);
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
);
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
);
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
);
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
);
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
;
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
469 iDasherX
= myint(xmap(iDasherX
/ static_cast < double >(GetLongParameter(LP_MAX_Y
))) * (myint
)GetLongParameter(LP_MAX_Y
));
470 iDasherY
= m_ymap
.map(iDasherY
);
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
) );
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
);
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
);
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
);
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
);
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);
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);
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);
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);
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
550 int eOrientation( GetLongParameter(LP_REAL_ORIENTATION
) );
552 switch( eOrientation
) {
553 case Dasher::Opts::LeftToRight
:
554 Screen2Dasher(Screen()->GetWidth(),0,iDasherX
,iDasherY
,false,true);
556 case Dasher::Opts::RightToLeft
:
557 Screen2Dasher(0,0,iDasherX
,iDasherY
,false,true);
559 case Dasher::Opts::TopToBottom
:
560 Screen2Dasher(0,Screen()->GetHeight(),iDasherX
,iDasherY
,false,true);
562 case Dasher::Opts::BottomToTop
:
563 Screen2Dasher(0,0,iDasherX
,iDasherY
,false,true);
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
578 int eOrientation( GetLongParameter(LP_REAL_ORIENTATION
) );
580 switch( eOrientation
) {
581 case Dasher::Opts::LeftToRight
:
582 Screen2Dasher(0,Screen()->GetHeight(),iDasherX
,iDasherY
,false,true);
584 case Dasher::Opts::RightToLeft
:
585 Screen2Dasher(Screen()->GetWidth(),Screen()->GetHeight(),iDasherX
,iDasherY
,false,true);
587 case Dasher::Opts::TopToBottom
:
588 Screen2Dasher(Screen()->GetWidth(),0,iDasherX
,iDasherY
,false,true);
590 case Dasher::Opts::BottomToTop
:
591 Screen2Dasher(Screen()->GetWidth(),Screen()->GetHeight(),iDasherX
,iDasherY
,false,true);
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
606 int eOrientation( GetLongParameter(LP_REAL_ORIENTATION
) );
608 switch( eOrientation
) {
609 case Dasher::Opts::LeftToRight
:
610 Screen2Dasher(0,Screen()->GetHeight(),iDasherX
,iDasherY
,false,true);
612 case Dasher::Opts::RightToLeft
:
613 Screen2Dasher(Screen()->GetWidth(),Screen()->GetHeight(),iDasherX
,iDasherY
,false,true);
615 case Dasher::Opts::TopToBottom
:
616 Screen2Dasher(Screen()->GetWidth(),0,iDasherX
,iDasherY
,false,true);
618 case Dasher::Opts::BottomToTop
:
619 Screen2Dasher(Screen()->GetWidth(),Screen()->GetHeight(),iDasherX
,iDasherY
,false,true);
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)
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
649 // Raw secreen coordinates
651 // TODO - autocalibration should be at the level of the eyetracker filter
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
658 Screen2Dasher( iInputX
, iInputY
, iDasherX
, iDasherY
, false, true );
659 else if( iMode
== 1 )
660 Screen2Dasher( iInputX
, iInputY
, iDasherX
, iDasherY
, true, false );
662 Screen2Dasher( iInputX
, iInputY
, iDasherX
, iDasherY
, false, true );
665 // Raw dasher coordinates
678 if( GetLongParameter(LP_YSCALE
) > 0 ) {
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
));
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
702 if(iX
> Screen()->GetWidth())
703 iX
= Screen()->GetWidth();
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
,
716 myint
&iDasherX
, myint
&iDasherY
,
717 Dasher::VECTOR_SYMBOL_PROB
* pAdded
,
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) {
739 mousey
= pCoordinates
[0];
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
758 if(GetBoolParameter(BP_NUMBER_DIMENSIONS
))
760 else if(GetBoolParameter(BP_EYETRACKER_MODE
))
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
775 // iDasherX = myint(xmap(iDasherX / static_cast < double >(GetLongParameter(LP_MAX_Y))) * GetLongParameter(LP_MAX_Y));
776 // iDasherY = m_ymap.map(iDasherY);
780 void CDasherViewSquare::NewDrawGoTo(myint iDasherMin
, myint iDasherMax
, bool bActive
) {
781 myint
iHeight(iDasherMax
- iDasherMin
);
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() {
809 void CDasherViewSquare::ResetSumCounter() {
813 void CDasherViewSquare::ResetYAutoOffset() {
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
;
824 m_iScalingFactor
= 100000000;
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
;
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
) {
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
) {
858 else if(m_ySum
< -m_yFilterTimescale
)
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))
880 // if(loc > GetLongParameter(LP_MAX_Y))
881 // DasherDrawCentredRectangle(-50, GetLongParameter(LP_MAX_Y), 5, 135, Opts::ColorSchemes(Objects), false);
884 // DasherDrawCentredRectangle(-50, 0, 5, 135, Opts::ColorSchemes(Objects), false);
887 // DasherDrawCentredRectangle(-50, loc, 7, 135, Opts::ColorSchemes(Objects), false);