Various small changes
[dasher.git] / Src / DasherCore / DasherView.cpp
blobc4efca8db682df942a752c941e2dc33efba1b615
1 // DasherView.cpp
2 //
3 /////////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (c) 2001-2005 David Ward
6 //
7 /////////////////////////////////////////////////////////////////////////////
9 #include "../Common/Common.h"
11 #include "DasherView.h"
12 #include "Event.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
20 #ifdef _WIN32
21 #ifdef _DEBUG
22 #define DEBUG_NEW new( _NORMAL_BLOCK, THIS_FILE, __LINE__ )
23 #define new DEBUG_NEW
24 #undef THIS_FILE
25 static char THIS_FILE[] = __FILE__;
26 #endif
27 #endif
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) {
39 default:
40 break;
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);
56 return true;
59 int CDasherView::GetCoordinateCount() {
60 // TODO: Do we really need support for co-ordinate counts other than 2?
61 if(m_pInput)
62 return m_pInput->GetCoordinateCount();
63 else
64 return 0;
67 int CDasherView::GetCoordinates(int iN, myint * pCoordinates) {
68 if(m_pInput)
69 return m_pInput->GetCoordinates(iN, pCoordinates);
70 else
71 return 0;
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
84 m_pInput = _pInput;
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() {
97 m_pScreen->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);
109 if(iColour != -1) {
110 Screen()->Polyline(ScreenPoints, n, iWidth, iColour);
112 else {
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) {
150 screenint iScreenX;
151 screenint iScreenY;
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;
172 myint iDasherMinX;
173 myint iDasherMinY;
174 myint iDasherMaxX;
175 myint iDasherMaxY;
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
194 // screen
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)
212 Size *= 20;
213 else if(iLeftTimesFontSize < (myint)GetLongParameter(LP_MAX_Y) * 159 / 160)
214 Size *= 14;
215 else
216 Size *= 11;
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;
236 break;
237 case (Dasher::Opts::RightToLeft):
238 newleft2 = iScreenAnchorX - TextWidth;
239 newtop2 = iScreenAnchorY - TextHeight / 2;
240 newright2 = iScreenAnchorX;
241 newbottom2 = iScreenAnchorY + TextHeight / 2;
242 break;
243 case (Dasher::Opts::TopToBottom):
244 newleft2 = iScreenAnchorX - TextWidth / 2;
245 newtop2 = iScreenAnchorY;
246 newright2 = iScreenAnchorX + TextWidth / 2;
247 newbottom2 = iScreenAnchorY + TextHeight;
248 break;
249 case (Dasher::Opts::BottomToTop):
250 newleft2 = iScreenAnchorX - TextWidth / 2;
251 newtop2 = iScreenAnchorY - TextHeight;
252 newright2 = iScreenAnchorX + TextWidth / 2;
253 newbottom2 = iScreenAnchorY;
254 break;
255 default:
256 break;
259 // Update the value of mostleft to take into account the new text
261 if(bShove) {
262 myint iDasherNewLeft;
263 myint iDasherNewTop;
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);