[dasher: 17/27] Rewrite DasherViewSquare, incorporating DelayedText
- From: Patrick Welche <pwelche src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [dasher: 17/27] Rewrite DasherViewSquare, incorporating DelayedText
- Date: Wed, 18 Aug 2010 15:11:06 +0000 (UTC)
commit 4c9cf5657a0a2306d0727d695f4c6f3dca4843b1
Author: Alan Lawrence <acl33 inf phy cam ac uk>
Date: Sun Jan 10 17:45:47 2010 +0000
Rewrite DasherViewSquare, incorporating DelayedText
BP_MULTISIZE_FONTS means LP_DASHER_FONTSIZE is min pt. size, up to 2.5*that;
same 3-size scheme as before (pt size 11/14/20 * param) if disabled
Removed screen size check to render nodes, test dasher size vs LP_MIN_NODE_SIZE
(screen size check broke vertical orientations, and did little for horizontal!)
LP_SHAPE_TYPE selects between disjoint/overlapping rects, triangles, trunctris,
quadrics (experimental, nonlinearity breaks) and semicircles (inc nonlinearity!)
Absolute value LP_OUTLINE_WIDTH gives width to draw box outlines; fill iff>=0
(Re)moved RenderNode(Part,Outline)Fast into new RecursiveRender
Src/DasherCore/DasherInterfaceBase.cpp | 2 +-
Src/DasherCore/DasherViewSquare.cpp | 880 ++++++++++++++-------------
Src/DasherCore/DasherViewSquare.h | 59 +-
Src/DasherCore/Parameters.h | 13 +-
Src/MacOSX/Dasher.xcodeproj/project.pbxproj | 8 -
Src/iPhone/Classes/MiscSettings.mm | 2 +
6 files changed, 504 insertions(+), 460 deletions(-)
---
diff --git a/Src/DasherCore/DasherInterfaceBase.cpp b/Src/DasherCore/DasherInterfaceBase.cpp
index 52ef96e..6e1f8a3 100644
--- a/Src/DasherCore/DasherInterfaceBase.cpp
+++ b/Src/DasherCore/DasherInterfaceBase.cpp
@@ -275,7 +275,7 @@ void CDasherInterfaceBase::InterfaceEventHandler(Dasher::CEvent *pEvent) {
switch (pEvt->m_iParameter) {
- case BP_OUTLINE_MODE:
+ case LP_OUTLINE_WIDTH:
ScheduleRedraw();
break;
case BP_DRAW_MOUSE:
diff --git a/Src/DasherCore/DasherViewSquare.cpp b/Src/DasherCore/DasherViewSquare.cpp
index f0ec7ad..e4c00d1 100644
--- a/Src/DasherCore/DasherViewSquare.cpp
+++ b/Src/DasherCore/DasherViewSquare.cpp
@@ -95,127 +95,6 @@ void CDasherViewSquare::HandleEvent(Dasher::CEvent *pEvent) {
}
}
-/// Draw text specified in Dasher co-ordinates. The position is
-/// specified as two co-ordinates, intended to the be the corners of
-/// the leading edge of the containing box.
-
-void CDasherViewSquare::DasherDrawText(myint iAnchorX1, myint iAnchorY1, myint iAnchorX2, myint iAnchorY2, const std::string &sDisplayText, int &mostleft, bool bShove) {
-
- // Don't draw text which will overlap with text in an ancestor.
-
- if(iAnchorX1 > mostleft)
- iAnchorX1 = mostleft;
-
- if(iAnchorX2 > mostleft)
- iAnchorX2 = mostleft;
-
- myint iDasherMinX;
- myint iDasherMinY;
- myint iDasherMaxX;
- myint iDasherMaxY;
-
- VisibleRegion(iDasherMinX, iDasherMinY, iDasherMaxX, iDasherMaxY);
-
- iAnchorY1 = std::min( iDasherMaxY, std::max( iDasherMinY, iAnchorY1 ) );
- iAnchorY2 = std::min( iDasherMaxY, std::max( iDasherMinY, iAnchorY2 ) );
-
- screenint iScreenAnchorX1;
- screenint iScreenAnchorY1;
- screenint iScreenAnchorX2;
- screenint iScreenAnchorY2;
-
- // FIXME - Truncate here before converting - otherwise we risk integer overflow in screen coordinates
-
- Dasher2Screen(iAnchorX1, iAnchorY1, iScreenAnchorX1, iScreenAnchorY1);
- Dasher2Screen(iAnchorX2, iAnchorY2, iScreenAnchorX2, iScreenAnchorY2);
-
- // Truncate the ends of the anchor line to be on the screen - this
- // prevents us from loosing characters off the top and bottom of the
- // screen
-
- // TruncateToScreen(iScreenAnchorX1, iScreenAnchorY1);
- // TruncateToScreen(iScreenAnchorX2, iScreenAnchorY2);
-
- // Actual anchor point is the midpoint of the anchor line
-
- screenint iScreenAnchorX((iScreenAnchorX1 + iScreenAnchorX2) / 2);
- screenint iScreenAnchorY((iScreenAnchorY1 + iScreenAnchorY2) / 2);
-
- // Compute font size based on position
- int Size = GetLongParameter( LP_DASHER_FONTSIZE );
-
- // FIXME - this could be much more elegant, and probably needs a
- // rethink anyway - behvaiour here is too dependent on screen size
-
- screenint iLeftTimesFontSize = ((myint)GetLongParameter(LP_MAX_Y) - (iAnchorX1 + iAnchorX2)/ 2 )*Size;
- if(iLeftTimesFontSize < (myint)GetLongParameter(LP_MAX_Y) * 19/ 20)
- Size *= 20;
- else if(iLeftTimesFontSize < (myint)GetLongParameter(LP_MAX_Y) * 159 / 160)
- Size *= 14;
- else
- Size *= 11;
-
-
- screenint TextWidth, TextHeight;
-
- Screen()->TextSize(sDisplayText, &TextWidth, &TextHeight, Size);
-
- // Poistion of text box relative to anchor depends on orientation
-
- screenint newleft2 = 0;
- screenint newtop2 = 0;
- screenint newright2 = 0;
- screenint newbottom2 = 0;
-
- switch (Dasher::Opts::ScreenOrientations(GetLongParameter(LP_REAL_ORIENTATION))) {
- case (Dasher::Opts::LeftToRight):
- newleft2 = iScreenAnchorX;
- newtop2 = iScreenAnchorY - TextHeight / 2;
- newright2 = iScreenAnchorX + TextWidth;
- newbottom2 = iScreenAnchorY + TextHeight / 2;
- break;
- case (Dasher::Opts::RightToLeft):
- newleft2 = iScreenAnchorX - TextWidth;
- newtop2 = iScreenAnchorY - TextHeight / 2;
- newright2 = iScreenAnchorX;
- newbottom2 = iScreenAnchorY + TextHeight / 2;
- break;
- case (Dasher::Opts::TopToBottom):
- newleft2 = iScreenAnchorX - TextWidth / 2;
- newtop2 = iScreenAnchorY;
- newright2 = iScreenAnchorX + TextWidth / 2;
- newbottom2 = iScreenAnchorY + TextHeight;
- break;
- case (Dasher::Opts::BottomToTop):
- newleft2 = iScreenAnchorX - TextWidth / 2;
- newtop2 = iScreenAnchorY - TextHeight;
- newright2 = iScreenAnchorX + TextWidth / 2;
- newbottom2 = iScreenAnchorY;
- break;
- default:
- break;
- }
-
- // Update the value of mostleft to take into account the new text
-
- if(bShove) {
- myint iDasherNewLeft;
- myint iDasherNewTop;
- myint iDasherNewRight;
- myint iDasherNewBottom;
-
- Screen2Dasher(newleft2, newtop2, iDasherNewLeft, iDasherNewTop);
- Screen2Dasher(newright2, newbottom2, iDasherNewRight, iDasherNewBottom);
-
- mostleft = std::min(iDasherNewRight, iDasherNewLeft);
- }
-
- // Actually draw the text. We use DelayDrawText as the text should
- // be overlayed once all of the boxes have been drawn.
-
- m_DelayDraw.DelayDrawText(sDisplayText, newleft2, newtop2, Size);
-}
-
void CDasherViewSquare::RenderNodes(CDasherNode *pRoot, myint iRootMin, myint iRootMax,
CExpansionPolicy &policy) {
DASHER_ASSERT(pRoot != 0);
@@ -234,363 +113,522 @@ void CDasherViewSquare::RenderNodes(CDasherNode *pRoot, myint iRootMin, myint iR
Dasher2Screen(iRootMax-iRootMin, iRootMin, iScreenLeft, iScreenTop);
Dasher2Screen(0, iRootMax, iScreenRight, iScreenBottom);
- //ifiScreenTop < 0)
- // iScreenTop = 0;
-
- //if(iScreenLeft < 0)
- // iScreenLeft=0;
-
- //// TODO: Should these be right on the boundary?
- //if(iScreenBottom > Screen()->GetHeight())
- // iScreenBottom=Screen()->GetHeight();
-
- //if(iScreenRight > Screen()->GetWidth())
- // iScreenRight=Screen()->GetWidth();
-
// Blank the region around the root node:
if(iRootMin > iDasherMinY)
DasherDrawRectangle(iDasherMaxX, iDasherMinY, iDasherMinX, iRootMin, 0, -1, Nodes1, 0);
- //if(iScreenTop > 0)
- // Screen()->DrawRectangle(0, 0, Screen()->GetWidth(), iScreenTop, 0, -1, Nodes1, false, true, 1);
-
if(iRootMax < iDasherMaxY)
DasherDrawRectangle(iDasherMaxX, iRootMax, iDasherMinX, iDasherMaxY, 0, -1, Nodes1, 0);
- //if(iScreenBottom <= Screen()->GetHeight())
- // Screen()->DrawRectangle(0, iScreenBottom, Screen()->GetWidth(), Screen()->GetHeight(), 0, -1, Nodes1, false, true, 1);
+ //to left (greater Dasher X)
+ if (iRootMax - iRootMin < iDasherMaxX)
+ DasherDrawRectangle(iDasherMaxX, std::max(iRootMin,iDasherMinY), iRootMax-iRootMin, std::min(iRootMax,iDasherMaxY), 0, -1, Nodes1, 0);
+ //to right (margin)
DasherDrawRectangle(0, iDasherMinY, iDasherMinX, iDasherMaxY, 0, -1, Nodes1, 0);
// Screen()->DrawRectangle(iScreenRight, std::max(0, (int)iScreenTop),
// Screen()->GetWidth(), std::min(Screen()->GetHeight(), (int)iScreenBottom),
// 0, -1, Nodes1, false, true, 1);
// Render the root node (and children)
- RecursiveRender(pRoot, iRootMin, iRootMax, iDasherMaxX, policy, std::numeric_limits<double>::infinity(), iDasherMaxX,0,0);
+ RecursiveRender(pRoot, iRootMin, iRootMax, NULL, policy, std::numeric_limits<double>::infinity(), 0);
// Labels are drawn in a second parse to get the overlapping right
- m_DelayDraw.Draw(Screen());
-
+ for (vector<CTextString *>::iterator it=m_DelayedTexts.begin(), E=m_DelayedTexts.end(); it!=E; it++)
+ DoDelayedText(*it);
+ m_DelayedTexts.clear();
+
// Finally decorate the view
Crosshair((myint)GetLongParameter(LP_OX));
}
-//min size in *Dasher co-ordinates* to consider rendering a node
-#define QUICK_REJECT 50
-//min size in *screen* (pixel) co-ordinates to render a node
-#define MIN_SIZE 2
+/// Draw text specified in Dasher co-ordinates. The position is
+/// specified as two co-ordinates, intended to the be the corners of
+/// the leading edge of the containing box.
-bool CDasherViewSquare::CheckRender(CDasherNode *pRender, myint y1, myint y2,
- int mostleft, CExpansionPolicy &policy, double dMaxCost,
- myint parent_width, int parent_color, int iDepth)
-{
- if (y2-y1 >= QUICK_REJECT)
- {
- myint iDasherMinX;
- myint iDasherMinY;
- myint iDasherMaxX;
- myint iDasherMaxY;
- VisibleRegion(iDasherMinX, iDasherMinY, iDasherMaxX, iDasherMaxY);
-
- if (y1 <= iDasherMaxY && y2 >= iDasherMinY)
- {
- screenint iScreenX1;
- screenint iScreenY1;
- screenint iScreenX2;
- screenint iScreenY2;
-
- Dasher2Screen(0, std::max(y1, iDasherMinY), iScreenX1, iScreenY1);
- Dasher2Screen(0, std::min(y2, iDasherMaxY), iScreenX2, iScreenY2);
-
- Cint32 iHeight = std::max(myint(iScreenY2 - iScreenY1),myint( 0));
+CDasherViewSquare::CTextString *CDasherViewSquare::DasherDrawText(myint iDasherMaxX, myint iDasherMidY, const std::string &sDisplayText, CTextString *pParent, int iColor) {
+
+ screenint x,y;
+ Dasher2Screen(iDasherMaxX, iDasherMidY, x, y);
- if (iHeight >= MIN_SIZE)
- {
- //node should be rendered!
-
- RecursiveRender(pRender, y1, y2, mostleft, policy, dMaxCost, parent_width, parent_color, iDepth);
- return true;
- }
- }
+ //compute font size...
+ int iSize = GetLongParameter(LP_DASHER_FONTSIZE);
+ {
+ const myint iMaxY(GetLongParameter(LP_MAX_Y));
+ if (GetBoolParameter(BP_MULTISIZE_FONTS)) {
+ //font size maxes out at ((iMaxY*3)/2)+iMaxY)/iMaxY = 3/2*smallest
+ // which is reached when iDasherMaxX == iMaxY/2, i.e. the crosshair
+ iSize = ((min(iDasherMaxX*3,(iMaxY*3)/2) + iMaxY) * iSize) / iMaxY;
+ } else {
+ //old style fonts; ignore iSize passed-in.
+ iSize = GetLongParameter(LP_DASHER_FONTSIZE);
+ screenint iLeftTimesFontSize = (iMaxY - iDasherMaxX )*iSize;
+ if(iLeftTimesFontSize < iMaxY * 19/ 20)
+ iSize *= 20;
+ else if(iLeftTimesFontSize < iMaxY * 159 / 160)
+ iSize *= 14;
+ else
+ iSize *= 11;
+ }
}
- // We get here if the node is too small to render or is off-screen.
- // So, collapse it immediately.
- //
- // In game mode, we get here if the child is too small to draw, but we need the
- // coordinates - if this is the case then we shouldn't delete any children.
- //
- // TODO: Should probably render the parent segment here anyway (or
- // in the above)
- if(!pRender->GetFlag(NF_GAME))
- pRender->Delete_children();
- return false;
+
+ CTextString *pRet = new CTextString(sDisplayText, x, y, iSize, iColor);
+ vector<CTextString *> &dest(pParent ? pParent->m_children : m_DelayedTexts);
+ dest.push_back(pRet);
+ return pRet;
}
-void CDasherViewSquare::RecursiveRender(CDasherNode *pRender, myint y1, myint y2,
- int mostleft, CExpansionPolicy &policy, double dMaxCost,
- myint parent_width,int parent_color, int iDepth)
-{
- DASHER_ASSERT_VALIDPTR_RW(pRender);
-
-// if(iDepth == 2)
-// std::cout << pRender->GetDisplayInfo()->strDisplayText << std::endl;
-
- // TODO: We need an overhall of the node creation/deletion logic -
- // make sure that we only maintain the minimum number of nodes which
- // are actually needed. This is especially true at the moment in
- // Game mode, which feels very sluggish. Node creation also feels
- // slower in Windows than Linux, especially if many nodes are
- // created at once (eg untrained Hiragana)
+void CDasherViewSquare::DoDelayedText(CTextString *pText) {
+
+ Dasher::Opts::ScreenOrientations orient = Dasher::Opts::ScreenOrientations(GetLongParameter(LP_REAL_ORIENTATION));
+
+ //note that it'd be better to compute old-style font sizes here, or even after shunting
+ // across according to the aiMax array, but this needs Dasher co-ordinates, which were
+ // more easily available at CTextString creation time. If it really doesn't look as good,
+ // can put in extra calls to Screen2Dasher....
+ screenint x(pText->m_ix), y(pText->m_iy), textWidth, textHeight;
+ Screen()->TextSize(pText->m_String, &textWidth, &textHeight, pText->m_iSize);
+ switch (orient) {
+ case Dasher::Opts::LeftToRight: {
+ screenint iRight = x + textWidth;
+ if (iRight < Screen()->GetWidth()) {
+ Screen()->DrawString(pText->m_String, x, y-textHeight/2, pText->m_iSize, pText->m_iColor);
+ for (vector<CTextString *>::iterator it = pText->m_children.begin(); it!=pText->m_children.end(); it++) {
+ CTextString *pChild=*it;
+ pChild->m_ix = max(pChild->m_ix, iRight);
+ DoDelayedText(pChild);
+ }
+ pText->m_children.clear();
+ }
+ break;
+ }
+ case Dasher::Opts::RightToLeft: {
+ screenint iLeft = x-textWidth;
+ if (iLeft>=0) {
+ Screen()->DrawString(pText->m_String, x - textWidth, y-textHeight/2, pText->m_iSize, pText->m_iColor);
+ for (vector<CTextString *>::iterator it = pText->m_children.begin(); it!=pText->m_children.end(); it++) {
+ CTextString *pChild=*it;
+ pChild->m_ix = min(pChild->m_ix, iLeft);
+ DoDelayedText(*it);
+ }
+ pText->m_children.clear();
+ }
+ break;
+ }
+ case Dasher::Opts::TopToBottom: {
+ screenint iBottom = y + textHeight;
+ if (iBottom < Screen()->GetHeight()) {
+ Screen()->DrawString(pText->m_String, x-textWidth/2, y, pText->m_iSize, pText->m_iColor);
+ for (vector<CTextString *>::iterator it = pText->m_children.begin(); it!=pText->m_children.end(); it++) {
+ CTextString *pChild=*it;
+ pChild->m_iy = max(pChild->m_iy, iBottom);
+ DoDelayedText(*it);
+ }
+ pText->m_children.clear();
+ }
+ break;
+ }
+ case Dasher::Opts::BottomToTop: {
+ screenint iTop = y - textHeight;
+ if (y>=0) {
+ Screen()->DrawString(pText->m_String, x-textWidth/2, y-textHeight, pText->m_iSize, pText->m_iColor);
+ for (vector<CTextString *>::iterator it = pText->m_children.begin(); it!=pText->m_children.end(); it++) {
+ CTextString *pChild=*it;
+ pChild->m_iy = min(pChild->m_iy, iTop);
+ DoDelayedText(*it);
+ }
+ pText->m_children.clear();
+ }
+ break;
+ }
+ }
+ free(pText);
+}
- ++m_iRenderCount;
-
- // myint trange = y2 - y1;
+CDasherViewSquare::CTextString::~CTextString() {
+ for (vector<CTextString *>::iterator it = m_children.begin(); it!=m_children.end(); it++)
+ free(*it);
+}
- // Attempt to draw the region to the left of this node inside its parent.
+void CDasherViewSquare::TruncateTri(myint x, myint y1, myint y2, myint midy1, myint midy2, int fillColor, int outlineColor, int lineWidth) {
+ DASHER_ASSERT (y1<midy1 && midy1 <= midy2 && midy2 < y2);
+ myint iVisibleMinX, iVisibleMaxX, iVisibleMinY, iVisibleMaxY;
+ VisibleRegion(iVisibleMinX, iVisibleMinY, iVisibleMaxX, iVisibleMaxY);
+
+ myint x1(x), x2(x); //(max)x-coords of the two lines
+ myint tempx1(0),tempx2(0); //& min x-coords
+ //intersect y1's diagonal with screen
+ if (!ClipLineToVisible(x1,midy1,tempx1,y1)) {
+ //entirely offscreen....i.e. off top/bottom
+ DASHER_ASSERT (midy1 < iVisibleMinY);
+ midy1 = y1 = iVisibleMinY;
+ x1 = min(x1, iVisibleMaxX);
+ tempx1=0;
+ }
+ //intersect y2's diagonal with screen
+ if (!ClipLineToVisible(tempx2, y2, x2, midy2)) {
+ //entirely offscreen again, i.e. off bottom/top
+ DASHER_ASSERT(midy2 > iVisibleMaxY);
+ midy2 = y2 = iVisibleMaxY;
+ x2 = min(x2, iVisibleMaxX);
+ tempx2=0;
+ }
+ if (x1!=x2) {
+ //both will be clipped to be <= iVisibleMaxX by above. If they are still
+ // unequal, one must have been further clipped by passing off top/bottom
+ // (i.e., the point of max x is off the top/off the bottom), in which case
+ // the other line is entirely offscreen:
+ DASHER_ASSERT(midy1 == midy2); //point/line of max x has been removed
+
+ if (x1<x2) {
+ //(0,y1) - (x1,midy1) hit max-y edge of screen
+ //(0,y2) - (x2,midy2) entirely offscreen
+ DASHER_ASSERT(midy1==iVisibleMaxY && y2 == midy2);
+ x2=x1;
+ } else {
+ // (0,y2) - (x2, midy2) hit min-y edge of screen
+ // (0,y1) - (x1,midy1) entirely offscreen
+ DASHER_ASSERT(midy2 == iVisibleMinY && y1 == midy1);
+ x1=x2;
+ }
+ }
+ // midy1,x1 is now start point
+ vector<CDasherScreen::point> pts(1);
+ Dasher2Screen(x1, midy1, pts[0].x, pts[0].y);
+ DasherLine2Screen(x1, midy1, tempx1, y1, pts);
+ if (tempx1) {
+ //did not reach y axis
+ DASHER_ASSERT(y1 == iVisibleMinY);
+ pts.push_back(CDasherScreen::point());
+ Dasher2Screen(0, iVisibleMinY, pts.back().x, pts.back().y);
+ }
+ //that gets us to the min-y (y1) end of the line along the y-axis
-
-// if(iDepth == 2) {
-// std::cout << "y1: " << y1 << " y2: " << y2 << std::endl;
-
- // Set the NF_SUPER flag if this node entirely frames the visual
- // area.
+ //add line along y-axis...
+ pts.push_back(CDasherScreen::point());
+ Dasher2Screen(0, y2, pts.back().x, pts.back().y);
- // TODO: too slow?
- // TODO: use flags more rather than delete/reparent lists
- myint iDasherMinX;
- myint iDasherMinY;
- myint iDasherMaxX;
- myint iDasherMaxY;
+ if (tempx2) {
+ //y2's diagonal did not reach y-axis
+ DASHER_ASSERT(y2 == iVisibleMaxY);
+ pts.push_back(CDasherScreen::point());
+ Dasher2Screen(tempx2, iVisibleMaxY, pts.back().x, pts.back().y);
+ }
+ //and the diagonal part...
+ DasherLine2Screen(tempx2, y2, x2, midy2, pts);
+
+ if (midy1 != midy2) {
+ //is the max-x extent a line, after cropping - i.e. handles both
+ // normal triangle (orig midy1==orig midy2) being cropped to screen edge,
+ // and trunc tri (orig midy1 < orig midy2, possibly cropped) cases
+ DASHER_ASSERT(x1 == x2);
+ pts.push_back(CDasherScreen::point());
+ Dasher2Screen(x1, midy1, pts.back().x, pts.back().y);
+ } else DASHER_ASSERT(pts.back().x == pts[0].x && pts.back().y == pts[0].y);
+
+ CDasherScreen::point *p_array=new CDasherScreen::point[pts.size()];
+ for (unsigned int i = 0; i<pts.size(); i++) p_array[i] = pts[i];
+ Screen()->Polygon(p_array, pts.size(), fillColor, outlineColor, lineWidth);
+ delete[] p_array;
+}
+
+#define sq(X) ((X)*(X))
+void CDasherViewSquare::Circle(myint Range, myint y1, myint y2, int fCol, int oCol, int lWidth) {
+ std::vector<CDasherScreen::point> pts;
+ myint cy((y1+y2)/2),r(Range/2), x1, x2;
+ myint iDasherMinX, iDasherMinY, iDasherMaxX, iDasherMaxY;
VisibleRegion(iDasherMinX, iDasherMinY, iDasherMaxX, iDasherMaxY);
- DasherDrawRectangle(std::min(parent_width,iDasherMaxX), std::max(y1,iDasherMinY), std::min(y2-y1,iDasherMaxX), std::min(y2,iDasherMaxY), parent_color, -1, Nodes1, 0);
-
- const std::string &sDisplayText(pRender->getDisplayText());
- if( sDisplayText.size() > 0 )
- {
- DasherDrawText(y2-y1, y1, y2-y1, y2, sDisplayText, mostleft, pRender->bShove());
+ CDasherScreen::point p;
+ //run along bottom edge...
+ if (y1 < iDasherMinY) {
+ Dasher2Screen(0, iDasherMinY, p.x, p.y);
+ pts.push_back(p);
+ //intersect with bottom edge
+ x1 = min(iDasherMaxX, myint(sqrt(r*r - sq(cy-iDasherMinY))));
+ y1 = iDasherMinY;
+ } else {
+ x1=0;
}
-
- pRender->SetFlag(NF_SUPER, !IsSpaceAroundNode(y1,y2));
-
- // If there are no children then we still need to render the parent
- if(pRender->ChildCount() == 0) {
- DasherDrawRectangle(std::min(y2-y1,iDasherMaxX), std::min(y2,iDasherMaxY),0, std::max(y1,iDasherMinY), pRender->getColour(), -1, Nodes1, 0);
- //also allow it to be expanded, it's big enough.
- policy.pushNode(pRender, y1, y2, true, dMaxCost);
- return;
+ Dasher2Screen(x1,y1,p.x,p.y);
+ pts.push_back(p);
+
+ //and along top...
+ if (y2 > iDasherMaxY) {
+ //intersect...
+ x2 = min(iDasherMaxX, myint(sqrt(r*r - sq(iDasherMaxY-cy))));
+ Dasher2Screen(x2, y2=iDasherMaxY, p.x, p.y);
+ //that's target point for end of curved section.
+ if (x2==iDasherMaxX && x1==iDasherMaxX) {
+ //circle entirely covers screen
+ DASHER_ASSERT(y1==iDasherMinY);
+ DasherDrawRectangle(iDasherMaxX, iDasherMaxY, 0, iDasherMinY, fCol, oCol, Nodes1, lWidth);
+ return;
+ }
+ //will also need final point at top-right (0,y2 in dasher coords)....
+ } else {
+ Dasher2Screen(x2=0,y2,p.x,p.y);
}
+ CircleTo(cy,r,y1,x1,y2,x2,p,pts);
+ if (iDasherMaxY == y2) {
+ Dasher2Screen(0, iDasherMaxX, p.x, p.y);
+ pts.push_back(p);
+ }
+ CDasherScreen::point *p_array = new CDasherScreen::point[pts.size()];
+ for (unsigned int i=0; i<pts.size(); i++) p_array[i] = pts[i];
+ Screen()->Polygon(p_array, pts.size(), fCol, oCol, lWidth);
+ delete[] p_array;
+}
- //Node has children. It can therefore be collapsed...however,
- // we don't allow a node covering the crosshair to be collapsed
- // (at best this'll mean there's nowhere useful to go forwards;
- // at worst, all kinds of crashes trying to do text output!)
- if (!pRender->GetFlag(NF_GAME) && !pRender->GetFlag(NF_SEEN))
- dMaxCost = policy.pushNode(pRender, y1, y2, false, dMaxCost);
-
- // Render children
- int norm = (myint)GetLongParameter(LP_NORMALIZATION);
-
- myint lasty=y1;
-
-
- int id=-1;
- // int lower=-1,upper=-1;
- myint temp_parentwidth=y2-y1;
- int temp_parentcolor = pRender->getColour();
-
- const myint Range(y2 - y1);
-
- if (CDasherNode *pChild = pRender->onlyChildRendered)
+void CDasherViewSquare::CircleTo(myint cy, myint r, myint y1, myint x1, myint y3, myint x3, CDasherScreen::point dest, vector<CDasherScreen::point> &pts) {
+ myint y2((y1+y3)/2);
+ myint x2(sqrt(sq(r)-sq(cy-y2))*2);
+ CDasherScreen::point mid; //where midpoint of circle/arc should be
+ Dasher2Screen(x2, y2, mid.x, mid.y); //(except "midpoint" measured along y axis)
+ int lmx=(pts.back().x + dest.x)/2, lmy = (pts.back().y + dest.y)/2; //midpoint of straight line
+ if (dest.y-pts.back().y<2 || abs(mid.x-lmx) + abs(mid.y-lmy)<2) {
+ //okay, use straight line
+ pts.push_back(dest);
+ } else {
+ CircleTo(cy, r, y1, x1, y2, x2, mid, pts);
+ CircleTo(cy, r, y2, x2, y3, x3, dest, pts);
+ }
+}
+#undef sq
+void CDasherViewSquare::Quadric(myint Range, myint lowY, myint highY, int fillColor, int outlineColour, int lineWidth) {
+ static const double RR2=1.0/sqrt(2.0);
+ const int midY=(lowY+highY)/2;
+#define NUM_STEPS 40
+ CDasherScreen::point p_array[2*NUM_STEPS+2];
+ myint minX,maxX,minY,maxY;
+ VisibleRegion(minX, minY, maxX, maxY);
{
- //if child still covers screen, render _just_ it and return
- myint newy1 = y1 + (Range * (myint)pChild->Lbnd()) / (myint)norm;
- myint newy2 = y1 + (Range * (myint)pChild->Hbnd()) / (myint)norm;
- if (newy1 < iDasherMinY && newy2 > iDasherMaxY) {
- //still covers entire screen. Parent should too...
- DASHER_ASSERT(dMaxCost == std::numeric_limits<double>::infinity());
-
- //don't inc iDepth, meaningless when covers the screen
- RecursiveRender(pChild, newy1, newy2, mostleft,
- policy, dMaxCost,
- temp_parentwidth, temp_parentcolor, iDepth);
- //leave pRender->onlyChildRendered set, so remaining children are skipped
+ myint x1(0), y1(highY), x2(Range*RR2),y2(highY*RR2 + midY*(1.0-RR2)), x3(Range), y3(midY);
+ for (int i=0; i<=NUM_STEPS; i++) {
+ double f=i/(double)NUM_STEPS, of = 1.0-f;
+ Dasher2Screen(min(maxX,myint(of*of*x1 + 2.0*of*f*x2 + f*f*x3)), max(minY,min(maxY,myint(of*of*y1 + 2.0*of*f*y2 + f*f*y3))), p_array[i].x, p_array[i].y);
}
- else
- pRender->onlyChildRendered = NULL;
}
-
- if (!pRender->onlyChildRendered)
- { //render all children...
- for(CDasherNode::ChildMap::const_iterator i = pRender->GetChildren().begin();
- i != pRender->GetChildren().end(); i++) {
- id++;
- CDasherNode *pChild = *i;
-
- myint newy1 = y1 + (Range * (myint)pChild->Lbnd()) / (myint)norm;/// norm and lbnd are simple ints
- myint newy2 = y1 + (Range * (myint)pChild->Hbnd()) / (myint)norm;
- if (newy1 < iDasherMinY && newy2 > iDasherMaxY) {
- DASHER_ASSERT(dMaxCost == std::numeric_limits<double>::infinity());
- pRender->onlyChildRendered = pChild;
- RecursiveRender(pChild, newy1, newy2, mostleft, policy, dMaxCost, temp_parentwidth, temp_parentcolor, iDepth);
- //ensure we don't blank over this child in "finishing off" the parent (!)
- lasty=newy2;
- break; //no need to render any more children!
+ {
+ myint x1(Range), y1(midY), x2(Range*RR2), y2(lowY*RR2 + midY*(1.0-RR2)), x3(0), y3(lowY);
+ for (int i=0; i<=NUM_STEPS; i++) {
+ double f=i/(double)NUM_STEPS, of = 1.0-f;
+ Dasher2Screen(min(maxX,myint(of*of*x1 + 2.0*of*f*x2 + f*f*x3)),max(minY,min(maxY,myint(of*of*y1 + 2.0*of*f*y2 + f*f*y3))), p_array[i+NUM_STEPS+1].x, p_array[i+NUM_STEPS+1].y);
}
- if (CheckRender(pChild, newy1, newy2, mostleft, policy, dMaxCost,
- temp_parentwidth, temp_parentcolor, iDepth+1))
- {
-
- if (lasty<newy1) {
- //if child has been drawn then the interval between him and the
- //last drawn child should be drawn too.
- //std::cout << "Fill in: " << lasty << " " << newy1 << std::endl;
-
- RenderNodePartFast(temp_parentcolor, lasty, newy1, mostleft,
- pRender->getDisplayText(),
- pRender->bShove(),
- temp_parentwidth);
- }
-
- lasty = newy2;
- }
- }
+ }
- // Finish off the drawing process
-
- // if(iDepth == 1) {
- // Theres a chance that we haven't yet filled the entire parent, so finish things off if necessary.
- if(lasty<y2) {
- RenderNodePartFast(temp_parentcolor, lasty, y2, mostleft,
- pRender->getDisplayText(),
- pRender->bShove(),
- temp_parentwidth);
- }
- }
- // Draw the outline
- if(pRender->getColour() != -1) {//-1 = invisible
- RenderNodeOutlineFast(pRender->getColour(),
- y1, y2, mostleft,
- pRender->getDisplayText(),
- pRender->bShove());
- }
- // }
+ Screen()->Polygon(p_array, 2*NUM_STEPS+2, fillColor, outlineColour, lineWidth);
+#undef NUM_STEPS
}
bool CDasherViewSquare::IsSpaceAroundNode(myint y1, myint y2) {
- myint iDasherMinX;
- myint iDasherMinY;
- myint iDasherMaxX;
- myint iDasherMaxY;
-
- VisibleRegion(iDasherMinX, iDasherMinY, iDasherMaxX, iDasherMaxY);
-
- return ((y2 - y1) < iDasherMaxX) || (y1 > iDasherMinY) || (y2 < iDasherMaxY);
+ myint iVisibleMinX;
+ myint iVisibleMinY;
+ myint iVisibleMaxX;
+ myint iVisibleMaxY;
+
+ VisibleRegion(iVisibleMinX, iVisibleMinY, iVisibleMaxX, iVisibleMaxY);
+ const myint maxX(y2-y1);
+ if ((maxX < iVisibleMaxX) || (y1 > iVisibleMinY) || (y2 < iVisibleMaxY))
+ return true; //space around sq => space around anything smaller!
+ switch (GetLongParameter(LP_SHAPE_TYPE)) {
+ case 0: //non-overlapping rects
+ case 1: //overlapping rects
+ return false;
+ case 2: { //simple triangles
+ const myint iMidY((y1+y2)/2);
+ return (iMidY < iVisibleMaxY && (y2-iVisibleMaxY)*maxX < iVisibleMaxX*(y2-iMidY))
+ || (iMidY > iVisibleMinY && (iVisibleMinY-y1)*maxX < iVisibleMaxX*(iMidY-y1));
+ }
+ case 3: { //truncated triangles
+ const myint y113((y1+y1+y2)/3), y123((y1+y2+y2)/3);
+ return (y123 < iVisibleMaxY && (y2-iVisibleMaxY)*maxX < iVisibleMaxX*(y2-y123))
+ || (y113 > iVisibleMinY && (iVisibleMinY-y1)*maxX < iVisibleMaxX*(y123-y1));
+ }
+ case 4: //quadric.
+ //erm. seems hard. fall-through to circle, as it isn't far out -
+ // unfortunately it's not a conservative approximation, the circle
+ // covers the quadric not the other way around, so we'll say the
+ // circle covers the screen when the quadric doesn't :-(. However
+ // atm circles seem better generally so fixing quadrics is a low priority!
+ case 5: { //circle - or rather ellipse, x diameter is twice y diam, hence the *2 to normalize
+ const myint iMidY((y1+y2)/2); //centerX=0, radius = maxX
+ const myint maxYDiff(max(iVisibleMaxY-iMidY,iMidY-iVisibleMinY)*2);
+ return maxYDiff*maxYDiff + iVisibleMaxX*iVisibleMaxX > maxX*maxX;
+ }
+ }
}
-// Draw the outline of a node
-int CDasherViewSquare::RenderNodeOutlineFast(const int Color, myint y1, myint y2, int &mostleft, const std::string &sDisplayText, bool bShove) {
-
- // Commenting because click mode occasionally fails this assert.
- // I don't know why. -- cjb.
- if (!(y2 >= y1)) { return 1; }
+void CDasherViewSquare::RecursiveRender(CDasherNode *pRender, myint y1, myint y2,
+ CTextString *pPrevText, CExpansionPolicy &policy, double dMaxCost,
+ int parent_color)
+{
+ DASHER_ASSERT_VALIDPTR_RW(pRender);
+
+ ++m_iRenderCount;
+
+ // Set the NF_SUPER flag if this node entirely frames the visual
+ // area.
- // TODO - Get sensible limits here (to allow for non-linearities)
myint iDasherMinX;
myint iDasherMinY;
myint iDasherMaxX;
myint iDasherMaxY;
-
VisibleRegion(iDasherMinX, iDasherMinY, iDasherMaxX, iDasherMaxY);
-
- screenint iScreenX1;
- screenint iScreenY1;
- screenint iScreenX2;
- screenint iScreenY2;
+ pRender->SetFlag(NF_SUPER, !IsSpaceAroundNode(y1, y2));
- Dasher2Screen(0, std::max(y1, iDasherMinY), iScreenX1, iScreenY1);
- Dasher2Screen(0, std::min(y2, iDasherMaxY), iScreenX2, iScreenY2);
+ const int myColor = pRender->getColour();
- Cint32 iHeight = std::max(myint(iScreenY2 - iScreenY1),myint( 0));
- Cint32 iWidth = std::max(myint(iScreenX2 - iScreenX1),myint( 0));
-
- if((iHeight <= 1) && (iWidth <= 1))
- return 0; // We're too small to render
-
- if((y1 > iDasherMaxY) || (y2 < iDasherMinY)){
- return 0; // We're entirely off screen, so don't render.
+ const std::string &sDisplayText(pRender->getDisplayText());
+ if( sDisplayText.size() > 0 )
+ {
+ const int textColor = GetLongParameter(LP_OUTLINE_WIDTH)<0 ? myColor : 4;
+ myint ny1 = std::min(iDasherMaxY, std::max(iDasherMinY, y1)),
+ ny2 = std::min(iDasherMaxY, std::max(iDasherMinY, y2));
+ CTextString *pText = DasherDrawText(y2-y1, (ny1+ny2)/2, sDisplayText, pPrevText, textColor);
+ if (pRender->bShove()) pPrevText = pText;
+ }
+
+ const myint Range(y2-y1);
+ // Draw (well, fill) node...
+ if (GetLongParameter(LP_OUTLINE_WIDTH)>=0) {
+ switch (GetLongParameter(LP_SHAPE_TYPE)) {
+ case 0: //non-overlapping rects
+ if(pRender->ChildCount() > 0) break;
+ //else, if no children, still need to render node as simple rect - so fall through to 'overlapping' case
+ case 1: //overlapping rects
+ DasherDrawRectangle(std::min(Range,iDasherMaxX), std::min(y2,iDasherMaxY),0, std::max(y1,iDasherMinY), myColor, -1, Nodes1, 0);
+ break;
+ case 2: //simple triangles
+ TruncateTri(Range, y1, y2, (y1+y2)/2, (y1+y2)/2, myColor, -1, 0);
+ break;
+ case 3: //truncated triangles
+ TruncateTri(Range, y1, y2, (y1+y1+y2)/3, (y1+y2+y2)/3, myColor, -1, 0);
+ break;
+ case 4:
+ Quadric(Range, y1, y2, myColor, -1, 0);
+ break;
+ case 5:
+ Circle(Range, y1, y2, myColor, -1, 0);
+ break;
+ }
}
-
- // TODO: This should be earlier?
- if(!GetBoolParameter(BP_OUTLINE_MODE))
- return 1;
-
- myint iDasherSize(y2 - y1);
-
-
-
- // std::cout << std::min(iDasherSize,iDasherMaxX) << " " << std::min(y2,iDasherMaxY) << " 0 " << std::max(y1,iDasherMinY) << std::endl;
-
- DasherDrawRectangle(0, std::min(y1,iDasherMaxY),std::min(iDasherSize,iDasherMaxX), std::max(y2,iDasherMinY), -1, Color, Nodes1, 1);
-
-// // FIXME - get rid of pointless assignment below
-
-// int iTruncation(GetLongParameter(LP_TRUNCATION)); // Trucation farction times 100;
-
-// if(iTruncation == 0) { // Regular squares
-
-// }
-// else {
-// // TODO: Put something back here?
-// }
-
- return 1;
-}
-
-
-// Draw a filled block of a node right down to the baseline (intended
-// for the case when you have no visible child)
-int CDasherViewSquare::RenderNodePartFast(const int Color, myint y1, myint y2, int &mostleft, const std::string &sDisplayText, bool bShove,myint iParentWidth ) {
-
- // Commenting because click mode occasionally fails this assert.
- // I don't know why. -- cjb.
- if (!(y2 >= y1)) { return 1; }
-
- // TODO - Get sensible limits here (to allow for non-linearities)
- myint iDasherMinX;
- myint iDasherMinY;
- myint iDasherMaxX;
- myint iDasherMaxY;
-
- VisibleRegion(iDasherMinX, iDasherMinY, iDasherMaxX, iDasherMaxY);
-
- screenint iScreenX1;
- screenint iScreenY1;
- screenint iScreenX2;
- screenint iScreenY2;
- Dasher2Screen(0, std::max(y1, iDasherMinY), iScreenX1, iScreenY1);
- Dasher2Screen(0, std::min(y2, iDasherMaxY), iScreenX2, iScreenY2);
-
- // std::cout << "Fill in components: " << iScreenY1 << " " << iScreenY2 << std::endl;
-
- Cint32 iHeight = std::max(myint(iScreenY2 - iScreenY1),myint( 0));
- Cint32 iWidth = std::max(myint(iScreenX2 - iScreenX1),myint( 0));
-
- if((iHeight < 1) && (iWidth < 1)) {
- // std::cout << "b" << std::endl;
- return 0; // We're too small to render
+ if (pRender->ChildCount() == 0) {
+ //allow empty node to be expanded, it's big enough.
+ policy.pushNode(pRender, y1, y2, true, dMaxCost);
+ //fall through to draw outline
+ } else {
+ //Node has children. It can therefore be collapsed...however,
+ // we don't allow a node covering the crosshair to be collapsed
+ // (at best this'll mean there's nowhere useful to go forwards;
+ // at worst, all kinds of crashes trying to do text output!)
+ if (!pRender->GetFlag(NF_GAME) && !pRender->GetFlag(NF_SEEN))
+ dMaxCost = policy.pushNode(pRender, y1, y2, false, dMaxCost);
+
+ // Render children
+ int norm = (myint)GetLongParameter(LP_NORMALIZATION);
+
+ int id=-1;
+
+ if (CDasherNode *pChild = pRender->onlyChildRendered)
+ {
+ //if child still covers screen, render _just_ it and return
+ myint newy1 = y1 + (Range * (myint)pChild->Lbnd()) / (myint)norm;
+ myint newy2 = y1 + (Range * (myint)pChild->Hbnd()) / (myint)norm;
+ if (newy1 < iDasherMinY && newy2 > iDasherMaxY) {
+ //still covers entire screen. Parent should too...
+ DASHER_ASSERT(dMaxCost == std::numeric_limits<double>::infinity());
+
+ if (GetLongParameter(LP_OUTLINE_WIDTH)>=0 && GetLongParameter(LP_SHAPE_TYPE)==0) //fill in to it's left...
+ if (newy2-newy1 < iDasherMaxX)
+ DasherDrawRectangle(std::min(Range,iDasherMaxX), std::max(y1,iDasherMinY), newy2-newy1, std::min(y2,iDasherMaxY), myColor, -1, Nodes1, 0);
+ RecursiveRender(pChild, newy1, newy2, pPrevText,
+ policy, dMaxCost,
+ myColor);
+ //leave pRender->onlyChildRendered set, so remaining children are skipped
+ }
+ else
+ pRender->onlyChildRendered = NULL;
+ }
+
+ if (!pRender->onlyChildRendered) {
+ //render all children...
+ myint lasty=y1;
+ for(CDasherNode::ChildMap::const_iterator i = pRender->GetChildren().begin();
+ i != pRender->GetChildren().end(); i++) {
+ id++;
+ CDasherNode *pChild = *i;
+
+ myint newy1 = y1 + (Range * (myint)pChild->Lbnd()) / (myint)norm;/// norm and lbnd are simple ints
+ myint newy2 = y1 + (Range * (myint)pChild->Hbnd()) / (myint)norm;
+ if (newy1 < iDasherMinY && newy2 > iDasherMaxY) {
+ DASHER_ASSERT(dMaxCost == std::numeric_limits<double>::infinity());
+ pRender->onlyChildRendered = pChild;
+ if (newy2-newy1 < iDasherMaxX)
+ DasherDrawRectangle(std::min(Range,iDasherMaxX), std::max(y1,iDasherMinY), newy2-newy1, std::min(y2,iDasherMaxY), myColor, -1, Nodes1, 0);
+ RecursiveRender(pChild, newy1, newy2, pPrevText, policy, dMaxCost, myColor);
+ //ensure we don't blank over this child in "finishing off" the parent (!)
+ lasty=newy2;
+ break; //no need to render any more children!
+ }
+ if (newy2-newy1 >= GetLongParameter(LP_MIN_NODE_SIZE) //simple test if big enough
+ && newy1 <= iDasherMaxY && newy2 >= iDasherMinY) //at least partly on screen
+ {
+ //child should be rendered!
+ if (GetLongParameter(LP_SHAPE_TYPE)==0) {
+ if (GetLongParameter(LP_OUTLINE_WIDTH)>=0) {
+ //fill in to its left
+ DasherDrawRectangle(std::min(y2-y1,iDasherMaxX), std::max(newy1,iDasherMinY), std::min(newy2-newy1,iDasherMaxX), std::min(newy2,iDasherMaxY), myColor, -1, Nodes1, 0);
+
+ if (lasty<newy1) //fill in interval above child up to the last drawn child
+ DasherDrawRectangle(std::min(Range,iDasherMaxX), std::min(newy1,iDasherMaxY),0, std::max(lasty,iDasherMinY), myColor, -1, Nodes1, 0);
+ }
+ lasty = newy2;
+ }
+ RecursiveRender(pChild, newy1, newy2, pPrevText, policy, dMaxCost, myColor);
+ } else {
+ // We get here if the node is too small to render or is off-screen.
+ // So, collapse it immediately.
+ //
+ // In game mode, we get here if the child is too small to draw, but we need the
+ // coordinates - if this is the case then we shouldn't delete any children.
+ if(!pChild->GetFlag(NF_GAME))
+ pChild->Delete_children();
+ }
+ }
+ //all children rendered.
+ if (GetLongParameter(LP_OUTLINE_WIDTH)>=0 && GetLongParameter(LP_SHAPE_TYPE)==0) {
+ // Finish off the drawing process, filling in any part of the parent below the last-rendered child
+ if(lasty<y2)
+ DasherDrawRectangle(std::min(Range,iDasherMaxX), std::min(y2, iDasherMaxY), 0, std::max(lasty, iDasherMinY), myColor, -1, Nodes1, 0);
+ }
+ }
+ //end rendering children, fall through to outline
}
-
- if((y1 > iDasherMaxY) || (y2 < iDasherMinY)){
- //std::cout << "a" << std::endl;
- return 0; // We're entirely off screen, so don't render.
+ // Lastly, draw the outline
+ if(GetLongParameter(LP_OUTLINE_WIDTH) && pRender->getColour()!=-1) {
+ switch (GetLongParameter(LP_SHAPE_TYPE)) {
+ case 0: //non-overlapping rects
+ //fallthrough; same as
+ case 1: //overlapping rects
+ DasherDrawRectangle(std::min(Range,iDasherMaxX), std::min(y2,iDasherMaxY),0, std::max(y1,iDasherMinY), -1, myColor, Nodes1, abs(GetLongParameter(LP_OUTLINE_WIDTH)));
+ break;
+ case 2: //simple triangles
+ TruncateTri(Range, y1, y2, (y1+y2)/2, (y1+y2)/2, -1, myColor, abs(GetLongParameter(LP_OUTLINE_WIDTH)));
+ break;
+ case 3: //truncated triangles
+ TruncateTri(Range, y1, y2, (y1+y1+y2)/3, (y1+y2+y2)/3, -1, myColor, abs(GetLongParameter(LP_OUTLINE_WIDTH)));
+ break;
+ case 4:
+ Quadric(Range, y1, y2, -1, myColor, abs(GetLongParameter(LP_OUTLINE_WIDTH)));
+ break;
+ case 5:
+ Circle(Range, y1, y2, -1, myColor, abs(GetLongParameter(LP_OUTLINE_WIDTH)));
+ break;
+ }
}
-
- DasherDrawRectangle(std::min(iParentWidth,iDasherMaxX), std::min(y2,iDasherMaxY),0, std::max(y1,iDasherMinY), Color, -1, Nodes1, 0);
-
- return 1;
}
/// Convert screen co-ordinates to dasher co-ordinates. This doesn't
diff --git a/Src/DasherCore/DasherViewSquare.h b/Src/DasherCore/DasherViewSquare.h
index 963d0a9..da37c67 100644
--- a/Src/DasherCore/DasherViewSquare.h
+++ b/Src/DasherCore/DasherViewSquare.h
@@ -100,44 +100,53 @@ public:
/// @}
private:
+ ///draw a possibly-truncated triangle given dasher-space coords & accounting for non-linearity
+ /// @param x = max dasher-x extent
+ /// @param y1, y2 = dasher-y extent along y-axis
+ /// @param midy1,midy2 = extent along line of max x (midy1==midy2 => triangle, midy1<midy2 => truncated tri)
+ void TruncateTri(myint x, myint y1, myint y2, myint midy1, myint midy2, int fillColor, int outlineColor, int lineWidth);
+ void CircleTo(myint cy, myint r, myint y1, myint x1, myint y3, myint x3, CDasherScreen::point dest, vector<CDasherScreen::point> &pts);
+ void Circle(myint Range, myint lowY, myint highY, int fCol, int oCol, int lWidth);
+ void Quadric(myint Range, myint lowY, myint highY, int fillColor, int outlineColour, int lineWidth);
+ ///draw isoceles triangle, with baseline from y1-y2 along y axis (x=0), and other point at (x,(y1+y2)/2)
+ /// (all in Dasher coords).
+ void Triangle(myint x, myint y1, myint y2, int fillColor, int outlineColor, int lineWidth);
+
+ class CTextString {
+ public: //to CDasherViewSquare...
+ ///Creates a request that string str will be drawn.
+ /// x,y are screen coords of midpoint of leading edge;
+ /// iSize is desired size (already computed from requested position)
+ CTextString(const std::string & str, screenint x, screenint y, int iSize, int iColor)
+ : m_String(str), m_ix(x), m_iy(y), m_iSize(iSize), m_iColor(iColor) {
+ }
+ ~CTextString();
+ std::string m_String;
+ screenint m_ix,m_iy;
+ vector<CTextString *> m_children;
+ int m_iSize;
+ int m_iColor;
+ };
+
+ std::vector<CTextString *> m_DelayedTexts;
+
+ void DoDelayedText(CTextString *pText);
///
/// Draw text specified in Dasher co-ordinates
///
- void DasherDrawText(myint iAnchorX1, myint iAnchorY1, myint iAnchorX2, myint iAnchorY2, const std::string & sDisplayText, int &mostleft, bool bShove);
+ CTextString *DasherDrawText(myint iMaxX, myint iMidY, const std::string & sDisplayText, CTextString *pParent, int iColor);
- CDelayedDraw m_DelayDraw;
-
///
/// Render the current state of the model.
///
virtual void RenderNodes(CDasherNode *pRoot, myint iRootMin, myint iRootMax, CExpansionPolicy &policy);
///
- /// Recursively render all nodes in a tree. Responsible for all the Render_node calls
+ /// (Recursively) render a node and all contained subnodes. Responsible for rendering exactly the area contained within the node.
///
+ void RecursiveRender(CDasherNode * Render, myint y1, myint y2, CTextString *prevText, CExpansionPolicy &policy, double dMaxCost,int parent_color);
- void RecursiveRender(CDasherNode * Render, myint y1, myint y2, int mostleft, CExpansionPolicy &policy, double dMaxCost, myint parent_width,int parent_color, int iDepth);
-
- ///Check that a node is large enough, and onscreen, to render;
- ///calls RecursiveRender if so, or collapses the node immediately if not
- bool CheckRender(CDasherNode * Render, myint y1, myint y2, int mostleft, CExpansionPolicy &policy, double dMaxCost, myint parent_width,int parent_color, int iDepth);
-
- /// Render a single node
- /// \param Color The colour to draw it
- /// \param y1 Upper extent.
- /// \param y2 Lower extent
- /// \param mostleft The left most position in which the text (l->r)
- /// can be displayed in order to avoid overlap. This is updated by
- /// the function to allow for the new text
- /// \param sDisplayText Text to display.
- /// \param bShove Whether the node shoves
- /// \todo Character and displaytext are redundant. We shouldn't need
- /// to know about alphabets here, so only use the latterr
- // int RenderNode(const int Color, myint y1, myint y2, int &mostleft, const std::string &sDisplayText, bool bShove);
-
- int RenderNodeOutlineFast(const int Color, myint y1, myint y2, int &mostleft, const std::string &sDisplayText, bool bShove);
- int RenderNodePartFast(const int Color, myint y1, myint y2, int &mostleft, const std::string &sDisplayText, bool bShove, myint iParentWidth);
#ifdef _WIN32
///
/// FIXME - couldn't find windows version of round(double) so here's one!
diff --git a/Src/DasherCore/Parameters.h b/Src/DasherCore/Parameters.h
index 61b50f7..cf8650d 100644
--- a/Src/DasherCore/Parameters.h
+++ b/Src/DasherCore/Parameters.h
@@ -30,11 +30,11 @@
// All parameters go into the enums here
// They are unique across the different types
enum {
- BP_DRAW_MOUSE_LINE, BP_DRAW_MOUSE, BP_CURVE_MOUSE_LINE,
+ BP_MULTISIZE_FONTS, BP_DRAW_MOUSE_LINE, BP_DRAW_MOUSE, BP_CURVE_MOUSE_LINE,
BP_SHOW_SLIDER, BP_START_MOUSE,
BP_START_SPACE, BP_STOP_IDLE, BP_CONTROL_MODE,
BP_COLOUR_MODE, BP_MOUSEPOS_MODE,
- BP_OUTLINE_MODE, BP_PALETTE_CHANGE,
+ BP_PALETTE_CHANGE,
BP_AUTOCALIBRATE, BP_DASHER_PAUSED,
BP_GAME_MODE, BP_TRAINING, BP_REDRAW, BP_LM_DICTIONARY,
BP_LM_LETTER_EXCLUSION, BP_AUTO_SPEEDCONTROL,
@@ -52,14 +52,14 @@ enum {
enum {
LP_ORIENTATION = END_OF_BPS, LP_REAL_ORIENTATION, LP_MAX_BITRATE, LP_FRAMERATE,
- LP_VIEW_ID, LP_LANGUAGE_MODEL_ID, LP_DASHER_FONTSIZE,
+ LP_VIEW_ID, LP_LANGUAGE_MODEL_ID, LP_DASHER_FONTSIZE, LP_SHAPE_TYPE,
LP_UNIFORM, LP_YSCALE, LP_MOUSEPOSDIST, LP_STOP_IDLETIME,
LP_LM_MAX_ORDER, LP_LM_EXCLUSION,
LP_LM_UPDATE_EXCLUSION, LP_LM_ALPHA, LP_LM_BETA,
LP_LM_MIXTURE, LP_MOUSE_POS_BOX, LP_NORMALIZATION, LP_LINE_WIDTH,
LP_LM_WORD_ALPHA, LP_USER_LOG_LEVEL_MASK,
LP_ZOOMSTEPS, LP_B, LP_S, LP_BUTTON_SCAN_TIME, LP_R, LP_RIGHTZOOM,
- LP_NODE_BUDGET, LP_NONLINEAR_X,
+ LP_NODE_BUDGET, LP_OUTLINE_WIDTH, LP_MIN_NODE_SIZE, LP_NONLINEAR_X,
LP_BOOSTFACTOR, LP_AUTOSPEED_SENSITIVITY, LP_SOCKET_PORT, LP_SOCKET_INPUT_X_MIN, LP_SOCKET_INPUT_X_MAX,
LP_SOCKET_INPUT_Y_MIN, LP_SOCKET_INPUT_Y_MAX, LP_OX, LP_OY, LP_MAX_Y, LP_INPUT_FILTER,
LP_CIRCLE_PERCENT, LP_TWO_BUTTON_OFFSET, LP_HOLD_TIME, LP_MULTIPRESS_TIME,
@@ -124,6 +124,7 @@ struct sp_table {
// The only important thing here is that these are in the same order
// as the enum declarations (could add check in class that enforces this instead)
static bp_table boolparamtable[] = {
+ {BP_MULTISIZE_FONTS, "MultiSizeFonts", PERS, false, "Use multiple font sizes"},
{BP_DRAW_MOUSE_LINE, "DrawMouseLine", PERS, true, "Draw Mouse Line"},
{BP_DRAW_MOUSE, "DrawMouse", PERS, false, "Draw Mouse Position"},
{BP_CURVE_MOUSE_LINE, "CurveMouseLine", PERS, false, "Curve mouse line according to screen nonlinearity"},
@@ -138,7 +139,6 @@ static bp_table boolparamtable[] = {
{BP_CONTROL_MODE, "ControlMode", PERS, false, "ControlMode"},
{BP_COLOUR_MODE, "ColourMode", PERS, true, "ColourMode"},
{BP_MOUSEPOS_MODE, "StartOnMousePosition", PERS, false, "StartOnMousePosition"},
- {BP_OUTLINE_MODE, "OutlineBoxes", PERS, true, "OutlineBoxes"},
{BP_PALETTE_CHANGE, "PaletteChange", PERS, true, "PaletteChange"},
{BP_AUTOCALIBRATE, "Autocalibrate", PERS, true, "Autocalibrate"},
{BP_DASHER_PAUSED, "DasherPaused", !PERS, true, "Dasher Paused"},
@@ -194,6 +194,7 @@ static lp_table longparamtable[] = {
{LP_VIEW_ID, "ViewID", PERS, 1, "ViewID"},
{LP_LANGUAGE_MODEL_ID, "LanguageModelID", PERS, 0, "LanguageModelID"},
{LP_DASHER_FONTSIZE, "DasherFontSize", PERS, 2, "DasherFontSize"},
+ {LP_SHAPE_TYPE, "RenderStyle", PERS, 0, "Shapes to render in (0/1=disjoint/overlapping rects, 2/3=triangles/truncated, 4=quadrics, 5=circles)"},
{LP_UNIFORM, "UniformTimes1000", PERS, 50, "UniformTimes1000"},
{LP_YSCALE, "YScaling", PERS, 0, "YScaling"},
{LP_MOUSEPOSDIST, "MousePositionBoxDistance", PERS, 50, "MousePositionBoxDistance"},
@@ -224,6 +225,8 @@ static lp_table longparamtable[] = {
#else
{LP_NODE_BUDGET, "NodeBudget", PERS, 3000, "Target (min) number of node objects to maintain"},
#endif
+ {LP_OUTLINE_WIDTH, "OutlineWidth", PERS, 0, "Absolute value is line width to draw boxes (fill iff >=0)" },
+ {LP_MIN_NODE_SIZE, "MinNodeSize", PERS, 50, "Minimum size of node (in dasher coords) to draw" },
#ifdef WITH_MAEMO
{LP_NONLINEAR_X, "NonLinearX", PERS, 0, "Nonlinear compression of X-axis (0 = none, higher = more extreme)"},
#else
diff --git a/Src/MacOSX/Dasher.xcodeproj/project.pbxproj b/Src/MacOSX/Dasher.xcodeproj/project.pbxproj
index d48b771..e09fb7f 100755
--- a/Src/MacOSX/Dasher.xcodeproj/project.pbxproj
+++ b/Src/MacOSX/Dasher.xcodeproj/project.pbxproj
@@ -74,7 +74,6 @@
1948BEE00C226CFD001DFA32 /* DasherViewSquare.inl in Resources */ = {isa = PBXBuildFile; fileRef = 1948BE3A0C226CFD001DFA32 /* DasherViewSquare.inl */; };
1948BEE10C226CFD001DFA32 /* DefaultFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1948BE3B0C226CFD001DFA32 /* DefaultFilter.cpp */; };
1948BEE20C226CFD001DFA32 /* DefaultFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 1948BE3C0C226CFD001DFA32 /* DefaultFilter.h */; };
- 1948BEE30C226CFD001DFA32 /* DelayedDraw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1948BE3D0C226CFD001DFA32 /* DelayedDraw.cpp */; };
1948BEE40C226CFD001DFA32 /* DynamicFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1948BE3E0C226CFD001DFA32 /* DynamicFilter.cpp */; };
1948BEE50C226CFD001DFA32 /* DynamicFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 1948BE3F0C226CFD001DFA32 /* DynamicFilter.h */; };
1948BEE60C226CFD001DFA32 /* Event.h in Headers */ = {isa = PBXBuildFile; fileRef = 1948BE400C226CFD001DFA32 /* Event.h */; };
@@ -340,7 +339,6 @@
19F8C7E60C858A2800276B4F /* I18n.h in Headers */ = {isa = PBXBuildFile; fileRef = 19F8C7E50C858A2800276B4F /* I18n.h */; };
19F8C7F90C858E9900276B4F /* TrainingHelper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 19F8C7F70C858E9900276B4F /* TrainingHelper.cpp */; };
19F8C7FA0C858E9900276B4F /* TrainingHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 19F8C7F80C858E9900276B4F /* TrainingHelper.h */; };
- 3300114910A2E9C900D31B1D /* DelayedDraw.h in Headers */ = {isa = PBXBuildFile; fileRef = 3300114810A2E9C900D31B1D /* DelayedDraw.h */; };
3300115210A2EA7700D31B1D /* ExpansionPolicy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3300115010A2EA7700D31B1D /* ExpansionPolicy.cpp */; };
3300115310A2EA7700D31B1D /* ExpansionPolicy.h in Headers */ = {isa = PBXBuildFile; fileRef = 3300115110A2EA7700D31B1D /* ExpansionPolicy.h */; };
33008360120CB7F900C41FAA /* ConvertingAlphMgr.h in Headers */ = {isa = PBXBuildFile; fileRef = 3300835E120CB7F900C41FAA /* ConvertingAlphMgr.h */; };
@@ -475,7 +473,6 @@
1948BE3A0C226CFD001DFA32 /* DasherViewSquare.inl */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = DasherViewSquare.inl; sourceTree = "<group>"; };
1948BE3B0C226CFD001DFA32 /* DefaultFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DefaultFilter.cpp; sourceTree = "<group>"; };
1948BE3C0C226CFD001DFA32 /* DefaultFilter.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DefaultFilter.h; sourceTree = "<group>"; };
- 1948BE3D0C226CFD001DFA32 /* DelayedDraw.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DelayedDraw.cpp; sourceTree = "<group>"; };
1948BE3E0C226CFD001DFA32 /* DynamicFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DynamicFilter.cpp; sourceTree = "<group>"; };
1948BE3F0C226CFD001DFA32 /* DynamicFilter.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DynamicFilter.h; sourceTree = "<group>"; };
1948BE400C226CFD001DFA32 /* Event.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Event.h; sourceTree = "<group>"; };
@@ -757,7 +754,6 @@
29B97319FDCFA39411CA2CEA /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/MainMenu.nib; sourceTree = "<group>"; };
29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
- 3300114810A2E9C900D31B1D /* DelayedDraw.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DelayedDraw.h; sourceTree = "<group>"; };
3300115010A2EA7700D31B1D /* ExpansionPolicy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExpansionPolicy.cpp; sourceTree = "<group>"; };
3300115110A2EA7700D31B1D /* ExpansionPolicy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExpansionPolicy.h; sourceTree = "<group>"; };
3300835E120CB7F900C41FAA /* ConvertingAlphMgr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConvertingAlphMgr.h; sourceTree = "<group>"; };
@@ -985,10 +981,8 @@
1948BE3A0C226CFD001DFA32 /* DasherViewSquare.inl */,
1948BE3B0C226CFD001DFA32 /* DefaultFilter.cpp */,
1948BE3C0C226CFD001DFA32 /* DefaultFilter.h */,
- 1948BE3D0C226CFD001DFA32 /* DelayedDraw.cpp */,
3300115010A2EA7700D31B1D /* ExpansionPolicy.cpp */,
3300115110A2EA7700D31B1D /* ExpansionPolicy.h */,
- 3300114810A2E9C900D31B1D /* DelayedDraw.h */,
1948BE3E0C226CFD001DFA32 /* DynamicFilter.cpp */,
1948BE3F0C226CFD001DFA32 /* DynamicFilter.h */,
1948BE400C226CFD001DFA32 /* Event.h */,
@@ -1497,7 +1491,6 @@
33135354102C6D8E00E28220 /* CompassMode.h in Headers */,
33135356102C6D8E00E28220 /* ButtonMode.h in Headers */,
3300115310A2EA7700D31B1D /* ExpansionPolicy.h in Headers */,
- 3300114910A2E9C900D31B1D /* DelayedDraw.h in Headers */,
339055E81195FBD0001BE240 /* Queue.h in Headers */,
33008360120CB7F900C41FAA /* ConvertingAlphMgr.h in Headers */,
339794D5120F2A9600CEA168 /* AlphInfo.h in Headers */,
@@ -1796,7 +1789,6 @@
1948BEDB0C226CFD001DFA32 /* DasherView.cpp in Sources */,
1948BEDE0C226CFD001DFA32 /* DasherViewSquare.cpp in Sources */,
1948BEE10C226CFD001DFA32 /* DefaultFilter.cpp in Sources */,
- 1948BEE30C226CFD001DFA32 /* DelayedDraw.cpp in Sources */,
1948BEE40C226CFD001DFA32 /* DynamicFilter.cpp in Sources */,
1948BEE70C226CFD001DFA32 /* EventHandler.cpp in Sources */,
1948BEE90C226CFD001DFA32 /* EyetrackerFilter.cpp in Sources */,
diff --git a/Src/iPhone/Classes/MiscSettings.mm b/Src/iPhone/Classes/MiscSettings.mm
index 2e158e4..7490d54 100644
--- a/Src/iPhone/Classes/MiscSettings.mm
+++ b/Src/iPhone/Classes/MiscSettings.mm
@@ -15,6 +15,8 @@ static SModuleSettings _settings[] = { //note iStep and string description are i
{LP_NODE_BUDGET, T_LONG, 400, 10000, 1, 0, ""}, //hopefully appropriate for an iPhone 3GS?
{LP_MARGIN_WIDTH, T_LONG, 100, 900, 1, 0, ""},
{LP_DASHER_FONTSIZE, T_LONG, 1, 3, 1, 1, ""},
+ {LP_SHAPE_TYPE, T_LONG, 1, 5, 1, -1, ""},
+ {LP_OUTLINE_WIDTH, T_LONG, -5, 5, 1, -1, ""},
{BP_AUTO_SPEEDCONTROL, T_BOOL, -1, -1, -1, -1, ""},
{LP_NONLINEAR_X, T_LONG, 0, 10, 1, -1, ""},
{BP_DOUBLE_X, T_BOOL, -1, -1, -1, -1, ""},
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]