Updated from Mahogany source

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/WX_2_2_BRANCH@7378 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Karsten Ballüder
2000-05-10 20:00:53 +00:00
parent bf49fbcff9
commit 548812d9af
5 changed files with 382 additions and 129 deletions

View File

@@ -10,6 +10,14 @@ by Karsten Ballueder <ballueder@usa.net>.
This is still work in progress, so if you want to make any significant This is still work in progress, so if you want to make any significant
changes, please get in touch with me before. changes, please get in touch with me before.
*** THIS SOURCE IS USUALLY OUTDATED AND FOR DEMONSTRATION ONLY ***
*** GET THE VERY LATEST VERSION OF THE WXLAYOUT CLASSES FROM ***
*** THE SOURCE OF THE MAHOGANY MAIL/NEWS CLIENT, AVAILABLE FROM ***
*** http://www.wxwindows.org/Mahogany/ ***
There are three building blocks for rich text editing: There are three building blocks for rich text editing:
wxllist : wxllist :

View File

@@ -1,7 +1,7 @@
/*-*- c++ -*-******************************************************** /*-*- c++ -*-********************************************************
* wxllist: wxLayoutList, a layout engine for text and graphics * * wxllist: wxLayoutList, a layout engine for text and graphics *
* * * *
* (C) 1998-1999 by Karsten Ball<6C>der (Ballueder@usa.net) * * (C) 1998-2000 by Karsten Ball<6C>der (Ballueder@gmx.net) *
* * * *
* $Id$ * $Id$
*******************************************************************/ *******************************************************************/
@@ -60,6 +60,7 @@
#include <ctype.h> #include <ctype.h>
/// This should never really get created /// This should never really get created
#define WXLLIST_TEMPFILE "__wxllist.tmp" #define WXLLIST_TEMPFILE "__wxllist.tmp"
@@ -72,16 +73,19 @@
{ {
"invalid", "text", "cmd", "icon" "invalid", "text", "cmd", "icon"
}; };
void wxString
wxLayoutObject::Debug(void) wxLayoutObject::DebugDump(void) const
{ {
WXLO_DEBUG(("%s",g_aTypeStrings[GetType()])); wxString str;
str.Printf("%s",g_aTypeStrings[GetType()]);
return str;
} }
#else #else
# define TypeString(t) "" # define TypeString(t) ""
# define WXLO_DEBUG(x) # define WXLO_DEBUG(x)
#endif #endif
// FIXME under MSW, this constant is needed to make the thing properly redraw // 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 // 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 // waste time looking for it right now. Search for occurences of
@@ -165,6 +169,7 @@ bool Contains(const wxRect &r, const wxPoint &p)
//@} //@}
static
void ReadString(wxString &to, wxString &from) void ReadString(wxString &to, wxString &from)
{ {
to = ""; to = "";
@@ -187,7 +192,7 @@ wxLayoutObject::Read(wxString &istr)
{ {
wxString tmp; wxString tmp;
ReadString(tmp, istr); ReadString(tmp, istr);
int type = -1; int type = WXLO_TYPE_INVALID;
sscanf(tmp.c_str(),"%d", &type); sscanf(tmp.c_str(),"%d", &type);
switch(type) switch(type)
@@ -370,11 +375,14 @@ wxLayoutObjectText::Layout(wxDC &dc, class wxLayoutList *llist)
#ifdef WXLAYOUT_DEBUG #ifdef WXLAYOUT_DEBUG
void wxString
wxLayoutObjectText::Debug(void) wxLayoutObjectText::DebugDump(void) const
{ {
wxLayoutObject::Debug(); wxString str;
WXLO_DEBUG((" `%s`", m_Text.c_str())); str = wxLayoutObject::DebugDump();
wxString str2;
str2.Printf(" `%s`", m_Text.c_str());
return str+str2;
} }
#endif #endif
@@ -412,7 +420,7 @@ wxLayoutObjectIcon::Write(wxString &ostr)
wxString file = wxGetTempFileName("wxloexport"); wxString file = wxGetTempFileName("wxloexport");
ostr << WXLO_TYPE_ICON << '\n' ostr << (int) WXLO_TYPE_ICON << '\n'
<< file << '\n'; << file << '\n';
m_Icon->SaveFile(file, WXLO_BITMAP_FORMAT); m_Icon->SaveFile(file, WXLO_BITMAP_FORMAT);
} }
@@ -449,11 +457,7 @@ wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap *icon)
{ {
m_Icon = icon; m_Icon = icon;
if(! m_Icon) if(! m_Icon)
#if wxICON_IS_BITMAP
m_Icon = new wxIcon;
#else
m_Icon = new wxBitmap; m_Icon = new wxBitmap;
#endif
} }
void void
@@ -557,25 +561,25 @@ wxLayoutObjectCmd::Copy(void)
void void
wxLayoutObjectCmd::Write(wxString &ostr) wxLayoutObjectCmd::Write(wxString &ostr)
{ {
ostr << WXLO_TYPE_CMD << '\n' ostr << (int) WXLO_TYPE_CMD << '\n'
<< m_StyleInfo->family << '\n' << (int) m_StyleInfo->family << '\n'
<< m_StyleInfo->size << '\n' << (int) m_StyleInfo->size << '\n'
<< m_StyleInfo->style << '\n' << (int) m_StyleInfo->style << '\n'
<< m_StyleInfo->weight << '\n' << (int) m_StyleInfo->weight << '\n'
<< m_StyleInfo->underline << '\n' << (int) m_StyleInfo->underline << '\n'
<< m_StyleInfo->m_fg_valid << '\n' << (int) m_StyleInfo->m_fg_valid << '\n'
<< m_StyleInfo->m_bg_valid << '\n'; << (int) m_StyleInfo->m_bg_valid << '\n';
if(m_StyleInfo->m_fg_valid) if(m_StyleInfo->m_fg_valid)
{ {
ostr << m_StyleInfo->m_fg.Red() << '\n' ostr << (int) m_StyleInfo->m_fg.Red() << '\n'
<< m_StyleInfo->m_fg.Green() << '\n' << (int) m_StyleInfo->m_fg.Green() << '\n'
<< m_StyleInfo->m_fg.Blue() << '\n'; << (int) m_StyleInfo->m_fg.Blue() << '\n';
} }
if(m_StyleInfo->m_bg_valid) if(m_StyleInfo->m_bg_valid)
{ {
ostr << m_StyleInfo->m_bg.Red() << '\n' ostr << (int) m_StyleInfo->m_bg.Red() << '\n'
<< m_StyleInfo->m_bg.Green() << '\n' << (int) m_StyleInfo->m_bg.Green() << '\n'
<< m_StyleInfo->m_bg.Blue() << '\n'; << (int) m_StyleInfo->m_bg.Blue() << '\n';
} }
} }
/* static */ /* static */
@@ -665,10 +669,9 @@ wxLayoutLine::wxLayoutLine(wxLayoutLine *prev, wxLayoutList *llist)
m_Length = 0; m_Length = 0;
m_updateLeft = -1; m_updateLeft = -1;
MarkDirty(0);
m_Previous = prev; m_Previous = prev;
m_Next = NULL; m_Next = NULL;
MarkDirty(0);
m_LineNumber = 0; m_LineNumber = 0;
RecalculatePosition(llist); RecalculatePosition(llist);
@@ -1273,7 +1276,9 @@ wxLayoutLine::Break(CoordType xpos, wxLayoutList *llist)
wxLayoutLine *newLine = new wxLayoutLine(this, llist); wxLayoutLine *newLine = new wxLayoutLine(this, llist);
// split object at i: // 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; wxString left, right;
wxLayoutObjectText *tobj = (wxLayoutObjectText *) *i; wxLayoutObjectText *tobj = (wxLayoutObjectText *) *i;
@@ -1304,6 +1309,130 @@ wxLayoutLine::Break(CoordType xpos, wxLayoutList *llist)
return newLine; return newLine;
} }
bool
wxLayoutLine::Wrap(CoordType wrapmargin, wxLayoutList *llist)
{
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 != NULLIT, FALSE, "Cannot find object covering wrapmargin.");
// from this object on, the rest of the line must be copied to the
// next one:
wxLOiterator copyObject = NULLIT;
// if we split a text-object, we must pre-pend some text to the
// next line later on, remember it here:
wxString prependText = "";
// 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 != NULLIT && (**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 != NULLIT && 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 != NULLIT)
{
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 ));
wxASSERT(xpos >= 0);
llist->MoveCursorTo( wxPoint( xpos, m_Next->GetLineNumber()) );
}
return TRUE; // we wrapped the line
}
void void
wxLayoutLine::ReNumber(void) wxLayoutLine::ReNumber(void)
{ {
@@ -1389,7 +1518,7 @@ wxLayoutLine::GetWrapPosition(CoordType column)
{ {
do do
{ {
if( isspace(((wxLayoutObjectText*)*i)->GetText().c_str()[(size_t)offset])) if(isspace(((wxLayoutObjectText*)*i)->GetText().c_str()[(size_t)offset]))
return column; return column;
else else
{ {
@@ -1418,25 +1547,23 @@ wxLayoutLine::GetWrapPosition(CoordType column)
i++; i++;
} }
if(i == NULLIT) return -1; //why should this happen? if(i == NULLIT) 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(); pos += (**i).GetLength();
i++; return pos;
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
} }
#ifdef WXLAYOUT_DEBUG #ifdef WXLAYOUT_DEBUG
void void
wxLayoutLine::Debug(void) wxLayoutLine::Debug(void) const
{ {
wxString tmp;
wxPoint pos = GetPosition(); wxPoint pos = GetPosition();
WXLO_DEBUG(("Line %ld, Pos (%ld,%ld), Height %ld, BL %ld, Font: %d", WXLO_DEBUG(("Line %ld, Pos (%ld,%ld), Height %ld, BL %ld, Font: %d",
(long int) GetLineNumber(), (long int) GetLineNumber(),
@@ -1445,7 +1572,9 @@ wxLayoutLine::Debug(void)
(long int) m_BaseLine, (long int) m_BaseLine,
(int) m_StyleInfo.family)); (int) m_StyleInfo.family));
if(m_ObjectList.begin() != NULLIT) if(m_ObjectList.begin() != NULLIT)
(**m_ObjectList.begin()).Debug(); {
WXLO_DEBUG(((**m_ObjectList.begin()).DebugDump().c_str()));
}
} }
#endif #endif
@@ -1592,9 +1721,22 @@ wxLayoutList::Read(wxString &istr)
while(istr.Length()) while(istr.Length())
{ {
wxLayoutObject *obj = wxLayoutObject::Read(istr); // check for a linebreak:
if(obj) wxString tmp;
Insert(obj); tmp = istr.BeforeFirst('\n');
int type = WXLO_TYPE_INVALID;
sscanf(tmp.c_str(),"%d", &type);
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: */ /* Now we use the current_si to restore our last font settings: */
Insert(new wxLayoutObjectCmd(current_si)); Insert(new wxLayoutObjectCmd(current_si));
@@ -1746,6 +1888,7 @@ wxLayoutList::MoveCursorVertically(int n)
{ {
n--; n--;
m_CursorPos.y ++; m_CursorPos.y ++;
last = m_CursorLine;
m_CursorLine = m_CursorLine->GetNextLine(); m_CursorLine = m_CursorLine->GetNextLine();
} }
if(! m_CursorLine) if(! m_CursorLine)
@@ -1983,9 +2126,10 @@ wxLayoutList::Insert(wxString const &text)
AddCursorPosToUpdateRect(); AddCursorPosToUpdateRect();
wxASSERT(m_CursorLine->GetLength() >= m_CursorPos.x);
if ( !m_CursorLine->Insert(m_CursorPos.x, text) ) if ( !m_CursorLine->Insert(m_CursorPos.x, text) )
return false; return false;
m_CursorPos.x += text.Length(); m_CursorPos.x += text.Length();
m_movedCursor = true; m_movedCursor = true;
@@ -2076,29 +2220,22 @@ wxLayoutList::LineBreak(void)
bool bool
wxLayoutList::WrapLine(CoordType column) wxLayoutList::WrapLine(CoordType column)
{ {
if(m_CursorPos.x <= column || column < 1) return m_CursorLine->Wrap(column, this);
return false; // do nothing yet }
else
bool
wxLayoutList::WrapAll(CoordType column)
{
wxLayoutLine *line = m_FirstLine;
if(! line)
return FALSE;
bool rc = TRUE;
while(line && rc)
{ {
CoordType xpos = m_CursorLine->GetWrapPosition(column); rc &= line->Wrap(column, this);
if(xpos == -1) line = line->GetNextLine();
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->MarkDirty();
m_movedCursor = true;
return true;
} }
return rc;
} }
bool bool
@@ -2262,6 +2399,9 @@ wxLayoutList::Layout(wxDC &dc, CoordType bottom, bool forceAll,
// If one line was dirty, we need to re-calculate all // If one line was dirty, we need to re-calculate all
// following lines, too. // following lines, too.
bool wasDirty = forceAll; 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; wxLayoutLine *line = m_FirstLine;
while(line) while(line)
{ {
@@ -2271,6 +2411,8 @@ wxLayoutList::Layout(wxDC &dc, CoordType bottom, bool forceAll,
// if any previous line was dirty, we need to layout all // if any previous line was dirty, we need to layout all
// following lines: // following lines:
wasDirty wasDirty
// go on until we find the cursorline
|| ! cursorReached
// layout dirty lines: // layout dirty lines:
|| line->IsDirty() || line->IsDirty()
// always layout the cursor line toupdate the cursor // always layout the cursor line toupdate the cursor
@@ -2278,6 +2420,9 @@ wxLayoutList::Layout(wxDC &dc, CoordType bottom, bool forceAll,
|| line == m_CursorLine || line == m_CursorLine
// or if it's the line we are asked to look for: // or if it's the line we are asked to look for:
|| (cpos && line->GetLineNumber() == cpos->y) || (cpos && line->GetLineNumber() == cpos->y)
// layout at least the desired region:
|| (bottom == -1 )
|| (line->GetPosition().y <= bottom)
) )
{ {
if(line->IsDirty()) if(line->IsDirty())
@@ -2299,17 +2444,20 @@ wxLayoutList::Layout(wxDC &dc, CoordType bottom, bool forceAll,
if ( csize ) if ( csize )
*csize = m_CursorSize; *csize = m_CursorSize;
} }
cursorReached = TRUE;
} }
else else
{
if(cpos && line->GetLineNumber() == cpos->y) if(cpos && line->GetLineNumber() == cpos->y)
{
line->Layout(dc, this, line->Layout(dc, this,
cpos, cpos,
csize, NULL, cpos->x); csize, NULL, cpos->x);
else cursorReached = TRUE;
line->Layout(dc, this); }
// little condition to speed up redrawing: else
if(bottom != -1 && line->GetPosition().y > bottom) line->Layout(dc, this);
break; }
} }
line = line->GetNextLine(); line = line->GetNextLine();
} }
@@ -2385,7 +2533,7 @@ wxLayoutList::Draw(wxDC &dc,
} }
InvalidateUpdateRect(); InvalidateUpdateRect();
WXLO_DEBUG(("Selection is %s : l%d,%ld/%ld,%ld", WXLO_DEBUG(("Selection is %s : %ld,%ld/%ld,%ld",
m_Selection.m_valid ? "valid" : "invalid", m_Selection.m_valid ? "valid" : "invalid",
m_Selection.m_CursorA.x, m_Selection.m_CursorA.y, m_Selection.m_CursorA.x, m_Selection.m_CursorA.y,
m_Selection.m_CursorB.x, m_Selection.m_CursorB.y)); m_Selection.m_CursorB.x, m_Selection.m_CursorB.y));
@@ -2500,7 +2648,7 @@ wxLayoutList::DrawCursor(wxDC &dc, bool active, wxPoint const &translate)
#ifdef WXLAYOUT_DEBUG #ifdef WXLAYOUT_DEBUG
WXLO_DEBUG(("Drawing cursor (%ld,%ld) at %ld,%ld, size %ld,%ld, line: %ld, len %ld", 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)m_CursorPos.x, (long)m_CursorPos.y,
(long)coords.x, (long)coords.y, (long)coords.x, (long)coords.y,
(long)m_CursorSize.x, (long)m_CursorSize.y, (long)m_CursorSize.x, (long)m_CursorSize.y,
(long)m_CursorLine->GetLineNumber(), (long)m_CursorLine->GetLineNumber(),
(long)m_CursorLine->GetLength())); (long)m_CursorLine->GetLength()));
@@ -2522,7 +2670,8 @@ wxLayoutList::DrawCursor(wxDC &dc, bool active, wxPoint const &translate)
dc.DrawRectangle(coords.x, coords.y, dc.DrawRectangle(coords.x, coords.y,
m_CursorSize.x, m_CursorSize.y); m_CursorSize.x, m_CursorSize.y);
SetUpdateRect(coords.x, coords.y); SetUpdateRect(coords.x, coords.y);
SetUpdateRect(coords.x+m_CursorSize.x, coords.y+m_CursorSize.y); SetUpdateRect(coords.x+m_CursorSize.x,
coords.y+m_CursorSize.y);
} }
else else
{ {
@@ -2883,7 +3032,7 @@ wxLayoutList::GetSelection(wxLayoutDataObject *wxlo, bool invalidate)
while((exp = wxLayoutExport( &status, WXLO_EXPORT_AS_OBJECTS)) != NULL) while((exp = wxLayoutExport( &status, WXLO_EXPORT_AS_OBJECTS)) != NULL)
{ {
if(exp->type == WXLO_EXPORT_EMPTYLINE) if(exp->type == WXLO_EXPORT_EMPTYLINE)
; //FIXME missing support for linebreaks in string format string << (int) WXLO_TYPE_LINEBREAK << '\n';
else else
exp->content.object->Write(string); exp->content.object->Write(string);
delete exp; delete exp;

View File

@@ -1,7 +1,7 @@
/*-*- c++ -*-******************************************************** /*-*- c++ -*-********************************************************
* wxLayoutList.h - a formatted text rendering engine for wxWindows * * wxLayoutList.h - a formatted text rendering engine for wxWindows *
* * * *
* (C) 1999 by Karsten Ball<6C>der (ballueder@gmx.net) * * (C) 1999-2000 by Karsten Ball<6C>der (ballueder@gmx.net) *
* * * *
* $Id$ * $Id$
*******************************************************************/ *******************************************************************/
@@ -38,17 +38,38 @@
# define WXLAYOUT_USE_CARET 1 # define WXLAYOUT_USE_CARET 1
#endif // __WXMSW__ #endif // __WXMSW__
// do not enable debug mode within Mahogany // do not enable debug mode within Mahogany unless in debug mode
#if defined(__WXDEBUG__) && ! defined(M_BASEDIR) #if defined(__WXDEBUG__) && (( ! defined(M_BASEDIR) )|| defined(DEBUG))
# define WXLAYOUT_DEBUG # define WXLAYOUT_DEBUG
#endif #endif
#ifdef WXLAYOUT_DEBUG #ifdef WXLAYOUT_DEBUG
# define WXLO_TRACE(x) wxLogDebug(x) # define WXLO_TRACE(x) wxLogDebug(x)
// activate profiling: # define WXLO_PROFILE
#else #else
# define WXLO_TRACE(x) # define WXLO_TRACE(x)
#endif #endif
/* Some profiling code: */
#if defined (WXLO_PROFILE)
#include <sys/time.h>
#include <unistd.h>
# define WXLO_TIMER_DEFINE(x) static struct timeval x
# define WXLO_TIMER_START(x) gettimeofday(&x,NULL)
# define WXLO_TIMER_STOP(x) { struct timeval y; \
gettimeofday(&y,NULL); \
x.tv_sec -= y.tv_sec; x.tv_usec -= y.tv_usec; }
# define WXLO_TIMER_PRINT(x) wxLogDebug("Timer " #x " elapsed: %ld", \
(long)(x.tv_sec * -1000 - x.tv_usec));
#else
# define WXLO_TIMER_DEFINE(x)
# define WXLO_TIMER_START(x)
# define WXLO_TIMER_STOP(x)
# define WXLO_TIMER_PRINT(x)
#endif
#define WXLO_DEBUG_URECT 0 #define WXLO_DEBUG_URECT 0
#ifndef WXLO_DEFAULTFONTSIZE #ifndef WXLO_DEFAULTFONTSIZE
@@ -71,7 +92,9 @@ enum wxLayoutObjectType
/// command object, containing font or colour changes /// command object, containing font or colour changes
WXLO_TYPE_CMD, WXLO_TYPE_CMD,
/// icon object, any kind of image /// icon object, any kind of image
WXLO_TYPE_ICON WXLO_TYPE_ICON,
/// a linebreak, does not exist as an object
WXLO_TYPE_LINEBREAK
}; };
/// Type used for coordinates in drawing. Must be signed. /// Type used for coordinates in drawing. Must be signed.
@@ -171,7 +194,7 @@ public:
virtual ~wxLayoutObject() { if(m_UserData) m_UserData->DecRef(); } virtual ~wxLayoutObject() { if(m_UserData) m_UserData->DecRef(); }
#ifdef WXLAYOUT_DEBUG #ifdef WXLAYOUT_DEBUG
virtual void Debug(void); virtual wxString DebugDump(void) const;
#endif #endif
/** Tells the object about some user data. This data is associated /** Tells the object about some user data. This data is associated
@@ -266,7 +289,7 @@ public:
static wxLayoutObjectText *Read(wxString &istr); static wxLayoutObjectText *Read(wxString &istr);
#ifdef WXLAYOUT_DEBUG #ifdef WXLAYOUT_DEBUG
virtual void Debug(void); virtual wxString DebugDump(void) const;
#endif #endif
virtual CoordType GetLength(void) const { return strlen(m_Text.c_str()); } virtual CoordType GetLength(void) const { return strlen(m_Text.c_str()); }
@@ -475,11 +498,18 @@ public:
void Append(wxLayoutObject * obj) void Append(wxLayoutObject * obj)
{ {
wxASSERT(obj); wxASSERT(obj);
m_ObjectList.push_back(obj); m_ObjectList.push_back(obj);
m_Length += obj->GetLength(); m_Length += obj->GetLength();
} }
/** This function prepends an object to the line. */
void Prepend(wxLayoutObject * obj)
{
wxASSERT(obj);
m_ObjectList.push_front(obj);
m_Length += obj->GetLength();
}
/** This function appens the next line to this, i.e. joins the two /** This function appens the next line to this, i.e. joins the two
lines into one. lines into one.
*/ */
@@ -498,6 +528,13 @@ public:
*/ */
wxLayoutLine *Break(CoordType xpos, wxLayoutList *llist); wxLayoutLine *Break(CoordType xpos, wxLayoutList *llist);
/** This function wraps the line: breaks it at a suitable point
and merges it with the next.
@param wrapmargin
@return TRUE if broken
*/
bool Wrap(CoordType wrapmargin, wxLayoutList *llist);
/** Deletes the next word from this position, including leading /** Deletes the next word from this position, including leading
whitespace. whitespace.
This function does not delete over font changes, i.e. a word This function does not delete over font changes, i.e. a word
@@ -662,7 +699,7 @@ public:
CoordType to = -1); CoordType to = -1);
#ifdef WXLAYOUT_DEBUG #ifdef WXLAYOUT_DEBUG
void Debug(void); void Debug(void) const;
#endif #endif
wxLayoutStyleInfo const & GetStyleInfo() const { return m_StyleInfo; } wxLayoutStyleInfo const & GetStyleInfo() const { return m_StyleInfo; }
@@ -680,6 +717,7 @@ public:
} }
m_Dirty = true; m_Dirty = true;
if(m_Next) m_Next->MarkDirty();
} }
/// Reset the dirty flag /// Reset the dirty flag
void MarkClean() { m_Dirty = false; m_updateLeft = -1; } void MarkClean() { m_Dirty = false; m_updateLeft = -1; }
@@ -815,7 +853,8 @@ public:
/// Returns current cursor position. /// Returns current cursor position.
const wxPoint &GetCursorPos(wxDC &dc) const { return m_CursorPos; } const wxPoint &GetCursorPos(wxDC &dc) const { return m_CursorPos; }
const wxPoint &GetCursorPos() const { return m_CursorPos; } const wxPoint &GetCursorPos() const { return m_CursorPos; }
wxLayoutLine * GetCursorLine(void) { return m_CursorLine; }
/// move cursor to the end of text /// move cursor to the end of text
void MoveCursorToEnd(void) void MoveCursorToEnd(void)
{ {
@@ -845,6 +884,12 @@ public:
@return true if line got broken @return true if line got broken
*/ */
bool WrapLine(CoordType column); bool WrapLine(CoordType column);
/** Wraps the complete buffer.
@param column the break position for the line, maximum length
@return true if line got broken
*/
bool WrapAll(CoordType column);
/** This function deletes npos cursor positions. /** This function deletes npos cursor positions.
@param npos how many positions @param npos how many positions
@return true if everything got deleted @return true if everything got deleted
@@ -1142,7 +1187,8 @@ public:
/// get the line by number /// get the line by number
wxLayoutLine *GetLine(CoordType index) const; wxLayoutLine *GetLine(CoordType index) const;
/** Reads objects from a string and inserts them. /** Reads objects from a string and inserts them. Returns NULL if
string is empty or a linebreak was found.
@param istr stream to read from, will bee changed @param istr stream to read from, will bee changed
*/ */
void Read(wxString &istr); void Read(wxString &istr);

