wxLayoutLine::wxLayoutLine(wxLayoutLine *prev, wxLayoutList *llist)
{
- m_LineNumber = 0;
m_Width = m_Height = 0;
m_Length = 0;
+
m_updateLeft = -1;
MarkDirty(0);
+
m_Previous = prev;
m_Next = NULL;
+
+ m_LineNumber = 0;
RecalculatePosition(llist);
+
if(m_Previous)
{
- m_LineNumber = m_Previous->GetLineNumber()+1;
+ m_LineNumber = m_Previous->GetLineNumber() + 1;
m_Next = m_Previous->GetNextLine();
m_Previous->m_Next = this;
}
+
if(m_Next)
{
m_Next->m_Previous = this;
}
m_StyleInfo = llist->GetDefaultStyleInfo();
+
+ llist->IncNumLines();
}
wxLayoutLine::~wxLayoutLine()
}
wxLayoutObjectList::iterator
-wxLayoutLine::FindObjectScreen(wxDC &dc,
+wxLayoutLine::FindObjectScreen(wxDC &dc, wxLayoutList *llist,
CoordType xpos, CoordType *cxpos,
bool *found) const
{
wxASSERT(cxpos);
- wxASSERT(cxpos);
+
+ llist->ApplyStyle(GetStyleInfo(), dc);
+
wxLayoutObjectList::iterator i;
CoordType x = 0, cx = 0, width;
for(i = m_ObjectList.begin(); i != NULLIT; i++)
{
- width = (**i).GetWidth();
+ wxLayoutObject *obj = *i;
+ if ( obj->GetType() == WXLO_TYPE_CMD )
+ {
+ // this will set the correct font for the objects which follow
+ obj->Layout(dc, llist);
+ }
+
+ width = obj->GetWidth();
if( x <= xpos && xpos <= x + width )
{
- *cxpos = cx + (**i).GetOffsetScreen(dc, xpos-x);
- if(found) *found = true;
+ *cxpos = cx + obj->GetOffsetScreen(dc, xpos-x);
+
+ if ( found )
+ *found = true;
return i;
}
- x += (**i).GetWidth();
- cx += (**i).GetLength();
+
+ x += obj->GetWidth();
+ cx += obj->GetLength();
}
+
// behind last object:
*cxpos = cx;
- if(found) *found = false;
+
+ if (found)
+ *found = false;
return m_ObjectList.tail();
}
wxLayoutLine *
wxLayoutLine::DeleteLine(bool update, wxLayoutList *llist)
{
- if(m_Next) m_Next->m_Previous = m_Previous;
- if(m_Previous) m_Previous->m_Next = m_Next;
+ // maintain linked list integrity
+ if(m_Next)
+ m_Next->m_Previous = m_Previous;
+ if(m_Previous)
+ m_Previous->m_Next = m_Next;
+
+ wxLayoutLine *next = m_Next;
+ if ( next )
+ {
+ // get the line numbers right again
+ next->MoveLines(-1);
+ }
+
if(update)
{
- m_Next->MoveLines(-1);
- m_Next->RecalculatePositions(1, llist);
+ if ( next )
+ next->RecalculatePositions(1, llist);
+
/* We assume that if we have more than one object in the list,
this means that we have a command object, so we need to
update the following lines. */
)
MarkNextDirty(-1);
}
- wxLayoutLine *next = m_Next;
+
delete this;
+
+ llist->DecNumLines();
+
return next;
}
#endif // 0
}
+ llist->DecNumLines();
+
delete oldnext;
}
m_caret = NULL;
#endif // WXLAYOUT_USE_CARET
+ m_numLines = 0;
m_FirstLine = NULL;
InvalidateUpdateRect();
Clear();
wxLayoutList::~wxLayoutList()
{
InternalClear();
+ Empty();
m_FirstLine->DeleteLine(false, this);
+
+ wxASSERT_MSG( m_numLines == 0, "line count calculation broken" );
}
void
void
wxLayoutList::InternalClear(void)
{
- Empty();
m_Selection.m_selecting = false;
m_Selection.m_valid = false;
m_DefaultStyleInfo = wxLayoutStyleInfo(family, size, style, weight,
underline, fg, bg);
m_CurrentStyleInfo = m_DefaultStyleInfo;
+
+ // Empty() should be called after we set m_DefaultStyleInfo because
+ // otherwise the style info for the first line (created in Empty()) would be
+ // incorrect
+ Empty();
}
wxPoint
CoordType moveDistance = 0;
CoordType offset;
- for ( wxLOiterator i = m_CursorLine->FindObject(m_CursorPos.x, &offset);
+ wxLayoutLine *lineCur = m_CursorLine;
+ for ( wxLOiterator i = lineCur->FindObject(m_CursorPos.x, &offset);
n != 0;
n > 0 ? i++ : i-- )
{
if ( i == NULLIT )
- return false;
+ {
+ if ( n > 0 )
+ {
+ // moving forward, pass to the first object of the next line
+ moveDistance++;
+ lineCur = lineCur->GetNextLine();
+ if ( lineCur )
+ i = lineCur->GetFirstObject();
+ }
+ else
+ {
+ // moving backwards, pass to the last object of the prev line
+ moveDistance--;
+ lineCur = lineCur->GetPreviousLine();
+ if ( lineCur )
+ i = lineCur->GetLastObject();
+ }
+
+ if ( i == NULLIT )
+ {
+ // moved to the end/beginning of text
+ return false;
+ }
+ }
wxLayoutObject *obj = *i;
+
+ if ( offset == -1 )
+ {
+ // calculate offset: we are either at the very beginning or the very
+ // end of the object, so it isn't very difficult (the only time when
+ // offset is != -1 is for the very first iteration when its value is
+ // returned by FindObject)
+ if ( n > 0 )
+ offset = 0;
+ else
+ offset = obj->GetLength();
+ }
+
if( obj->GetType() != WXLO_TYPE_TEXT )
{
// any visible non text objects count as one word
if ( n > 0 )
{
// can't move further in this text object
- n--;
-
canAdvance = false;
+
+ // still should move over the object border
+ moveDistance++;
+ n--;
}
else if ( offset > 0 )
{
}
else // backwards
{
- if ( isspace(*p) )
+ // in these 2 cases we took 1 char too much
+ if ( (p < start) || isspace(*p) )
+ {
p++;
+ }
}
- n > 0 ? n-- : n++;
+ CoordType moveDelta = p - start - offset;
+ if ( (n < 0) && (offset == tobj->GetLength() - 1) )
+ {
+ // because we substracted 1 from offset in this case above, now
+ // compensate for it
+ moveDelta--;
+ }
- moveDistance = p - start - offset;
+ if ( moveDelta != 0 )
+ {
+ moveDistance += moveDelta;
+
+ n > 0 ? n-- : n++;
+ }
}
}
- // except for the first iteration, offset is 0
- offset = 0;
+ // except for the first iteration, offset is calculated in the beginning
+ // of the loop
+ offset = -1;
}
MoveCursorHorizontally(moveDistance);
wxLayoutList::LineBreak(void)
{
wxASSERT(m_CursorLine);
- bool setFirst = (m_CursorLine == m_FirstLine && m_CursorPos.x == 0);
AddCursorPosToUpdateRect();
height = m_CursorLine->GetHeight();
m_CursorLine = m_CursorLine->Break(m_CursorPos.x, this);
- if(setFirst) // we were at beginning of first line
- m_FirstLine = m_CursorLine->GetPreviousLine();
- if(m_CursorPos.x != 0)
+ if(m_CursorLine->GetPreviousLine() == NULL)
+ m_FirstLine = m_CursorLine;
+ if(m_CursorPos.x > 0)
m_CursorPos.y++;
m_CursorPos.x = 0;
+ // The following code will produce a height which is guaranteed to
+ // be too high: old lineheight + the height of both new lines.
+ // We can probably drop the old line height and start with height =
+ // 0. FIXME
wxLayoutLine *prev = m_CursorLine->GetPreviousLine();
- wxCHECK_MSG(prev, false, "just broke the line, where is the previous one?");
-
- height += prev->GetHeight();
+ if(prev)
+ height += prev->GetHeight();
+ height += m_CursorLine->GetHeight();
m_movedCursor = true;
// The following Layout() calls will update our
// m_CurrentStyleInfo if needed.
if(line == m_CursorLine)
+ {
line->Layout(dc, this,
(wxPoint *)&m_CursorScreenPos,
(wxPoint *)&m_CursorSize,
&m_CursorStyleInfo,
m_CursorPos.x);
- if(cpos && line->GetLineNumber() == cpos->y)
- line->Layout(dc, this,
- cpos,
- csize, NULL, cpos->x);
+ // we cannot layout the line twice, so copy the coords:
+ if(cpos && line ->GetLineNumber() == cpos->y)
+ {
+ *cpos = m_CursorScreenPos;
+ if ( csize )
+ *csize = m_CursorSize;
+ }
+ }
+ else
+ if(cpos && line->GetLineNumber() == cpos->y)
+ line->Layout(dc, this,
+ cpos,
+ csize, NULL, cpos->x);
else
line->Layout(dc, this);
// little condition to speed up redrawing:
}
line->Draw(dc, this, offset);
}
-#if 0
- else
- line->Layout(dc, this);
-#endif
- // little condition to speed up redrawing:
+ // little condition to speed up redrawing:
if(bottom != -1 && line->GetPosition().y > bottom) break;
line = line->GetNextLine();
}
#endif
line = line->GetNextLine();
}
- if(line == NULL)
+
+ if ( !line )
{
- if(found) *found = false;
+ if ( found )
+ *found = false;
+
return NULL; // not found
}
- if(cursorPos) cursorPos->y = line->GetLineNumber();
+
+ if ( cursorPos )
+ cursorPos->y = line->GetLineNumber();
+
// Now, find the object in the line:
- wxLOiterator i = line->FindObjectScreen(dc, pos.x,
- cursorPos ? & cursorPos->x : NULL ,
+ wxLOiterator i = line->FindObjectScreen(dc, this,
+ pos.x,
+ cursorPos ? &cursorPos->x : NULL,
found);
return (i == NULLIT) ? NULL : *i;
return;
}
+ // We now know that the two lines are different:
wxLayoutLine
- * firstLine = NULL,
- * lastLine = NULL;
-
- for(firstLine = m_FirstLine;
- firstLine && firstLine->GetLineNumber() < m_Selection.m_CursorA.y;
- firstLine=firstLine->GetNextLine())
- ;
- if(!firstLine || firstLine->GetLineNumber() != m_Selection.m_CursorA.y)
- return;
-
-
- for(lastLine = m_FirstLine;
- lastLine && lastLine->GetLineNumber() < m_Selection.m_CursorB.y;
- lastLine=lastLine->GetNextLine())
- ;
- if(!lastLine || lastLine->GetLineNumber() != m_Selection.m_CursorB.y)
- return;
-
-
- // We now know that the two lines are different:
+ * firstLine = GetLine(m_Selection.m_CursorA.y),
+ * lastLine = GetLine(m_Selection.m_CursorB.y);
// First, delete what's left of this line:
MoveCursorTo(m_Selection.m_CursorA);
DeleteToEndOfLine();
- wxLayoutLine *nextLine = firstLine->GetNextLine();
+ wxLayoutLine *prevLine = firstLine->GetPreviousLine(),
+ *nextLine = firstLine->GetNextLine();
while(nextLine && nextLine != lastLine)
nextLine = nextLine->DeleteLine(false, this);
// Now nextLine = lastLine;
Delete(1); // This joins firstLine and nextLine
- Delete(m_Selection.m_CursorB.x); // This deletes the first x
- // positions
+ Delete(m_Selection.m_CursorB.x); // This deletes the first x positions
- /// Recalculate:
- firstLine->RecalculatePositions(1, this);
+ // Recalculate the line positions and numbers but notice that firstLine
+ // might not exist any more - it could be deleted by Delete(1) above
+ wxLayoutLine *firstLine2 = prevLine ? prevLine->GetNextLine() : m_FirstLine;
+ firstLine2->RecalculatePositions(1, this);
}
/// Starts highlighting the selection