*******************************************************************/
/*
-
+
*/
-
+
#ifdef __GNUG__
-#pragma implementation "wxllist.h"
+ #pragma implementation "wxllist.h"
#endif
-#include "Mpch.h"
+#include <wx/wxprec.h>
-
-#include "wx/wxprec.h"
#ifdef __BORLANDC__
# pragma hdrstop
#endif
+#include "Mpch.h"
+
#ifdef M_BASEDIR
# include "gui/wxllist.h"
+# include "gui/wxlparser.h"
# define SHOW_SELECTIONS 1
#else
# include "wxllist.h"
#endif
#ifndef USE_PCH
-# include "iostream.h"
-# include <wx/dc.h>
-# include <wx/dcps.h>
-# include <wx/print.h>
-# include <wx/log.h>
+# include <iostream.h>
+
+# include <wx/dc.h>
+# include <wx/dcps.h>
+# include <wx/print.h>
+# include <wx/log.h>
+# include <wx/filefn.h>
#endif
+#ifdef WXLAYOUT_USE_CARET
+# include <wx/caret.h>
+#endif // WXLAYOUT_USE_CARET
+
#include <ctype.h>
/// This should never really get created
#ifdef WXLAYOUT_DEBUG
-# define TypewxString(t) g_aTypewxStrings[t]
+# define TypeString(t) g_aTypeStrings[t]
# define WXLO_DEBUG(x) wxLogDebug x
- static const char *g_aTypewxStrings[] =
- {
+ static const char *g_aTypeStrings[] =
+ {
"invalid", "text", "cmd", "icon"
};
void
wxLayoutObject::Debug(void)
{
- WXLO_DEBUG(("%s",g_aTypewxStrings[GetType()]));
+ WXLO_DEBUG(("%s",g_aTypeStrings[GetType()]));
}
-#else
-# define TypewxString(t) ""
-# define WXLO_DEBUG(x)
+#else
+# define TypeString(t) ""
+# define WXLO_DEBUG(x)
#endif
+// FIXME under MSW, this constant is needed to make the thing properly redraw
+// itself - I don't know where the size calculation error is and I can't
+// waste time looking for it right now. Search for occurences of
+// MSW_CORRECTION to find all the places where I did it.
+#ifdef __WXMSW__
+ static const int MSW_CORRECTION = 5;
+#else
+ static const int MSW_CORRECTION = 0;
+#endif
/// Cursors smaller than this disappear in XOR drawing mode
#define WXLO_MINIMUM_CURSOR_WIDTH 4
#define WXLO_CURSORCHAR "E"
/** @name Helper functions */
//@{
-/// allows me to compare to wxPoints
-bool operator ==(wxPoint const &p1, wxPoint const &p2)
-{
- return p1.x == p2.x && p1.y == p2.y;
-}
-
-/// allows me to compare to wxPoints
-bool operator !=(wxPoint const &p1, wxPoint const &p2)
-{
- return p1.x != p2.x || p1.y != p2.y;
-}
-
/// allows me to compare to wxPoints
bool operator <=(wxPoint const &p1, wxPoint const &p2)
{
r.x = x;
else if(r.x + r.width < x)
r.width = x - r.x;
-
+
if(r.y > y)
r.y = y;
else if(r.y + r.height < y)
//@}
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+void ReadString(wxString &to, wxString &from)
+{
+ to = "";
+ const char *cptr = from.c_str();
+ while(*cptr && *cptr != '\n')
+ to += *cptr++;
+ if(*cptr) cptr++;
+ from = cptr;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ wxLayoutObject
+
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* static */
+wxLayoutObject *
+wxLayoutObject::Read(wxString &istr)
+{
+ wxString tmp;
+ ReadString(tmp, istr);
+ int type = -1;
+ sscanf(tmp.c_str(),"%d", &type);
+
+ switch(type)
+ {
+ case WXLO_TYPE_TEXT:
+ return wxLayoutObjectText::Read(istr);
+ case WXLO_TYPE_CMD:
+ return wxLayoutObjectCmd::Read(istr);
+ case WXLO_TYPE_ICON:
+ return wxLayoutObjectIcon::Read(istr);
+ default:
+ return NULL;
+ }
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
wxLayoutObjectText
return obj;
}
+
+void
+wxLayoutObjectText::Write(wxString &ostr)
+{
+ ostr << (int) WXLO_TYPE_TEXT << '\n'
+ << m_Text << '\n';
+}
+/* static */
+wxLayoutObjectText *
+wxLayoutObjectText::Read(wxString &istr)
+{
+ wxString text;
+ ReadString(text, istr);
+
+ return new wxLayoutObjectText(text);
+}
+
wxPoint
wxLayoutObjectText::GetSize(CoordType *top, CoordType *bottom) const
{
wxLayoutList *wxllist,
CoordType begin, CoordType end)
{
- if(begin == -1)
+ if( end <= 0)
dc.DrawText(m_Text, coords.x, coords.y-m_Top);
else
{
xpos = coords.x,
ypos = coords.y-m_Top;
long width, height, descent;
-
+
+ if(begin < 0) begin = 0;
+ if( end > (signed)m_Text.Length() )
+ end = m_Text.Length();
+
str = m_Text.Mid(0, begin);
dc.DrawText(str, xpos, ypos);
dc.GetTextExtent(str, &width, &height, &descent);
height, descent = 0l;
if(xpos == 0) return 0; // easy
-
+
while(width < xpos && offs < maxlen)
{
dc.GetTextExtent(m_Text.substr(0,offs),
&width, &height, &descent);
offs++;
}
- /* We have to substract 1 to compensate for the offs++, and another
+ /* We have to substract 1 to compensate for the offs++, and another
one because we don't want to position the cursor behind the
object what we clicked on, but before - otherwise it looks
funny. */
- return (xpos > 2) ? offs-2 : 0;
+ return (xpos > 2) ? offs-2 : 0;
}
void
-wxLayoutObjectText::Layout(wxDC &dc, class wxLayoutList * )
+wxLayoutObjectText::Layout(wxDC &dc, class wxLayoutList *llist)
{
long descent = 0l;
- dc.GetTextExtent(m_Text,&m_Width, &m_Height, &descent);
+ // now this is done in wxLayoutLine::Layout(), but this code might be
+ // reenabled later - in principle, it's more efficient
+#if 0
+ CoordType widthOld = m_Width,
+ heightOld = m_Height;
+#endif // 0
+
+ dc.GetTextExtent(m_Text, &m_Width, &m_Height, &descent);
+
+#if 0
+ if ( widthOld != m_Width || heightOld != m_Height )
+ {
+ // as the text length changed, it must be refreshed
+ wxLayoutLine *line = GetLine();
+
+ wxCHECK_RET( line, "wxLayoutObjectText can't refresh itself" );
+
+ // as our size changed, we need to repaint the part which was appended
+ wxPoint position(line->GetPosition());
+
+ // this is not the most efficient way (we repaint the whole line), but
+ // it's not too slow and is *simple*
+ if ( widthOld < m_Width )
+ widthOld = m_Width;
+ if ( heightOld < m_Height )
+ heightOld = m_Height;
+
+ llist->SetUpdateRect(position.x + widthOld + MSW_CORRECTION,
+ position.y + heightOld + MSW_CORRECTION);
+ }
+#endif // 0
+
m_Bottom = descent;
m_Top = m_Height - m_Bottom;
}
+
#ifdef WXLAYOUT_DEBUG
void
wxLayoutObjectText::Debug(void)
}
#endif
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
wxLayoutObjectIcon
m_Icon = new wxBitmap(icon);
}
+
+void
+wxLayoutObjectIcon::Write(wxString &ostr)
+{
+ /* Exports icon through a temporary file. */
+
+ wxString file = wxGetTempFileName("wxloexport");
+
+ ostr << WXLO_TYPE_ICON << '\n'
+ << file << '\n';
+ m_Icon->SaveFile(file, WXLO_BITMAP_FORMAT);
+}
+/* static */
+wxLayoutObjectIcon *
+wxLayoutObjectIcon::Read(wxString &istr)
+{
+ wxString file;
+ ReadString(file, istr);
+
+ if(! wxFileExists(file))
+ return NULL;
+ wxLayoutObjectIcon *obj = new wxLayoutObjectIcon;
+
+ if(!obj->m_Icon->LoadFile(file, WXLO_BITMAP_FORMAT))
+ {
+ delete obj;
+ return NULL;
+ }
+ else
+ return obj;
+}
+
wxLayoutObject *
wxLayoutObjectIcon::Copy(void)
{
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
wxLayoutObjectCmd
{
family = ifamily; size = isize;
style = istyle; weight = iweight;
- underline = iul;
+ underline = iul != 0;
if(fg)
{
m_fg = *fg;
wxLayoutObjectCmd::wxLayoutObjectCmd(int family, int size, int style, int
weight, int underline,
wxColour *fg, wxColour *bg)
-
+
{
m_StyleInfo = new wxLayoutStyleInfo(family, size,style,weight,underline,fg,bg);
}
return obj;
}
+void
+wxLayoutObjectCmd::Write(wxString &ostr)
+{
+ ostr << WXLO_TYPE_CMD << '\n'
+ << m_StyleInfo->size << '\n'
+ << m_StyleInfo->family << '\n'
+ << m_StyleInfo->style << '\n'
+ << m_StyleInfo->weight << '\n'
+ << m_StyleInfo->underline << '\n'
+ << m_StyleInfo->m_fg_valid << '\n'
+ << m_StyleInfo->m_bg_valid << '\n';
+ if(m_StyleInfo->m_fg_valid)
+ {
+ ostr << m_StyleInfo->m_fg.Red() << '\n'
+ << m_StyleInfo->m_fg.Green() << '\n'
+ << m_StyleInfo->m_fg.Blue() << '\n';
+ }
+ if(m_StyleInfo->m_bg_valid)
+ {
+ ostr << m_StyleInfo->m_bg.Red() << '\n'
+ << m_StyleInfo->m_bg.Green() << '\n'
+ << m_StyleInfo->m_bg.Blue() << '\n';
+ }
+}
+/* static */
+wxLayoutObjectCmd *
+wxLayoutObjectCmd::Read(wxString &istr)
+{
+ wxLayoutObjectCmd *obj = new wxLayoutObjectCmd;
+
+ wxString tmp;
+ ReadString(tmp, istr);
+ sscanf(tmp.c_str(),"%d", &obj->m_StyleInfo->size);
+ ReadString(tmp, istr);
+ sscanf(tmp.c_str(),"%d", &obj->m_StyleInfo->family);
+ ReadString(tmp, istr);
+ sscanf(tmp.c_str(),"%d", &obj->m_StyleInfo->style);
+ ReadString(tmp, istr);
+ sscanf(tmp.c_str(),"%d", &obj->m_StyleInfo->weight);
+ ReadString(tmp, istr);
+ sscanf(tmp.c_str(),"%d", &obj->m_StyleInfo->underline);
+ ReadString(tmp, istr);
+ sscanf(tmp.c_str(),"%d", &obj->m_StyleInfo->m_fg_valid);
+ ReadString(tmp, istr);
+ sscanf(tmp.c_str(),"%d", &obj->m_StyleInfo->m_bg_valid);
+ if(obj->m_StyleInfo->m_fg_valid)
+ {
+ int red, green, blue;
+ ReadString(tmp, istr);
+ sscanf(tmp.c_str(),"%d", &red);
+ ReadString(tmp, istr);
+ sscanf(tmp.c_str(),"%d", &green);
+ ReadString(tmp, istr);
+ sscanf(tmp.c_str(),"%d", &blue);
+ obj->m_StyleInfo->m_fg = wxColour(red, green, blue);
+ }
+ if(obj->m_StyleInfo->m_bg_valid)
+ {
+ int red, green, blue;
+ ReadString(tmp, istr);
+ sscanf(tmp.c_str(),"%d", &red);
+ ReadString(tmp, istr);
+ sscanf(tmp.c_str(),"%d", &green);
+ ReadString(tmp, istr);
+ sscanf(tmp.c_str(),"%d", &blue);
+ obj->m_StyleInfo->m_bg = wxColour(red, green, blue);
+ }
+ return obj;
+}
+
wxLayoutObjectCmd::~wxLayoutObjectCmd()
{
}
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
The wxLayoutLine object
m_LineNumber = 0;
m_Width = m_Height = 0;
m_Length = 0;
- m_Dirty = true;
+ MarkDirty(0);
m_Previous = prev;
m_Next = NULL;
RecalculatePosition(llist);
{
wxASSERT(m_Previous || GetLineNumber() == 0);
+ wxPoint posOld(m_Position);
+
if(m_Previous)
{
m_Position = m_Previous->GetPosition();
}
else
m_Position = wxPoint(0,0);
- llist->SetUpdateRect(m_Position);
+
+ if ( m_Position != posOld )
+ {
+ // the whole line moved and must be repainted
+ llist->SetUpdateRect(m_Position);
+ llist->SetUpdateRect(m_Position.x + GetWidth() + MSW_CORRECTION,
+ m_Position.y + GetHeight() + MSW_CORRECTION);
+ llist->SetUpdateRect(posOld);
+ llist->SetUpdateRect(posOld.x + GetWidth() + MSW_CORRECTION,
+ posOld.y + GetHeight() + MSW_CORRECTION);
+ }
+
return m_Position;
}
void
wxLayoutLine::RecalculatePositions(int recurse, wxLayoutList *llist)
{
+ //FIXME: is this really needed? We run Layout() anyway.
+ // Recursing here, drives computation time up exponentially, as
+ // each line will cause all following lines to be recalculated.
+ // Yes, or linenumbers go wrong.
+
wxASSERT(recurse >= 0);
wxPoint pos = m_Position;
CoordType height = m_Height;
-
+
// WXLO_TRACE("RecalculatePositions()");
RecalculatePosition(llist);
if(m_Next)
if(recurse > 0)
m_Next->RecalculatePositions(--recurse, llist);
else if(pos != m_Position || m_Height != height)
- m_Next->RecalculatePositions(0, llist);
+ m_Next->RecalculatePositions(0, llist);
}
}
i,
found = NULLIT;
CoordType x = 0, len;
-
+
/* We search through the objects. As we don't like returning the
object that the cursor is behind, we just remember such an
object in "found" so we can return it if there is really no
wxASSERT(cxpos);
wxLayoutObjectList::iterator i;
CoordType x = 0, cx = 0, width;
-
+
for(i = m_ObjectList.begin(); i != NULLIT; i++)
{
width = (**i).GetWidth();
cpos = 0,
relpos = -1;
wxString const *text;
-
+
for(wxLOiterator i = m_ObjectList.begin(); i != m_ObjectList.end(); i++)
{
if(cpos >= xpos) // search from here!
{
wxASSERT(xpos >= 0);
wxASSERT(obj != NULL);
- //FIXME: this could be optimised, for now be prudent:
- m_Dirty = true;
+
+ MarkDirty(xpos);
+
CoordType offset;
wxLOiterator i = FindObject(xpos, &offset);
if(i == NULLIT)
m_ObjectList.insert(i,new wxLayoutObjectText(left));
return true;
}
-
+
bool
-wxLayoutLine::Insert(CoordType xpos, wxString text)
+wxLayoutLine::Insert(CoordType xpos, const wxString& text)
{
wxASSERT(xpos >= 0);
- //FIXME: this could be optimised, for now be prudent:
- m_Dirty = true;
+
+ MarkDirty(xpos);
+
CoordType offset;
wxLOiterator i = FindObject(xpos, &offset);
if(i != NULLIT && (**i).GetType() == WXLO_TYPE_TEXT)
wxLayoutObjectText *tobj = (wxLayoutObjectText *) *i;
tobj->GetText().insert(offset, text);
m_Length += text.Length();
-
- return true;
}
else
- return Insert(xpos, new wxLayoutObjectText(text));
+ {
+ if ( !Insert(xpos, new wxLayoutObjectText(text)) )
+ return false;
+ }
+
+ return true;
}
CoordType
wxASSERT(xpos >= 0);
wxASSERT(npos >= 0);
- //FIXME: this could be optimised, for now be prudent:
- m_Dirty = true;
+ MarkDirty(xpos);
wxLOiterator i = FindObject(xpos, &offset);
while(npos > 0)
{
{
if(xpos == GetLength())
return npos;
- else
+ else
{ // at the end of an object
// move to begin of next object:
i++; offset = 0;
((wxLayoutObjectText *)(*i))->GetText().Remove(offset,max);
}
}
+
return npos;
}
{
wxASSERT(xpos >= 0);
CoordType offset;
- //FIXME: this could be optimised, for now be prudent:
- m_Dirty = true;
+ MarkDirty(xpos);
wxLOiterator i = FindObject(xpos, &offset);
if(i == NULLIT) return false;
if((**i).GetType() != WXLO_TYPE_TEXT)
{
- // This should only happen when at end of line, behind a non-text
+ // This should only happen when at end of line, behind a non-text
// object:
if(offset == (**i).GetLength()) return false;
m_Length -= (**i).GetLength(); // -1
((wxLayoutObjectText *)*i)->GetText().erase(offset,count);
m_Length -= count;
return true;
- }
+ }
}
wxASSERT(0); // we should never arrive here
}
wxLayoutObjectList::iterator i;
wxPoint pos = offset;
pos = pos + GetPosition();
-
+
pos.y += m_BaseLine;
CoordType xpos = 0; // cursorpos, lenght of line
{
// parts of the line need highlighting
tempto = xpos+(**i).GetLength();
- if(tempto >= from && xpos <= to)
- {
- tempto = to-xpos;
- if(tempto > (**i).GetLength())
- tempto = (**i).GetLength();
- CoordType tmp = from-xpos;
- if(tmp < 0) tmp = 0;
- (**i).Draw(dc, pos, llist, from-xpos, tempto);
- }
- else
- {
- llist->EndHighlighting(dc); // FIXME! inefficient
- (**i).Draw(dc, pos, llist);
- }
+ (**i).Draw(dc, pos, llist, from-xpos, to-xpos);
}
else
(**i).Draw(dc, pos, llist);
wxLayoutList *llist,
wxPoint *cursorPos,
wxPoint *cursorSize,
- int cx)
+ int cx)
{
wxLayoutObjectList::iterator i;
+ // when a line becomes dirty, we redraw it from the place where it was
+ // changed till the end of line (because the following wxLayoutObjects are
+ // moved when the preceding one changes) - calculate the update rectangle.
+ CoordType updateTop = m_Position.y,
+ updateLeft = -1,
+ updateWidth = m_Width,
+ updateHeight = m_Height;
+
CoordType
- oldHeight = m_Height;
- CoordType
- topHeight, bottomHeight; // above and below baseline
+ topHeight = 0,
+ bottomHeight = 0; // above and below baseline
CoordType
- objHeight = 0,
- objTopHeight, objBottomHeight;
+ objTopHeight, objBottomHeight; // above and below baseline
CoordType
len, count = 0;
- m_Height = 0; m_BaseLine = 0;
+
+ CoordType heightOld = m_Height;
+
+ m_Height = 0;
m_Width = 0;
- topHeight = 0; bottomHeight = 0;
- wxPoint size;
+ m_BaseLine = 0;
+
bool cursorFound = false;
- m_Dirty = false;
-
if(cursorPos)
{
*cursorPos = m_Position;
//llist->ApplyStyle(&m_StyleInfo, dc);
for(i = m_ObjectList.begin(); i != NULLIT; i++)
{
- (**i).Layout(dc, llist);
- size = (**i).GetSize(&objTopHeight, &objBottomHeight);
+ wxLayoutObject *obj = *i;
+ obj->Layout(dc, llist);
+ wxPoint sizeObj = obj->GetSize(&objTopHeight, &objBottomHeight);
if(cursorPos && ! cursorFound)
- { // we need to check whether the text cursor is here
- len = (**i).GetLength();
+ {
+ // we need to check whether the text cursor is here
+ len = obj->GetLength();
if(count <= cx && count+len > cx)
{
- if((**i).GetType() == WXLO_TYPE_TEXT)
+ if(obj->GetType() == WXLO_TYPE_TEXT)
{
len = cx - count; // pos in object
CoordType width, height, descent;
- dc.GetTextExtent((*(wxLayoutObjectText*)*i).GetText().substr(0,len),
+ dc.GetTextExtent((*(wxLayoutObjectText*)*i).GetText().substr(0,len),
&width, &height, &descent);
cursorPos->x += width;
cursorPos->y = m_Position.y;
wxString str;
- if(len < (**i).GetLength())
+ if(len < obj->GetLength())
str = (*(wxLayoutObjectText*)*i).GetText().substr(len,1);
else
str = WXLO_CURSORCHAR;
wxASSERT(cursorSize);
// Just in case some joker inserted an empty string object:
if(width == 0) width = WXLO_MINIMUM_CURSOR_WIDTH;
- if(height == 0) height = objHeight;
+ if(height == 0) height = sizeObj.y;
cursorSize->x = width;
cursorSize->y = height;
cursorFound = true; // no more checks
}
- else
- { // on some other object
+ else
+ {
+ // on some other object
CoordType top, bottom; // unused
- *cursorSize = (**i).GetSize(&top,&bottom);
+ *cursorSize = obj->GetSize(&top,&bottom);
cursorPos->y = m_Position.y;
cursorFound = true; // no more checks
}
else
{
count += len;
- cursorPos->x += (**i).GetWidth();
+ cursorPos->x += obj->GetWidth();
}
} // cursor finding
- objHeight = size.y;
- m_Width += size.x;
- if(objHeight > m_Height) m_Height = objHeight;
- if(objTopHeight > topHeight) topHeight = objTopHeight;
- if(objBottomHeight > bottomHeight) bottomHeight = objBottomHeight;
- }
- if(topHeight + bottomHeight > m_Height) m_Height =
- topHeight+bottomHeight;
+
+ m_Width += sizeObj.x;
+ if(sizeObj.y > m_Height)
+ {
+ m_Height = sizeObj.y;
+ }
+
+ if(objTopHeight > topHeight)
+ topHeight = objTopHeight;
+ if(objBottomHeight > bottomHeight)
+ bottomHeight = objBottomHeight;
+ }
+
+ if ( IsDirty() )
+ {
+ if ( updateHeight < m_Height )
+ updateHeight = m_Height;
+ if ( updateWidth < m_Width )
+ updateWidth = m_Width;
+
+ // update all line if we don't know where to start from
+ if ( updateLeft == -1 )
+ updateLeft = 0;
+
+ llist->SetUpdateRect(updateLeft, updateTop);
+ llist->SetUpdateRect(updateLeft + updateWidth + MSW_CORRECTION,
+ updateTop + updateHeight + MSW_CORRECTION);
+ }
+
+ if(topHeight + bottomHeight > m_Height)
+ {
+ m_Height = topHeight+bottomHeight;
+ }
+
m_BaseLine = topHeight;
if(m_Height == 0)
m_BaseLine = m_Height - descent;
}
-
// tell next line about coordinate change
- if(m_Next && objHeight != oldHeight)
+ if(m_Next && m_Height != heightOld)
+ {
+ // FIXME isn't this done in RecalculatePositions() below anyhow?
m_Next->RecalculatePositions(0, llist);
+ }
// We need to check whether we found a valid cursor size:
if(cursorPos)
if(m_BaseLine >= cursorSize->y) // the normal case anyway
cursorPos->y += m_BaseLine-cursorSize->y;
}
+
RecalculatePositions(1, llist);
+
+ MarkClean();
}
wxLayoutLine::Break(CoordType xpos, wxLayoutList *llist)
{
wxASSERT(xpos >= 0);
- //FIXME: this could be optimised, for now be prudent:
- m_Dirty = true;
-
- if(xpos == 0)
+
+ MarkDirty(xpos);
+
+ /* If we are at the begin of a line, we want to move all other
+ lines down and stay with the cursor where we are. However, if we
+ are in an empty line, we want to move down with it. */
+ if(xpos == 0 && GetLength() > 0)
{ // insert an empty line before this one
wxLayoutLine *prev = new wxLayoutLine(m_Previous, llist);
if(m_Previous == NULL)
// before this.
prev->m_Next = this;
m_Previous = prev;
- m_Previous->m_Height = GetHeight(); // this is a wild guess
+ m_Previous->m_Height = 0; // this is a wild guess
}
- MoveLines(+1);
if(m_Next)
m_Next->RecalculatePositions(1, llist);
- return this;
+ return m_Previous;
}
-
+
CoordType offset;
wxLOiterator i = FindObject(xpos, &offset);
if(i == NULLIT)
i++; // don't move this object to the new list
}
else
+ {
if(offset > 0)
i++; // move objects from here to new list
+ }
while(i != m_ObjectList.end())
{
- newLine->Append(*i);
- m_Length -= (**i).GetLength();
+ wxLayoutObject *obj = *i;
+ newLine->Append(obj);
+ m_Length -= obj->GetLength();
+
m_ObjectList.remove(i); // remove without deleting it
}
if(m_Next)
m_Next->RecalculatePositions(2, llist);
return newLine;
}
-
+
void
wxLayoutLine::MergeNextLine(wxLayoutList *llist)
{
- wxASSERT(GetNextLine());
+ wxCHECK_RET(GetNextLine(),"wxLayout internal error: no next line to merge");
wxLayoutObjectList &list = GetNextLine()->m_ObjectList;
wxLOiterator i;
- //FIXME: this could be optimised, for now be prudent:
- m_Dirty = true;
-
+
+ MarkDirty(GetWidth());
+
+ wxLayoutObject *last = NULL;
for(i = list.begin(); i != list.end();)
{
- Append(*i);
- list.remove(i); // remove without deleting it
+ wxLayoutObject *current = *i;
+
+ // merge text objects together for efficiency
+ if ( last && last->GetType() == WXLO_TYPE_TEXT &&
+ current->GetType() == WXLO_TYPE_TEXT )
+ {
+ wxLayoutObjectText *textObj = (wxLayoutObjectText *)last;
+ wxString text(textObj->GetText());
+ text += ((wxLayoutObjectText *)current)->GetText();
+ textObj->SetText(text);
+
+ list.erase(i); // remove and delete it
+ }
+ else
+ {
+ // just append the object "as was"
+ Append(current);
+
+ list.remove(i); // remove without deleting it
+ }
}
wxASSERT(list.empty());
+
wxLayoutLine *oldnext = GetNextLine();
- SetNext(GetNextLine()->GetNextLine());
+ wxLayoutLine *nextLine = oldnext->GetNextLine();
+ SetNext(nextLine);
+ if ( nextLine )
+ {
+ nextLine->MoveLines(-1);
+ }
+ else
+ {
+ // this is now done in Delete(), but if this function is ever called
+ // from elsewhere, we might have to move refresh code back here (in
+ // order not to duplicate it)
+#if 0
+ wxPoint pos(oldnext->GetPosition());
+ llist->SetUpdateRect(pos);
+ llist->SetUpdateRect(pos.x + oldnext->GetWidth() + MSW_CORRECTION,
+ pos.y + oldnext->GetHeight() + MSW_CORRECTION);
+#endif // 0
+ }
+
delete oldnext;
- RecalculatePositions(1, llist);
}
CoordType
wxLOiterator i = FindObject(column, &offset);
if(i == NULLIT) return -1; // cannot wrap
- // go backwards through the list and look for space in text objects
+ // go backwards through the list and look for space in text objects
do
{
if((**i).GetType() == WXLO_TYPE_TEXT)
pos -= (**i).GetLength();
return pos; // in front of it
}
-
+
#ifdef WXLAYOUT_DEBUG
void
CoordType firstOffset, lastOffset;
if(to == -1) to = GetLength();
-
+ if(from == to) return;
+
wxLOiterator first = FindObject(from, &firstOffset);
wxLOiterator last = FindObject(to, &lastOffset);
// Common special case: only one object
- if( *first == *last )
+ if( first != NULLIT && last != NULLIT && *first == *last )
{
if( (**first).GetType() == WXLO_TYPE_TEXT )
{
}
}
- // If we reach here, we can safely copy the whole first object from
+ // If we reach here, we can safely copy the whole first object from
// the firstOffset position on:
if((**first).GetType() == WXLO_TYPE_TEXT && firstOffset != 0)
{
else if(firstOffset == 0)
llist->Insert( (**first).Copy() );
// else nothing to copy :-(
-
+
// Now we copy all objects before the last one:
wxLOiterator i = first; i++;
for( ; i != last; i++)
}
}
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-
+
The wxLayoutList object
-
+
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
wxLayoutList::wxLayoutList()
{
+#ifdef WXLAYOUT_USE_CARET
+ m_caret = NULL;
+#endif // WXLAYOUT_USE_CARET
+
m_FirstLine = NULL;
InvalidateUpdateRect();
Clear();
m_DefaultSetting.m_fg = *wxBLACK;
m_DefaultSetting.m_bg_valid = TRUE;
m_DefaultSetting.m_bg = *wxWHITE;
-
+
m_CurrentSetting = m_DefaultSetting;
}
cfg = wxTheColourDatabase->FindColour(fg);
if( bg )
cbg = wxTheColourDatabase->FindColour(bg);
-
+
SetFont(family,size,style,weight,underline,cfg,cbg);
}
wxLayoutList::FindText(const wxString &needle, const wxPoint &cpos) const
{
int xpos;
-
+
wxLayoutLine *line;
for(line = m_FirstLine;
line;
bool
wxLayoutList::MoveCursorTo(wxPoint const &p)
{
- SetUpdateRect(m_CursorScreenPos);
- SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+ AddCursorPosToUpdateRect();
+
wxLayoutLine *line = m_FirstLine;
while(line && line->GetLineNumber() != p.y)
line = line->GetNextLine();
}
return false;
}
-
+
bool
wxLayoutList::MoveCursorVertically(int n)
{
- SetUpdateRect(m_CursorScreenPos);
- SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+ AddCursorPosToUpdateRect();
+
bool rc;
if(n < 0) // move up
{
bool
wxLayoutList::MoveCursorHorizontally(int n)
{
- SetUpdateRect(m_CursorScreenPos);
- SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+ AddCursorPosToUpdateRect();
+
int move;
while(n < 0)
{
wxLayoutList::Insert(wxString const &text)
{
wxASSERT(m_CursorLine);
- SetUpdateRect(m_CursorScreenPos);
- SetUpdateRect(m_CursorScreenPos+m_CursorSize);
- m_CursorLine->Insert(m_CursorPos.x, text);
+ wxASSERT_MSG( text.Find('\n') == wxNOT_FOUND, "use wxLayoutImportText!" );
+
+ if ( !text )
+ return true;
+
+ AddCursorPosToUpdateRect();
+
+ if ( !m_CursorLine->Insert(m_CursorPos.x, text) )
+ return false;
+
m_CursorPos.x += text.Length();
- m_CursorLine->RecalculatePositions(true, this); //FIXME needed?
+
+ m_CursorLine->RecalculatePositions(0, this);
+
return true;
}
wxLayoutList::Insert(wxLayoutObject *obj)
{
wxASSERT(m_CursorLine);
- SetUpdateRect(m_CursorScreenPos);
- SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+
+ 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?
+
+ m_CursorLine->RecalculatePositions(0, this);
+
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);
- SetUpdateRect(m_CursorScreenPos);
- SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+
+ 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();
- m_CursorPos.y++;
+ if(m_CursorPos.x != 0)
+ m_CursorPos.y++;
m_CursorPos.x = 0;
- m_CursorLine->RecalculatePositions(true, this); //FIXME needed?
+// 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;
}
//else:
CoordType newpos = m_CursorPos.x - xpos - 1;
m_CursorPos.x = xpos;
- SetUpdateRect(m_CursorScreenPos);
- SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+
+ AddCursorPosToUpdateRect();
+
LineBreak();
Delete(1); // delete the space
m_CursorPos.x = newpos;
- m_CursorLine->RecalculatePositions(true, this); //FIXME needed?
+
+ m_CursorLine->RecalculatePositions(1, this);
+
return true;
}
}
bool
wxLayoutList::Delete(CoordType npos)
{
- wxASSERT(m_CursorLine);
- SetUpdateRect(m_CursorScreenPos);
- SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+ 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)
- 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);
+
+ 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);
+ DeleteLines(1);
#endif
-
- left--;
- }
- else
- {
- // Need to join next line
- if(! m_CursorLine->GetNextLine())
- break; // cannot
+
+ left--;
+ }
else
{
- m_CursorLine->MergeNextLine(this);
- left--;
+ // Need to join next line
+ if(! m_CursorLine->GetNextLine())
+ break; // cannot
+ else
+ {
+ wasMerged = true;
+ wxLayoutLine *next = m_CursorLine->GetNextLine();
+ if ( next )
+ {
+ totalHeight += next->GetHeight();
+ totalWidth += next->GetWidth();
+
+ m_CursorLine->MergeNextLine(this);
+ left--;
+ }
+ else
+ {
+ wxFAIL_MSG("can't delete all this");
+
+ return false;
+ }
+ }
}
}
}
- while(left);
- m_CursorLine->RecalculatePositions(true, this); //FIXME needed?
+ 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);
+ SetUpdateRect(position.x + totalWidth + MSW_CORRECTION,
+ position.y + totalHeight + MSW_CORRECTION);
+ }
+
return left == 0;
}
{
wxASSERT(m_CursorLine);
wxLayoutLine *line;
- SetUpdateRect(m_CursorScreenPos);
- SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+
+ AddCursorPosToUpdateRect();
+
while(n > 0)
{
if(!m_CursorLine->GetNextLine())
}
/*
- Is called before each Draw(). Now, it will re-layout all lines which
+ 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);
+
+ // FIXME this is completely wrong - we should start by first *visible* line
+ // (and stop on the last one) instead of looping over all lines!!
+ wxLayoutLine *line = m_FirstLine;
while(line)
{
if(forceAll || line->IsDirty())
(wxPoint *)&m_CursorSize, m_CursorPos.x);
else
line->Layout(dc, this);
- line->RecalculatePosition(this);
- // little condition to speed up redrawing:
- if(bottom != -1 && line->GetPosition().y > bottom) break;
+
+ // little condition to speed up redrawing:
+ if(bottom != -1 && line->GetPosition().y > bottom)
+ break;
}
+
+ line->RecalculatePositions(1, this);
line = line->GetNextLine();
}
m_CursorLine->GetNextLine() == NULL &&
m_CursorLine == m_FirstLine));
#endif
- SetUpdateRect(m_CursorScreenPos);
- SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+ AddCursorPosToUpdateRect();
}
void
{
wxLayoutLine *line = m_FirstLine;
- Layout(dc);
+ 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();
// 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;
+#if 0
+ // we need to run a layout here to get font sizes right :-(
+
+ // VZ: we can't call Layout() from here because it marks the line as
+ // clean and it is not refreshed when it's called from wxLayoutList::
+ // Layout() - if we really need to do this, we should introduce an
+ // extra argument to Layout() to prevent the line from MarkClean()ing
+ // itself here
line->Layout(dc, this);
+#endif
line = line->GetNextLine();
}
if(line == NULL)
cursorPos ? & cursorPos->x : NULL ,
found);
return (i == NULLIT) ? NULL : *i;
-
+
}
wxPoint
return wxPoint(0,0);
wxPoint maxPoint(0,0);
-
+
// find last line:
while(line)
{
void
wxLayoutList::DrawCursor(wxDC &dc, bool active, wxPoint const &translate)
{
- wxPoint coords;
- coords = m_CursorScreenPos;
- coords.x += translate.x;
- coords.y += translate.y;
+ 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_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));
}
dc.SetLogicalFunction(wxCOPY);
//dc.SetBrush(wxNullBrush);
+#endif // WXLAYOUT_USE_CARET/!WXLAYOUT_USE_CARET
}
void
}
void
-wxLayoutList::StartSelection(void)
+wxLayoutList::StartSelection(wxPoint cpos)
{
- 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;
+ 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(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", m_CursorPos.x, m_CursorPos.y));
- m_Selection.m_CursorB = m_CursorPos;
+ 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))
{
}
void
-wxLayoutList::EndSelection(void)
+wxLayoutList::EndSelection(wxPoint cpos)
{
- ContinueSelection();
- WXLO_DEBUG(("Ending selection at %ld/%ld", m_CursorPos.x, m_CursorPos.y));
+ 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;
}
return;
m_Selection.m_valid = false;
-
+
// Only delete part of the current line?
if(m_Selection.m_CursorA.y == m_Selection.m_CursorB.y)
{
Delete(1); // This joins firstLine and nextLine
Delete(m_Selection.m_CursorB.x); // This deletes the first x
// positions
-
+
/// Recalculate:
firstLine->RecalculatePositions(1, this);
}
-
+
/// Starts highlighting the selection
void
wxLayoutList::StartHighlighting(wxDC &dc)
#if SHOW_SELECTIONS
dc.SetTextForeground(m_CurrentSetting.m_bg);
dc.SetTextBackground(m_CurrentSetting.m_fg);
+ dc.SetBackgroundMode(wxSOLID);
#endif
}
#if SHOW_SELECTIONS
dc.SetTextForeground(m_CurrentSetting.m_fg);
dc.SetTextBackground(m_CurrentSetting.m_bg);
+ dc.SetBackgroundMode(wxTRANSPARENT);
#endif
}
}
wxLayoutList *
-wxLayoutList::GetSelection(void)
+wxLayoutList::GetSelection(wxLayoutDataObject *wxlo, bool invalidate)
{
if(! m_Selection.m_valid)
{
else
return NULL;
}
-
- m_Selection.m_valid = false;
- return Copy( m_Selection.m_CursorA, m_Selection.m_CursorB );
+
+ if(invalidate) m_Selection.m_valid = false;
+
+ wxLayoutList *llist = Copy( m_Selection.m_CursorA,
+ m_Selection.m_CursorB );
+
+ if(llist && wxlo) // export as data object, too
+ {
+ wxString string;
+
+ wxLayoutExportObject *export;
+ wxLayoutExportStatus status(llist);
+ while((export = wxLayoutExport( &status, WXLO_EXPORT_AS_OBJECTS)) != NULL)
+ {
+ if(export->type == WXLO_EXPORT_EMPTYLINE)
+ ; //FIXME missing support for linebreaks in string format
+ else
+ export->content.object->Write(string);
+ delete export;
+ }
+
+ wxlo->SetData(string.c_str(), string.Length()+1);
+ }
+ return llist;
}
#ifdef WXLAYOUT_DEBUG
void
-wxLayoutList::Debug(void)
+wxLayoutList::Debug(void)
{
wxLayoutLine *line;
#endif
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
wxLayoutPrintout
{
m_llist = llist;
m_title = title;
+ // remove any highlighting which could interfere with printing:
+ m_llist->StartSelection();
+ m_llist->EndSelection();
}
wxLayoutPrintout::~wxLayoutPrintout()
{
// The following bit is taken from the printing sample, let's see
// whether it works for us.
-
+
/* You might use THIS code to set the printer DC to ROUGHLY reflect
* the screen text size. This page also draws lines of actual length 5cm
* on the page.
ppiPrinterX = 72;
ppiPrinterY = 72;
}
-
+
// This scales the DC so that the printout roughly represents the
// the screen scaling. The text point size _should_ be the right size
// but in fact is too small for some reason. This is a detail that will
wxDC *dc = GetDC();
ScaleDC(dc);
-
+
if (dc)
{
int top, bottom;
// This is the length of the printable area.
m_PrintoutHeight = m_PageHeight - (int) (m_PageHeight * 0.15);
m_PrintoutHeight = (int)( m_PrintoutHeight / scale); // we want to use the real paper height
-
-
+
+
m_NumOfPages = 1 +
(int)( m_llist->GetSize().y / (float)(m_PrintoutHeight));
const wxBrush& brush = dc.GetBrush();
const wxPen& pen = dc.GetPen();
const wxFont& font = dc.GetFont();
-
+
dc.SetBrush(*wxWHITE_BRUSH);
dc.SetPen(wxPen(*wxBLACK,0,wxSOLID));
dc.DrawRoundedRectangle(topleft.x,
topleft.y,bottomright.x-topleft.x,
- bottomright.y-topleft.y);
+ bottomright.y-topleft.y);
dc.SetBrush(*wxBLACK_BRUSH);
wxFont myfont = wxFont((WXLO_DEFAULTFONTSIZE*12)/10,
wxSWISS,wxNORMAL,wxBOLD,false,"Helvetica");
wxFont &
-wxFontCache::GetFont(int family, int size, int style, int weight,
+wxFontCache::GetFont(int family, int size, int style, int weight,
bool underline)
{
for(wxFCEList::iterator i = m_FontList.begin();
m_FontList.push_back(fce);
return fce->GetFont();
}
-
+