+ SetUpdateRect(m_CursorScreenPos);
+ SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+ int move;
+ while(n < 0)
+ {
+ if(m_CursorPos.x == 0) // at begin of line
+ {
+ if(! MoveCursorVertically(-1))
+ break;
+ MoveCursorToEndOfLine();
+ n++;
+ continue;
+ }
+ move = -n;
+ if(move > m_CursorPos.x) move = m_CursorPos.x;
+ m_CursorPos.x -= move; n += move;
+ }
+
+ while(n > 0)
+ {
+ int len = m_CursorLine->GetLength();
+ if(m_CursorPos.x == len) // at end of line
+ {
+ if(! MoveCursorVertically(1))
+ break;
+ MoveCursorToBeginOfLine();
+ n--;
+ continue;
+ }
+ move = n;
+ if( move >= len-m_CursorPos.x) move = len-m_CursorPos.x;
+ m_CursorPos.x += move;
+ n -= move;
+ }
+ return n == 0;
+}
+
+bool
+wxLayoutList::Insert(wxString const &text)
+{
+ wxASSERT(m_CursorLine);
+ SetUpdateRect(m_CursorScreenPos);
+ SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+ m_CursorLine->Insert(m_CursorPos.x, text);
+ m_CursorPos.x += text.Length();
+ m_CursorLine->RecalculatePositions(true, this); //FIXME needed?
+ return true;
+}
+
+bool
+wxLayoutList::Insert(wxLayoutObject *obj)
+{
+ wxASSERT(m_CursorLine);
+ SetUpdateRect(m_CursorScreenPos);
+ SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+ m_CursorLine->Insert(m_CursorPos.x, obj);
+ m_CursorPos.x += obj->GetLength();
+ m_CursorLine->RecalculatePositions(true, this); //FIXME needed?
+ return true;
+}
+
+bool
+wxLayoutList::LineBreak(void)
+{
+ wxASSERT(m_CursorLine);
+ bool setFirst = (m_CursorLine == m_FirstLine && m_CursorPos.x == 0);
+ SetUpdateRect(m_CursorScreenPos);
+ SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+ m_CursorLine = m_CursorLine->Break(m_CursorPos.x, this);
+ if(setFirst) // we were at beginning of first line
+ m_FirstLine = m_CursorLine->GetPreviousLine();
+ m_CursorPos.y++;
+ m_CursorPos.x = 0;
+ m_CursorLine->RecalculatePositions(true, this); //FIXME needed?
+ return true;
+}
+
+bool
+wxLayoutList::WrapLine(CoordType column)
+{
+ if(m_CursorPos.x <= column || column < 1)
+ return false; // do nothing yet
+ else
+ {
+ CoordType xpos = m_CursorLine->GetWrapPosition(column);
+ if(xpos == -1)
+ return false; // cannot break line
+ //else:
+ CoordType newpos = m_CursorPos.x - xpos - 1;
+ m_CursorPos.x = xpos;
+ SetUpdateRect(m_CursorScreenPos);
+ SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+ LineBreak();
+ Delete(1); // delete the space
+ m_CursorPos.x = newpos;
+ m_CursorLine->RecalculatePositions(true, this); //FIXME needed?
+ return true;
+ }
+}
+
+bool
+wxLayoutList::Delete(CoordType npos)
+{
+ wxASSERT(m_CursorLine);
+ SetUpdateRect(m_CursorScreenPos);
+ SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+ CoordType left;
+ do
+ {
+ left = m_CursorLine->Delete(m_CursorPos.x, npos);
+ if(left == 0)
+ return true;
+ // More to delete, continue on next line.
+ // First, check if line is empty:
+ if(m_CursorLine->GetLength() == 0)
+ { // in this case, updating could probably be optimised
+#ifdef WXLO_DEBUG
+ wxASSERT(DeleteLines(1) == 0);
+#else
+ DeleteLines(1);
+#endif
+
+ left--;
+ }
+ else
+ {
+ // Need to join next line
+ if(! m_CursorLine->GetNextLine())
+ break; // cannot
+ else
+ {
+ m_CursorLine->MergeNextLine(this);
+ left--;
+ }
+ }
+ }
+ while(left);
+ m_CursorLine->RecalculatePositions(true, this); //FIXME needed?
+ return left == 0;
+}
+
+int
+wxLayoutList::DeleteLines(int n)
+{
+ wxASSERT(m_CursorLine);
+ wxLayoutLine *line;
+ SetUpdateRect(m_CursorScreenPos);
+ SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+ while(n > 0)
+ {
+ if(!m_CursorLine->GetNextLine())
+ { // we cannot delete this line, but we can clear it
+ MoveCursorToBeginOfLine();
+ DeleteToEndOfLine();
+ m_CursorLine->RecalculatePositions(2, this);
+ return n-1;
+ }
+ //else:
+ line = m_CursorLine;
+ m_CursorLine = m_CursorLine->DeleteLine(true, this);
+ n--;
+ if(line == m_FirstLine) m_FirstLine = m_CursorLine;
+ wxASSERT(m_FirstLine);
+ wxASSERT(m_CursorLine);
+ }
+ m_CursorLine->RecalculatePositions(2, this);
+ return n;
+}
+
+void
+wxLayoutList::Recalculate(wxDC &dc, CoordType bottom)
+{
+ wxLayoutLine *line = m_FirstLine;
+
+ // first, make sure everything is calculated - this might not be
+ // needed, optimise it later
+ ApplyStyle(m_DefaultSetting, dc);
+ while(line)
+ {
+ line->RecalculatePosition(this); // so we don't need to do it all the time
+ // little condition to speed up redrawing:
+ if(bottom != -1 && line->GetPosition().y > bottom) break;
+ line = line->GetNextLine();
+ }
+}
+
+void
+wxLayoutList::UpdateCursorScreenPos(wxDC &dc)
+{
+ wxASSERT(m_CursorLine);
+ m_CursorLine->Layout(dc, this, (wxPoint *)&m_CursorScreenPos, (wxPoint *)&m_CursorSize, m_CursorPos.x);
+}
+
+wxPoint
+wxLayoutList::GetCursorScreenPos(wxDC &dc)
+{
+ UpdateCursorScreenPos(dc);
+ return m_CursorScreenPos;
+}
+
+void
+wxLayoutList::Layout(wxDC &dc, CoordType bottom)
+{
+ wxLayoutLine *line = m_FirstLine;
+
+ // first, make sure everything is calculated - this might not be
+ // needed, optimise it later
+ ApplyStyle(m_DefaultSetting, dc);
+ while(line)
+ {
+ if(line == m_CursorLine)
+ line->Layout(dc, this, (wxPoint *)&m_CursorScreenPos, (wxPoint *)&m_CursorSize, m_CursorPos.x);
+ else
+ line->Layout(dc, this);
+ // little condition to speed up redrawing:
+ if(bottom != -1 && line->GetPosition().y > bottom) break;
+ line = line->GetNextLine();
+ }
+
+///FIXME: disabled for now
+#if 0
+ // can only be 0 if we are on the first line and have no next line
+ wxASSERT(m_CursorSize.x != 0 || (m_CursorLine &&
+ m_CursorLine->GetNextLine() == NULL &&
+ m_CursorLine == m_FirstLine));
+#endif
+ SetUpdateRect(m_CursorScreenPos);
+ SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+}
+
+void
+wxLayoutList::Draw(wxDC &dc,
+ wxPoint const &offset,
+ CoordType top,
+ CoordType bottom)
+{
+ wxLayoutLine *line = m_FirstLine;
+
+ Layout(dc, bottom);
+ ApplyStyle(m_DefaultSetting, dc);
+ wxBrush brush(m_ColourBG, wxSOLID);
+ dc.SetBrush(brush);
+
+ while(line)
+ {
+ // only draw if between top and bottom:
+ if((top == -1 || line->GetPosition().y + line->GetHeight() >= top))
+ line->Draw(dc, this, offset);
+ // little condition to speed up redrawing:
+ if(bottom != -1 && line->GetPosition().y > bottom) break;
+ line = line->GetNextLine();
+ }
+ InvalidateUpdateRect();
+
+ WXLO_DEBUG(("Selection is %s : l%d,%ld/%ld,%ld",
+ m_Selection.m_valid ? "valid" : "invalid",
+ m_Selection.m_CursorA.x, m_Selection.m_CursorA.y,
+ m_Selection.m_CursorB.x, m_Selection.m_CursorB.y));
+}
+
+wxLayoutObject *
+wxLayoutList::FindObjectScreen(wxDC &dc, wxPoint const pos,
+ wxPoint *cursorPos,
+ bool *found)
+{
+ // First, find the right line:
+ wxLayoutLine *line = m_FirstLine;
+ wxPoint p;
+
+ // we need to run a layout here to get font sizes right :-(
+ ApplyStyle(m_DefaultSetting, dc);
+ while(line)
+ {
+ p = line->GetPosition();
+ if(p.y <= pos.y && p.y+line->GetHeight() >= pos.y)
+ break;
+ line->Layout(dc, this);
+ line = line->GetNextLine();
+ }
+ if(line == NULL)
+ {
+ if(found) *found = false;
+ return NULL; // not found
+ }
+ if(cursorPos) cursorPos->y = line->GetLineNumber();
+ // Now, find the object in the line:
+ wxLOiterator i = line->FindObjectScreen(dc, pos.x,
+ cursorPos ? & cursorPos->x : NULL ,
+ found);
+ return (i == NULLIT) ? NULL : *i;
+
+}
+
+wxPoint
+wxLayoutList::GetSize(void) const
+{
+ wxLayoutLine
+ *line = m_FirstLine,
+ *last = line;
+ if(! line)
+ return wxPoint(0,0);
+
+ wxPoint maxPoint(0,0);
+
+ // find last line:
+ while(line)
+ {
+ if(line->GetWidth() > maxPoint.x)
+ maxPoint.x = line->GetWidth();
+ last = line;
+ line = line->GetNextLine();
+ }
+
+ maxPoint.y = last->GetPosition().y + last->GetHeight();
+ return maxPoint;
+}
+
+
+void
+wxLayoutList::DrawCursor(wxDC &dc, bool active, wxPoint const &translate)
+{
+ wxPoint coords;
+ coords = m_CursorScreenPos;
+ coords.x += translate.x;
+ coords.y += translate.y;
+
+#ifdef WXLAYOUT_DEBUG
+ WXLO_DEBUG(("Drawing cursor (%ld,%ld) at %ld,%ld, size %ld,%ld, line: %ld, len %ld",
+ (long)m_CursorPos.x, (long)m_CursorPos.y,
+ (long)coords.x, (long)coords.y,
+ (long)m_CursorSize.x, (long)m_CursorSize.y,
+ (long)m_CursorLine->GetLineNumber(),
+ (long)m_CursorLine->GetLength()));
+#endif
+
+ dc.SetBrush(*wxBLACK_BRUSH);
+ dc.SetLogicalFunction(wxXOR);
+ dc.SetPen(wxPen(*wxBLACK,1,wxSOLID));
+ if(active)
+ {
+ dc.DrawRectangle(coords.x, coords.y,
+ m_CursorSize.x, m_CursorSize.y);
+ SetUpdateRect(coords.x, coords.y);
+ SetUpdateRect(coords.x+m_CursorSize.x, coords.y+m_CursorSize.y);
+ }
+ else
+ {
+ dc.DrawLine(coords.x, coords.y+m_CursorSize.y-1,
+ coords.x, coords.y);
+ SetUpdateRect(coords.x, coords.y+m_CursorSize.y-1);
+ SetUpdateRect(coords.x, coords.y);
+ }
+ dc.SetLogicalFunction(wxCOPY);
+ //dc.SetBrush(wxNullBrush);
+}
+
+void
+wxLayoutList::SetUpdateRect(CoordType x, CoordType y)
+{
+ if(m_UpdateRectValid)
+ GrowRect(m_UpdateRect, x, y);
+ else
+ {
+ m_UpdateRect.x = x;
+ m_UpdateRect.y = y;
+ m_UpdateRect.width = 4; // large enough to avoid surprises from
+ m_UpdateRect.height = 4;// wxGTK :-)
+ m_UpdateRectValid = true;
+ }
+}
+
+void
+wxLayoutList::StartSelection(void)
+{
+ WXLO_DEBUG(("Starting selection at %ld/%ld", m_CursorPos.x, m_CursorPos.y));
+ m_Selection.m_CursorA = m_CursorPos;
+ m_Selection.m_CursorB = m_CursorPos;
+ m_Selection.m_selecting = true;
+ m_Selection.m_valid = false;
+}
+
+void
+wxLayoutList::ContinueSelection(void)
+{
+ wxASSERT(m_Selection.m_selecting == true);
+ wxASSERT(m_Selection.m_valid == false);
+ WXLO_DEBUG(("Continuing selection at %ld/%ld", m_CursorPos.x, m_CursorPos.y));
+ m_Selection.m_CursorB = m_CursorPos;
+ // We always want m_CursorA <= m_CursorB!
+ if(! (m_Selection.m_CursorA <= m_Selection.m_CursorB))
+ {
+ wxPoint help = m_Selection.m_CursorB;
+ m_Selection.m_CursorB = m_Selection.m_CursorA;
+ m_Selection.m_CursorA = help;
+ }
+}
+
+void
+wxLayoutList::EndSelection(void)
+{
+ ContinueSelection();
+ WXLO_DEBUG(("Ending selection at %ld/%ld", m_CursorPos.x, m_CursorPos.y));
+ m_Selection.m_selecting = false;
+ m_Selection.m_valid = true;
+}
+
+
+bool
+wxLayoutList::IsSelecting(void)
+{
+ return m_Selection.m_selecting;
+}
+
+bool
+wxLayoutList::IsSelected(const wxPoint &cursor)
+{
+ if(! m_Selection.m_valid && ! m_Selection.m_selecting)
+ return false;
+ return m_Selection.m_CursorA <= cursor
+ && cursor <= m_Selection.m_CursorB;
+}
+
+
+/** Tests whether this layout line is selected and needs
+ highlighting.
+ @param line to test for
+ @return 0 = not selected, 1 = fully selected, -1 = partially
+ selected
+ */
+int
+wxLayoutList::IsSelected(const wxLayoutLine *line, CoordType *from,
+ CoordType *to)
+{
+ wxASSERT(line); wxASSERT(to); wxASSERT(from);
+
+ if(! m_Selection.m_valid && ! m_Selection.m_selecting)