3 /////////////////////////////////////////////////////////////////////////////
5 // Copyright (c) 2001-2005 David Ward
7 /////////////////////////////////////////////////////////////////////////////
9 #include "../Common/Common.h"
11 #include "DasherView.h"
13 #include "EventHandler.h"
14 #include "DasherModel.h"
15 #include "DasherInput.h"
19 using namespace Dasher
;
21 // Track memory leaks on Windows to the line that new'd the memory
24 #define DEBUG_NEW new( _NORMAL_BLOCK, THIS_FILE, __LINE__ )
27 static char THIS_FILE
[] = __FILE__
;
31 /////////////////////////////////////////////////////////////////////////////
33 CDasherView::CDasherView(CEventHandler
*pEventHandler
, CSettingsStore
*pSettingsStore
, CDasherScreen
*DasherScreen
)
34 :CDasherComponent(pEventHandler
, pSettingsStore
), m_pScreen(DasherScreen
), m_pInput(0) {
37 void CDasherView::HandleEvent(Dasher::CEvent
*pEvent
) {
38 if(pEvent
->m_iEventType
== 1) {
39 Dasher::CParameterNotificationEvent
* pEvt(static_cast < Dasher::CParameterNotificationEvent
* >(pEvent
));
41 switch (pEvt
->m_iParameter
) {
42 case BP_DASHER_PAUSED
:
51 /////////////////////////////////////////////////////////////////////////////
53 void CDasherView::ChangeScreen(CDasherScreen
*NewScreen
) {
54 m_pScreen
= NewScreen
;
57 /////////////////////////////////////////////////////////////////////////////
59 bool CDasherView::Render(CDasherNode
*pRoot
, myint iRootMin
, myint iRootMax
, std::vector
<CDasherNode
*> &vNodeList
, std::vector
<CDasherNode
*> &vDeleteList
, bool bRedrawDisplay
, bool bGameMode
) {
63 Screen()->SetLoadBackground(false);
64 RenderNodes(pRoot
, iRootMin
, iRootMax
, vNodeList
, vDeleteList
, &iGamePointer
);
67 DrawGameModePointer(iGamePointer
);
72 int CDasherView::GetCoordinateCount() {
73 // TODO: Do we really need support for co-ordinate counts other than 2?
75 return m_pInput
->GetCoordinateCount();
80 int CDasherView::GetInputCoordinates(int iN
, myint
* pCoordinates
) {
82 return m_pInput
->GetCoordinates(iN
, pCoordinates
);
87 void CDasherView::SetInput(CDasherInput
* _pInput
) {
88 // TODO: Is it sensible to make this responsible for the input
89 // device - I guess it makes sense for now
91 DASHER_ASSERT_VALIDPTR_RW(_pInput
);
93 // Don't delete the old input class; whoever is calling this method
94 // might want to keep several Input class instances around and
95 // change which one is currently driving dasher without deleting any
99 // Tell the new object about maximum values
101 myint iMaxCoordinates
[2];
103 iMaxCoordinates
[0] = GetLongParameter(LP_MAX_Y
);
104 iMaxCoordinates
[1] = GetLongParameter(LP_MAX_Y
);
106 m_pInput
->SetMaxCoordinates(2, iMaxCoordinates
);
109 void CDasherView::Display() {
111 Screen()->SetLoadBackground(true);
112 m_pScreen
->Display();
115 /// Draw a polyline specified in Dasher co-ordinates
117 void CDasherView::DasherPolyline(myint
*x
, myint
*y
, int n
, int iWidth
, int iColour
) {
119 CDasherScreen::point
* ScreenPoints
= new CDasherScreen::point
[n
];
121 for(int i(0); i
< n
; ++i
)
122 Dasher2Screen(x
[i
], y
[i
], ScreenPoints
[i
].x
, ScreenPoints
[i
].y
);
125 Screen()->Polyline(ScreenPoints
, n
, iWidth
, iColour
);
128 Screen()->Polyline(ScreenPoints
, n
, iWidth
,0);//no color given
130 delete[]ScreenPoints
;
133 // Draw a filled polygon specified in Dasher co-ordinates
135 void CDasherView::DasherPolygon(myint
*x
, myint
*y
, int n
, int iColour
) {
137 CDasherScreen::point
* ScreenPoints
= new CDasherScreen::point
[n
];
139 for(int i(0); i
< n
; ++i
)
140 Dasher2Screen(x
[i
], y
[i
], ScreenPoints
[i
].x
, ScreenPoints
[i
].y
);
142 Screen()->Polygon(ScreenPoints
, n
, iColour
);
143 delete[]ScreenPoints
;
146 // Draw a box specified in Dasher co-ordinates
148 void CDasherView::DasherDrawRectangle(myint iLeft
, myint iTop
, myint iRight
, myint iBottom
, const int Color
, int iOutlineColour
, Opts::ColorSchemes ColorScheme
, bool bDrawOutline
, bool bFill
, int iThickness
) {
150 screenint iScreenLeft
;
151 screenint iScreenTop
;
152 screenint iScreenRight
;
153 screenint iScreenBottom
;
155 Dasher2Screen(iLeft
, iTop
, iScreenLeft
, iScreenTop
);
156 Dasher2Screen(iRight
, iBottom
, iScreenRight
, iScreenBottom
);
158 Screen()->DrawRectangle(iScreenLeft
, iScreenTop
, iScreenRight
, iScreenBottom
, Color
, iOutlineColour
, ColorScheme
, bDrawOutline
, bFill
, iThickness
);
161 /// Draw a rectangle centred on a given dasher co-ordinate, but with a size specified in screen co-ordinates (used for drawing the mouse blob)
163 void CDasherView::DasherDrawCentredRectangle(myint iDasherX
, myint iDasherY
, screenint iSize
, const int Color
, Opts::ColorSchemes ColorScheme
, bool bDrawOutline
) {
168 Dasher2Screen(iDasherX
, iDasherY
, iScreenX
, iScreenY
);
170 Screen()->DrawRectangle(iScreenX
- iSize
, iScreenY
- iSize
, iScreenX
+ iSize
, iScreenY
+ iSize
, Color
, -1, ColorScheme
, bDrawOutline
, true, 1);
173 /// Draw text specified in Dasher co-ordinates. The position is
174 /// specified as two co-ordinates, intended to the be the corners of
175 /// the leading edge of the containing box.
177 void CDasherView::DasherDrawText(myint iAnchorX1
, myint iAnchorY1
, myint iAnchorX2
, myint iAnchorY2
, const std::string
&sDisplayText
, int &mostleft
, bool bShove
) {
179 // Don't draw text which will overlap with text in an ancestor.
181 if(iAnchorX1
> mostleft
)
182 iAnchorX1
= mostleft
;
184 if(iAnchorX2
> mostleft
)
185 iAnchorX2
= mostleft
;
192 VisibleRegion(iDasherMinX
, iDasherMinY
, iDasherMaxX
, iDasherMaxY
);
194 iAnchorY1
= std::min( iDasherMaxY
, std::max( iDasherMinY
, iAnchorY1
) );
195 iAnchorY2
= std::min( iDasherMaxY
, std::max( iDasherMinY
, iAnchorY2
) );
197 screenint iScreenAnchorX1
;
198 screenint iScreenAnchorY1
;
199 screenint iScreenAnchorX2
;
200 screenint iScreenAnchorY2
;
202 // FIXME - Truncate here before converting - otherwise we risk integer overflow in screen coordinates
204 Dasher2Screen(iAnchorX1
, iAnchorY1
, iScreenAnchorX1
, iScreenAnchorY1
);
205 Dasher2Screen(iAnchorX2
, iAnchorY2
, iScreenAnchorX2
, iScreenAnchorY2
);
207 // Truncate the ends of the anchor line to be on the screen - this
208 // prevents us from loosing characters off the top and bottom of the
211 // TruncateToScreen(iScreenAnchorX1, iScreenAnchorY1);
212 // TruncateToScreen(iScreenAnchorX2, iScreenAnchorY2);
214 // Actual anchor point is the midpoint of the anchor line
216 screenint
iScreenAnchorX((iScreenAnchorX1
+ iScreenAnchorX2
) / 2);
217 screenint
iScreenAnchorY((iScreenAnchorY1
+ iScreenAnchorY2
) / 2);
219 // Compute font size based on position
220 int Size
= GetLongParameter( LP_DASHER_FONTSIZE
);
222 // FIXME - this could be much more elegant, and probably needs a
223 // rethink anyway - behvaiour here is too dependent on screen size
225 screenint iLeftTimesFontSize
= ((myint
)GetLongParameter(LP_MAX_Y
) - (iAnchorX1
+ iAnchorX2
)/ 2 )*Size
;
226 if(iLeftTimesFontSize
< (myint
)GetLongParameter(LP_MAX_Y
) * 19/ 20)
228 else if(iLeftTimesFontSize
< (myint
)GetLongParameter(LP_MAX_Y
) * 159 / 160)
234 screenint TextWidth
, TextHeight
;
236 Screen()->TextSize(sDisplayText
, &TextWidth
, &TextHeight
, Size
);
238 // Poistion of text box relative to anchor depends on orientation
240 screenint newleft2
= 0;
241 screenint newtop2
= 0;
242 screenint newright2
= 0;
243 screenint newbottom2
= 0;
245 switch (Dasher::Opts::ScreenOrientations(GetLongParameter(LP_REAL_ORIENTATION
))) {
246 case (Dasher::Opts::LeftToRight
):
247 newleft2
= iScreenAnchorX
;
248 newtop2
= iScreenAnchorY
- TextHeight
/ 2;
249 newright2
= iScreenAnchorX
+ TextWidth
;
250 newbottom2
= iScreenAnchorY
+ TextHeight
/ 2;
252 case (Dasher::Opts::RightToLeft
):
253 newleft2
= iScreenAnchorX
- TextWidth
;
254 newtop2
= iScreenAnchorY
- TextHeight
/ 2;
255 newright2
= iScreenAnchorX
;
256 newbottom2
= iScreenAnchorY
+ TextHeight
/ 2;
258 case (Dasher::Opts::TopToBottom
):
259 newleft2
= iScreenAnchorX
- TextWidth
/ 2;
260 newtop2
= iScreenAnchorY
;
261 newright2
= iScreenAnchorX
+ TextWidth
/ 2;
262 newbottom2
= iScreenAnchorY
+ TextHeight
;
264 case (Dasher::Opts::BottomToTop
):
265 newleft2
= iScreenAnchorX
- TextWidth
/ 2;
266 newtop2
= iScreenAnchorY
- TextHeight
;
267 newright2
= iScreenAnchorX
+ TextWidth
/ 2;
268 newbottom2
= iScreenAnchorY
;
274 // Update the value of mostleft to take into account the new text
277 myint iDasherNewLeft
;
279 myint iDasherNewRight
;
280 myint iDasherNewBottom
;
282 Screen2Dasher(newleft2
, newtop2
, iDasherNewLeft
, iDasherNewTop
,false,true);
283 Screen2Dasher(newright2
, newbottom2
, iDasherNewRight
, iDasherNewBottom
,false,true);
285 mostleft
= std::min(iDasherNewRight
, iDasherNewLeft
);
288 // Actually draw the text. We use DelayDrawText as the text should
289 // be overlayed once all of the boxes have been drawn.
291 m_pDelayDraw
->DelayDrawText(sDisplayText
, newleft2
, newtop2
, Size
);
295 int CDasherView::GetCoordinates(unsigned long Time
, myint
&iDasherX
, myint
&iDasherY
) {
297 // FIXME - Actually turn autocalibration on and off!
298 // FIXME - AutoCalibrate should use Dasher co-ordinates, not raw mouse co-ordinates?
299 // FIXME - Have I broken this by moving it before the offset is applied?
300 // FIXME - put ymap stuff back in
301 // FIXME - optimise this
302 // TODO: Time isn't used!
304 int iCoordinateCount(GetCoordinateCount());
306 myint
*pCoordinates(new myint
[iCoordinateCount
]);
308 int iType(GetInputCoordinates(iCoordinateCount
, pCoordinates
));
313 if(iCoordinateCount
== 1) {
315 mousey
= pCoordinates
[0];
318 mousex
= pCoordinates
[0];
319 mousey
= pCoordinates
[1];
322 delete[]pCoordinates
;
324 Screen2Dasher(mousex
, mousey
, iDasherX
, iDasherY
, false, true );
328 // iDasherX = myint(xmap(iDasherX / static_cast < double >(GetLongParameter(LP_MAX_Y))) * GetLongParameter(LP_MAX_Y));
329 // iDasherY = m_ymap.map(iDasherY);