X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/378f7b3f897e5959d6c8d89b4a7bc514b7617396..bcf4a975e4eedf899004cf629f5b61ea718e94c0:/user/wxLayout/wxllist.cpp diff --git a/user/wxLayout/wxllist.cpp b/user/wxLayout/wxllist.cpp index 3d9054444f..f0e15342f6 100644 --- a/user/wxLayout/wxllist.cpp +++ b/user/wxLayout/wxllist.cpp @@ -6,30 +6,46 @@ * $Id$ *******************************************************************/ +/* + + */ + #ifdef __GNUG__ -#pragma implementation "wxllist.h" + #pragma implementation "wxllist.h" #endif -#include "wx/wxprec.h" +#include + #ifdef __BORLANDC__ # pragma hdrstop #endif +#include "Mpch.h" -//#include "Mpch.h" -#ifdef M_PREFIX +#ifdef M_BASEDIR # include "gui/wxllist.h" +# include "gui/wxlparser.h" +# define SHOW_SELECTIONS 1 #else # include "wxllist.h" +# include "wxlparser.h" +# define SHOW_SELECTIONS 1 #endif + #ifndef USE_PCH -# include "iostream.h" -# include -# include -# include -# include +# include + +# include +# include +# include +# include +# include #endif +#ifdef WXLAYOUT_USE_CARET +# include +#endif // WXLAYOUT_USE_CARET + #include /// This should never really get created @@ -37,23 +53,32 @@ #ifdef WXLAYOUT_DEBUG -# define TypewxString(t) g_aTypewxStrings[t] +# define TypeString(t) g_aTypeStrings[t] # define WXLO_DEBUG(x) wxLogDebug x - static const char *g_aTypewxStrings[] = - { + static const char *g_aTypeStrings[] = + { "invalid", "text", "cmd", "icon" }; void wxLayoutObject::Debug(void) { - WXLO_DEBUG(("%s",g_aTypewxStrings[GetType()])); + WXLO_DEBUG(("%s",g_aTypeStrings[GetType()])); } -#else -# define TypewxString(t) "" -# define WXLO_DEBUG(x) +#else +# define TypeString(t) "" +# define WXLO_DEBUG(x) #endif +// FIXME under MSW, this constant is needed to make the thing properly redraw +// itself - I don't know where the size calculation error is and I can't +// waste time looking for it right now. Search for occurences of +// MSW_CORRECTION to find all the places where I did it. +#ifdef __WXMSW__ + static const int MSW_CORRECTION = 5; +#else + static const int MSW_CORRECTION = 0; +#endif /// Cursors smaller than this disappear in XOR drawing mode #define WXLO_MINIMUM_CURSOR_WIDTH 4 @@ -63,34 +88,80 @@ /** @name Helper functions */ //@{ /// allows me to compare to wxPoints -bool operator ==(wxPoint const &p1, wxPoint const &p2) +bool operator <=(wxPoint const &p1, wxPoint const &p2) { - return p1.x == p2.x && p1.y == p2.y; + return p1.y < p2.y || (p1.y == p2.y && p1.x <= p2.x); } -/// allows me to compare to wxPoints -bool operator !=(wxPoint const &p1, wxPoint const &p2) +/// grows a wxRect so that it includes the given point + +static +void GrowRect(wxRect &r, CoordType x, CoordType y) { - return p1.x != p2.x || p1.y != p2.y; -} + if(r.x > x) + r.x = x; + else if(r.x + r.width < x) + r.width = x - r.x; -/// grows a wxRect so that it includes the given point + if(r.y > y) + r.y = y; + else if(r.y + r.height < y) + r.height = y - r.y; +} -static void GrowRect(wxRect &r, const wxPoint & p) +#if 0 +// unused +/// returns true if the point is in the rectangle +static +bool Contains(const wxRect &r, const wxPoint &p) { - if(r.x > p.x) - r.x = p.x; - else if(r.x + r.width < p.x) - r.width = p.x - r.x; - - if(r.y > p.y) - r.y = p.y; - else if(r.y + r.height < p.y) - r.height = p.y - r.y; + return r.x <= p.x && r.y <= p.y && (r.x+r.width) >= p.x && (r.y + r.height) >= p.y; } +#endif + + //@} -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +void ReadString(wxString &to, wxString &from) +{ + to = ""; + const char *cptr = from.c_str(); + while(*cptr && *cptr != '\n') + to += *cptr++; + if(*cptr) cptr++; + from = cptr; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + wxLayoutObject + + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* static */ +wxLayoutObject * +wxLayoutObject::Read(wxString &istr) +{ + wxString tmp; + ReadString(tmp, istr); + int type = -1; + sscanf(tmp.c_str(),"%d", &type); + + switch(type) + { + case WXLO_TYPE_TEXT: + return wxLayoutObjectText::Read(istr); + case WXLO_TYPE_CMD: + return wxLayoutObjectCmd::Read(istr); + case WXLO_TYPE_ICON: + return wxLayoutObjectIcon::Read(istr); + default: + return NULL; + } +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * wxLayoutObjectText @@ -117,6 +188,23 @@ wxLayoutObjectText::Copy(void) return obj; } + +void +wxLayoutObjectText::Write(wxString &ostr) +{ + ostr << (int) WXLO_TYPE_TEXT << '\n' + << m_Text << '\n'; +} +/* static */ +wxLayoutObjectText * +wxLayoutObjectText::Read(wxString &istr) +{ + wxString text; + ReadString(text, istr); + + return new wxLayoutObjectText(text); +} + wxPoint wxLayoutObjectText::GetSize(CoordType *top, CoordType *bottom) const { @@ -126,9 +214,38 @@ wxLayoutObjectText::GetSize(CoordType *top, CoordType *bottom) const } void -wxLayoutObjectText::Draw(wxDC &dc, wxPoint const &coords) +wxLayoutObjectText::Draw(wxDC &dc, wxPoint const &coords, + wxLayoutList *wxllist, + CoordType begin, CoordType end) { - dc.DrawText(m_Text, coords.x, coords.y-m_Top); + if( end <= 0) + dc.DrawText(m_Text, coords.x, coords.y-m_Top); + else + { + // highlight the bit between begin and len + wxString str; + CoordType + xpos = coords.x, + ypos = coords.y-m_Top; + long width, height, descent; + + if(begin < 0) begin = 0; + if( end > (signed)m_Text.Length() ) + end = m_Text.Length(); + + str = m_Text.Mid(0, begin); + dc.DrawText(str, xpos, ypos); + dc.GetTextExtent(str, &width, &height, &descent); + xpos += width; + wxllist->StartHighlighting(dc); + str = m_Text.Mid(begin, end-begin); + dc.DrawText(str, xpos, ypos); + dc.GetTextExtent(str, &width, &height, &descent); + xpos += width; + wxllist->EndHighlighting(dc); + str = m_Text.Mid(end, m_Text.Length()-end); + dc.DrawText(str, xpos, ypos); + } } CoordType @@ -142,30 +259,62 @@ wxLayoutObjectText::GetOffsetScreen(wxDC &dc, CoordType xpos) const height, descent = 0l; if(xpos == 0) return 0; // easy - + while(width < xpos && offs < maxlen) { dc.GetTextExtent(m_Text.substr(0,offs), &width, &height, &descent); offs++; } - /* We have to substract 1 to compensate for the offs++, and another + /* We have to substract 1 to compensate for the offs++, and another one because we don't want to position the cursor behind the object what we clicked on, but before - otherwise it looks funny. */ - return (xpos > 2) ? offs-2 : 0; + return (xpos > 2) ? offs-2 : 0; } void -wxLayoutObjectText::Layout(wxDC &dc) +wxLayoutObjectText::Layout(wxDC &dc, class wxLayoutList *llist) { long descent = 0l; - dc.GetTextExtent(m_Text,&m_Width, &m_Height, &descent); + // now this is done in wxLayoutLine::Layout(), but this code might be + // reenabled later - in principle, it's more efficient +#if 0 + CoordType widthOld = m_Width, + heightOld = m_Height; +#endif // 0 + + dc.GetTextExtent(m_Text, &m_Width, &m_Height, &descent); + +#if 0 + if ( widthOld != m_Width || heightOld != m_Height ) + { + // as the text length changed, it must be refreshed + wxLayoutLine *line = GetLine(); + + wxCHECK_RET( line, "wxLayoutObjectText can't refresh itself" ); + + // as our size changed, we need to repaint the part which was appended + wxPoint position(line->GetPosition()); + + // this is not the most efficient way (we repaint the whole line), but + // it's not too slow and is *simple* + if ( widthOld < m_Width ) + widthOld = m_Width; + if ( heightOld < m_Height ) + heightOld = m_Height; + + llist->SetUpdateRect(position.x + widthOld + MSW_CORRECTION, + position.y + heightOld + MSW_CORRECTION); + } +#endif // 0 + m_Bottom = descent; m_Top = m_Height - m_Bottom; } + #ifdef WXLAYOUT_DEBUG void wxLayoutObjectText::Debug(void) @@ -175,7 +324,7 @@ wxLayoutObjectText::Debug(void) } #endif -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * wxLayoutObjectIcon @@ -186,6 +335,38 @@ wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap const &icon) m_Icon = new wxBitmap(icon); } + +void +wxLayoutObjectIcon::Write(wxString &ostr) +{ + /* Exports icon through a temporary file. */ + + wxString file = wxGetTempFileName("wxloexport"); + + ostr << WXLO_TYPE_ICON << '\n' + << file << '\n'; + m_Icon->SaveFile(file, WXLO_BITMAP_FORMAT); +} +/* static */ +wxLayoutObjectIcon * +wxLayoutObjectIcon::Read(wxString &istr) +{ + wxString file; + ReadString(file, istr); + + if(! wxFileExists(file)) + return NULL; + wxLayoutObjectIcon *obj = new wxLayoutObjectIcon; + + if(!obj->m_Icon->LoadFile(file, WXLO_BITMAP_FORMAT)) + { + delete obj; + return NULL; + } + else + return obj; +} + wxLayoutObject * wxLayoutObjectIcon::Copy(void) { @@ -201,14 +382,16 @@ wxLayoutObjectIcon::wxLayoutObjectIcon(wxBitmap *icon) } void -wxLayoutObjectIcon::Draw(wxDC &dc, wxPoint const &coords) +wxLayoutObjectIcon::Draw(wxDC &dc, wxPoint const &coords, + wxLayoutList *wxllist, + CoordType begin, CoordType /* len */) { dc.DrawBitmap(*m_Icon, coords.x, coords.y-m_Icon->GetHeight(), (m_Icon->GetMask() == NULL) ? FALSE : TRUE); } void -wxLayoutObjectIcon::Layout(wxDC & /* dc */) +wxLayoutObjectIcon::Layout(wxDC & /* dc */, class wxLayoutList * ) { } @@ -222,104 +405,205 @@ wxLayoutObjectIcon::GetSize(CoordType *top, CoordType *bottom) const -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - wxLayoutObjectIcon + wxLayoutObjectCmd * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -wxLayoutObjectCmd::wxLayoutObjectCmd(int size, int family, int style, int - weight, bool underline, - wxColour const *fg, wxColour const *bg) - + +wxLayoutStyleInfo::wxLayoutStyleInfo(int ifamily, + int isize, + int istyle, + int iweight, + int iul, + wxColour *fg, + wxColour *bg) +{ + family = ifamily; size = isize; + style = istyle; weight = iweight; + underline = iul != 0; + if(fg) + { + m_fg = *fg; + m_fg_valid = TRUE; + } + else + m_fg = *wxBLACK; + if(bg) + { + m_bg = *bg; + m_bg_valid = TRUE; + } + else + m_bg = *wxWHITE; +} + +#define COPY_SI_(what) if(right.what != -1) what = right.what; + +wxLayoutStyleInfo & +wxLayoutStyleInfo::operator=(const wxLayoutStyleInfo &right) +{ + COPY_SI_(family); + COPY_SI_(style); + COPY_SI_(size); + COPY_SI_(weight); + COPY_SI_(underline); + if(right.m_fg_valid) m_fg = right.m_fg; + if(right.m_bg_valid) m_bg = right.m_bg; + return *this; +} + +wxLayoutObjectCmd::wxLayoutObjectCmd(int family, int size, int style, int + weight, int underline, + wxColour *fg, wxColour *bg) + { - m_font = new wxFont(size,family,style,weight,underline); - m_ColourFG = fg; - m_ColourBG = bg; + m_StyleInfo = new wxLayoutStyleInfo(family, size,style,weight,underline,fg,bg); } wxLayoutObject * wxLayoutObjectCmd::Copy(void) { - wxLayoutStyleInfo si; - GetStyle(&si); - wxLayoutObjectCmd *obj = new wxLayoutObjectCmd( - si.size, si.family, si.style, si.weight, si.underline, - m_ColourFG, m_ColourBG); + m_StyleInfo->size, + m_StyleInfo->family, + m_StyleInfo->style, + m_StyleInfo->weight, + m_StyleInfo->underline, + m_StyleInfo->m_fg_valid ? + &m_StyleInfo->m_fg : NULL, + m_StyleInfo->m_bg_valid ? + &m_StyleInfo->m_bg : NULL); obj->SetUserData(m_UserData); return obj; } +void +wxLayoutObjectCmd::Write(wxString &ostr) +{ + ostr << WXLO_TYPE_CMD << '\n' + << m_StyleInfo->size << '\n' + << m_StyleInfo->family << '\n' + << m_StyleInfo->style << '\n' + << m_StyleInfo->weight << '\n' + << m_StyleInfo->underline << '\n' + << m_StyleInfo->m_fg_valid << '\n' + << m_StyleInfo->m_bg_valid << '\n'; + if(m_StyleInfo->m_fg_valid) + { + ostr << m_StyleInfo->m_fg.Red() << '\n' + << m_StyleInfo->m_fg.Green() << '\n' + << m_StyleInfo->m_fg.Blue() << '\n'; + } + if(m_StyleInfo->m_bg_valid) + { + ostr << m_StyleInfo->m_bg.Red() << '\n' + << m_StyleInfo->m_bg.Green() << '\n' + << m_StyleInfo->m_bg.Blue() << '\n'; + } +} +/* static */ +wxLayoutObjectCmd * +wxLayoutObjectCmd::Read(wxString &istr) +{ + wxLayoutObjectCmd *obj = new wxLayoutObjectCmd; + + wxString tmp; + ReadString(tmp, istr); + sscanf(tmp.c_str(),"%d", &obj->m_StyleInfo->size); + ReadString(tmp, istr); + sscanf(tmp.c_str(),"%d", &obj->m_StyleInfo->family); + ReadString(tmp, istr); + sscanf(tmp.c_str(),"%d", &obj->m_StyleInfo->style); + ReadString(tmp, istr); + sscanf(tmp.c_str(),"%d", &obj->m_StyleInfo->weight); + ReadString(tmp, istr); + sscanf(tmp.c_str(),"%d", &obj->m_StyleInfo->underline); + ReadString(tmp, istr); + sscanf(tmp.c_str(),"%d", &obj->m_StyleInfo->m_fg_valid); + ReadString(tmp, istr); + sscanf(tmp.c_str(),"%d", &obj->m_StyleInfo->m_bg_valid); + if(obj->m_StyleInfo->m_fg_valid) + { + int red, green, blue; + ReadString(tmp, istr); + sscanf(tmp.c_str(),"%d", &red); + ReadString(tmp, istr); + sscanf(tmp.c_str(),"%d", &green); + ReadString(tmp, istr); + sscanf(tmp.c_str(),"%d", &blue); + obj->m_StyleInfo->m_fg = wxColour(red, green, blue); + } + if(obj->m_StyleInfo->m_bg_valid) + { + int red, green, blue; + ReadString(tmp, istr); + sscanf(tmp.c_str(),"%d", &red); + ReadString(tmp, istr); + sscanf(tmp.c_str(),"%d", &green); + ReadString(tmp, istr); + sscanf(tmp.c_str(),"%d", &blue); + obj->m_StyleInfo->m_bg = wxColour(red, green, blue); + } + return obj; +} + wxLayoutObjectCmd::~wxLayoutObjectCmd() { - delete m_font; + delete m_StyleInfo; } -void -wxLayoutObjectCmd::GetStyle(wxLayoutStyleInfo *si) const +wxLayoutStyleInfo * +wxLayoutObjectCmd::GetStyle(void) const { - si->size = m_font->GetPointSize(); - si->family = m_font->GetFamily(); - si->style = m_font->GetStyle(); - si->underline = m_font->GetUnderlined(); - si->weight = m_font->GetWeight(); - - si->fg_red = m_ColourFG->Red(); - si->fg_green = m_ColourFG->Green(); - si->fg_blue = m_ColourFG->Blue(); - si->bg_red = m_ColourBG->Red(); - si->bg_green = m_ColourBG->Green(); - si->bg_blue = m_ColourBG->Blue(); + return m_StyleInfo; } void -wxLayoutObjectCmd::Draw(wxDC &dc, wxPoint const & /* coords */) +wxLayoutObjectCmd::Draw(wxDC &dc, wxPoint const & /* coords */, + wxLayoutList *wxllist, + CoordType begin, CoordType /* len */) { - wxASSERT(m_font); - dc.SetFont(*m_font); - if(m_ColourFG) - dc.SetTextForeground(*m_ColourFG); - if(m_ColourBG) - dc.SetTextBackground(*m_ColourBG); + wxASSERT(m_StyleInfo); + wxllist->ApplyStyle(m_StyleInfo, dc); } void -wxLayoutObjectCmd::Layout(wxDC &dc) +wxLayoutObjectCmd::Layout(wxDC &dc, class wxLayoutList * llist) { // this get called, so that recalculation uses right font sizes - Draw(dc, wxPoint(0,0)); + Draw(dc, wxPoint(0,0), llist); } -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * The wxLayoutLine object * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -wxLayoutLine::wxLayoutLine(wxLayoutLine *prev) +wxLayoutLine::wxLayoutLine(wxLayoutLine *prev, wxLayoutList *llist) { m_LineNumber = 0; - m_Height = 0; + m_Width = m_Height = 0; m_Length = 0; - m_Dirty = true; + MarkDirty(0); m_Previous = prev; m_Next = NULL; - RecalculatePosition(); + RecalculatePosition(llist); if(m_Previous) { m_LineNumber = m_Previous->GetLineNumber()+1; m_Next = m_Previous->GetNextLine(); m_Previous->m_Next = this; - m_Height = m_Previous->GetHeight(); } if(m_Next) { m_Next->m_Previous = this; m_Next->MoveLines(+1); - m_Next->RecalculatePositions(1); + m_Next->RecalculatePositions(1,llist); } } @@ -329,33 +613,54 @@ wxLayoutLine::~wxLayoutLine() } wxPoint -wxLayoutLine::RecalculatePosition(void) +wxLayoutLine::RecalculatePosition(wxLayoutList *llist) { + wxASSERT(m_Previous || GetLineNumber() == 0); + + wxPoint posOld(m_Position); + if(m_Previous) - m_Position = m_Previous->GetPosition() + - wxPoint(0,m_Previous->GetHeight()); + { + m_Position = m_Previous->GetPosition(); + m_Position.y += m_Previous->GetHeight(); + } else m_Position = wxPoint(0,0); + + if ( m_Position != posOld ) + { + // the whole line moved and must be repainted + llist->SetUpdateRect(m_Position); + llist->SetUpdateRect(m_Position.x + GetWidth() + MSW_CORRECTION, + m_Position.y + GetHeight() + MSW_CORRECTION); + llist->SetUpdateRect(posOld); + llist->SetUpdateRect(posOld.x + GetWidth() + MSW_CORRECTION, + posOld.y + GetHeight() + MSW_CORRECTION); + } + return m_Position; } void -wxLayoutLine::RecalculatePositions(int recurse) +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(); + RecalculatePosition(llist); if(m_Next) { if(recurse > 0) - { - if(m_Next) m_Next->RecalculatePositions(--recurse); - } + m_Next->RecalculatePositions(--recurse, llist); else if(pos != m_Position || m_Height != height) - if(m_Next) m_Next->RecalculatePositions(); + m_Next->RecalculatePositions(0, llist); } } @@ -364,39 +669,48 @@ wxLayoutLine::FindObject(CoordType xpos, CoordType *offset) const { wxASSERT(xpos >= 0); wxASSERT(offset); - wxLayoutObjectList::iterator i; + wxLayoutObjectList::iterator + i, + found = NULLIT; CoordType x = 0, len; - + /* We search through the objects. As we don't like returning the + object that the cursor is behind, we just remember such an + object in "found" so we can return it if there is really no + further object following it. */ for(i = m_ObjectList.begin(); i != NULLIT; i++) { len = (**i).GetLength(); if( x <= xpos && xpos <= x + len ) { *offset = xpos-x; - return i; + if(xpos == x + len) // is there another object behind? + found = i; + else // we are really inside this object + return i; } x += (**i).GetLength(); } - return NULLIT; + return found; // ==NULL if really none found } wxLayoutObjectList::iterator -wxLayoutLine::FindObjectScreen(wxDC &dc, CoordType xpos, CoordType *cxpos) const +wxLayoutLine::FindObjectScreen(wxDC &dc, + CoordType xpos, CoordType *cxpos, + bool *found) const { wxASSERT(cxpos); wxASSERT(cxpos); wxLayoutObjectList::iterator i; CoordType x = 0, cx = 0, width; - + for(i = m_ObjectList.begin(); i != NULLIT; i++) { - (**i).Layout(dc); width = (**i).GetWidth(); if( x <= xpos && xpos <= x + width ) { *cxpos = cx + (**i).GetOffsetScreen(dc, xpos-x); - wxLogDebug("wxLayoutLine::FindObjectScreen: cursor xpos = %ld", *cxpos); + if(found) *found = true; return i; } x += (**i).GetWidth(); @@ -404,14 +718,50 @@ wxLayoutLine::FindObjectScreen(wxDC &dc, CoordType xpos, CoordType *cxpos) const } // behind last object: *cxpos = cx; + if(found) *found = false; return m_ObjectList.tail(); } +/** Finds text in this line. + @param needle the text to find + @param xpos the position where to start the search + @return the cursoor coord where it was found or -1 +*/ +CoordType +wxLayoutLine::FindText(const wxString &needle, CoordType xpos) const +{ + int + cpos = 0, + relpos = -1; + wxString const *text; + + for(wxLOiterator i = m_ObjectList.begin(); i != m_ObjectList.end(); i++) + { + if(cpos >= xpos) // search from here! + { + if((**i).GetType() == WXLO_TYPE_TEXT) + { + text = & ((wxLayoutObjectText*)(*i))->GetText(); + relpos = text->Find(needle); + if(relpos >= cpos-xpos) // -1 if not found + { + return cpos+relpos; + } + } + cpos += (**i).GetLength(); + } + } + return -1; // not found +} + bool wxLayoutLine::Insert(CoordType xpos, wxLayoutObject *obj) { wxASSERT(xpos >= 0); wxASSERT(obj != NULL); + + MarkDirty(xpos); + CoordType offset; wxLOiterator i = FindObject(xpos, &offset); if(i == NULLIT) @@ -461,11 +811,14 @@ wxLayoutLine::Insert(CoordType xpos, wxLayoutObject *obj) m_ObjectList.insert(i,new wxLayoutObjectText(left)); return true; } - + bool -wxLayoutLine::Insert(CoordType xpos, wxString text) +wxLayoutLine::Insert(CoordType xpos, const wxString& text) { wxASSERT(xpos >= 0); + + MarkDirty(xpos); + CoordType offset; wxLOiterator i = FindObject(xpos, &offset); if(i != NULLIT && (**i).GetType() == WXLO_TYPE_TEXT) @@ -473,11 +826,14 @@ wxLayoutLine::Insert(CoordType xpos, wxString text) wxLayoutObjectText *tobj = (wxLayoutObjectText *) *i; tobj->GetText().insert(offset, text); m_Length += text.Length(); - - return true; } else - return Insert(xpos, new wxLayoutObjectText(text)); + { + if ( !Insert(xpos, new wxLayoutObjectText(text)) ) + return false; + } + + return true; } CoordType @@ -487,6 +843,7 @@ wxLayoutLine::Delete(CoordType xpos, CoordType npos) wxASSERT(xpos >= 0); wxASSERT(npos >= 0); + MarkDirty(xpos); wxLOiterator i = FindObject(xpos, &offset); while(npos > 0) { @@ -517,7 +874,7 @@ wxLayoutLine::Delete(CoordType xpos, CoordType npos) { if(xpos == GetLength()) return npos; - else + else { // at the end of an object // move to begin of next object: i++; offset = 0; @@ -532,6 +889,7 @@ wxLayoutLine::Delete(CoordType xpos, CoordType npos) ((wxLayoutObjectText *)(*i))->GetText().Remove(offset,max); } } + return npos; } @@ -540,6 +898,7 @@ wxLayoutLine::DeleteWord(CoordType xpos) { wxASSERT(xpos >= 0); CoordType offset; + MarkDirty(xpos); wxLOiterator i = FindObject(xpos, &offset); @@ -548,7 +907,7 @@ wxLayoutLine::DeleteWord(CoordType xpos) if(i == NULLIT) return false; if((**i).GetType() != WXLO_TYPE_TEXT) { - // This should only happen when at end of line, behind a non-text + // This should only happen when at end of line, behind a non-text // object: if(offset == (**i).GetLength()) return false; m_Length -= (**i).GetLength(); // -1 @@ -568,28 +927,28 @@ wxLayoutLine::DeleteWord(CoordType xpos) str = str.substr(offset,str.Length()-offset); // Find out how many positions we need to delete: // 1. eat leading space - while(isspace(str[count])) count++; + while(isspace(str.c_str()[count])) count++; // 2. eat the word itself: - while(isalnum(str[count])) count++; + 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(0); // we should never arrive here } wxLayoutLine * -wxLayoutLine::DeleteLine(bool update) +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); + m_Next->RecalculatePositions(1, llist); } wxLayoutLine *next = m_Next; delete this; @@ -597,68 +956,108 @@ wxLayoutLine::DeleteLine(bool update) } void -wxLayoutLine::Draw(wxDC &dc, const wxPoint & offset) const +wxLayoutLine::Draw(wxDC &dc, + wxLayoutList *llist, + const wxPoint & offset) const { wxLayoutObjectList::iterator i; wxPoint pos = offset; pos = pos + GetPosition(); - + pos.y += m_BaseLine; - + + CoordType xpos = 0; // cursorpos, lenght of line + + CoordType from, to, tempto; + //FIXME This doesn't work yet, needs updating afterr default + //settings for list or a wxLayoutObjectCmd have changed: + //llist->ApplyStyle(&((wxLayoutLine *)this)->m_StyleInfo, dc); + int highlight = llist->IsSelected(this, &from, &to); +// WXLO_DEBUG(("highlight=%d", highlight )); + if(highlight == 1) // we need to draw the whole line inverted! + llist->StartHighlighting(dc); + else + llist->EndHighlighting(dc); + for(i = m_ObjectList.begin(); i != NULLIT; i++) { - (**i).Draw(dc, pos); + if(highlight == -1) // partially highlight line + { + // parts of the line need highlighting + tempto = xpos+(**i).GetLength(); + (**i).Draw(dc, pos, llist, from-xpos, to-xpos); + } + else + (**i).Draw(dc, pos, llist); pos.x += (**i).GetWidth(); + xpos += (**i).GetLength(); } } void -wxLayoutLine::Layout(wxDC &dc, wxPoint *cursorPos, +wxLayoutLine::Layout(wxDC &dc, + wxLayoutList *llist, + wxPoint *cursorPos, wxPoint *cursorSize, - int cx) + int cx) { wxLayoutObjectList::iterator i; + // when a line becomes dirty, we redraw it from the place where it was + // changed till the end of line (because the following wxLayoutObjects are + // moved when the preceding one changes) - calculate the update rectangle. + CoordType updateTop = m_Position.y, + updateLeft = -1, + updateWidth = m_Width, + updateHeight = m_Height; + CoordType - oldHeight = m_Height; - CoordType - topHeight, bottomHeight; // above and below baseline + topHeight = 0, + bottomHeight = 0; // above and below baseline CoordType - objHeight = 0, - objTopHeight, objBottomHeight; + objTopHeight, objBottomHeight; // above and below baseline CoordType len, count = 0; - m_Height = 0; m_BaseLine = 0; + + CoordType heightOld = m_Height; + + m_Height = 0; m_Width = 0; - topHeight = 0; bottomHeight = 0; - wxPoint size; + m_BaseLine = 0; + bool cursorFound = false; if(cursorPos) { *cursorPos = m_Position; + if(cursorSize) *cursorSize = wxPoint(0,0); } - + + //FIXME This doesn't work yet, needs updating afterr default + //settings for list or a wxLayoutObjectCmd have changed: + //llist->ApplyStyle(&m_StyleInfo, dc); for(i = m_ObjectList.begin(); i != NULLIT; i++) { - (**i).Layout(dc); - size = (**i).GetSize(&objTopHeight, &objBottomHeight); + wxLayoutObject *obj = *i; + obj->Layout(dc, llist); + wxPoint sizeObj = obj->GetSize(&objTopHeight, &objBottomHeight); if(cursorPos && ! cursorFound) - { // we need to check whether the text cursor is here - len = (**i).GetLength(); + { + // we need to check whether the text cursor is here + len = obj->GetLength(); if(count <= cx && count+len > cx) { - if((**i).GetType() == WXLO_TYPE_TEXT) + if(obj->GetType() == WXLO_TYPE_TEXT) { len = cx - count; // pos in object CoordType width, height, descent; - dc.GetTextExtent((*(wxLayoutObjectText*)*i).GetText().substr(0,len), + dc.GetTextExtent((*(wxLayoutObjectText*)*i).GetText().substr(0,len), &width, &height, &descent); cursorPos->x += width; cursorPos->y = m_Position.y; wxString str; - if(len < (**i).GetLength()) + if(len < obj->GetLength()) str = (*(wxLayoutObjectText*)*i).GetText().substr(len,1); else str = WXLO_CURSORCHAR; @@ -666,15 +1065,16 @@ wxLayoutLine::Layout(wxDC &dc, wxPoint *cursorPos, wxASSERT(cursorSize); // Just in case some joker inserted an empty string object: if(width == 0) width = WXLO_MINIMUM_CURSOR_WIDTH; - if(height == 0) height = objHeight; + if(height == 0) height = sizeObj.y; cursorSize->x = width; cursorSize->y = height; cursorFound = true; // no more checks } - else - { // on some other object + else + { + // on some other object CoordType top, bottom; // unused - *cursorSize = (**i).GetSize(&top,&bottom); + *cursorSize = obj->GetSize(&top,&bottom); cursorPos->y = m_Position.y; cursorFound = true; // no more checks } @@ -682,39 +1082,59 @@ wxLayoutLine::Layout(wxDC &dc, wxPoint *cursorPos, else { count += len; - cursorPos->x += (**i).GetWidth(); + cursorPos->x += obj->GetWidth(); } } // cursor finding - objHeight = size.y; - m_Width += size.x; - if(objHeight > m_Height) m_Height = objHeight; - if(objTopHeight > topHeight) topHeight = objTopHeight; - if(objBottomHeight > bottomHeight) bottomHeight = objBottomHeight; - } - if(topHeight + bottomHeight > m_Height) m_Height = - topHeight+bottomHeight; + + m_Width += sizeObj.x; + if(sizeObj.y > m_Height) + { + m_Height = sizeObj.y; + } + + if(objTopHeight > topHeight) + topHeight = objTopHeight; + if(objBottomHeight > bottomHeight) + bottomHeight = objBottomHeight; + } + + if ( IsDirty() ) + { + if ( updateHeight < m_Height ) + updateHeight = m_Height; + if ( updateWidth < m_Width ) + updateWidth = m_Width; + + // update all line if we don't know where to start from + if ( updateLeft == -1 ) + updateLeft = 0; + + llist->SetUpdateRect(updateLeft, updateTop); + llist->SetUpdateRect(updateLeft + updateWidth + MSW_CORRECTION, + updateTop + updateHeight + MSW_CORRECTION); + } + + if(topHeight + bottomHeight > m_Height) + { + m_Height = topHeight+bottomHeight; + } + m_BaseLine = topHeight; if(m_Height == 0) { - if(GetPreviousLine()) // empty line - { - m_Height = GetPreviousLine()->GetHeight(); - m_BaseLine = GetPreviousLine()->m_BaseLine; - } - else - { - CoordType width, height, descent; - dc.GetTextExtent(WXLO_CURSORCHAR, &width, &height, &descent); - m_Height = height; - m_BaseLine = m_Height - descent; - } + CoordType width, height, descent; + dc.GetTextExtent(WXLO_CURSORCHAR, &width, &height, &descent); + m_Height = height; + m_BaseLine = m_Height - descent; } - // tell next line about coordinate change - if(m_Next && objHeight != oldHeight) - m_Next->RecalculatePositions(); + if(m_Next && m_Height != heightOld) + { + // FIXME isn't this done in RecalculatePositions() below anyhow? + m_Next->RecalculatePositions(0, llist); + } // We need to check whether we found a valid cursor size: if(cursorPos) @@ -723,54 +1143,54 @@ wxLayoutLine::Layout(wxDC &dc, wxPoint *cursorPos, // line or on a command object: if(cursorSize->y < WXLO_MINIMUM_CURSOR_WIDTH) { - if(m_BaseLine > 0) - { - cursorSize->y = m_BaseLine; - if(cursorSize->x < WXLO_MINIMUM_CURSOR_WIDTH) cursorSize->x = WXLO_MINIMUM_CURSOR_WIDTH; - } - else // empty line - { - CoordType width, height, descent; - dc.GetTextExtent(WXLO_CURSORCHAR, &width, &height, &descent); - cursorSize->x = width; - cursorSize->y = height; - } + CoordType width, height, descent; + dc.GetTextExtent(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(); } wxLayoutLine * -wxLayoutLine::Break(CoordType xpos) +wxLayoutLine::Break(CoordType xpos, wxLayoutList *llist) { wxASSERT(xpos >= 0); - - if(xpos == 0) + + MarkDirty(xpos); + + /* If we are at the begin of a line, we want to move all other + lines down and stay with the cursor where we are. However, if we + are in an empty line, we want to move down with it. */ + if(xpos == 0 && GetLength() > 0) { // insert an empty line before this one - wxLayoutLine *prev = new wxLayoutLine(m_Previous); + 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 = GetHeight(); // this is a wild guess + m_Previous->m_Height = 0; // this is a wild guess } - MoveLines(+1); if(m_Next) - m_Next->RecalculatePositions(1); - return this; + m_Next->RecalculatePositions(1, llist); + return m_Previous; } - + CoordType offset; wxLOiterator i = FindObject(xpos, &offset); if(i == NULLIT) // must be at the end of the line then - return new wxLayoutLine(this); + return new wxLayoutLine(this, llist); // split this line: - wxLayoutLine *newLine = new wxLayoutLine(this); + wxLayoutLine *newLine = new wxLayoutLine(this, llist); // split object at i: if((**i).GetType() == WXLO_TYPE_TEXT && offset != 0) { @@ -785,38 +1205,81 @@ wxLayoutLine::Break(CoordType xpos) i++; // don't move this object to the new list } else + { if(offset > 0) i++; // move objects from here to new list + } while(i != m_ObjectList.end()) { - newLine->Append(*i); - m_Length -= (**i).GetLength(); + wxLayoutObject *obj = *i; + newLine->Append(obj); + m_Length -= obj->GetLength(); + m_ObjectList.remove(i); // remove without deleting it } if(m_Next) - m_Next->RecalculatePositions(2); + m_Next->RecalculatePositions(2, llist); return newLine; } - + void -wxLayoutLine::MergeNextLine(void) +wxLayoutLine::MergeNextLine(wxLayoutList *llist) { - wxASSERT(GetNextLine()); + wxCHECK_RET(GetNextLine(),"wxLayout internal error: no next line to merge"); wxLayoutObjectList &list = GetNextLine()->m_ObjectList; wxLOiterator i; - + + MarkDirty(GetWidth()); + + wxLayoutObject *last = NULL; for(i = list.begin(); i != list.end();) { - Append(*i); - list.remove(i); // remove without deleting it + wxLayoutObject *current = *i; + + // merge text objects together for efficiency + if ( last && last->GetType() == WXLO_TYPE_TEXT && + current->GetType() == WXLO_TYPE_TEXT ) + { + wxLayoutObjectText *textObj = (wxLayoutObjectText *)last; + wxString text(textObj->GetText()); + text += ((wxLayoutObjectText *)current)->GetText(); + textObj->SetText(text); + + list.erase(i); // remove and delete it + } + else + { + // just append the object "as was" + Append(current); + + list.remove(i); // remove without deleting it + } } wxASSERT(list.empty()); + wxLayoutLine *oldnext = GetNextLine(); - SetNext(GetNextLine()->GetNextLine()); + wxLayoutLine *nextLine = oldnext->GetNextLine(); + SetNext(nextLine); + if ( nextLine ) + { + nextLine->MoveLines(-1); + } + else + { + // this is now done in Delete(), but if this function is ever called + // from elsewhere, we might have to move refresh code back here (in + // order not to duplicate it) +#if 0 + wxPoint pos(oldnext->GetPosition()); + llist->SetUpdateRect(pos); + llist->SetUpdateRect(pos.x + oldnext->GetWidth() + MSW_CORRECTION, + pos.y + oldnext->GetHeight() + MSW_CORRECTION); +#endif // 0 + } + delete oldnext; - RecalculatePositions(1); } CoordType @@ -826,14 +1289,14 @@ wxLayoutLine::GetWrapPosition(CoordType column) wxLOiterator i = FindObject(column, &offset); if(i == NULLIT) return -1; // cannot wrap - // go backwards through the list and look for space in text objects + // go backwards through the list and look for space in text objects do { if((**i).GetType() == WXLO_TYPE_TEXT) { do { - if( isspace(((wxLayoutObjectText*)*i)->GetText()[(size_t)offset])) + if( isspace(((wxLayoutObjectText*)*i)->GetText().c_str()[(size_t)offset])) return column; else { @@ -874,69 +1337,167 @@ wxLayoutLine::GetWrapPosition(CoordType column) pos -= (**i).GetLength(); return pos; // in front of it } - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - The wxLayoutList object - - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -wxLayoutList::wxLayoutList() +#ifdef WXLAYOUT_DEBUG +void +wxLayoutLine::Debug(void) { - m_DefaultSetting = NULL; - m_FirstLine = NULL; - InvalidateUpdateRect(); - Clear(); -} + wxString tmp; + wxPoint pos = GetPosition(); + WXLO_DEBUG(("Line %ld, Pos (%ld,%ld), Height %ld", + (long int) GetLineNumber(), + (long int) pos.x, (long int) pos.y, + (long int) GetHeight())); + if(m_ObjectList.begin() != NULLIT) + (**m_ObjectList.begin()).Debug(); -wxLayoutList::~wxLayoutList() -{ - InternalClear(); } +#endif void -wxLayoutList::Empty(void) +wxLayoutLine::Copy(wxLayoutList *llist, + CoordType from, + CoordType to) { - while(m_FirstLine) - m_FirstLine = m_FirstLine->DeleteLine(false); + CoordType firstOffset, lastOffset; - m_CursorPos = wxPoint(0,0); - m_CursorScreenPos = wxPoint(0,0); - m_CursorSize = wxPoint(0,0); - m_FirstLine = new wxLayoutLine(NULL); // empty first line - m_CursorLine = m_FirstLine; -} + if(to == -1) to = GetLength(); + if(from == to) return; + wxLOiterator first = FindObject(from, &firstOffset); + wxLOiterator last = FindObject(to, &lastOffset); -void -wxLayoutList::InternalClear(void) -{ - Empty(); - if(m_DefaultSetting) + // Common special case: only one object + if( first != NULLIT && last != NULLIT && *first == *last ) { - delete m_DefaultSetting; - m_DefaultSetting = NULL; + if( (**first).GetType() == WXLO_TYPE_TEXT ) + { + llist->Insert(new wxLayoutObjectText( + ((wxLayoutObjectText + *)*first)->GetText().substr(firstOffset, + lastOffset-firstOffset)) + ); + return; + } + else // what can we do? + { + if(lastOffset > firstOffset) // i.e. +1 :-) + llist->Insert( (**first).Copy() ); + return; + } } -} -void + // If we reach here, we can safely copy the whole first object from + // the firstOffset position on: + if((**first).GetType() == WXLO_TYPE_TEXT && firstOffset != 0) + { + llist->Insert(new wxLayoutObjectText( + ((wxLayoutObjectText *)*first)->GetText().substr(firstOffset)) + ); + } + else if(firstOffset == 0) + llist->Insert( (**first).Copy() ); + // else nothing to copy :-( + + // Now we copy all objects before the last one: + wxLOiterator i = first; i++; + for( ; i != last; i++) + llist->Insert( (**i).Copy() ); + + // And now the last object: + if(lastOffset != 0) + { + if( (**last).GetType() == WXLO_TYPE_TEXT ) + { + llist->Insert(new wxLayoutObjectText( + ((wxLayoutObjectText *)*last)->GetText().substr(0,lastOffset)) + ); + } + else + llist->Insert( (**last).Copy() ); + } +} + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + The wxLayoutList object + + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +wxLayoutList::wxLayoutList() +{ +#ifdef WXLAYOUT_USE_CARET + m_caret = NULL; +#endif // WXLAYOUT_USE_CARET + + m_FirstLine = NULL; + InvalidateUpdateRect(); + Clear(); +} + +wxLayoutList::~wxLayoutList() +{ + InternalClear(); + m_FirstLine->DeleteLine(false, this); +} + +void +wxLayoutList::Empty(void) +{ + while(m_FirstLine) + m_FirstLine = m_FirstLine->DeleteLine(false, this); + + m_CursorPos = wxPoint(0,0); + m_CursorScreenPos = wxPoint(0,0); + m_CursorSize = wxPoint(0,0); + m_FirstLine = new wxLayoutLine(NULL, this); // empty first line + m_CursorLine = m_FirstLine; + InvalidateUpdateRect(); +} + + +void +wxLayoutList::InternalClear(void) +{ + Empty(); + m_Selection.m_selecting = false; + m_Selection.m_valid = false; + + m_DefaultSetting.family = wxSWISS; + m_DefaultSetting.size = WXLO_DEFAULTFONTSIZE; + m_DefaultSetting.style = wxNORMAL; + m_DefaultSetting.weight = wxNORMAL; + m_DefaultSetting.underline = 0; + m_DefaultSetting.m_fg_valid = TRUE; + m_DefaultSetting.m_fg = *wxBLACK; + m_DefaultSetting.m_bg_valid = TRUE; + m_DefaultSetting.m_bg = *wxWHITE; + + m_CurrentSetting = m_DefaultSetting; +} + +void wxLayoutList::SetFont(int family, int size, int style, int weight, - int underline, wxColour const *fg, - wxColour const *bg) -{ - if(family != -1) m_FontFamily = family; - if(size != -1) m_FontPtSize = size; - if(style != -1) m_FontStyle = style; - if(weight != -1) m_FontWeight = weight; - if(underline != -1) m_FontUnderline = underline != 0; - - if(fg != NULL) m_ColourFG = fg; - if(bg != NULL) m_ColourBG = bg; - + int underline, wxColour *fg, + wxColour *bg) +{ + if(family != -1) m_CurrentSetting.family = family; + if(size != -1) m_CurrentSetting.size = size; + if(style != -1) m_CurrentSetting.style = style; + if(weight != -1) m_CurrentSetting.weight = weight; + if(underline != -1) m_CurrentSetting.underline = underline != 0; + if(fg) m_CurrentSetting.m_fg = *fg; + if(bg) m_CurrentSetting.m_bg = *bg; Insert( - new wxLayoutObjectCmd(m_FontPtSize,m_FontFamily,m_FontStyle,m_FontWeight,m_FontUnderline, - m_ColourFG, m_ColourBG)); + new wxLayoutObjectCmd( + m_CurrentSetting.family, + m_CurrentSetting.size, + m_CurrentSetting.style, + m_CurrentSetting.weight, + m_CurrentSetting.underline, + fg, bg)); } void @@ -944,50 +1505,56 @@ wxLayoutList::SetFont(int family, int size, int style, int weight, int underline, char const *fg, char const *bg) { - wxColour const - * cfg = NULL, - * cbg = NULL; + wxColour + *cfg = NULL, + *cbg = NULL; if( fg ) cfg = wxTheColourDatabase->FindColour(fg); if( bg ) cbg = wxTheColourDatabase->FindColour(bg); - + SetFont(family,size,style,weight,underline,cfg,cbg); } void wxLayoutList::Clear(int family, int size, int style, int weight, - int /* underline */, char const *fg, char const *bg) + int underline, wxColour *fg, wxColour *bg) { InternalClear(); - - // set defaults - m_FontPtSize = size; - m_FontUnderline = false; - m_FontFamily = family; - m_FontStyle = style; - m_FontWeight = weight; - m_ColourFG = wxTheColourDatabase->FindColour(fg); - m_ColourBG = wxTheColourDatabase->FindColour(bg); + m_DefaultSetting = wxLayoutStyleInfo(family, size, style, weight, + underline, fg, bg); + m_CurrentSetting = m_DefaultSetting; +} - if(! m_ColourFG) m_ColourFG = wxBLACK; - if(! m_ColourBG) m_ColourBG = wxWHITE; - - if(m_DefaultSetting) - delete m_DefaultSetting; +wxPoint +wxLayoutList::FindText(const wxString &needle, const wxPoint &cpos) const +{ + int xpos; - m_DefaultSetting = new - wxLayoutObjectCmd(m_FontPtSize,m_FontFamily,m_FontStyle, - m_FontWeight,m_FontUnderline, - m_ColourFG, m_ColourBG); + wxLayoutLine *line; + for(line = m_FirstLine; + line; + line = line->GetNextLine()) + { + if(line->GetLineNumber() >= cpos.y) + { + xpos = line->FindText(needle, + (line->GetLineNumber() == cpos.y) ? + cpos.x : 0); + if(xpos != -1) + return wxPoint(xpos, line->GetLineNumber()); + } + } + return wxPoint(-1,-1); } - bool wxLayoutList::MoveCursorTo(wxPoint const &p) { + AddCursorPosToUpdateRect(); + wxLayoutLine *line = m_FirstLine; while(line && line->GetLineNumber() != p.y) line = line->GetNextLine(); @@ -1009,10 +1576,13 @@ wxLayoutList::MoveCursorTo(wxPoint const &p) } return false; } - + bool wxLayoutList::MoveCursorVertically(int n) { + AddCursorPosToUpdateRect(); + + bool rc; if(n < 0) // move up { if(m_CursorLine == m_FirstLine) return false; @@ -1026,13 +1596,13 @@ wxLayoutList::MoveCursorVertically(int n) { m_CursorLine = m_FirstLine; m_CursorPos.y = 0; - return false; + rc = false; } else { if(m_CursorPos.x > m_CursorLine->GetLength()) m_CursorPos.x = m_CursorLine->GetLength(); - return true; + rc = true; } } else // move down @@ -1049,20 +1619,23 @@ wxLayoutList::MoveCursorVertically(int n) { m_CursorLine = last; m_CursorPos.y ++; - return false; + rc = false; } else { if(m_CursorPos.x > m_CursorLine->GetLength()) m_CursorPos.x = m_CursorLine->GetLength(); - return true; + rc = true; } } + return rc; } bool wxLayoutList::MoveCursorHorizontally(int n) { + AddCursorPosToUpdateRect(); + int move; while(n < 0) { @@ -1102,8 +1675,20 @@ bool wxLayoutList::Insert(wxString const &text) { wxASSERT(m_CursorLine); - m_CursorLine->Insert(m_CursorPos.x, text); + wxASSERT_MSG( text.Find('\n') == wxNOT_FOUND, "use wxLayoutImportText!" ); + + if ( !text ) + return true; + + AddCursorPosToUpdateRect(); + + if ( !m_CursorLine->Insert(m_CursorPos.x, text) ) + return false; + m_CursorPos.x += text.Length(); + + m_CursorLine->RecalculatePositions(0, this); + return true; } @@ -1111,22 +1696,70 @@ bool wxLayoutList::Insert(wxLayoutObject *obj) { wxASSERT(m_CursorLine); + + if(! m_CursorLine) + m_CursorLine = GetFirstLine(); + + AddCursorPosToUpdateRect(); + m_CursorLine->Insert(m_CursorPos.x, obj); m_CursorPos.x += obj->GetLength(); + + m_CursorLine->RecalculatePositions(0, this); + return true; } +bool +wxLayoutList::Insert(wxLayoutList *llist) +{ + wxASSERT(llist); + bool rc = TRUE; + + for(wxLayoutLine *line = llist->GetFirstLine(); + line; + line = line->GetNextLine() + ) + { + for(wxLOiterator i = line->GetFirstObject(); + i != NULLIT; + i++) + rc |= Insert(*i); + LineBreak(); + } + return rc; +} + bool wxLayoutList::LineBreak(void) { wxASSERT(m_CursorLine); - bool setFirst = (m_CursorLine == m_FirstLine && m_CursorPos.x == 0); - m_CursorLine = m_CursorLine->Break(m_CursorPos.x); + + AddCursorPosToUpdateRect(); + + wxPoint position(m_CursorLine->GetPosition()); + + wxCoord width = m_CursorLine->GetWidth(), + height = m_CursorLine->GetHeight(); + + m_CursorLine = m_CursorLine->Break(m_CursorPos.x, this); if(setFirst) // we were at beginning of first line m_FirstLine = m_CursorLine->GetPreviousLine(); - m_CursorPos.y++; + if(m_CursorPos.x != 0) + m_CursorPos.y++; m_CursorPos.x = 0; +// doesn't help m_CursorLine.MarkDirty(); + + wxLayoutLine *prev = m_CursorLine->GetPreviousLine(); + wxCHECK_MSG(prev, false, "just broke the line, where is the previous one?"); + + height += prev->GetHeight(); + + SetUpdateRect(position); + SetUpdateRect(position.x + width + MSW_CORRECTION, + position.y + height + MSW_CORRECTION); + return true; } @@ -1143,9 +1776,15 @@ wxLayoutList::WrapLine(CoordType column) //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); + return true; } } @@ -1153,38 +1792,79 @@ wxLayoutList::WrapLine(CoordType column) bool wxLayoutList::Delete(CoordType npos) { - wxASSERT(m_CursorLine); + wxCHECK_MSG(m_CursorLine, false, "can't delete in non existing line"); + wxASSERT_MSG(npos > 0, "nothing to delete?"); + + AddCursorPosToUpdateRect(); + + // were other lines appended to this one (this is important to know because + // this means that our width _increased_ as the result of deletion) + bool wasMerged = false; + + // the size of the region to update + CoordType totalHeight = m_CursorLine->GetHeight(), + totalWidth = m_CursorLine->GetWidth(); + CoordType left; do { left = m_CursorLine->Delete(m_CursorPos.x, npos); - if(left == 0) - return true; - // More to delete, continue on next line. - // First, check if line is empty: - if(m_CursorLine->GetLength() == 0) - { // in this case, updating could probably be optimised -#ifdef WXLO_DEBUG - wxASSERT(DeleteLines(1) == 0); + + if( left > 0 ) + { + // More to delete, continue on next line. + + // First, check if line is empty: + if(m_CursorLine->GetLength() == 0) + { + // in this case, updating could probably be optimised +#ifdef WXLO_DEBUG + wxASSERT(DeleteLines(1) == 0); #else - DeleteLines(1); + DeleteLines(1); #endif - - left--; - } - else - { - // Need to join next line - if(! m_CursorLine->GetNextLine()) - break; // cannot + + left--; + } else { - m_CursorLine->MergeNextLine(); - left--; + // Need to join next line + if(! m_CursorLine->GetNextLine()) + break; // cannot + else + { + wasMerged = true; + wxLayoutLine *next = m_CursorLine->GetNextLine(); + if ( next ) + { + totalHeight += next->GetHeight(); + totalWidth += next->GetWidth(); + + m_CursorLine->MergeNextLine(this); + left--; + } + else + { + wxFAIL_MSG("can't delete all this"); + + return false; + } + } } } } - while(left); + while ( left> 0 ); + + // we need to update the whole tail of the line and the lines which + // disappeared + if ( wasMerged ) + { + wxPoint position(m_CursorLine->GetPosition()); + SetUpdateRect(position); + SetUpdateRect(position.x + totalWidth + MSW_CORRECTION, + position.y + totalHeight + MSW_CORRECTION); + } + return left == 0; } @@ -1193,37 +1873,41 @@ wxLayoutList::DeleteLines(int n) { wxASSERT(m_CursorLine); wxLayoutLine *line; + + AddCursorPosToUpdateRect(); + while(n > 0) { if(!m_CursorLine->GetNextLine()) { // we cannot delete this line, but we can clear it MoveCursorToBeginOfLine(); DeleteToEndOfLine(); + m_CursorLine->RecalculatePositions(2, this); return n-1; } //else: line = m_CursorLine; - m_CursorLine = m_CursorLine->DeleteLine(true); + m_CursorLine = m_CursorLine->DeleteLine(true, this); n--; if(line == m_FirstLine) m_FirstLine = m_CursorLine; wxASSERT(m_FirstLine); wxASSERT(m_CursorLine); } - m_CursorLine->RecalculatePositions(2); + m_CursorLine->RecalculatePositions(2, this); return n; } void -wxLayoutList::Recalculate(wxDC &dc, CoordType bottom) const +wxLayoutList::Recalculate(wxDC &dc, CoordType bottom) { wxLayoutLine *line = m_FirstLine; // first, make sure everything is calculated - this might not be // needed, optimise it later - m_DefaultSetting->Layout(dc); + ApplyStyle(&m_DefaultSetting, dc); while(line) { - line->RecalculatePosition(); // so we don't need to do it all the time + line->RecalculatePosition(this); // so we don't need to do it all the time // little condition to speed up redrawing: if(bottom != -1 && line->GetPosition().y > bottom) break; line = line->GetNextLine(); @@ -1231,21 +1915,50 @@ wxLayoutList::Recalculate(wxDC &dc, CoordType bottom) const } void -wxLayoutList::Layout(wxDC &dc, CoordType bottom) const +wxLayoutList::UpdateCursorScreenPos(wxDC &dc) { - wxLayoutLine *line = m_FirstLine; + wxASSERT(m_CursorLine); + m_CursorLine->Layout(dc, this, (wxPoint *)&m_CursorScreenPos, (wxPoint *)&m_CursorSize, m_CursorPos.x); +} + +wxPoint +wxLayoutList::GetCursorScreenPos(wxDC &dc) +{ + UpdateCursorScreenPos(dc); + return m_CursorScreenPos; +} +/* + Is called before each Draw(). Now, it will re-layout all lines which + have changed. +*/ +void +wxLayoutList::Layout(wxDC &dc, CoordType bottom, bool forceAll) +{ // first, make sure everything is calculated - this might not be // needed, optimise it later - m_DefaultSetting->Layout(dc); + ApplyStyle(&m_DefaultSetting, dc); + + // FIXME this is completely wrong - we should start by first *visible* line + // (and stop on the last one) instead of looping over all lines!! + wxLayoutLine *line = m_FirstLine; while(line) { - if(line == m_CursorLine) - line->Layout(dc, (wxPoint *)&m_CursorScreenPos, (wxPoint *)&m_CursorSize, m_CursorPos.x); - else - line->Layout(dc); - // little condition to speed up redrawing: - if(bottom != -1 && line->GetPosition().y > bottom) break; + if(forceAll || line->IsDirty()) + { + line->GetStyleInfo() = m_CurrentSetting; + if(line == m_CursorLine) + line->Layout(dc, this, (wxPoint *)&m_CursorScreenPos, + (wxPoint *)&m_CursorSize, m_CursorPos.x); + else + line->Layout(dc, this); + + // little condition to speed up redrawing: + if(bottom != -1 && line->GetPosition().y > bottom) + break; + } + + line->RecalculatePositions(1, this); line = line->GetNextLine(); } @@ -1256,58 +1969,81 @@ wxLayoutList::Layout(wxDC &dc, CoordType bottom) const m_CursorLine->GetNextLine() == NULL && m_CursorLine == m_FirstLine)); #endif + AddCursorPosToUpdateRect(); } void -wxLayoutList::Draw(wxDC &dc, wxPoint const &offset, - CoordType top, CoordType bottom) const +wxLayoutList::Draw(wxDC &dc, + wxPoint const &offset, + CoordType top, + CoordType bottom) { wxLayoutLine *line = m_FirstLine; - Layout(dc, bottom); - m_DefaultSetting->Draw(dc, wxPoint(0,0)); - wxBrush *brush = new wxBrush(*m_ColourBG, wxSOLID); - dc.SetBrush(*brush); - delete brush; - + Layout(dc); + ApplyStyle(&m_DefaultSetting, dc); + wxBrush brush(m_CurrentSetting.m_bg, wxSOLID); + dc.SetBrush(brush); + dc.SetBackgroundMode(wxTRANSPARENT); + while(line) { // only draw if between top and bottom: - if((top == -1 || line->GetPosition().y >= top)) - line->Draw(dc, offset); + if((top == -1 || line->GetPosition().y + line->GetHeight() >= top)) + line->Draw(dc, this, offset); + else + line->Layout(dc, this); // little condition to speed up redrawing: - if(bottom != -1 && line->GetPosition().y + line->GetHeight() > bottom) break; + if(bottom != -1 && line->GetPosition().y > bottom) break; 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)); + InvalidateUpdateRect(); + + WXLO_DEBUG(("Selection is %s : l%d,%ld/%ld,%ld", + m_Selection.m_valid ? "valid" : "invalid", + m_Selection.m_CursorA.x, m_Selection.m_CursorA.y, + m_Selection.m_CursorB.x, m_Selection.m_CursorB.y)); } wxLayoutObject * -wxLayoutList::FindObjectScreen(wxDC &dc, wxPoint const pos, wxPoint *cursorPos) +wxLayoutList::FindObjectScreen(wxDC &dc, wxPoint const pos, + wxPoint *cursorPos, + bool *found) { // First, find the right line: wxLayoutLine *line = m_FirstLine; wxPoint p; - - // we need to run a layout here to get font sizes right :-( - m_DefaultSetting->Layout(dc); + + ApplyStyle(&m_DefaultSetting, dc); while(line) { p = line->GetPosition(); if(p.y <= pos.y && p.y+line->GetHeight() >= pos.y) break; - line->Layout(dc); +#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) return NULL; // not found + 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->x); + wxLOiterator i = line->FindObjectScreen(dc, pos.x, + cursorPos ? & cursorPos->x : NULL , + found); return (i == NULLIT) ? NULL : *i; - + } wxPoint @@ -1320,7 +2056,7 @@ wxLayoutList::GetSize(void) const return wxPoint(0,0); wxPoint maxPoint(0,0); - + // find last line: while(line) { @@ -1334,13 +2070,12 @@ wxLayoutList::GetSize(void) const return maxPoint; } + void wxLayoutList::DrawCursor(wxDC &dc, bool active, wxPoint const &translate) { - wxPoint coords; - coords = m_CursorScreenPos; - coords.x += translate.x; - coords.y += translate.y; + 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", @@ -1349,41 +2084,367 @@ wxLayoutList::DrawCursor(wxDC &dc, bool active, wxPoint const &translate) (long)m_CursorSize.x, (long)m_CursorSize.y, (long)m_CursorLine->GetLineNumber(), (long)m_CursorLine->GetLength())); + + wxLogStatus("Cursor is at (%d, %d)", m_CursorPos.x, m_CursorPos.y); #endif - + +#ifdef WXLAYOUT_USE_CARET + m_caret->Move(coords); +#else // !WXLAYOUT_USE_CARET dc.SetBrush(*wxBLACK_BRUSH); dc.SetLogicalFunction(wxXOR); dc.SetPen(wxPen(*wxBLACK,1,wxSOLID)); if(active) - dc.DrawRectangle(coords.x, coords.y, m_CursorSize.x, - m_CursorSize.y); + { + 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+m_CursorSize.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 } -/** Called by the objects to update the update rectangle. - @param p a point to include in it -*/ void -wxLayoutList::SetUpdateRect(const wxPoint &p) +wxLayoutList::SetUpdateRect(CoordType x, CoordType y) { if(m_UpdateRectValid) - GrowRect(m_UpdateRect, p); + GrowRect(m_UpdateRect, x, y); else { - m_UpdateRect.x = p.x; - m_UpdateRect.y = p.y; + m_UpdateRect.x = x; + m_UpdateRect.y = y; m_UpdateRect.width = 4; // large enough to avoid surprises from m_UpdateRect.height = 4;// wxGTK :-) m_UpdateRectValid = true; } } +void +wxLayoutList::StartSelection(wxPoint cpos) +{ + if(cpos.x == -1) + cpos = m_CursorPos; + WXLO_DEBUG(("Starting selection at %ld/%ld", cpos.x, cpos.y)); + m_Selection.m_CursorA = cpos; + m_Selection.m_CursorB = cpos; + m_Selection.m_selecting = true; + m_Selection.m_valid = false; +} + +void +wxLayoutList::ContinueSelection(wxPoint cpos) +{ + if(cpos.x == -1) + cpos = m_CursorPos; + wxASSERT(m_Selection.m_selecting == true); + wxASSERT(m_Selection.m_valid == false); + WXLO_DEBUG(("Continuing selection at %ld/%ld", cpos.x, cpos.y)); + if(m_Selection.m_CursorB <= cpos) + m_Selection.m_CursorB = cpos; + else + m_Selection.m_CursorA = cpos; + // We always want m_CursorA <= m_CursorB! + if(! (m_Selection.m_CursorA <= m_Selection.m_CursorB)) + { + wxPoint help = m_Selection.m_CursorB; + m_Selection.m_CursorB = m_Selection.m_CursorA; + m_Selection.m_CursorA = help; + } +} + +void +wxLayoutList::EndSelection(wxPoint cpos) +{ + if(cpos.x == -1) + cpos = m_CursorPos; + ContinueSelection(cpos); + WXLO_DEBUG(("Ending selection at %ld/%ld", cpos.x, cpos.y)); + m_Selection.m_selecting = false; + m_Selection.m_valid = true; +} + + +bool +wxLayoutList::IsSelecting(void) +{ + return m_Selection.m_selecting; +} + +bool +wxLayoutList::IsSelected(const wxPoint &cursor) +{ + if(! m_Selection.m_valid && ! m_Selection.m_selecting) + return false; + return m_Selection.m_CursorA <= cursor + && cursor <= m_Selection.m_CursorB; +} + + +/** Tests whether this layout line is selected and needs + highlighting. + @param line to test for + @return 0 = not selected, 1 = fully selected, -1 = partially + selected + */ +int +wxLayoutList::IsSelected(const wxLayoutLine *line, CoordType *from, + CoordType *to) +{ + wxASSERT(line); wxASSERT(to); wxASSERT(from); + + if(! m_Selection.m_valid && ! m_Selection.m_selecting) + return 0; + + CoordType y = line->GetLineNumber(); + if(m_Selection.m_CursorA.y < y && m_Selection.m_CursorB.y > y) + return 1; + else if(m_Selection.m_CursorA.y == y) + { + *from = m_Selection.m_CursorA.x; + if(m_Selection.m_CursorB.y == y) + *to = m_Selection.m_CursorB.x; + else + *to = line->GetLength(); + return -1; + } + else if(m_Selection.m_CursorB.y == y) + { + *to = m_Selection.m_CursorB.x; + if(m_Selection.m_CursorA.y == y) + *from = m_Selection.m_CursorA.x; + else + *from = 0; + return -1; + } + else + return 0; +} + +void +wxLayoutList::DeleteSelection(void) +{ + if(! m_Selection.m_valid) + return; + + m_Selection.m_valid = false; + + // Only delete part of the current line? + if(m_Selection.m_CursorA.y == m_Selection.m_CursorB.y) + { + MoveCursorTo(m_Selection.m_CursorA); + Delete(m_Selection.m_CursorB.x - m_Selection.m_CursorA.x); + return; + } + + + wxLayoutLine + * firstLine = NULL, + * lastLine = NULL; + + for(firstLine = m_FirstLine; + firstLine && firstLine->GetLineNumber() < m_Selection.m_CursorA.y; + firstLine=firstLine->GetNextLine()) + ; + if(!firstLine || firstLine->GetLineNumber() != m_Selection.m_CursorA.y) + return; + + + for(lastLine = m_FirstLine; + lastLine && lastLine->GetLineNumber() < m_Selection.m_CursorB.y; + lastLine=lastLine->GetNextLine()) + ; + if(!lastLine || lastLine->GetLineNumber() != m_Selection.m_CursorB.y) + return; + + + // We now know that the two lines are different: + + // First, delete what's left of this line: + MoveCursorTo(m_Selection.m_CursorA); + DeleteToEndOfLine(); + + wxLayoutLine *nextLine = firstLine->GetNextLine(); + while(nextLine && nextLine != lastLine) + nextLine = nextLine->DeleteLine(false, this); + + // Now nextLine = lastLine; + Delete(1); // This joins firstLine and nextLine + Delete(m_Selection.m_CursorB.x); // This deletes the first x + // positions + + /// Recalculate: + firstLine->RecalculatePositions(1, this); +} + +/// Starts highlighting the selection +void +wxLayoutList::StartHighlighting(wxDC &dc) +{ +#if SHOW_SELECTIONS + dc.SetTextForeground(m_CurrentSetting.m_bg); + dc.SetTextBackground(m_CurrentSetting.m_fg); + dc.SetBackgroundMode(wxSOLID); +#endif +} + +/// Ends highlighting the selection +void +wxLayoutList::EndHighlighting(wxDC &dc) +{ +#if SHOW_SELECTIONS + dc.SetTextForeground(m_CurrentSetting.m_fg); + dc.SetTextBackground(m_CurrentSetting.m_bg); + dc.SetBackgroundMode(wxTRANSPARENT); +#endif +} + + +wxLayoutList * +wxLayoutList::Copy(const wxPoint &from, + const wxPoint &to) +{ + 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; + + 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; + + wxLayoutExportObject *export; + wxLayoutExportStatus status(llist); + while((export = wxLayoutExport( &status, WXLO_EXPORT_AS_OBJECTS)) != NULL) + { + if(export->type == WXLO_EXPORT_EMPTYLINE) + ; //FIXME missing support for linebreaks in string format + else + export->content.object->Write(string); + delete export; + } + + wxlo->SetData(string.c_str(), string.Length()+1); + } + return llist; +} + + + +#define COPY_SI(what) if(si->what != -1) { m_CurrentSetting.what = si->what; fontChanged = TRUE; } + +void +wxLayoutList::ApplyStyle(wxLayoutStyleInfo *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_CurrentSetting) ); + + if(si->m_fg_valid) + { + m_CurrentSetting.m_fg = si->m_fg; + dc.SetTextForeground(m_CurrentSetting.m_fg); + } + if(si->m_bg_valid) + { + m_CurrentSetting.m_bg = si->m_bg; + dc.SetTextBackground(m_CurrentSetting.m_bg); + } +} + + +#ifdef WXLAYOUT_DEBUG + +void +wxLayoutList::Debug(void) +{ + wxLayoutLine *line; -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + for(line = m_FirstLine; + line; + line = line->GetNextLine()) + line->Debug(); +} + +#endif + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * wxLayoutPrintout @@ -1395,6 +2456,13 @@ wxLayoutPrintout::wxLayoutPrintout(wxLayoutList *llist, { m_llist = llist; m_title = title; + // remove any highlighting which could interfere with printing: + m_llist->StartSelection(); + m_llist->EndSelection(); +} + +wxLayoutPrintout::~wxLayoutPrintout() +{ } float @@ -1402,7 +2470,7 @@ 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. @@ -1423,7 +2491,7 @@ wxLayoutPrintout::ScaleDC(wxDC *dc) 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 @@ -1452,7 +2520,7 @@ bool wxLayoutPrintout::OnPrintPage(int page) wxDC *dc = GetDC(); ScaleDC(dc); - + if (dc) { int top, bottom; @@ -1482,14 +2550,14 @@ void wxLayoutPrintout::GetPageInfo(int *minPage, int *maxPage, int *selPageFrom, float scale = ScaleDC(&psdc); psdc.GetSize(&m_PageWidth, &m_PageHeight); - // This sets a left/top origin of 10% and 5%: - m_Offset = wxPoint(m_PageWidth/10, m_PageHeight/20); + // This sets a left/top origin of 15% and 20%: + m_Offset = wxPoint((15*m_PageWidth)/100, m_PageHeight/20); // This is the length of the printable area. m_PrintoutHeight = m_PageHeight - (int) (m_PageHeight * 0.15); m_PrintoutHeight = (int)( m_PrintoutHeight / scale); // we want to use the real paper height - - + + m_NumOfPages = 1 + (int)( m_llist->GetSize().y / (float)(m_PrintoutHeight)); @@ -1520,12 +2588,12 @@ wxLayoutPrintout::DrawHeader(wxDC &dc, const wxBrush& brush = dc.GetBrush(); const wxPen& pen = dc.GetPen(); const wxFont& font = dc.GetFont(); - + dc.SetBrush(*wxWHITE_BRUSH); dc.SetPen(wxPen(*wxBLACK,0,wxSOLID)); dc.DrawRoundedRectangle(topleft.x, topleft.y,bottomright.x-topleft.x, - bottomright.y-topleft.y); + bottomright.y-topleft.y); dc.SetBrush(*wxBLACK_BRUSH); wxFont myfont = wxFont((WXLO_DEFAULTFONTSIZE*12)/10, wxSWISS,wxNORMAL,wxBOLD,false,"Helvetica"); @@ -1548,3 +2616,18 @@ wxLayoutPrintout::DrawHeader(wxDC &dc, #endif +wxFont & +wxFontCache::GetFont(int family, int size, int style, int weight, + bool underline) +{ + for(wxFCEList::iterator i = m_FontList.begin(); + i != m_FontList.end(); i++) + if( (**i).Matches(family, size, style, weight, underline) ) + return (**i).GetFont(); + // not found: + wxFontCacheEntry *fce = new wxFontCacheEntry(family, size, style, + weight, underline); + m_FontList.push_back(fce); + return fce->GetFont(); +} +