/*-*- c++ -*-********************************************************
* wxllist: wxLayoutList, a layout engine for text and graphics *
* *
- * (C) 1998-1999 by Karsten Ballüder (Ballueder@usa.net) *
+ * (C) 1998-2000 by Karsten Ballüder (Ballueder@gmx.net) *
* *
* $Id$
*******************************************************************/
# pragma implementation "wxllist.h"
#endif
-#include <wx/wxprec.h>
+#include "wx/wxprec.h"
#ifdef __BORLANDC__
# pragma hdrstop
#include "Mpch.h"
#ifdef M_BASEDIR
+# include "Mcommon.h"
# include "gui/wxllist.h"
# include "gui/wxlparser.h"
# define SHOW_SELECTIONS 1
#endif
#ifndef USE_PCH
-# include <iostream.h>
+#if wxUSE_IOSTREAMH
+ #include <iostream.h>
+#else
+ #include <iostream>
+#endif
-# include <wx/dc.h>
-# include <wx/dcps.h>
-# include <wx/print.h>
-# include <wx/log.h>
-# include <wx/filefn.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>
+# include "wx/caret.h"
#endif // WXLAYOUT_USE_CARET
#include <ctype.h>
+
/// This should never really get created
#define WXLLIST_TEMPFILE "__wxllist.tmp"
# define TypeString(t) g_aTypeStrings[t]
# define WXLO_DEBUG(x) wxLogDebug x
- static const char *g_aTypeStrings[] =
+ static const wxChar *g_aTypeStrings[] =
{
- "invalid", "text", "cmd", "icon"
+ _T("invalid"), _T("text"), _T("cmd"), _T("icon")
};
- void
- wxLayoutObject::Debug(void)
+ wxString
+ wxLayoutObject::DebugDump() const
{
- WXLO_DEBUG(("%s",g_aTypeStrings[GetType()]));
+ wxString str;
+ str.Printf(wxT("%s"), g_aTypeStrings[GetType()]);
+ return str;
}
#else
-# define TypeString(t) ""
-# define WXLO_DEBUG(x)
+# 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
//@}
+static
void ReadString(wxString &to, wxString &from)
{
- to = "";
- const char *cptr = from.c_str();
- while(*cptr && *cptr != '\n')
- to += *cptr++;
- if(*cptr) cptr++;
- from = cptr;
+ to = wxT("");
+ const wxChar *cptr = from.c_str();
+ while(*cptr && *cptr != wxT('\n'))
+ {
+ to += cptr;
+ cptr++;
+ }
+
+ if(*cptr) cptr++;
+
+ from = cptr;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
wxLayoutObject *
wxLayoutObject::Read(wxString &istr)
{
- wxString tmp;
- ReadString(tmp, istr);
- int type = -1;
- sscanf(tmp.c_str(),"%d", &type);
+ wxString tmp;
+ ReadString(tmp, istr);
+ long l = WXLO_TYPE_INVALID;
+ tmp.ToLong(&l);
+ int type = (int) l;
- 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;
- }
+ 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);
+ }
+
+ return NULL;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
}
wxLayoutObject *
-wxLayoutObjectText::Copy(void)
+wxLayoutObjectText::Copy()
{
wxLayoutObjectText *obj = new wxLayoutObjectText(m_Text);
obj->m_Width = m_Width;
&width, &height, &descent);
offs++;
}
- /* We have to substract 1 to compensate for the offs++, and another
+ /* We have to subtract 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. */
}
void
-wxLayoutObjectText::Layout(wxDC &dc, class wxLayoutList *llist)
+wxLayoutObjectText::Layout(wxDC &dc, class wxLayoutList *WXUNUSED(llist))
{
long descent = 0l;
heightOld = m_Height;
#endif // 0
+#ifdef __WXDEBUG__
+ CoordType a,b,c,d,e,f;
+ dc.GetTextExtent(_T("test "), &a, &b, &c);
+ dc.GetTextExtent(_T("test"), &d, &e, &f);
+ wxASSERT(a != d);
+ wxASSERT(b == e);
+ wxASSERT(c == f);
+ dc.GetTextExtent(_T(" "), &d, &e, &f);
+ wxASSERT(a > 0);
+#endif
dc.GetTextExtent(m_Text, &m_Width, &m_Height, &descent);
#if 0
#ifdef WXLAYOUT_DEBUG
-void
-wxLayoutObjectText::Debug(void)
+wxString
+wxLayoutObjectText::DebugDump() const
{
- wxLayoutObject::Debug();
- WXLO_DEBUG((" `%s`", m_Text.c_str()));
+ wxString str;
+ str = wxLayoutObject::DebugDump();
+ wxString str2;
+ str2.Printf(wxT(" `%s`"), m_Text.c_str());
+ return str+str2;
}
#endif
wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap const &icon)
{
+ if ( !icon.Ok() )
+ {
+ wxFAIL_MSG(wxT("invalid icon"));
+
+ m_Icon = NULL;
+
+ return;
+ }
+
+#ifdef __WXMSW__
+ // FIXME ugly, ugly, ugly - but the only way to avoid slicing
+ m_Icon = icon.GetHBITMAP() ? new wxBitmap(icon)
+ : new wxBitmap(wxBitmap((const wxBitmap &)icon));
+#else // !MSW
m_Icon = new wxBitmap(icon);
+#endif // MSW/!MSW
}
{
/* Exports icon through a temporary file. */
- wxString file = wxGetTempFileName("wxloexport");
+ wxString file = wxGetTempFileName(_T("wxloexport"));
- ostr << WXLO_TYPE_ICON << '\n'
+ ostr << (int) WXLO_TYPE_ICON << '\n'
<< file << '\n';
m_Icon->SaveFile(file, WXLO_BITMAP_FORMAT);
}
delete obj;
return NULL;
}
- else
- return obj;
+
+ return obj;
}
wxLayoutObject *
-wxLayoutObjectIcon::Copy(void)
+wxLayoutObjectIcon::Copy()
{
wxLayoutObjectIcon *obj = new wxLayoutObjectIcon(new
wxBitmap(*m_Icon));
wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap *icon)
{
m_Icon = icon;
+ if(! m_Icon)
+ m_Icon = new wxBitmap;
}
void
wxLayoutObjectIcon::Draw(wxDC &dc, wxPoint const &coords,
- wxLayoutList *wxllist,
- CoordType begin, CoordType /* len */)
+ wxLayoutList *WXUNUSED(wxllist),
+ CoordType WXUNUSED(begin), CoordType WXUNUSED(len) )
{
dc.DrawBitmap(*m_Icon, coords.x, coords.y-m_Icon->GetHeight(),
- (m_Icon->GetMask() == NULL) ? FALSE : TRUE);
+ (m_Icon->GetMask() == NULL) ? false : true);
}
void
m_StyleInfo = new wxLayoutStyleInfo(family, size,style,weight,underline,fg,bg);
}
+wxLayoutObjectCmd::wxLayoutObjectCmd(const wxLayoutStyleInfo &si)
+
+{
+ m_StyleInfo = new wxLayoutStyleInfo;
+ *m_StyleInfo = si;
+}
+
wxLayoutObject *
-wxLayoutObjectCmd::Copy(void)
+wxLayoutObjectCmd::Copy()
{
wxLayoutObjectCmd *obj = new wxLayoutObjectCmd(
- m_StyleInfo->size,
m_StyleInfo->family,
+ m_StyleInfo->size,
m_StyleInfo->style,
m_StyleInfo->weight,
m_StyleInfo->underline,
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';
+ ostr << (int) WXLO_TYPE_CMD << '\n'
+ << (int) m_StyleInfo->family << '\n'
+ << (int) m_StyleInfo->size << '\n'
+ << (int) m_StyleInfo->style << '\n'
+ << (int) m_StyleInfo->weight << '\n'
+ << (int) m_StyleInfo->underline << '\n'
+ << (int) m_StyleInfo->m_fg_valid << '\n'
+ << (int) 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';
+ ostr << (int) m_StyleInfo->m_fg.Red() << '\n'
+ << (int) m_StyleInfo->m_fg.Green() << '\n'
+ << (int) 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';
+ ostr << (int) m_StyleInfo->m_bg.Red() << '\n'
+ << (int) m_StyleInfo->m_bg.Green() << '\n'
+ << (int) 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 *obj = new wxLayoutObjectCmd;
+
+ long l = 0;
+ wxString tmp;
+ ReadString(tmp, istr);
+ tmp.ToLong(&l);
+ obj->m_StyleInfo->family = (int) l;
+
+
+ ReadString(tmp, istr);
+ tmp.ToLong(&l);
+ obj->m_StyleInfo->size = (int) l;
+
+ ReadString(tmp, istr);
+ tmp.ToLong(&l);
+ obj->m_StyleInfo->style = (int) l;
+
+ ReadString(tmp, istr);
+ tmp.ToLong(&l);
+ obj->m_StyleInfo->weight = (int) l;
+
+ ReadString(tmp, istr);
+ tmp.ToLong(&l);
+ obj->m_StyleInfo->underline = (int) l;
+
+ ReadString(tmp, istr);
+ tmp.ToLong(&l);
+ obj->m_StyleInfo->m_fg_valid = (int) l;
+
+ ReadString(tmp, istr);
+ tmp.ToLong(&l);
+ obj->m_StyleInfo->m_bg_valid = (int) l;
+
+ if(obj->m_StyleInfo->m_fg_valid)
+ {
+ unsigned char red, green, blue;
+ ReadString(tmp, istr);
+ tmp.ToLong(&l);
+ red = (unsigned char) l;
+
+ ReadString(tmp, istr);
+ tmp.ToLong(&l);
+ green = (unsigned char) l;
+
+ ReadString(tmp, istr);
+ tmp.ToLong(&l);
+ blue = (unsigned char) l;
+
+ obj->m_StyleInfo->m_fg = wxColour(red, green, blue);
+ }
+
+ if(obj->m_StyleInfo->m_bg_valid)
+ {
+ unsigned char red, green, blue;
+ ReadString(tmp, istr);
+ tmp.ToLong(&l);
+ red = (unsigned char) l;
+
+ ReadString(tmp, istr);
+ tmp.ToLong(&l);
+ green = (unsigned char) l;
+
+ ReadString(tmp, istr);
+ tmp.ToLong(&l);
+ blue = (unsigned char) l;
+
+ obj->m_StyleInfo->m_bg = wxColour(red, green, blue);
+ }
+
+ return obj;
}
}
wxLayoutStyleInfo *
-wxLayoutObjectCmd::GetStyle(void) const
+wxLayoutObjectCmd::GetStyle() const
{
return m_StyleInfo;
}
void
-wxLayoutObjectCmd::Draw(wxDC &dc, wxPoint const & /* coords */,
+wxLayoutObjectCmd::Draw(wxDC &dc, wxPoint const & WXUNUSED(coords),
wxLayoutList *wxllist,
- CoordType begin, CoordType /* len */)
+ CoordType WXUNUSED(begin), CoordType WXUNUSED(len))
{
wxASSERT(m_StyleInfo);
wxllist->ApplyStyle(*m_StyleInfo, dc);
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;
+ MarkDirty(0);
+
+ m_LineNumber = 0;
RecalculatePosition(llist);
+
+ MarkDirty();
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_Next->MoveLines(+1);
- m_Next->RecalculatePositions(1,llist);
+ m_Next->ReNumber();
}
m_StyleInfo = llist->GetDefaultStyleInfo();
-}
-wxLayoutLine::~wxLayoutLine()
-{
- // kbList cleans itself
+ llist->IncNumLines();
}
wxPoint
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);
- }
-}
wxLayoutObjectList::iterator
wxLayoutLine::FindObject(CoordType xpos, CoordType *offset) const
wxASSERT(offset);
wxLayoutObjectList::iterator
i,
- found = NULLIT;
+ found(NULL),
+ nulled(NULL);
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
further object following it. */
- for(i = m_ObjectList.begin(); i != NULLIT; i++)
+ for(i = m_ObjectList.begin(); i != nulled; i++)
{
len = (**i).GetLength();
if( x <= xpos && xpos <= x + len )
}
wxLayoutObjectList::iterator
-wxLayoutLine::FindObjectScreen(wxDC &dc,
+wxLayoutLine::FindObjectScreen(wxDC &dc, wxLayoutList *llist,
CoordType xpos, CoordType *cxpos,
bool *found) const
{
wxASSERT(cxpos);
- wxASSERT(cxpos);
- wxLayoutObjectList::iterator i;
+
+ llist->ApplyStyle(GetStyleInfo(), dc);
+
+ wxLayoutObjectList::iterator i, nulled(NULL);
CoordType x = 0, cx = 0, width;
- for(i = m_ObjectList.begin(); i != NULLIT; i++)
+ for(i = m_ObjectList.begin(); i != nulled; 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();
}
CoordType
wxLayoutLine::FindText(const wxString &needle, CoordType xpos) const
{
- int
- cpos = 0,
- relpos = -1;
+ int cpos = 0;
wxString const *text;
for(wxLOiterator i = m_ObjectList.begin(); i != m_ObjectList.end(); i++)
if((**i).GetType() == WXLO_TYPE_TEXT)
{
text = & ((wxLayoutObjectText*)(*i))->GetText();
- relpos = text->Find(needle);
+ int relpos = text->Find(needle);
if(relpos >= cpos-xpos) // -1 if not found
{
return cpos+relpos;
MarkDirty(xpos);
- // If we insert a command object, we need to recalculate all lines
- // to update their styleinfo structure.
- if(obj->GetType() == WXLO_TYPE_CMD)
- MarkNextDirty(-1);
-
CoordType offset;
wxLOiterator i = FindObject(xpos, &offset);
- if(i == NULLIT)
+ wxLayoutObjectList::iterator nulled(NULL);
+ if(i == nulled)
{
if(xpos == 0 ) // aha, empty line!
{
CoordType offset;
wxLOiterator i = FindObject(xpos, &offset);
- if(i != NULLIT && (**i).GetType() == WXLO_TYPE_TEXT)
+ wxLayoutObjectList::iterator nulled(NULL);
+ if(i != nulled && (**i).GetType() == WXLO_TYPE_TEXT)
{
wxLayoutObjectText *tobj = (wxLayoutObjectText *) *i;
tobj->GetText().insert(offset, text);
wxASSERT(npos >= 0);
MarkDirty(xpos);
wxLOiterator i = FindObject(xpos, &offset);
+ wxLayoutObjectList::iterator nulled(NULL);
while(npos > 0)
{
- if(i == NULLIT) return npos;
+ if(i == nulled) return npos;
// now delete from that object:
if((**i).GetType() != WXLO_TYPE_TEXT)
{
len = (**i).GetLength();
m_Length -= len;
npos -= len;
- // If we delete a command object, we need to recalculate all lines
- // to update their styleinfo structure.
- if((**i).GetType() == WXLO_TYPE_CMD)
- MarkNextDirty(-1);
m_ObjectList.erase(i);
}
else
return npos;
}
-void
-wxLayoutLine::MarkNextDirty(int recurse)
-{
- wxLayoutLine *line = GetNextLine();
- while(line && (recurse == -1 || recurse >= 0))
- {
- line->MarkDirty();
- line = line->GetNextLine();
- if(recurse > 0) recurse --;
- }
-}
-
bool
wxLayoutLine::DeleteWord(CoordType xpos)
{
- wxASSERT(xpos >= 0);
- CoordType offset;
- MarkDirty(xpos);
-
- wxLOiterator i = FindObject(xpos, &offset);
-
- for(;;)
- {
- if(i == NULLIT) return false;
- if((**i).GetType() != WXLO_TYPE_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
- m_ObjectList.erase(i);
- return true; // we are done
- }
- else
- { // text object:
- if(offset == (**i).GetLength()) // at end of object
- {
- i++; offset = 0;
- continue;
- }
- wxLayoutObjectText *tobj = (wxLayoutObjectText *)*i;
- size_t count = 0;
- wxString str = tobj->GetText();
- str = str.substr(offset,str.Length()-offset);
- // Find out how many positions we need to delete:
- // 1. eat leading space
- while(isspace(str.c_str()[count])) count++;
- // 2. eat the word itself:
- while(isalnum(str.c_str()[count])) count++;
- // now delete it:
- wxASSERT(count+offset <= (size_t) (**i).GetLength());
- ((wxLayoutObjectText *)*i)->GetText().erase(offset,count);
- m_Length -= count;
- return true;
- }
- }
+ wxASSERT(xpos >= 0);
+ CoordType offset;
+ MarkDirty(xpos);
+
+ wxLOiterator i = FindObject(xpos, &offset);
+ wxLayoutObjectList::iterator nulled(NULL);
+ for(;;)
+ {
+ if(i == nulled) return false;
+ if((**i).GetType() != WXLO_TYPE_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
+ m_ObjectList.erase(i);
+ return true; // we are done
+ }
+ else
+ { // text object:
+ if(offset == (**i).GetLength()) // at end of object
+ {
+ i++; offset = 0;
+ continue;
+ }
- wxFAIL_MSG("unreachable");
+ wxLayoutObjectText *tobj = (wxLayoutObjectText *)*i;
+ size_t count = 0;
+ wxString str = tobj->GetText();
+ str = str.substr(offset,str.Length()-offset);
+ // Find out how many positions we need to delete:
+ // 1. eat leading space
+ while(isspace(str.c_str()[count])) count++;
+ // 2. eat the word itself:
+ while(isalnum(str.c_str()[count])) count++;
+ // now delete it:
+ wxASSERT(count+offset <= (size_t) (**i).GetLength());
+ ((wxLayoutObjectText *)*i)->GetText().erase(offset,count);
+ m_Length -= count;
+
+ return true;
+ }
+ }
+
+ #if 0
+ wxFAIL_MSG(wxT("unreachable"));
+ #endif
}
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;
- if(update)
- {
- m_Next->MoveLines(-1);
- m_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. */
- if(m_ObjectList.size() > 1 ||
- ( m_ObjectList.begin() != NULLIT &&
- (**m_ObjectList.begin()).GetType() == WXLO_TYPE_CMD)
- )
- MarkNextDirty(-1);
- }
+ // maintain linked list integrity
+ if(m_Next)
+ m_Next->m_Previous = m_Previous;
+ if(m_Previous)
+ m_Previous->m_Next = m_Next;
+
+ // get the line numbers right again
+ if ( update && m_Next)
+ m_Next->ReNumber();
+
+ MarkDirty();
+
+ // we can't use m_Next after "delete this", so we must save this pointer
+ // first
wxLayoutLine *next = m_Next;
delete this;
+
+ llist->DecNumLines();
+
return next;
}
wxLayoutList *llist,
const wxPoint & offset) const
{
- wxLayoutObjectList::iterator i;
+ wxLayoutObjectList::iterator i, nulled(NULL);
wxPoint pos = offset;
pos = pos + GetPosition();
pos.y += m_BaseLine;
- CoordType xpos = 0; // cursorpos, lenght of line
+ CoordType xpos = 0; // cursorpos, length of line
- CoordType from, to, tempto;
+ CoordType from, to;
int highlight = llist->IsSelected(this, &from, &to);
// WXLO_DEBUG(("highlight=%d", highlight ));
else
llist->EndHighlighting(dc);
- for(i = m_ObjectList.begin(); i != NULLIT; i++)
+ for(i = m_ObjectList.begin(); i != nulled; i++)
{
if(highlight == -1) // partially highlight line
{
// parts of the line need highlighting
- tempto = xpos+(**i).GetLength();
+
+ // Next line commented, code has no effect
+ // xpos+(**i).GetLength();
(**i).Draw(dc, pos, llist, from-xpos, to-xpos);
}
else
wxLayoutList *llist,
wxPoint *cursorPos,
wxPoint *cursorSize,
+ wxLayoutStyleInfo *cursorStyle,
int cx,
- bool suppressSIupdate)
+ bool WXUNUSED(suppressSIupdate))
{
- wxLayoutObjectList::iterator i;
+ wxLayoutObjectList::iterator i, nulled(NULL);
// 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
bool cursorFound = false;
+ RecalculatePosition(llist);
+
if(cursorPos)
{
*cursorPos = m_Position;
}
m_StyleInfo = llist->GetStyleInfo(); // save current style
- for(i = m_ObjectList.begin(); i != NULLIT; i++)
+ for(i = m_ObjectList.begin(); i != nulled; i++)
{
wxLayoutObject *obj = *i;
obj->Layout(dc, llist);
if(len < obj->GetLength())
str = (*(wxLayoutObjectText*)*i).GetText().substr(len,1);
else
- str = WXLO_CURSORCHAR;
+ str = _T(WXLO_CURSORCHAR);
dc.GetTextExtent(str, &width, &height, &descent);
+ if(cursorStyle) // set style info
+ *cursorStyle = llist->GetStyleInfo();
if ( cursorSize )
{
// Just in case some joker inserted an empty string object:
{
// on some other object
CoordType top, bottom; // unused
- *cursorSize = obj->GetSize(&top,&bottom);
+ if(cursorSize)
+ *cursorSize = obj->GetSize(&top,&bottom);
cursorPos->y = m_Position.y;
cursorFound = true; // no more checks
}
if(m_Height == 0)
{
CoordType width, height, descent;
- dc.GetTextExtent(WXLO_CURSORCHAR, &width, &height, &descent);
+ dc.GetTextExtent(_T(WXLO_CURSORCHAR), &width, &height, &descent);
m_Height = height;
m_BaseLine = m_Height - descent;
}
// tell next line about coordinate change
if(m_Next && m_Height != heightOld)
{
- // FIXME isn't this done in RecalculatePositions() below anyhow?
- m_Next->RecalculatePositions(0, llist);
+ m_Next->MarkDirty();
}
// We need to check whether we found a valid cursor size:
{
// this might be the case if the cursor is at the end of the
// line or on a command object:
- if(cursorSize->y < WXLO_MINIMUM_CURSOR_WIDTH)
+ if(cursorSize->x < WXLO_MINIMUM_CURSOR_WIDTH)
{
CoordType width, height, descent;
- dc.GetTextExtent(WXLO_CURSORCHAR, &width, &height, &descent);
+ dc.GetTextExtent(_T(WXLO_CURSORCHAR), &width, &height, &descent);
cursorSize->x = width;
cursorSize->y = height;
}
if(m_BaseLine >= cursorSize->y) // the normal case anyway
cursorPos->y += m_BaseLine-cursorSize->y;
}
- RecalculatePositions(1, llist);
MarkClean();
}
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)
- { // We were in first line, need to link in new empty line
- // before this.
- prev->m_Next = this;
- m_Previous = prev;
- m_Previous->m_Height = 0; // this is a wild guess
- }
- if(m_Next)
- m_Next->RecalculatePositions(1, llist);
- return m_Previous;
- }
-
CoordType offset;
wxLOiterator i = FindObject(xpos, &offset);
- if(i == NULLIT)
+ wxLayoutObjectList::iterator nulled(NULL);
+ if(i == nulled)
// must be at the end of the line then
return new wxLayoutLine(this, llist);
// split this line:
wxLayoutLine *newLine = new wxLayoutLine(this, llist);
// split object at i:
- if((**i).GetType() == WXLO_TYPE_TEXT && offset != 0)
+ if((**i).GetType() == WXLO_TYPE_TEXT
+ && offset != 0
+ && offset != (**i).GetLength() )
{
wxString left, right;
wxLayoutObjectText *tobj = (wxLayoutObjectText *) *i;
m_ObjectList.remove(i); // remove without deleting it
}
if(m_Next)
- m_Next->RecalculatePositions(2, llist);
+ m_Next->MarkDirty();
return newLine;
}
+bool
+wxLayoutLine::Wrap(CoordType wrapmargin, wxLayoutList *llist)
+{
+ wxLayoutObjectList::iterator nulled(NULL);
+ if(GetLength() < wrapmargin)
+ return false; // nothing to do
+
+ // find the object which covers the wrapmargin:
+ CoordType offset;
+ wxLOiterator i = FindObject(wrapmargin, &offset);
+ wxCHECK_MSG( i != nulled, false,
+ wxT("Cannot find object covering wrapmargin."));
+
+ // from this object on, the rest of the line must be copied to the
+ // next one:
+ wxLOiterator copyObject = nulled;
+ // if we split a text-object, we must pre-pend some text to the
+ // next line later on, remember it here:
+ wxString prependText = _T("");
+ // we might need to adjust the cursor position later, so remember it
+ size_t xpos = llist->GetCursorPos().x;
+ // by how much did we shorten the current line:
+ size_t shorter = 0;
+ // remember cursor location of object
+ size_t objectCursorPos = 0;
+
+ size_t breakpos = offset;
+
+ if( (**i).GetType() != WXLO_TYPE_TEXT )
+ {
+ // break before a non-text object
+ copyObject = i;
+ }
+ else
+ {
+ bool foundSpace = false;
+ do
+ {
+// while(i != nulled && (**i).GetType() != WXLO_TYPE_TEXT)
+// i--;
+ // try to find a suitable place to split the object:
+ wxLayoutObjectText *tobj = (wxLayoutObjectText *)*i;
+ if((**i).GetType() == WXLO_TYPE_TEXT
+ && tobj->GetText().Length() >= breakpos)
+ {
+ do
+ {
+ foundSpace = isspace(tobj->GetText()[breakpos]) != 0;
+ if ( foundSpace )
+ break;
+ }
+ while ( breakpos-- > 0 );
+ }
+ else
+ {
+ breakpos = 0;
+ }
+
+ if(! foundSpace) // breakpos == 0!
+ {
+ if(i == m_ObjectList.begin())
+ return false; // could not break line
+ else
+ {
+ i--;
+ while(i != m_ObjectList.begin()
+ && (**i).GetType() != WXLO_TYPE_TEXT )
+ {
+ i--;
+ }
+ breakpos = (**i).GetLength();
+ }
+ }
+ }while(! foundSpace);
+ // before we actually break the object, we need to know at which
+ // cursorposition it starts, so we can restore the cursor if needed:
+ if( this == llist->GetCursorLine() && xpos >= breakpos )
+ {
+ for(wxLOiterator j = m_ObjectList.begin();
+ j != nulled && j != i; j++)
+ objectCursorPos += (**j).GetLength();
+ }
+ // now we know where to break it:
+ wxLayoutObjectText *tobj = (wxLayoutObjectText *)*i;
+ shorter = tobj->GetLength() - breakpos;
+ // remember text to copy from this object
+ prependText = tobj->GetText().Mid(breakpos+1);
+ tobj->SetText(tobj->GetText().Left(breakpos));
+ // copy every following object:
+ copyObject = i; copyObject ++;
+ }
+
+ // make sure there is an empty m_Next line:
+ (void) new wxLayoutLine(this, llist);
+ wxASSERT(m_Next);
+ // We need to move this and all following objects to the next
+ // line. Starting from the end of line, to keep the order right.
+ if(copyObject != nulled)
+ {
+ wxLOiterator j;
+ for(j = m_ObjectList.tail(); j != copyObject; j--)
+ m_Next->Prepend(*j);
+ m_Next->Prepend(*copyObject);
+ // and now remove them from this list:
+ while( copyObject != m_ObjectList.end() )
+ {
+ shorter += (**copyObject).GetLength();
+ m_ObjectList.remove(copyObject); // remove without deleting it
+ }
+ }
+ m_Length -= shorter;
+
+ if(prependText.Length() > 0)
+ m_Next->Insert(0, prependText);
+
+ // do we need to adjust the cursor position?
+ if( this == llist->GetCursorLine() && xpos >= breakpos)
+ {
+ xpos = objectCursorPos + (xpos - objectCursorPos - breakpos -
+ ((xpos > breakpos) ? 1 : 0 ));
+ #if 0
+ // this assert is useless when xpos has unsigned type
+ wxASSERT(xpos >= 0);
+ #endif
+ llist->MoveCursorTo( wxPoint( xpos, m_Next->GetLineNumber()) );
+ }
+ return true; // we wrapped the line
+}
+
+void
+wxLayoutLine::ReNumber()
+{
+ CoordType lineNo = m_Previous ? m_Previous->m_LineNumber+1 : 0;
+ m_LineNumber = lineNo++;
+
+ for(wxLayoutLine *next = GetNextLine();
+ next; next = next->GetNextLine())
+ next->m_LineNumber = lineNo++;
+}
void
wxLayoutLine::MergeNextLine(wxLayoutList *llist)
{
- wxCHECK_RET(GetNextLine(),"wxLayout internal error: no next line to merge");
+ wxCHECK_RET( GetNextLine(),
+ wxT("wxLayout internal error: no next line to merge"));
wxLayoutObjectList &list = GetNextLine()->m_ObjectList;
wxLOiterator i;
SetNext(nextLine);
if ( nextLine )
{
- nextLine->MoveLines(-1);
+ nextLine->ReNumber();
}
else
{
#endif // 0
}
+ llist->DecNumLines();
+
delete oldnext;
}
{
CoordType offset;
wxLOiterator i = FindObject(column, &offset);
- if(i == NULLIT) return -1; // cannot wrap
+ wxLayoutObjectList::iterator nulled(NULL);
+ if(i == nulled) return -1; // cannot wrap
// go backwards through the list and look for space in text objects
do
{
do
{
- if( isspace(((wxLayoutObjectText*)*i)->GetText().c_str()[(size_t)offset]))
+ if(isspace(((wxLayoutObjectText*)*i)->GetText().c_str()[(size_t)offset]))
return column;
else
{
column -= (**i).GetLength();
i--;
}
- if( i != NULLIT)
+ if( i != nulled)
offset = (**i).GetLength();
- }while(i != NULLIT);
+ }while(i != nulled);
/* If we reached the begin of the list and have more than one
object, that one is longer than the margin, so break behind
it. */
CoordType pos = 0;
i = m_ObjectList.begin();
- while(i != NULLIT && (**i).GetType() != WXLO_TYPE_TEXT)
+ while(i != nulled && (**i).GetType() != WXLO_TYPE_TEXT)
{
pos += (**i).GetLength();
i++;
}
- if(i == NULLIT) return -1; //why should this happen?
+ if(i == nulled) return -1; //why should this happen?
+
+ // now we are behind the one long text object and need to find the
+ // first space in it
+ for(offset = 0; offset < (**i).GetLength(); offset++)
+ if( isspace(((wxLayoutObjectText*)*i)->GetText().c_str()[(size_t)offset]))
+ {
+ return pos+offset;
+ }
pos += (**i).GetLength();
- i++;
- while(i != NULLIT && (**i).GetType() != WXLO_TYPE_TEXT)
- {
- pos += (**i).GetLength();
- i++;
- }
- if(i == NULLIT) return -1; //this is possible, if there is only one text object
- // now we are at the second text object:
- pos -= (**i).GetLength();
- return pos; // in front of it
+ return pos;
}
#ifdef WXLAYOUT_DEBUG
void
-wxLayoutLine::Debug(void)
+wxLayoutLine::Debug() const
{
- wxString tmp;
+ wxLayoutObjectList::iterator nulled(NULL);
wxPoint pos = GetPosition();
- WXLO_DEBUG(("Line %ld, Pos (%ld,%ld), Height %ld, BL %ld, Font: %d",
+ WXLO_DEBUG((wxT("Line %ld, Pos (%ld,%ld), Height %ld, BL %ld, Font: %d"),
(long int) GetLineNumber(),
(long int) pos.x, (long int) pos.y,
(long int) GetHeight(),
(long int) m_BaseLine,
(int) m_StyleInfo.family));
- if(m_ObjectList.begin() != NULLIT)
- (**m_ObjectList.begin()).Debug();
+ if(m_ObjectList.begin() != nulled)
+ {
+ WXLO_DEBUG(((**m_ObjectList.begin()).DebugDump().c_str()));
+ }
}
#endif
CoordType from,
CoordType to)
{
+ wxLayoutObjectList::iterator nulled(NULL);
CoordType firstOffset, lastOffset;
if(to == -1) to = GetLength();
wxLOiterator last = FindObject(to, &lastOffset);
// Common special case: only one object
- if( first != NULLIT && last != NULLIT && *first == *last )
+ if( first != nulled && last != nulled && *first == *last )
{
if( (**first).GetType() == WXLO_TYPE_TEXT )
{
m_caret = NULL;
#endif // WXLAYOUT_USE_CARET
+ m_numLines = 0;
m_FirstLine = NULL;
+ SetAutoFormatting(true);
+ ForceTotalLayout(true); // for the first time, do all
InvalidateUpdateRect();
Clear();
}
wxLayoutList::~wxLayoutList()
{
+ SetAutoFormatting(false);
InternalClear();
+ Empty();
m_FirstLine->DeleteLine(false, this);
+
+ wxASSERT_MSG( m_numLines == 0, wxT("line count calculation broken"));
}
void
-wxLayoutList::Empty(void)
+wxLayoutList::Empty()
{
while(m_FirstLine)
m_FirstLine = m_FirstLine->DeleteLine(false, this);
void
-wxLayoutList::InternalClear(void)
+wxLayoutList::InternalClear()
{
- Empty();
m_Selection.m_selecting = false;
m_Selection.m_valid = false;
m_DefaultStyleInfo.style = wxNORMAL;
m_DefaultStyleInfo.weight = wxNORMAL;
m_DefaultStyleInfo.underline = 0;
- m_DefaultStyleInfo.m_fg_valid = TRUE;
+ m_DefaultStyleInfo.m_fg_valid = true;
m_DefaultStyleInfo.m_fg = *wxBLACK;
- m_DefaultStyleInfo.m_bg_valid = TRUE;
+ m_DefaultStyleInfo.m_bg_valid = true;
m_DefaultStyleInfo.m_bg = *wxWHITE;
m_CurrentStyleInfo = m_DefaultStyleInfo;
+ m_CursorStyleInfo = m_DefaultStyleInfo;
}
+void
+wxLayoutList::Read(wxString &istr)
+{
+ /* In order to handle input of formatted string "nicely", we need
+ to restore our current font settings after the string. So first
+ of all, we create a StyleInfo structure with our current
+ settings. */
+ wxLayoutStyleInfo current_si = GetStyleInfo();
+
+ while(istr.Length())
+ {
+ // check for a linebreak:
+ wxString tmp;
+ tmp = istr.BeforeFirst('\n');
+ long l = WXLO_TYPE_INVALID;
+ tmp.ToLong(&l);
+ int type = (int) l;
+
+ if(type == WXLO_TYPE_LINEBREAK)
+ {
+ LineBreak();
+ istr = istr.AfterFirst('\n');
+ }
+ else
+ {
+ wxLayoutObject *obj = wxLayoutObject::Read(istr);
+ if(obj)
+ Insert(obj);
+ }
+ }
+ /* Now we use the current_si to restore our last font settings: */
+ Insert(new wxLayoutObjectCmd(current_si));
+}
+
+
void
wxLayoutList::SetFont(int family, int size, int style, int weight,
int underline, wxColour *fg,
void
wxLayoutList::SetFont(int family, int size, int style, int weight,
- int underline, char const *fg, char const *bg)
+ int underline, wxChar const *fg, wxChar const *bg)
{
- wxColour
- *cfg = NULL,
- *cbg = NULL;
-
- if( fg )
- cfg = wxTheColourDatabase->FindColour(fg);
- if( bg )
- cbg = wxTheColourDatabase->FindColour(bg);
+ wxColour cfg = wxTheColourDatabase->Find((fg)?fg:wxT("BLACK"));
+ wxColour cbg = wxTheColourDatabase->Find((bg)?bg:wxT("WHITE"));
- SetFont(family,size,style,weight,underline,cfg,cbg);
+ SetFont(family,size,style,weight,underline,&cfg,&cbg);
}
void
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
{
n--;
m_CursorPos.y ++;
+ last = m_CursorLine;
m_CursorLine = m_CursorLine->GetNextLine();
}
if(! m_CursorLine)
{
m_CursorLine = last;
- m_CursorPos.y ++;
+ m_CursorPos.y --;
rc = false;
}
else
bool
wxLayoutList::MoveCursorWord(int n, bool untilNext)
{
- wxCHECK_MSG( m_CursorLine, false, "no current line" );
- wxCHECK_MSG( n == -1 || n == +1, false, "not implemented yet" );
+ wxLayoutObjectList::iterator nulled(NULL);
+ wxCHECK_MSG( m_CursorLine, false, wxT("no current line") );
+ wxCHECK_MSG( n == -1 || n == +1, false, wxT("not implemented yet") );
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 ( i == nulled )
+ {
+ 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 == nulled )
+ {
+ // moved to the end/beginning of text
+ return false;
+ }
+
+ offset = -1;
+ }
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 )
{
if ( canAdvance )
{
const wxString& text = tobj->GetText();
- const char *start = text.c_str();
- const char *end = start + text.length();
- const char *p = start + offset;
+ const wxChar *start = text.c_str();
+ const wxChar *end = start + text.length();
+ const wxChar *p = start + offset;
if ( n < 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 subtracted 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::Insert(wxString const &text)
{
wxASSERT(m_CursorLine);
- wxASSERT_MSG( text.Find('\n') == wxNOT_FOUND, "use wxLayoutImportText!" );
+ wxASSERT_MSG( text.Find(wxT('\n')) == wxNOT_FOUND,
+ wxT("use wxLayoutImportText!") );
if ( !text )
return true;
AddCursorPosToUpdateRect();
+ wxASSERT(m_CursorLine->GetLength() >= m_CursorPos.x);
+
if ( !m_CursorLine->Insert(m_CursorPos.x, text) )
return false;
-
m_CursorPos.x += text.Length();
m_movedCursor = true;
- m_CursorLine->RecalculatePositions(0, this);
+ if(m_AutoFormat)
+ m_CursorLine->MarkDirty();
return true;
}
m_CursorPos.x += obj->GetLength();
m_movedCursor = true;
- m_CursorLine->RecalculatePositions(0, this);
+ if(m_AutoFormat)
+ m_CursorLine->MarkDirty();
return true;
}
bool
wxLayoutList::Insert(wxLayoutList *llist)
{
+ wxLayoutObjectList::iterator nulled(NULL);
wxASSERT(llist);
- bool rc = TRUE;
+ bool rc = true;
for(wxLayoutLine *line = llist->GetFirstLine();
line;
)
{
for(wxLOiterator i = line->GetFirstObject();
- i != NULLIT;
+ i != nulled;
i++)
rc |= Insert(*i);
LineBreak();
}
bool
-wxLayoutList::LineBreak(void)
+wxLayoutList::LineBreak()
{
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)
- m_CursorPos.y++;
+ if(m_CursorLine->GetPreviousLine() == NULL)
+ m_FirstLine = m_CursorLine;
+ 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;
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(1, this);
-
- m_movedCursor = true;
+ return m_CursorLine->Wrap(column, this);
+}
- return true;
+bool
+wxLayoutList::WrapAll(CoordType column)
+{
+ wxLayoutLine *line = m_FirstLine;
+ if(! line)
+ return false;
+ bool rc = true;
+ while(line && rc)
+ {
+ rc &= line->Wrap(column, this);
+ line = line->GetNextLine();
}
+ return rc;
}
bool
wxLayoutList::Delete(CoordType npos)
{
- wxCHECK_MSG(m_CursorLine, false, "can't delete in non existing line");
+ wxCHECK_MSG(m_CursorLine, false, wxT("can't delete in non existing line"));
if ( npos == 0 )
return true;
}
else
{
- wxFAIL_MSG("can't delete all this");
+ wxFAIL_MSG(wxT("can't delete all this"));
return false;
}
{ // we cannot delete this line, but we can clear it
MoveCursorToBeginOfLine();
DeleteToEndOfLine();
- m_CursorLine->RecalculatePositions(2, this);
+ if(m_AutoFormat)
+ m_CursorLine->MarkDirty();
return n-1;
}
//else:
wxASSERT(m_FirstLine);
wxASSERT(m_CursorLine);
}
- m_CursorLine->RecalculatePositions(2, this);
+ if(m_AutoFormat)
+ m_CursorLine->MarkDirty();
return n;
}
void
wxLayoutList::Recalculate(wxDC &dc, CoordType bottom)
{
+ if(! m_AutoFormat)
+ return;
wxLayoutLine *line = m_FirstLine;
// first, make sure everything is calculated - this might not be
}
wxPoint
-wxLayoutList::GetCursorScreenPos(wxDC &dc)
+wxLayoutList::GetCursorScreenPos() const
{
return m_CursorScreenPos;
}
*/
void
wxLayoutList::Layout(wxDC &dc, CoordType bottom, bool forceAll,
- wxPoint *cpos, wxPoint *csize)
+ wxPoint *cpos, wxPoint *csize)
{
- // first, make sure everything is calculated - this might not be
- // needed, optimise it later
- ApplyStyle(m_DefaultStyleInfo, dc);
+ // first, make sure everything is calculated - this might not be
+ // needed, optimise it later
+ ApplyStyle(m_DefaultStyleInfo, dc);
- // This one we always Layout() to get the current cursor
- // coordinates on the screen:
- m_CursorLine->MarkDirty();
- bool wasDirty = false;
- wxLayoutLine *line = m_FirstLine;
- while(line)
- {
- if(! wasDirty)
- ApplyStyle(line->GetStyleInfo(), dc);
- if(forceAll || line->IsDirty()
- || (cpos && line->GetLineNumber() == cpos->y))
- {
- // 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_CursorPos.x);
- if(cpos && line->GetLineNumber() == cpos->y)
- line->Layout(dc, this,
- cpos,
- csize, cpos->x);
+
+ if(m_ReLayoutAll)
+ {
+ forceAll = true;
+ bottom = -1;
+ }
+
+ ForceTotalLayout(false);
+
+
+ // If one line was dirty, we need to re-calculate all
+ // following lines, too.
+ bool wasDirty = forceAll;
+ // we need to layout until we reach at least the cursor line,
+ // otherwise we won't be able to scroll to it
+ bool cursorReached = false;
+ wxLayoutLine *line = m_FirstLine;
+ while(line)
+ {
+ if(! wasDirty)
+ ApplyStyle(line->GetStyleInfo(), dc);
+ if(
+ // if any previous line was dirty, we need to layout all
+ // following lines:
+ wasDirty
+ // go on until we find the cursorline
+ || ! cursorReached
+ // layout dirty lines:
+ || line->IsDirty()
+ // always layout the cursor line toupdate the cursor
+ // position and size:
+ || line == m_CursorLine
+ // or if it's the line we are asked to look for:
+ || (cpos && line->GetLineNumber() == cpos->y)
+ // layout at least the desired region:
+ || (bottom == -1 )
+ || (line->GetPosition().y <= bottom)
+ )
+ {
+ if(line->IsDirty())
+ wasDirty = 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);
+ // we cannot layout the line twice, so copy the coords:
+ if(cpos && line ->GetLineNumber() == cpos->y)
+ {
+ *cpos = m_CursorScreenPos;
+ if ( csize )
+ *csize = m_CursorSize;
+ }
+
+ cursorReached = true;
+ }
else
- line->Layout(dc, this);
- // little condition to speed up redrawing:
- if(bottom != -1 && line->GetPosition().y > bottom)
- break;
- wasDirty = true;
- }
- line->RecalculatePositions(1, this);
- line = line->GetNextLine();
- }
-
- // 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));
- AddCursorPosToUpdateRect();
+ {
+ if(cpos && line->GetLineNumber() == cpos->y)
+ {
+ line->Layout(dc, this,
+ cpos,
+ csize, NULL, cpos->x);
+ cursorReached = true;
+ }
+ else
+ line->Layout(dc, this);
+ }
+ }
+
+ line = line->GetNextLine();
+ }
+
+#ifndef WXLAYOUT_USE_CARET
+ // 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 // WXLAYOUT_USE_CARET
+
+ AddCursorPosToUpdateRect();
}
wxPoint
wxLayoutList::GetScreenPos(wxDC &dc, const wxPoint &cpos, wxPoint *csize)
{
- wxPoint pos = cpos;
- Layout(dc, -1, false, &pos, csize);
- return pos;
+ wxPoint pos = cpos;
+ Layout(dc, -1, false, &pos, csize);
+ return pos;
}
void
wxLayoutList::Draw(wxDC &dc,
wxPoint const &offset,
CoordType top,
- CoordType bottom)
-{
- wxLayoutLine *line = m_FirstLine;
-
- if ( m_Selection.m_discarded )
- {
- // calculate them if we don't have them already
- if ( !m_Selection.HasValidScreenCoords() )
- {
- m_Selection.m_ScreenA = GetScreenPos(dc, m_Selection.m_CursorA);
- m_Selection.m_ScreenB = GetScreenPos(dc, m_Selection.m_CursorB);
- }
-
- // invalidate the area which was previousle selected - and which is not
- // selected any more
- SetUpdateRect(m_Selection.m_ScreenA);
- SetUpdateRect(m_Selection.m_ScreenB);
+ CoordType bottom,
+ bool clipStrictly)
+{
+ wxLayoutLine *line = m_FirstLine;
+
+ if ( m_Selection.m_discarded )
+ {
+ // calculate them if we don't have them already
+ if ( !m_Selection.HasValidScreenCoords() )
+ {
+ m_Selection.m_ScreenA = GetScreenPos(dc, m_Selection.m_CursorA);
+ m_Selection.m_ScreenB = GetScreenPos(dc, m_Selection.m_CursorB);
+ }
+
+ // invalidate the area which was previousle selected - and which is not
+ // selected any more
+ SetUpdateRect(m_Selection.m_ScreenA);
+ SetUpdateRect(m_Selection.m_ScreenB);
+
+ m_Selection.m_discarded = false;
+ }
+
+ /* This call to Layout() will re-calculate and update all lines
+ marked as dirty.
+ */
+ Layout(dc, bottom);
+
+ ApplyStyle(m_DefaultStyleInfo, dc);
+ wxBrush brush(m_CurrentStyleInfo.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))
+ {
+ ApplyStyle(line->GetStyleInfo(), dc);
+ // little condition to speed up redrawing:
+ if( bottom != -1
+ && line->GetPosition().y
+ +(clipStrictly ? line->GetHeight() : 0) >= bottom)
+ break;
- m_Selection.m_discarded = false;
- }
+ line->Draw(dc, this, offset);
+ }
- /* We need to re-layout all dirty lines to update styleinfos
- etc. However, somehow we don't find all dirty lines... */
- Layout(dc); //,-1,true); //FIXME
- ApplyStyle(m_DefaultStyleInfo, dc);
- wxBrush brush(m_CurrentStyleInfo.m_bg, wxSOLID);
- dc.SetBrush(brush);
- dc.SetBackgroundMode(wxTRANSPARENT);
+ line = line->GetNextLine();
+ }
- bool style_set = false;
- while(line)
- {
- // only draw if between top and bottom:
- if((top == -1 ||
- line->GetPosition().y + line->GetHeight() >= top))
- {
-// if(! style_set)
- {
- ApplyStyle(line->GetStyleInfo(), dc);
- style_set = true;
- }
- line->Draw(dc, this, offset);
- }
-#if 0
- else
- line->Layout(dc, this);
-#endif
- // little condition to speed up redrawing:
- if(bottom != -1 && line->GetPosition().y > bottom) break;
- line = line->GetNextLine();
- }
- InvalidateUpdateRect();
+ 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));
+ WXLO_DEBUG((wxT("Selection is %s : %d,%d/%d,%d"),
+ m_Selection.m_valid ? wxT("valid") : wxT("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;
+ wxPoint *cursorPos, bool *found)
+{
+ wxLayoutObjectList::iterator nulled(NULL);
+ // First, find the right line:
+ wxLayoutLine
+ *line = m_FirstLine,
+ *lastline = m_FirstLine;
+ wxPoint p;
+
+ ApplyStyle(m_DefaultStyleInfo, dc);
+ while(line)
+ {
+ p = line->GetPosition();
+ if(p.y <= pos.y && p.y+line->GetHeight() >= pos.y)
+ break;
+ lastline = line;
+ line = line->GetNextLine();
+ }
- ApplyStyle(m_DefaultStyleInfo, 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)
- {
- 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;
+ bool didFind = line != NULL;
+
+ if ( !line )
+ {
+ // use the last line:
+ line = lastline;
+ }
+
+ if ( cursorPos )
+ cursorPos->y = line->GetLineNumber();
+
+ bool foundinline = true;
+ long cx = 0;
+
+ // Now, find the object in the line:
+ wxLOiterator i;
+
+ if (cursorPos)
+ {
+ i = line->FindObjectScreen(dc, this,
+ pos.x,
+ &cx,
+ &foundinline);
+ cursorPos->x = cx;
+ }
+ else
+ i = line->FindObjectScreen(dc, this,
+ pos.x,
+ NULL,
+ &foundinline);
+
+ if ( found )
+ *found = didFind && foundinline;
+
+ return (i == nulled) ? NULL : *i;
}
wxPoint
-wxLayoutList::GetSize(void) const
+wxLayoutList::GetSize() const
{
wxLayoutLine
*line = m_FirstLine,
void
-wxLayoutList::DrawCursor(wxDC &dc, bool active, wxPoint const &translate)
+wxLayoutList::DrawCursor(wxDC &
+#ifdef WXLAYOUT_USE_CARET
+ WXUNUSED(dc)
+#else
+ dc
+#endif
+ , bool
+#ifdef WXLAYOUT_USE_CARET
+ WXUNUSED(active)
+#else
+ active
+#endif
+ , wxPoint const &translate)
{
- if ( m_movedCursor )
- m_movedCursor = false;
+ if ( m_movedCursor )
+ m_movedCursor = false;
- wxPoint coords(m_CursorScreenPos);
- coords += 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);
+ WXLO_DEBUG((wxT("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(wxT("Cursor is at (%d, %d)"), m_CursorPos.x, m_CursorPos.y);
#endif
#ifdef WXLAYOUT_USE_CARET
- m_caret->Move(coords);
+ m_caret->Move(coords);
#else // !WXLAYOUT_USE_CARET
- dc.SetBrush(*wxWHITE_BRUSH);
- //FIXME: wxGTK XOR is borken at the moment!!!dc.SetLogicalFunction(wxXOR);
- 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);
+
+ wxASSERT(m_CursorSize.x >= WXLO_MINIMUM_CURSOR_WIDTH);
+ dc.SetBrush(*wxWHITE_BRUSH);
+ //FIXME: wxGTK XOR is borken at the moment!!!dc.SetLogicalFunction(wxXOR);
+ dc.SetPen(wxPen(*wxBLACK,1,wxSOLID));
+ if(active)
+ {
+ dc.SetLogicalFunction(wxXOR);
+ 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.SetLogicalFunction(wxCOPY);
+ 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;
- }
+ 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(const wxPoint& cposOrig, const wxPoint& spos)
{
- wxPoint cpos(cposOrig);
- 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_ScreenA = spos;
- m_Selection.m_ScreenB = spos;
- m_Selection.m_selecting = true;
- m_Selection.m_valid = false;
+ wxPoint cpos(cposOrig);
+ if ( cpos.x == -1 )
+ cpos = m_CursorPos;
+
+ WXLO_DEBUG((wxT("Starting selection at %d/%d"), cpos.x, cpos.y));
+
+ m_Selection.m_CursorA = cpos;
+ m_Selection.m_CursorB = cpos;
+ m_Selection.m_ScreenA = spos;
+ m_Selection.m_ScreenB = spos;
+ m_Selection.m_selecting = true;
+ m_Selection.m_valid = false;
}
void
wxASSERT(m_Selection.m_selecting == true);
wxASSERT(m_Selection.m_valid == false);
- WXLO_DEBUG(("Continuing selection at %ld/%ld", cpos.x, cpos.y));
+ WXLO_DEBUG((wxT("Continuing selection at %d/%d"), cpos.x, cpos.y));
- if ( m_Selection.m_CursorB <= cpos )
- {
- m_Selection.m_ScreenB = spos;
- m_Selection.m_CursorB = cpos;
- }
- else
- {
- m_Selection.m_ScreenA = spos;
- m_Selection.m_CursorA = cpos;
- }
-
- // we always want m_CursorA <= m_CursorB!
- if( m_Selection.m_CursorA > m_Selection.m_CursorB )
- {
- // exchange the start/end points
- wxPoint help = m_Selection.m_CursorB;
- m_Selection.m_CursorB = m_Selection.m_CursorA;
- m_Selection.m_CursorA = help;
-
- help = m_Selection.m_ScreenB;
- m_Selection.m_ScreenB = m_Selection.m_ScreenA;
- m_Selection.m_ScreenA = help;
- }
+ m_Selection.m_ScreenB = spos;
+ m_Selection.m_CursorB = cpos;
}
void
wxLayoutList::EndSelection(const wxPoint& cposOrig, const wxPoint& spos)
{
- wxPoint cpos(cposOrig);
- 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;
+ wxPoint cpos(cposOrig);
+
+ if(cpos.x == -1) cpos = m_CursorPos;
+
+ ContinueSelection(cpos, spos);
+
+ WXLO_DEBUG((wxT("Ending selection at %d/%d"), cpos.x, cpos.y));
+
+ // we always want m_CursorA <= m_CursorB!
+ if( m_Selection.m_CursorA > m_Selection.m_CursorB )
+ {
+ // exchange the start/end points
+ wxPoint help = m_Selection.m_CursorB;
+ m_Selection.m_CursorB = m_Selection.m_CursorA;
+ m_Selection.m_CursorA = help;
+
+ help = m_Selection.m_ScreenB;
+ m_Selection.m_ScreenB = m_Selection.m_ScreenA;
+ m_Selection.m_ScreenA = help;
+ }
+
+ m_Selection.m_selecting = false;
+ m_Selection.m_valid = true;
+ /// In case we just clicked somewhere, the selection will have zero
+ /// size, so we discard it immediately.
+ if(m_Selection.m_CursorA == m_Selection.m_CursorB)
+ {
+ DiscardSelection();
+ }
}
void
wxLayoutList::DiscardSelection()
{
- if ( !HasSelection() )
- return;
+ if ( !HasSelection() )
+ return;
- m_Selection.m_valid =
- m_Selection.m_selecting = false;
- m_Selection.m_discarded = true;
+ m_Selection.m_valid =
+ m_Selection.m_selecting = false;
+ m_Selection.m_discarded = true;
}
bool
-wxLayoutList::IsSelecting(void) const
+wxLayoutList::IsSelecting() const
{
- return m_Selection.m_selecting;
+ return m_Selection.m_selecting;
}
bool
wxLayoutList::IsSelected(const wxPoint &cursor) const
{
- if ( !HasSelection() )
- return false;
+ if ( !HasSelection() )
+ return false;
- return m_Selection.m_CursorA <= cursor && cursor <= m_Selection.m_CursorB;
+ return (
+ (m_Selection.m_CursorA <= cursor
+ && cursor <= m_Selection.m_CursorB)
+ || (m_Selection.m_CursorB <= cursor
+ && cursor <= m_Selection.m_CursorA)
+ );
}
*/
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;
+ 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)
+ || (m_Selection.m_CursorB.y < y && m_Selection.m_CursorA.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
+ {
+ if(m_Selection.m_CursorB > m_Selection.m_CursorA)
+ *to = line->GetLength();
+ else
+ *to = 0;
+ }
+
+ if(*to < *from)
+ {
+ CoordType help = *to;
+ *to = *from;
+ *from = help;
+ }
+
+ 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
+ {
+ if(m_Selection.m_CursorB > m_Selection.m_CursorA)
+ *from = 0;
+ else
+ *from = line->GetLength();
+ }
+
+ if(*to < *from)
+ {
+ CoordType help = *to;
+ *to = *from;
+ *from = help;
+ }
+ return -1;
+ }
+ else
+ {
+ return 0;
+ }
}
void
-wxLayoutList::DeleteSelection(void)
+wxLayoutList::DeleteSelection()
{
- 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;
- }
+ if (! m_Selection.m_valid)
+ return;
+ m_Selection.m_valid = false;
- 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;
+ // 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;
+ }
+ // We now know that the two lines are different:
- 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;
+ wxLayoutLine
+ * firstLine = GetLine(m_Selection.m_CursorA.y),
+ * lastLine = GetLine(m_Selection.m_CursorB.y);
+ // be a bit paranoid:
+ if(! firstLine || ! lastLine)
+ return;
- // We now know that the two lines are different:
+ // First, delete what's left of this line:
+ MoveCursorTo(m_Selection.m_CursorA);
+ DeleteToEndOfLine();
- // First, delete what's left of this line:
- MoveCursorTo(m_Selection.m_CursorA);
- DeleteToEndOfLine();
+ wxLayoutLine *prevLine = firstLine->GetPreviousLine(),
+ *nextLine = firstLine->GetNextLine();
- wxLayoutLine *nextLine = firstLine->GetNextLine();
- while(nextLine && nextLine != lastLine)
- nextLine = nextLine->DeleteLine(false, this);
+ 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
+ // 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);
+ // 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->MarkDirty();
}
/// Starts highlighting the selection
}
-wxLayoutList *
-wxLayoutList::Copy(const wxPoint &from,
- const wxPoint &to)
+wxLayoutLine *
+wxLayoutList::GetLine(CoordType index) const
{
- wxLayoutLine
- * firstLine = NULL,
- * lastLine = NULL;
-
- for(firstLine = m_FirstLine;
- firstLine && firstLine->GetLineNumber() < from.y;
- firstLine=firstLine->GetNextLine())
- ;
- if(!firstLine || firstLine->GetLineNumber() != from.y)
- return NULL;
+ wxASSERT_MSG( (0 <= index) && (index < (CoordType)m_numLines),
+ wxT("invalid index") );
- for(lastLine = m_FirstLine;
- lastLine && lastLine->GetLineNumber() < to.y;
- lastLine=lastLine->GetNextLine())
- ;
- if(!lastLine || lastLine->GetLineNumber() != to.y)
- return NULL;
+ wxLayoutLine *line;
+ CoordType n = index;
+#ifdef DEBUG
+ CoordType lineNo = 0;
+#endif
- if(to <= from)
- {
- wxLayoutLine *tmp = firstLine;
- firstLine = lastLine;
- lastLine = tmp;
- }
+ for ( line = m_FirstLine; line && n-- > 0; line = line->GetNextLine() )
+ {
+#ifdef DEBUG
+ wxASSERT(line->GetLineNumber() == lineNo );
+ lineNo++;
+#endif
+ }
- wxLayoutList *llist = new wxLayoutList();
+ if ( line )
+ {
+ // should be the right one
+ wxASSERT( line->GetLineNumber() == index );
+ }
- if(firstLine == lastLine)
- {
- firstLine->Copy(llist, from.x, to.x);
- }
- else
- {
- // Extract objects from first line
- firstLine->Copy(llist, from.x);
- llist->LineBreak();
- // Extract all lines between
- for(wxLayoutLine *line = firstLine->GetNextLine();
- line != lastLine;
- line = line->GetNextLine())
- {
- line->Copy(llist);
- llist->LineBreak();
- }
- // Extract objects from last line
- lastLine->Copy(llist, 0, to.x);
- }
- return llist;
+ return line;
+}
+
+
+wxLayoutList *
+wxLayoutList::Copy(const wxPoint &from,
+ const wxPoint &to)
+{
+ wxLayoutLine
+ * firstLine,
+ * lastLine;
+
+ for(firstLine = m_FirstLine;
+ firstLine && firstLine->GetLineNumber() < from.y;
+ firstLine=firstLine->GetNextLine())
+ ;
+
+ if(!firstLine || firstLine->GetLineNumber() != from.y)
+ return NULL;
+
+ for(lastLine = m_FirstLine;
+ lastLine && lastLine->GetLineNumber() < to.y;
+ lastLine=lastLine->GetNextLine())
+ ;
+
+ if(!lastLine || lastLine->GetLineNumber() != to.y)
+ return NULL;
+
+ if(to <= from)
+ {
+ wxLayoutLine *tmp = firstLine;
+ firstLine = lastLine;
+ lastLine = tmp;
+ }
+
+ wxLayoutList *llist = new wxLayoutList();
+
+ if(firstLine == lastLine)
+ {
+ firstLine->Copy(llist, from.x, to.x);
+ }
+ else
+ {
+ // Extract objects from first line
+ firstLine->Copy(llist, from.x);
+ llist->LineBreak();
+ // Extract all lines between
+ for ( wxLayoutLine *line = firstLine->GetNextLine();
+ line != lastLine;
+ line = line->GetNextLine() )
+ {
+ line->Copy(llist);
+ llist->LineBreak();
+ }
+
+ // Extract objects from last line
+ lastLine->Copy(llist, 0, to.x);
+ }
+
+ return llist;
}
wxLayoutList *
wxLayoutList::GetSelection(wxLayoutDataObject *wxlo, bool invalidate)
{
- if(! m_Selection.m_valid)
- {
- if(m_Selection.m_selecting)
- EndSelection();
- else
- return NULL;
- }
-
- 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;
+ if(! m_Selection.m_valid)
+ {
+ if(m_Selection.m_selecting)
+ EndSelection();
+ else
+ return NULL;
+ }
+
+ 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 *exp;
+ wxLayoutExportStatus status(llist);
+ while((exp = wxLayoutExport( &status, WXLO_EXPORT_AS_OBJECTS)) != NULL)
+ {
+ if(exp->type == WXLO_EXPORT_EMPTYLINE)
+ string << (int) WXLO_TYPE_LINEBREAK << '\n';
+ else
+ exp->content.object->Write(string);
+ delete exp;
+ }
- 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->SetLayoutData(string);
+ }
- wxlo->SetData(string.c_str(), string.Length()+1);
- }
- return llist;
+ return llist;
}
-#define COPY_SI(what) if(si.what != -1) { m_CurrentStyleInfo.what = si.what; fontChanged = TRUE; }
+#define COPY_SI(what) if(si.what != -1) { m_CurrentStyleInfo.what = si.what; fontChanged = true; }
void
wxLayoutList::ApplyStyle(wxLayoutStyleInfo const &si, wxDC &dc)
{
- bool fontChanged = FALSE;
- COPY_SI(family);
- COPY_SI(size);
- COPY_SI(style);
- COPY_SI(weight);
- COPY_SI(underline);
- if(fontChanged)
- dc.SetFont( m_FontCache.GetFont(m_CurrentStyleInfo) );
+ bool fontChanged = false;
+ COPY_SI(family);
+ COPY_SI(size);
+ COPY_SI(style);
+ COPY_SI(weight);
+ COPY_SI(underline);
+ if(fontChanged)
+ dc.SetFont( m_FontCache.GetFont(m_CurrentStyleInfo) );
- if(si.m_fg_valid)
- {
- m_CurrentStyleInfo.m_fg = si.m_fg;
- dc.SetTextForeground(m_CurrentStyleInfo.m_fg);
- }
- if(si.m_bg_valid)
- {
- m_CurrentStyleInfo.m_bg = si.m_bg;
- dc.SetTextBackground(m_CurrentStyleInfo.m_bg);
- }
+ if(si.m_fg_valid)
+ {
+ m_CurrentStyleInfo.m_fg = si.m_fg;
+ m_CurrentStyleInfo.m_fg_valid = true;
+ dc.SetTextForeground(m_CurrentStyleInfo.m_fg);
+ }
+
+ if(si.m_bg_valid)
+ {
+ m_CurrentStyleInfo.m_bg = si.m_bg;
+ m_CurrentStyleInfo.m_bg_valid = true;
+ dc.SetTextBackground(m_CurrentStyleInfo.m_bg);
+ }
}
#ifdef WXLAYOUT_DEBUG
void
-wxLayoutList::Debug(void)
+wxLayoutList::Debug()
{
- WXLO_DEBUG(("Cursor is in line %d, screen pos = (%d, %d)",
- m_CursorLine->GetLineNumber(),
- m_CursorScreenPos.x, m_CursorScreenPos.y));
+ WXLO_DEBUG((wxT("Cursor is in line %d, screen pos = (%d, %d)"),
+ (int)m_CursorLine->GetLineNumber(),
+ m_CursorScreenPos.x, m_CursorScreenPos.y));
- wxLayoutLine *line;
- for(line = m_FirstLine; line; line = line->GetNextLine())
- {
- line->Debug();
- }
+ wxLayoutLine *line;
+ for(line = m_FirstLine; line; line = line->GetNextLine())
+ {
+ line->Debug();
+ }
}
#endif
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
wxLayoutPrintout::wxLayoutPrintout(wxLayoutList *llist,
- wxString const & title)
-:wxPrintout(title)
-{
- m_llist = llist;
- m_title = title;
- // remove any highlighting which could interfere with printing:
- m_llist->StartSelection();
- m_llist->EndSelection();
-}
-
-wxLayoutPrintout::~wxLayoutPrintout()
+ wxString const & title)
+ :wxPrintout(title)
{
+ m_llist = llist;
+ m_title = title;
+ // remove any highlighting which could interfere with printing:
+ m_llist->StartSelection();
+ m_llist->EndSelection();
+ // force a full layout of the list:
+ m_llist->ForceTotalLayout();
+ // layout is called in ScaleDC() when we have a DC
}
float
wxLayoutPrintout::ScaleDC(wxDC *dc)
{
- // 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.
- */
- // Get the logical pixels per inch of screen and printer
- int ppiScreenX, ppiScreenY;
- GetPPIScreen(&ppiScreenX, &ppiScreenY);
- int ppiPrinterX, ppiPrinterY;
- GetPPIPrinter(&ppiPrinterX, &ppiPrinterY);
-
- if(ppiScreenX == 0) // not yet set, need to guess
- {
- ppiScreenX = 100;
- ppiScreenY = 100;
- }
- if(ppiPrinterX == 0) // not yet set, need to guess
- {
- 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
- // need to be addressed at some point but can be fudged for the
- // moment.
- float scale = (float)((float)ppiPrinterX/(float)ppiScreenX);
-
- // Now we have to check in case our real page size is reduced
- // (e.g. because we're drawing to a print preview memory DC)
- int pageWidth, pageHeight;
- int w, h;
- dc->GetSize(&w, &h);
- GetPageSizePixels(&pageWidth, &pageHeight);
- if(pageWidth != 0) // doesn't work always
- {
- // If printer pageWidth == current DC width, then this doesn't
- // change. But w might be the preview bitmap width, so scale down.
- scale = scale * (float)(w/(float)pageWidth);
- }
- dc->SetUserScale(scale, scale);
- return scale;
+ // 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.
+ */
+
+ // Get the logical pixels per inch of screen and printer
+ int ppiScreenX, ppiScreenY;
+ GetPPIScreen(&ppiScreenX, &ppiScreenY);
+ int ppiPrinterX, ppiPrinterY;
+ GetPPIPrinter(&ppiPrinterX, &ppiPrinterY);
+
+ if(ppiScreenX == 0) // not yet set, need to guess
+ {
+ ppiScreenX = 100;
+ ppiScreenY = 100;
+ }
+ wxUnusedVar(ppiScreenY);
+
+ if(ppiPrinterX == 0) // not yet set, need to guess
+ {
+ ppiPrinterX = 72;
+ ppiPrinterY = 72;
+ }
+ wxUnusedVar(ppiPrinterY);
+
+ // 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
+ // need to be addressed at some point but can be fudged for the
+ // moment.
+ float scale = (float)((float)ppiPrinterX/(float)ppiScreenX);
+
+ // Now we have to check in case our real page size is reduced
+ // (e.g. because we're drawing to a print preview memory DC)
+ int pageWidth, pageHeight;
+ int w, h;
+ dc->GetSize(&w, &h);
+ GetPageSizePixels(&pageWidth, &pageHeight);
+ wxUnusedVar(pageHeight);
+ if(pageWidth != 0) // doesn't work always
+ {
+ // If printer pageWidth == current DC width, then this doesn't
+ // change. But w might be the preview bitmap width, so scale down.
+ scale = scale * (float)(w/(float)pageWidth);
+ }
+
+ dc->SetUserScale(scale, scale);
+ return scale;
}
bool wxLayoutPrintout::OnPrintPage(int page)
{
- wxDC *dc = GetDC();
+ wxDC *dc = GetDC();
- ScaleDC(dc);
+ ScaleDC(dc);
- if (dc)
- {
- int top, bottom;
- top = (page - 1)*m_PrintoutHeight;
- bottom = top + m_PrintoutHeight;
- // SetDeviceOrigin() doesn't work here, so we need to manually
- // translate all coordinates.
- wxPoint translate(m_Offset.x,m_Offset.y-top);
- m_llist->Draw(*dc, translate, top, bottom);
- return true;
+ if (dc)
+ {
+ int top, bottom;
+ top = (page - 1)*m_PrintoutHeight;
+ bottom = top + m_PrintoutHeight;
+
+ WXLO_DEBUG((wxT("OnPrintPage(%d) printing from %d to %d"), page, top,
+ bottom));
+
+ // SetDeviceOrigin() doesn't work here, so we need to manually
+ // translate all coordinates.
+ wxPoint translate(m_Offset.x,m_Offset.y-top);
+ m_llist->Draw(*dc, translate, top, bottom, true /* clip strictly */);
+ return true;
}
else
+ {
return false;
+ }
}
void wxLayoutPrintout::GetPageInfo(int *minPage, int *maxPage, int *selPageFrom, int *selPageTo)
/* We allocate a temporary wxDC for printing, so that we can
determine the correct paper size and scaling. We don't actually
print anything on it. */
-#ifdef __WXMSW__
- wxPrinterDC psdc("","",WXLLIST_TEMPFILE,false);
+#if defined(__WXMSW__) || defined(__WXMAC__)
+ wxPrinterDC *psdc = new wxPrinterDC(wxEmptyString,wxEmptyString,_T(WXLLIST_TEMPFILE),false);
#else
- wxPostScriptDC psdc(WXLLIST_TEMPFILE,false);
+ wxPrintData data;
+ data.SetFilename(WXLLIST_TEMPFILE);
+ wxPostScriptDC *psdc = new wxPostScriptDC(data);
#endif
- float scale = ScaleDC(&psdc);
+ psdc->StartDoc(m_title);
+ // before we draw anything, me must make sure the list is properly
+ // laid out
+ m_llist->Layout(*psdc);
- psdc.GetSize(&m_PageWidth, &m_PageHeight);
- // This sets a left/top origin of 15% and 20%:
- m_Offset = wxPoint((15*m_PageWidth)/100, m_PageHeight/20);
+ float scale = ScaleDC(psdc);
+
+ psdc->GetSize(&m_PageWidth, &m_PageHeight);
+
+ // This sets a left/top origin of 15% and 5%:
+ m_Offset = wxPoint((15*m_PageWidth)/100, (5*m_PageHeight)/100);
// This is the length of the printable area.
- m_PrintoutHeight = m_PageHeight - (int) (m_PageHeight * 0.15);
+ m_PrintoutHeight = m_PageHeight - 2*m_Offset.y;
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));
*selPageFrom = 1;
*selPageTo = m_NumOfPages;
- wxRemoveFile(WXLLIST_TEMPFILE);
+ psdc->EndDoc();
+ delete psdc;
+ wxRemoveFile(_T(WXLLIST_TEMPFILE));
}
bool wxLayoutPrintout::HasPage(int pageNum)
}
/*
- Stupid wxWindows doesn't draw proper ellipses, so we comment this
+ Stupid wxWidgets doesn't draw proper ellipses, so we comment this
out. It's a waste of paper anyway.
*/
#if 0