View File

@@ -1,7 +1,7 @@
/*-*- c++ -*-******************************************************** /*-*- c++ -*-********************************************************
* wxLwindow.h : a scrolled Window for displaying/entering rich text* * wxLwindow.h : a scrolled Window for displaying/entering rich text*
* * * *
* (C) 1998, 1999 by Karsten Ball<6C>der (karsten@phy.hw.ac.uk) * * (C) 1998-2000 by Karsten Ball<6C>der (ballueder@gmx.net) *
* * * *
* $Id$ * $Id$
*******************************************************************/ *******************************************************************/
@@ -56,6 +56,7 @@
#include <ctype.h> #include <ctype.h>
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// macros // macros
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -66,6 +67,13 @@
# define WXLO_DEBUG(x) # define WXLO_DEBUG(x)
#endif #endif
// for profiling in debug mode:
WXLO_TIMER_DEFINE(UpdateTimer);
WXLO_TIMER_DEFINE(BlitTimer);
WXLO_TIMER_DEFINE(LayoutTimer);
WXLO_TIMER_DEFINE(TmpTimer);
WXLO_TIMER_DEFINE(DrawTimer);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// constants // constants
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -160,6 +168,7 @@ wxLayoutWindow::wxLayoutWindow(wxWindow *parent)
#ifndef __WXMSW__ #ifndef __WXMSW__
m_FocusFollowMode = false; m_FocusFollowMode = false;
#endif #endif
SetWordWrap(false);
SetWrapMargin(0); SetWrapMargin(0);
// no scrollbars initially // no scrollbars initially
@@ -230,10 +239,11 @@ wxLayoutWindow::OnMouse(int eventId, wxMouseEvent& event)
{ {
wxClientDC dc( this ); wxClientDC dc( this );
PrepareDC( dc ); PrepareDC( dc );
if ( eventId != WXLOWIN_MENU_MOUSEMOVE if ( (eventId != WXLOWIN_MENU_MOUSEMOVE
#ifndef __WXMSW__ #ifndef __WXMSW__
|| m_FocusFollowMode || m_FocusFollowMode
#endif #endif
) && (wxWindow::FindFocus() != this)
) )
SetFocus(); SetFocus();
@@ -479,6 +489,7 @@ wxLayoutWindow::OnChar(wxKeyEvent& event)
bool deletedSelection = false; bool deletedSelection = false;
// pressing any non-arrow key optionally replaces the selection: // pressing any non-arrow key optionally replaces the selection:
if(m_AutoDeleteSelection if(m_AutoDeleteSelection
&& IsEditable()
&& !m_Selecting && !m_Selecting
&& m_llist->HasSelection() && m_llist->HasSelection()
&& ! IsDirectionKey(keyCode) && ! IsDirectionKey(keyCode)
@@ -635,10 +646,21 @@ wxLayoutWindow::OnChar(wxKeyEvent& event)
case 'x': case 'x':
Cut(); Cut();
break; break;
case 'w':
if(m_WrapMargin > 0)
m_llist->WrapLine(m_WrapMargin);
break;
case 'q':
if(m_WrapMargin > 0)
m_llist->WrapAll(m_WrapMargin);
break;
#ifdef WXLAYOUT_DEBUG #ifdef WXLAYOUT_DEBUG
case WXK_F1: case WXK_F1:
m_llist->SetFont(-1,-1,-1,-1,true); // underlined m_llist->SetFont(-1,-1,-1,-1,true); // underlined
break; break;
case 'l':
Refresh(TRUE);
break;
#endif #endif
default: default:
// we don't handle it, maybe an accelerator? // we don't handle it, maybe an accelerator?
@@ -688,7 +710,9 @@ wxLayoutWindow::OnChar(wxKeyEvent& event)
} }
break; break;
case WXK_RETURN: case WXK_RETURN:
if(m_WrapMargin > 0) if(m_DoWordWrap &&
m_WrapMargin > 0
&& m_llist->GetCursorPos().x > m_WrapMargin)
m_llist->WrapLine(m_WrapMargin); m_llist->WrapLine(m_WrapMargin);
m_llist->LineBreak(); m_llist->LineBreak();
SetDirty(); SetDirty();
@@ -706,23 +730,19 @@ wxLayoutWindow::OnChar(wxKeyEvent& event)
SetDirty(); SetDirty();
} }
break; break;
default: default:
if((!(event.ControlDown() || event.AltDown() if((!(event.ControlDown() || event.AltDown()
)) ))
&& (keyCode < 256 && keyCode >= 32) && (keyCode < 256 && keyCode >= 32)
) )
{ {
if(m_WrapMargin > 0 && isspace(keyCode)) if(m_DoWordWrap
{ && m_WrapMargin > 0
bool wrapped = m_llist->WrapLine(m_WrapMargin); && m_llist->GetCursorPos().x > m_WrapMargin
// don<6F>t insert space as first thing in line && isspace(keyCode))
// after wrapping: m_llist->WrapLine(m_WrapMargin);
if(! wrapped || m_llist->GetCursorPos().x != 0) m_llist->Insert((char)keyCode);
m_llist->Insert((char)keyCode);
}
else
m_llist->Insert((char)keyCode);
SetDirty(); SetDirty();
} }
else else
@@ -765,7 +785,10 @@ wxLayoutWindow::ScrollToCursor(void)
{ {
//is always needed to make sure we know where the cursor is //is always needed to make sure we know where the cursor is
//if(IsDirty()) //if(IsDirty())
RequestUpdate(m_llist->GetUpdateRect()); //RequestUpdate(m_llist->GetUpdateRect());
ResizeScrollbars();
int x0,y0,x1,y1, dx, dy; int x0,y0,x1,y1, dx, dy;
@@ -802,7 +825,7 @@ wxLayoutWindow::ScrollToCursor(void)
ny = 0; ny = 0;
} }
if ( nx != -1 || ny != -1 ) if( nx != -1 || ny != -1 )
{ {
// set new view start // set new view start
Scroll(nx == -1 ? -1 : (nx+dx-1)/dx, ny == -1 ? -1 : (ny+dy-1)/dy); Scroll(nx == -1 ? -1 : (nx+dx-1)/dx, ny == -1 ? -1 : (ny+dy-1)/dy);
@@ -836,6 +859,7 @@ wxLayoutWindow::RequestUpdate(const wxRect *updateRect)
void void
wxLayoutWindow::InternalPaint(const wxRect *updateRect) wxLayoutWindow::InternalPaint(const wxRect *updateRect)
{ {
wxPaintDC dc( this ); wxPaintDC dc( this );
PrepareDC( dc ); PrepareDC( dc );
@@ -864,9 +888,9 @@ wxLayoutWindow::InternalPaint(const wxRect *updateRect)
updateRect->y+updateRect->height)); updateRect->y+updateRect->height));
} }
ResizeScrollbars(); ResizeScrollbars(true);
WXLO_TIMER_START(TmpTimer);
/* Check whether the window has grown, if so, we need to reallocate /* Check whether the window has grown, if so, we need to reallocate
the bitmap to be larger. */ the bitmap to be larger. */
if(x1 > m_bitmapSize.x || y1 > m_bitmapSize.y) if(x1 > m_bitmapSize.x || y1 > m_bitmapSize.y)
@@ -887,7 +911,8 @@ wxLayoutWindow::InternalPaint(const wxRect *updateRect)
0,wxTRANSPARENT)); 0,wxTRANSPARENT));
m_memDC->SetLogicalFunction(wxCOPY); m_memDC->SetLogicalFunction(wxCOPY);
m_memDC->Clear(); m_memDC->Clear();
WXLO_TIMER_STOP(TmpTimer);
// fill the background with the background bitmap // fill the background with the background bitmap
if(m_BGbitmap) if(m_BGbitmap)
{ {
@@ -922,7 +947,7 @@ wxLayoutWindow::InternalPaint(const wxRect *updateRect)
// update rectangle (although they are drawn on the memDC, this is // update rectangle (although they are drawn on the memDC, this is
// needed to erase it): // needed to erase it):
m_llist->InvalidateUpdateRect(); m_llist->InvalidateUpdateRect();
if(m_CursorVisibility != 0) if(m_CursorVisibility == 1)
{ {
// draw a thick cursor for editable windows with focus // draw a thick cursor for editable windows with focus
m_llist->DrawCursor(*m_memDC, m_llist->DrawCursor(*m_memDC,
@@ -930,6 +955,7 @@ wxLayoutWindow::InternalPaint(const wxRect *updateRect)
offset); offset);
} }
WXLO_TIMER_START(BlitTimer);
// Now copy everything to the screen: // Now copy everything to the screen:
#if 0 #if 0
// This somehow doesn't work, but even the following bit with the // This somehow doesn't work, but even the following bit with the
@@ -955,6 +981,8 @@ wxLayoutWindow::InternalPaint(const wxRect *updateRect)
// y1 += WXLO_YOFFSET; //FIXME might not be needed // y1 += WXLO_YOFFSET; //FIXME might not be needed
dc.Blit(x0,y0,x1,y1,m_memDC,0,0,wxCOPY,FALSE); dc.Blit(x0,y0,x1,y1,m_memDC,0,0,wxCOPY,FALSE);
} }
WXLO_TIMER_STOP(BlitTimer);
#ifdef WXLAYOUT_USE_CARET #ifdef WXLAYOUT_USE_CARET
// show the caret back after everything is redrawn // show the caret back after everything is redrawn
@@ -979,6 +1007,10 @@ wxLayoutWindow::InternalPaint(const wxRect *updateRect)
m_StatusBar->SetStatusText(label, m_StatusFieldCursor); m_StatusBar->SetStatusText(label, m_StatusFieldCursor);
} }
} }
WXLO_TIMER_PRINT(LayoutTimer);
WXLO_TIMER_PRINT(BlitTimer);
WXLO_TIMER_PRINT(TmpTimer);
} }
void void
@@ -999,14 +1031,20 @@ as needed.
void void
wxLayoutWindow::ResizeScrollbars(bool exact) wxLayoutWindow::ResizeScrollbars(bool exact)
{ {
if(! IsDirty())
return;
wxClientDC dc( this ); wxClientDC dc( this );
PrepareDC( dc ); PrepareDC( dc );
// m_llist->ForceTotalLayout(); // m_llist->ForceTotalLayout();
m_llist->Layout(dc);
if(! IsDirty())
{
// we are laying out just the minimum, but always up to the
// cursor line, so the cursor position is updated.
m_llist->Layout(dc, 0);
return;
}
WXLO_TIMER_START(LayoutTimer);
m_llist->Layout(dc, -1);
WXLO_TIMER_STOP(LayoutTimer);
ResetDirty(); ResetDirty();
wxPoint max = m_llist->GetSize(); wxPoint max = m_llist->GetSize();
@@ -1025,8 +1063,8 @@ wxLayoutWindow::ResizeScrollbars(bool exact)
// TODO why do we set both at once? they're independent... // TODO why do we set both at once? they're independent...
if( max.x > m_maxx - WXLO_ROFFSET if( max.x > m_maxx - WXLO_ROFFSET
|| max.y > m_maxy - WXLO_BOFFSET || max.y > m_maxy - WXLO_BOFFSET
|| max.x < m_maxx - X_SCROLL_PAGE || (max.x < m_maxx - X_SCROLL_PAGE)
|| max.y < m_maxy - Y_SCROLL_PAGE || (max.y < m_maxy - Y_SCROLL_PAGE)
|| exact ) || exact )
{ {
// text became too large // text became too large
@@ -1038,31 +1076,36 @@ wxLayoutWindow::ResizeScrollbars(bool exact)
} }
bool done = FALSE; bool done = FALSE;
if(max.x < X_SCROLL_PAGE) if(max.x < X_SCROLL_PAGE && m_hasHScrollbar)
{ {
SetScrollbars(0,-1,0,-1,0,-1,true); SetScrollbars(0,-1,0,-1,0,-1,true);
m_hasHScrollbar = FALSE; m_hasHScrollbar = FALSE;
done = TRUE; done = TRUE;
} }
if(max.y < Y_SCROLL_PAGE) if(max.y < Y_SCROLL_PAGE && m_hasVScrollbar)
{ {
SetScrollbars(-1,0,-1,0,-1,0,true); SetScrollbars(-1,0,-1,0,-1,0,true);
m_hasVScrollbar = FALSE; m_hasVScrollbar = FALSE;
done = TRUE; done = TRUE;
} }
if(! done) if(! done &&
// (max.x > X_SCROLL_PAGE || max.y > Y_SCROLL_PAGE)
(max.x > size.x - X_SCROLL_PAGE|| max.y > size.y - Y_SCROLL_PAGE)
)
{ {
ViewStart(&m_ViewStartX, &m_ViewStartY); ViewStart(&m_ViewStartX, &m_ViewStartY);
SetScrollbars(X_SCROLL_PAGE, SetScrollbars(X_SCROLL_PAGE,
Y_SCROLL_PAGE, Y_SCROLL_PAGE,
max.x / X_SCROLL_PAGE + 1, max.x / X_SCROLL_PAGE + 2,
max.y / Y_SCROLL_PAGE + 1, max.y / Y_SCROLL_PAGE + 2,
m_ViewStartX, m_ViewStartY, m_ViewStartX,
m_ViewStartY,
true); true);
m_hasHScrollbar = m_hasHScrollbar =
m_hasVScrollbar = true; m_hasVScrollbar = true;
// ScrollToCursor();
} }
m_maxx = max.x + X_SCROLL_PAGE; m_maxx = max.x + X_SCROLL_PAGE;
m_maxy = max.y + Y_SCROLL_PAGE; m_maxy = max.y + Y_SCROLL_PAGE;
} }

