+bool
+wxLayoutList::Insert(wxString const &text)
+{
+ wxASSERT(m_CursorLine);
+
+ AddCursorPosToUpdateRect();
+
+ 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);
+
+ if(! m_CursorLine)
+ m_CursorLine = GetFirstLine();
+
+ AddCursorPosToUpdateRect();
+
+ m_CursorLine->Insert(m_CursorPos.x, obj);
+ m_CursorPos.x += obj->GetLength();
+ m_CursorLine->RecalculatePositions(true, this); //FIXME needed?
+ return true;
+}
+
+bool
+wxLayoutList::Insert(wxLayoutList *llist)
+{
+ wxASSERT(llist);
+ bool rc = TRUE;
+
+ for(wxLayoutLine *line = llist->GetFirstLine();
+ line;
+ line = line->GetNextLine()
+ )
+ {
+ for(wxLOiterator i = line->GetFirstObject();
+ i != NULLIT;
+ i++)
+ rc |= Insert(*i);
+ LineBreak();
+ }
+ return rc;
+}
+
+bool
+wxLayoutList::LineBreak(void)
+{
+ wxASSERT(m_CursorLine);
+ bool setFirst = (m_CursorLine == m_FirstLine && m_CursorPos.x == 0);
+
+ AddCursorPosToUpdateRect();
+
+ wxPoint position(m_CursorLine->GetPosition());
+
+ wxCoord width = m_CursorLine->GetWidth(),
+ 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)
+ m_CursorPos.y++;
+ m_CursorPos.x = 0;
+// doesn't help m_CursorLine.MarkDirty();
+
+ wxLayoutLine *prev = m_CursorLine->GetPreviousLine();
+ wxCHECK_MSG(prev, false, "just broke the line, where is the previous one?");
+
+ height += prev->GetHeight();
+
+ SetUpdateRect(position);
+ SetUpdateRect(position.x + width + MSW_CORRECTION,
+ position.y + height + MSW_CORRECTION);
+
+ 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;
+
+ AddCursorPosToUpdateRect();
+
+ LineBreak();
+ Delete(1); // delete the space
+ m_CursorPos.x = newpos;
+ m_CursorLine->RecalculatePositions(true, this); //FIXME needed?
+ return true;
+ }
+}
+
+bool
+wxLayoutList::Delete(CoordType npos)
+{
+ wxCHECK_MSG(m_CursorLine, false, "can't delete in non existing line");
+ wxASSERT_MSG(npos > 0, "nothing to delete?");
+
+ AddCursorPosToUpdateRect();
+
+ // were other lines appended to this one (this is important to know because
+ // this means that our width _increased_ as the result of deletion)
+ bool wasMerged = false;
+
+ // the size of the region to update
+ CoordType totalHeight = m_CursorLine->GetHeight(),
+ totalWidth = m_CursorLine->GetWidth();
+
+ CoordType left;
+ do
+ {
+ left = m_CursorLine->Delete(m_CursorPos.x, npos);
+
+ if( left > 0 )
+ {
+ // 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
+ {
+ wasMerged = true;
+ wxLayoutLine *next = m_CursorLine->GetNextLine();
+ if ( next )
+ totalHeight += next->GetHeight();
+ m_CursorLine->MergeNextLine(this);
+ left--;
+ }
+ }
+ }
+ }
+ while ( left> 0 );
+
+ // we need to update the whole tail of the line and the lines which
+ // disappeared
+ if ( wasMerged )
+ {
+ wxPoint position(m_CursorLine->GetPosition());
+ SetUpdateRect(position.x + totalWidth + MSW_CORRECTION,
+ position.y + totalHeight + MSW_CORRECTION);
+ }
+
+ return left == 0;
+}
+
+int
+wxLayoutList::DeleteLines(int n)
+{
+ wxASSERT(m_CursorLine);
+ wxLayoutLine *line;
+
+ AddCursorPosToUpdateRect();
+
+ 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;
+}
+
+/*
+ Is called before each Draw(). Now, it will re-layout all lines which
+ have changed.
+*/
+void
+wxLayoutList::Layout(wxDC &dc, CoordType bottom, bool forceAll)
+{
+ 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(forceAll || line->IsDirty())
+ {
+ line->GetStyleInfo() = m_CurrentSetting;
+ 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->RecalculatePositions(1,this);
+ 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
+ AddCursorPosToUpdateRect();
+}
+
+void
+wxLayoutList::Draw(wxDC &dc,
+ wxPoint const &offset,
+ CoordType top,
+ CoordType bottom)
+{
+ wxLayoutLine *line = m_FirstLine;
+
+ Layout(dc);
+ ApplyStyle(&m_DefaultSetting, dc);
+ wxBrush brush(m_CurrentSetting.m_bg, wxSOLID);
+ dc.SetBrush(brush);
+ dc.SetBackgroundMode(wxTRANSPARENT);
+
+ while(line)
+ {
+ // only draw if between top and bottom:
+ if((top == -1 || line->GetPosition().y + line->GetHeight() >= top))
+ line->Draw(dc, this, offset);
+ else
+ line->Layout(dc, this);
+ // 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(m_CursorScreenPos);
+ coords += translate;
+
+#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()));
+
+ wxLogStatus("Cursor is at (%d, %d)", m_CursorPos.x, m_CursorPos.y);
+#endif
+
+#ifdef WXLAYOUT_USE_CARET
+ m_caret->Move(coords);
+#else // !WXLAYOUT_USE_CARET
+ 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);
+#endif // WXLAYOUT_USE_CARET/!WXLAYOUT_USE_CARET
+}
+
+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(wxPoint cpos)
+{
+ if(cpos.x == -1)
+ cpos = m_CursorPos;
+ WXLO_DEBUG(("Starting selection at %ld/%ld", cpos.x, cpos.y));
+ m_Selection.m_CursorA = cpos;
+ m_Selection.m_CursorB = cpos;
+ m_Selection.m_selecting = true;
+ m_Selection.m_valid = false;
+}
+
+void
+wxLayoutList::ContinueSelection(wxPoint cpos)
+{
+ if(cpos.x == -1)
+ cpos = m_CursorPos;
+ wxASSERT(m_Selection.m_selecting == true);
+ wxASSERT(m_Selection.m_valid == false);
+ WXLO_DEBUG(("Continuing selection at %ld/%ld", cpos.x, cpos.y));
+ if(m_Selection.m_CursorB <= cpos)
+ m_Selection.m_CursorB = cpos;
+ else
+ m_Selection.m_CursorA = cpos;
+ // 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(wxPoint cpos)
+{
+ if(cpos.x == -1)
+ cpos = m_CursorPos;
+ ContinueSelection(cpos);
+ WXLO_DEBUG(("Ending selection at %ld/%ld", cpos.x, cpos.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)
+ return 0;
+
+ CoordType y = line->GetLineNumber();
+ if(m_Selection.m_CursorA.y < y && m_Selection.m_CursorB.y > y)
+ return 1;
+ else if(m_Selection.m_CursorA.y == y)
+ {
+ *from = m_Selection.m_CursorA.x;
+ if(m_Selection.m_CursorB.y == y)
+ *to = m_Selection.m_CursorB.x;
+ else
+ *to = line->GetLength();
+ return -1;
+ }
+ else if(m_Selection.m_CursorB.y == y)
+ {
+ *to = m_Selection.m_CursorB.x;
+ if(m_Selection.m_CursorA.y == y)
+ *from = m_Selection.m_CursorA.x;
+ else
+ *from = 0;
+ return -1;
+ }
+ else
+ return 0;
+}
+
+void
+wxLayoutList::DeleteSelection(void)
+{
+ if(! m_Selection.m_valid)
+ return;
+
+ m_Selection.m_valid = false;
+
+ // Only delete part of the current line?
+ if(m_Selection.m_CursorA.y == m_Selection.m_CursorB.y)
+ {
+ MoveCursorTo(m_Selection.m_CursorA);
+ Delete(m_Selection.m_CursorB.x - m_Selection.m_CursorA.x);
+ return;
+ }
+
+
+ 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:
+
+ // First, delete what's left of this line:
+ MoveCursorTo(m_Selection.m_CursorA);
+ DeleteToEndOfLine();
+
+ wxLayoutLine *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
+
+ /// Recalculate:
+ firstLine->RecalculatePositions(1, this);