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"
17 using namespace Dasher
;
19 // Track memory leaks on Windows to the line that new'd the memory
22 #define DEBUG_NEW new( _NORMAL_BLOCK, THIS_FILE, __LINE__ )
25 static char THIS_FILE
[] = __FILE__
;
29 /////////////////////////////////////////////////////////////////////////////
31 CDasherView::CDasherView(CEventHandler
*pEventHandler
, CSettingsStore
*pSettingsStore
, CDasherScreen
*DasherScreen
)
32 :CDasherComponent(pEventHandler
, pSettingsStore
), m_pScreen(DasherScreen
), m_pInput(0) {
35 void CDasherView::HandleEvent(Dasher::CEvent
*pEvent
) {
36 if(pEvent
->m_iEventType
== 1) {
37 Dasher::CParameterNotificationEvent
* pEvt(static_cast < Dasher::CParameterNotificationEvent
* >(pEvent
));
38 switch (pEvt
->m_iParameter
) {
45 /////////////////////////////////////////////////////////////////////////////
47 void CDasherView::ChangeScreen(CDasherScreen
*NewScreen
) {
48 m_pScreen
= NewScreen
;
51 /////////////////////////////////////////////////////////////////////////////
53 bool CDasherView::Render(CDasherNode
*pRoot
, myint iRootMin
, myint iRootMax
, std::vector
<CDasherNode
*> &vNodeList
, std::vector
<CDasherNode
*> &vDeleteList
, bool bRedrawDisplay
) {
55 RenderNodes(pRoot
, iRootMin
, iRootMax
, vNodeList
, vDeleteList
);
59 int CDasherView::GetCoordinateCount() {
60 // TODO: Do we really need support for co-ordinate counts other than 2?
62 return m_pInput
->GetCoordinateCount();
67 int CDasherView::GetCoordinates(int iN
, myint
* pCoordinates
) {
69 return m_pInput
->GetCoordinates(iN
, pCoordinates
);
74 void CDasherView::SetInput(CDasherInput
* _pInput
) {
75 // TODO: Is it sensible to make this responsible for the input
76 // device - I guess it makes sense for now
78 DASHER_ASSERT_VALIDPTR_RW(_pInput
);
80 // Don't delete the old input class; whoever is calling this method
81 // might want to keep several Input class instances around and
82 // change which one is currently driving dasher without deleting any
86 // Tell the new object about maximum values
88 myint iMaxCoordinates
[2];
90 iMaxCoordinates
[0] = GetLongParameter(LP_MAX_Y
);
91 iMaxCoordinates
[1] = GetLongParameter(LP_MAX_Y
);
93 m_pInput
->SetMaxCoordinates(2, iMaxCoordinates
);
96 void CDasherView::Display() {
100 /// Draw a polyline specified in Dasher co-ordinates
102 void CDasherView::DasherPolyline(myint
*x
, myint
*y
, int n
, int iWidth
, int iColour
) {
104 CDasherScreen::point
* ScreenPoints
= new CDasherScreen::point
[n
];
106 for(int i(0); i
< n
; ++i
)
107 Dasher2Screen(x
[i
], y
[i
], ScreenPoints
[i
].x
, ScreenPoints
[i
].y
);
110 Screen()->Polyline(ScreenPoints
, n
, iWidth
, iColour
);
113 Screen()->Polyline(ScreenPoints
, n
, iWidth
);
115 delete[]ScreenPoints
;
118 // Draw a filled polygon specified in Dasher co-ordinates
120 void CDasherView::DasherPolygon(myint
*x
, myint
*y
, int n
, int iColour
) {
122 CDasherScreen::point
* ScreenPoints
= new CDasherScreen::point
[n
];
124 for(int i(0); i
< n
; ++i
)
125 Dasher2Screen(x
[i
], y
[i
], ScreenPoints
[i
].x
, ScreenPoints
[i
].y
);
127 Screen()->Polygon(ScreenPoints
, n
, iColour
);
128 delete[]ScreenPoints
;
131 // Draw a box specified in Dasher co-ordinates
133 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
) {
135 screenint iScreenLeft
;
136 screenint iScreenTop
;
137 screenint iScreenRight
;
138 screenint iScreenBottom
;
140 Dasher2Screen(iLeft
, iTop
, iScreenLeft
, iScreenTop
);
141 Dasher2Screen(iRight
, iBottom
, iScreenRight
, iScreenBottom
);
143 Screen()->DrawRectangle(iScreenLeft
, iScreenTop
, iScreenRight
, iScreenBottom
, Color
, iOutlineColour
, ColorScheme
, bDrawOutline
, bFill
, iThickness
);
146 /// 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)
148 void CDasherView::DasherDrawCentredRectangle(myint iDasherX
, myint iDasherY
, screenint iSize
, const int Color
, Opts::ColorSchemes ColorScheme
, bool bDrawOutline
) {
153 Dasher2Screen(iDasherX
, iDasherY
, iScreenX
, iScreenY
);
155 Screen()->DrawRectangle(iScreenX
- iSize
, iScreenY
- iSize
, iScreenX
+ iSize
, iScreenY
+ iSize
, Color
, -1, ColorScheme
, bDrawOutline
, true, 1);
158 /// Draw text specified in Dasher co-ordinates. The position is
159 /// specified as two co-ordinates, intended to the be the corners of
160 /// the leading edge of the containing box.
162 void CDasherView::DasherDrawText(myint iAnchorX1
, myint iAnchorY1
, myint iAnchorX2
, myint iAnchorY2
, const std::string
&sDisplayText
, int &mostleft
, bool bShove
) {
164 // Don't draw text which will overlap with text in an ancestor.
166 if(iAnchorX1
> mostleft
)
167 iAnchorX1
= mostleft
;
169 if(iAnchorX2
> mostleft
)
170 iAnchorX2
= mostleft
;
177 VisibleRegion(iDasherMinX
, iDasherMinY
, iDasherMaxX
, iDasherMaxY
);
179 iAnchorY1
= std::min( iDasherMaxY
, std::max( iDasherMinY
, iAnchorY1
) );
180 iAnchorY2
= std::min( iDasherMaxY
, std::max( iDasherMinY
, iAnchorY2
) );
182 screenint iScreenAnchorX1
;
183 screenint iScreenAnchorY1
;
184 screenint iScreenAnchorX2
;
185 screenint iScreenAnchorY2
;
187 // FIXME - Truncate here before converting - otherwise we risk integer overflow in screen coordinates
189 Dasher2Screen(iAnchorX1
, iAnchorY1
, iScreenAnchorX1
, iScreenAnchorY1
);
190 Dasher2Screen(iAnchorX2
, iAnchorY2
, iScreenAnchorX2
, iScreenAnchorY2
);
192 // Truncate the ends of the anchor line to be on the screen - this
193 // prevents us from loosing characters off the top and bottom of the
196 // TruncateToScreen(iScreenAnchorX1, iScreenAnchorY1);
197 // TruncateToScreen(iScreenAnchorX2, iScreenAnchorY2);
199 // Actual anchor point is the midpoint of the anchor line
201 screenint
iScreenAnchorX((iScreenAnchorX1
+ iScreenAnchorX2
) / 2);
202 screenint
iScreenAnchorY((iScreenAnchorY1
+ iScreenAnchorY2
) / 2);
204 // Compute font size based on position
205 int Size
= GetLongParameter( LP_DASHER_FONTSIZE
);
207 // FIXME - this could be much more elegant, and probably needs a
208 // rethink anyway - behvaiour here is too dependent on screen size
210 screenint iLeftTimesFontSize
= ((myint
)GetLongParameter(LP_MAX_Y
) - (iAnchorX1
+ iAnchorX2
)/ 2 )*Size
;
211 if(iLeftTimesFontSize
< (myint
)GetLongParameter(LP_MAX_Y
) * 19/ 20)
213 else if(iLeftTimesFontSize
< (myint
)GetLongParameter(LP_MAX_Y
) * 159 / 160)
219 screenint TextWidth
, TextHeight
;
221 Screen()->TextSize(sDisplayText
, &TextWidth
, &TextHeight
, Size
);
223 // Poistion of text box relative to anchor depends on orientation
225 screenint newleft2
= 0;
226 screenint newtop2
= 0;
227 screenint newright2
= 0;
228 screenint newbottom2
= 0;
230 switch (Dasher::Opts::ScreenOrientations(GetLongParameter(LP_REAL_ORIENTATION
))) {
231 case (Dasher::Opts::LeftToRight
):
232 newleft2
= iScreenAnchorX
;
233 newtop2
= iScreenAnchorY
- TextHeight
/ 2;
234 newright2
= iScreenAnchorX
+ TextWidth
;
235 newbottom2
= iScreenAnchorY
+ TextHeight
/ 2;
237 case (Dasher::Opts::RightToLeft
):
238 newleft2
= iScreenAnchorX
- TextWidth
;
239 newtop2
= iScreenAnchorY
- TextHeight
/ 2;
240 newright2
= iScreenAnchorX
;
241 newbottom2
= iScreenAnchorY
+ TextHeight
/ 2;
243 case (Dasher::Opts::TopToBottom
):
244 newleft2
= iScreenAnchorX
- TextWidth
/ 2;
245 newtop2
= iScreenAnchorY
;
246 newright2
= iScreenAnchorX
+ TextWidth
/ 2;
247 newbottom2
= iScreenAnchorY
+ TextHeight
;
249 case (Dasher::Opts::BottomToTop
):
250 newleft2
= iScreenAnchorX
- TextWidth
/ 2;
251 newtop2
= iScreenAnchorY
- TextHeight
;
252 newright2
= iScreenAnchorX
+ TextWidth
/ 2;
253 newbottom2
= iScreenAnchorY
;
259 // Update the value of mostleft to take into account the new text
262 myint iDasherNewLeft
;
264 myint iDasherNewRight
;
265 myint iDasherNewBottom
;
267 Screen2Dasher(newleft2
, newtop2
, iDasherNewLeft
, iDasherNewTop
,false,true);
268 Screen2Dasher(newright2
, newbottom2
, iDasherNewRight
, iDasherNewBottom
,false,true);
270 mostleft
= std::min(iDasherNewRight
, iDasherNewLeft
);
273 // Actually draw the text. We use DelayDrawText as the text should
274 // be overlayed once all of the boxes have been drawn.
276 m_pDelayDraw
->DelayDrawText(sDisplayText
, newleft2
, newtop2
, Size
);