View File

@@ -1,7 +1,7 @@
/*-*- c++ -*-******************************************************** /*-*- c++ -*-********************************************************
* wxLwindow.h : a scrolled Window for displaying/entering rich text* * wxLwindow.h : a scrolled Window for displaying/entering rich text*
* * * *
* (C) 1998-1999 by Karsten Ball<6C>der (karsten@phy.hw.ac.uk) * * (C) 1998-2000 by Karsten Ball<6C>der (ballueder@gmx.net) *
* * * *
* $Id$ * $Id$
*******************************************************************/ *******************************************************************/
@@ -118,6 +118,11 @@ public:
*/ */
void SetWrapMargin(CoordType margin) { m_WrapMargin = margin; } void SetWrapMargin(CoordType margin) { m_WrapMargin = margin; }
/** Toggle wordwrap as we type.
@param on true to activate word wrap
*/
void SetWordWrap(bool on = true) { m_DoWordWrap = on; }
/** Redraws the window. /** Redraws the window.
Internally, this stores the parameter and calls a refresh on Internally, this stores the parameter and calls a refresh on
wxMSW, draws directly on wxGTK. wxMSW, draws directly on wxGTK.
@@ -230,6 +235,10 @@ protected:
int m_maxx; int m_maxx;
int m_maxy; int m_maxy;
int m_lineHeight; int m_lineHeight;
/// do we want automatic word wrap?
bool m_DoWordWrap;
/// wrap margin
CoordType m_WrapMargin;
/// do we have the corresponding scrollbar? /// do we have the corresponding scrollbar?
bool m_hasHScrollbar, bool m_hasHScrollbar,
@@ -253,8 +262,6 @@ private:
bool m_Editable; bool m_Editable;
/// Are we currently building a selection with the keyboard? /// Are we currently building a selection with the keyboard?
bool m_Selecting; bool m_Selecting;
/// wrap margin
CoordType m_WrapMargin;
/// Has list changed since last redraw, e.g. in size? /// Has list changed since last redraw, e.g. in size?
bool m_Dirty; bool m_Dirty;
/// Has the list ever been modified? /// Has the list ever been modified?