ID_PRINT_SETUP_PS, ID_PAGE_SETUP_PS,ID_PREVIEW_PS,
ID_WRAP, ID_NOWRAP, ID_PASTE, ID_COPY, ID_CUT, ID_FIND,
ID_WXLAYOUT_DEBUG, ID_QUIT, ID_CLICK, ID_HTML, ID_TEXT,
- ID_TEST, ID_LONG_TEST };
+ ID_TEST, ID_LINEBREAKS_TEST, ID_LONG_TEST, ID_URL_TEST };
IMPLEMENT_DYNAMIC_CLASS( MyFrame, wxFrame )
MyFrame::MyFrame(void) :
- wxFrame( (wxFrame *) NULL, -1, (char *) "wxLayout", wxPoint(20,20), wxSize(600,360) )
+ wxFrame( (wxFrame *) NULL, -1, "wxLayout",
+ wxPoint(880,100), wxSize(256,256) )
{
CreateStatusBar( 2 );
file_menu->Append(ID_PREVIEW_PS, "Print Preview PostScript", "Preview (PostScript)");
#endif
file_menu->AppendSeparator();
- file_menu->Append( ID_TEXT, "Export Text");
- file_menu->Append( ID_HTML, "Export HTML");
- file_menu->Append( ID_QUIT, "Exit");
- menu_bar->Append(file_menu, "File" );
+ file_menu->Append( ID_TEXT, "Export &Text");
+ file_menu->Append( ID_HTML, "Export &HTML");
+ file_menu->Append( ID_QUIT, "E&xit");
+ menu_bar->Append(file_menu, "&File" );
wxMenu *edit_menu = new wxMenu;
- edit_menu->Append( ID_CLEAR, "Clear");
- edit_menu->Append( ID_ADD_SAMPLE, "Example");
- edit_menu->Append( ID_LONG_TEST, "Add many lines");
+ edit_menu->Append( ID_CLEAR, "C&lear");
+ edit_menu->Append( ID_ADD_SAMPLE, "&Example");
+ edit_menu->Append( ID_LONG_TEST, "Add &many lines");
edit_menu->AppendSeparator();
- edit_menu->Append(ID_WRAP, "Wrap mode", "Activate wrapping at pixel 200.");
- edit_menu->Append(ID_NOWRAP, "No-wrap mode", "Deactivate wrapping.");
+ edit_menu->Append( ID_LINEBREAKS_TEST, "Add &several lines");
+ edit_menu->Append( ID_URL_TEST, "Insert an &URL");
edit_menu->AppendSeparator();
- edit_menu->Append(ID_COPY, "Copy", "Copy text to clipboard.");
- edit_menu->Append(ID_CUT, "Cut", "Cut text to clipboard.");
- edit_menu->Append(ID_PASTE,"Paste", "Paste text from clipboard.");
- edit_menu->Append(ID_FIND, "Find", "Find text.");
- menu_bar->Append(edit_menu, "Edit" );
+ edit_menu->Append(ID_WRAP, "&Wrap mode", "Activate wrapping at pixel 200.");
+ edit_menu->Append(ID_NOWRAP, "&No-wrap mode", "Deactivate wrapping.");
+ edit_menu->AppendSeparator();
+ edit_menu->Append(ID_COPY, "&Copy", "Copy text to clipboard.");
+ edit_menu->Append(ID_CUT, "Cu&t", "Cut text to clipboard.");
+ edit_menu->Append(ID_PASTE,"&Paste", "Paste text from clipboard.");
+ edit_menu->Append(ID_FIND, "&Find", "Find text.");
+ menu_bar->Append(edit_menu, "&Edit" );
#ifndef __WXMSW__
menu_bar->Show( TRUE );
fgets(buffer,1024,in);
if(feof(in))
break;
- llist->Insert(buffer);
- llist->LineBreak();
+ wxLayoutImportText(llist, buffer);
}
}
llist->MoveCursorTo(wxPoint(0,0));
m_lwin->Refresh();
break;
}
+
+ case ID_LINEBREAKS_TEST:
+ wxLayoutImportText(m_lwin->GetLayoutList(),
+ "This is a text\n"
+ "with embedded line\n"
+ "breaks.\n");
+ break;
+
+ case ID_URL_TEST:
+ // VZ: this doesn't work, of course, but I think it should -
+ // wxLayoutWindow should have a flag m_highlightUrls and do it itself
+ // (instead of doing it manually like M does now)
+ m_lwin->GetLayoutList()->Insert("http://www.wxwindows.org/");
}
};
// 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 = 10;
+ static const int MSW_CORRECTION = 5;
#else
static const int MSW_CORRECTION = 0;
#endif
{
long descent = 0l;
+ // 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
llist->SetUpdateRect(position.x + widthOld + MSW_CORRECTION,
position.y + heightOld + MSW_CORRECTION);
}
+#endif // 0
m_Bottom = descent;
m_Top = m_Height - m_Bottom;
m_LineNumber = 0;
m_Width = m_Height = 0;
m_Length = 0;
- m_Dirty = true;
+ MarkDirty(0);
m_Previous = prev;
m_Next = NULL;
RecalculatePosition(llist);
{
wxASSERT(m_Previous || GetLineNumber() == 0);
+ wxPoint posOld(m_Position);
+
if(m_Previous)
{
m_Position = m_Previous->GetPosition();
}
else
m_Position = wxPoint(0,0);
- llist->SetUpdateRect(m_Position);
+
+ if ( m_Position != posOld )
+ {
+ // the whole line moved and must be repainted
+ llist->SetUpdateRect(m_Position);
+ llist->SetUpdateRect(m_Position.x + GetWidth() + MSW_CORRECTION,
+ m_Position.y + GetHeight() + MSW_CORRECTION);
+ llist->SetUpdateRect(posOld);
+ llist->SetUpdateRect(posOld.x + GetWidth() + MSW_CORRECTION,
+ posOld.y + GetHeight() + MSW_CORRECTION);
+ }
+
return m_Position;
}
wxASSERT(xpos >= 0);
wxASSERT(obj != NULL);
- // in any case, the object is going to belong to this line
- obj->AttachToLine(this);
+ MarkDirty(xpos);
- //FIXME: this could be optimised, for now be prudent:
- m_Dirty = true;
CoordType offset;
wxLOiterator i = FindObject(xpos, &offset);
if(i == NULLIT)
}
bool
-wxLayoutLine::Insert(CoordType xpos, wxString text)
+wxLayoutLine::Insert(CoordType xpos, const wxString& text)
{
wxASSERT(xpos >= 0);
- //FIXME: this could be optimised, for now be prudent:
- m_Dirty = true;
+
+ MarkDirty(xpos);
+
CoordType offset;
wxLOiterator i = FindObject(xpos, &offset);
if(i != NULLIT && (**i).GetType() == WXLO_TYPE_TEXT)
wxLayoutObjectText *tobj = (wxLayoutObjectText *) *i;
tobj->GetText().insert(offset, text);
m_Length += text.Length();
-
- return true;
}
else
- return Insert(xpos, new wxLayoutObjectText(text));
+ {
+ if ( !Insert(xpos, new wxLayoutObjectText(text)) )
+ return false;
+ }
+
+ return true;
}
CoordType
wxASSERT(xpos >= 0);
wxASSERT(npos >= 0);
- //FIXME: this could be optimised, for now be prudent:
- m_Dirty = true;
+ MarkDirty(xpos);
wxLOiterator i = FindObject(xpos, &offset);
while(npos > 0)
{
{
wxASSERT(xpos >= 0);
CoordType offset;
- //FIXME: this could be optimised, for now be prudent:
- m_Dirty = true;
+ MarkDirty(xpos);
wxLOiterator i = FindObject(xpos, &offset);
{
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
- oldWidth = m_Width,
- 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;
- bool cursorFound = false;
+ m_BaseLine = 0;
- m_Dirty = false;
+ bool cursorFound = false;
if(cursorPos)
{
//llist->ApplyStyle(&m_StyleInfo, dc);
for(i = m_ObjectList.begin(); i != NULLIT; i++)
{
- (**i).Layout(dc, llist);
- size = (**i).GetSize(&objTopHeight, &objBottomHeight);
+ wxLayoutObject *obj = *i;
+ obj->Layout(dc, llist);
+ wxPoint sizeObj = obj->GetSize(&objTopHeight, &objBottomHeight);
if(cursorPos && ! cursorFound)
- { // we need to check whether the text cursor is here
- len = (**i).GetLength();
+ {
+ // we need to check whether the text cursor is here
+ len = obj->GetLength();
if(count <= cx && count+len > cx)
{
- if((**i).GetType() == WXLO_TYPE_TEXT)
+ if(obj->GetType() == WXLO_TYPE_TEXT)
{
len = cx - count; // pos in object
CoordType width, height, descent;
cursorPos->x += width;
cursorPos->y = m_Position.y;
wxString str;
- if(len < (**i).GetLength())
+ if(len < obj->GetLength())
str = (*(wxLayoutObjectText*)*i).GetText().substr(len,1);
else
str = WXLO_CURSORCHAR;
wxASSERT(cursorSize);
// Just in case some joker inserted an empty string object:
if(width == 0) width = WXLO_MINIMUM_CURSOR_WIDTH;
- if(height == 0) height = objHeight;
+ if(height == 0) height = sizeObj.y;
cursorSize->x = width;
cursorSize->y = height;
cursorFound = true; // no more checks
}
else
- { // on some other object
+ {
+ // on some other object
CoordType top, bottom; // unused
- *cursorSize = (**i).GetSize(&top,&bottom);
+ *cursorSize = obj->GetSize(&top,&bottom);
cursorPos->y = m_Position.y;
cursorFound = true; // no more checks
}
else
{
count += len;
- cursorPos->x += (**i).GetWidth();
+ cursorPos->x += obj->GetWidth();
}
} // cursor finding
- objHeight = size.y;
- m_Width += size.x;
- if(objHeight > m_Height) m_Height = objHeight;
- if(objTopHeight > topHeight) topHeight = objTopHeight;
- if(objBottomHeight > bottomHeight) bottomHeight = objBottomHeight;
+
+ m_Width += sizeObj.x;
+ if(sizeObj.y > m_Height)
+ {
+ m_Height = sizeObj.y;
+ }
+
+ if(objTopHeight > topHeight)
+ topHeight = objTopHeight;
+ if(objBottomHeight > bottomHeight)
+ bottomHeight = objBottomHeight;
}
- // special case of a line which becomes empty (after deletion, for example):
- // we should invalidate the screen space it occupied (usually this happens
- // from wxLayoutObject::Layout called in the loop above)
- if ( m_ObjectList.empty() )
+ if ( IsDirty() )
{
- wxPoint position(GetPosition());
- llist->SetUpdateRect(position.x + oldWidth + MSW_CORRECTION,
- position.y + oldHeight + MSW_CORRECTION);
+ if ( updateHeight < m_Height )
+ updateHeight = m_Height;
+ if ( updateWidth < m_Width )
+ updateWidth = m_Width;
+
+ // update all line if we don't know where to start from
+ if ( updateLeft == -1 )
+ updateLeft = 0;
+
+ llist->SetUpdateRect(updateLeft, updateTop);
+ llist->SetUpdateRect(updateLeft + updateWidth + MSW_CORRECTION,
+ updateTop + updateHeight + MSW_CORRECTION);
}
if(topHeight + bottomHeight > m_Height)
+ {
m_Height = topHeight+bottomHeight;
+ }
+
m_BaseLine = topHeight;
if(m_Height == 0)
m_BaseLine = m_Height - descent;
}
-
// tell next line about coordinate change
- if(m_Next && objHeight != oldHeight)
+ if(m_Next && m_Height != heightOld)
+ {
+ // FIXME isn't this done in RecalculatePositions() below anyhow?
m_Next->RecalculatePositions(0, llist);
+ }
// We need to check whether we found a valid cursor size:
if(cursorPos)
if(m_BaseLine >= cursorSize->y) // the normal case anyway
cursorPos->y += m_BaseLine-cursorSize->y;
}
+
RecalculatePositions(1, llist);
+
+ MarkClean();
}
wxLayoutLine::Break(CoordType xpos, wxLayoutList *llist)
{
wxASSERT(xpos >= 0);
- //FIXME: this could be optimised, for now be prudent:
- m_Dirty = true;
+
+ 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
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)
wxCHECK_RET(GetNextLine(),"wxLayout internal error: no next line to merge");
wxLayoutObjectList &list = GetNextLine()->m_ObjectList;
wxLOiterator i;
- //FIXME: this could be optimised, for now be prudent:
- m_Dirty = true;
+
+ MarkDirty(GetWidth());
wxLayoutObject *last = NULL;
for(i = list.begin(); i != list.end();)
else
{
// just append the object "as was"
- current->UnattachFromLine();
Append(current);
list.remove(i); // remove without deleting it
wxLayoutLine *oldnext = GetNextLine();
wxLayoutLine *nextLine = oldnext->GetNextLine();
SetNext(nextLine);
- delete oldnext;
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
+ }
- // no RecalculatePositions needed - called from Delete() anyhow
+ delete oldnext;
}
CoordType
wxLayoutList::Insert(wxString const &text)
{
wxASSERT(m_CursorLine);
+ wxASSERT_MSG( text.Find('\n') == wxNOT_FOUND, "use wxLayoutImportText!" );
+
+ if ( !text )
+ return true;
AddCursorPosToUpdateRect();
- m_CursorLine->Insert(m_CursorPos.x, text);
+ if ( !m_CursorLine->Insert(m_CursorPos.x, text) )
+ return false;
+
m_CursorPos.x += text.Length();
- m_CursorLine->RecalculatePositions(true, this); //FIXME needed?
+
+ m_CursorLine->RecalculatePositions(0, this);
+
return true;
}
m_CursorLine->Insert(m_CursorPos.x, obj);
m_CursorPos.x += obj->GetLength();
- m_CursorLine->RecalculatePositions(true, this); //FIXME needed?
+
+ m_CursorLine->RecalculatePositions(0, this);
+
return true;
}
LineBreak();
Delete(1); // delete the space
m_CursorPos.x = newpos;
- m_CursorLine->RecalculatePositions(true, this); //FIXME needed?
+
+ m_CursorLine->RecalculatePositions(1, this);
+
return true;
}
}
wasMerged = true;
wxLayoutLine *next = m_CursorLine->GetNextLine();
if ( next )
+ {
totalHeight += next->GetHeight();
- m_CursorLine->MergeNextLine(this);
- left--;
+ totalWidth += next->GetWidth();
+
+ m_CursorLine->MergeNextLine(this);
+ left--;
+ }
+ else
+ {
+ wxFAIL_MSG("can't delete all this");
+
+ return false;
+ }
}
}
}
if ( wasMerged )
{
wxPoint position(m_CursorLine->GetPosition());
+ SetUpdateRect(position);
SetUpdateRect(position.x + totalWidth + MSW_CORRECTION,
position.y + totalHeight + MSW_CORRECTION);
}
void
wxLayoutList::Layout(wxDC &dc, CoordType bottom, bool forceAll)
{
- wxLayoutLine *line = m_FirstLine;
-
// first, make sure everything is calculated - this might not be
// needed, optimise it later
ApplyStyle(&m_DefaultSetting, dc);
+
+ // FIXME this is completely wrong - we should start by first *visible* line
+ // (and stop on the last one) instead of looping over all lines!!
+ wxLayoutLine *line = m_FirstLine;
while(line)
{
if(forceAll || line->IsDirty())
(wxPoint *)&m_CursorSize, m_CursorPos.x);
else
line->Layout(dc, this);
- // little condition to speed up redrawing:
- if(bottom != -1 && line->GetPosition().y > bottom) break;
+
+ // little condition to speed up redrawing:
+ if(bottom != -1 && line->GetPosition().y > bottom)
+ break;
}
- line->RecalculatePositions(1,this);
+
+ line->RecalculatePositions(1, this);
line = line->GetNextLine();
}
wxLayoutLine *line = m_FirstLine;
wxPoint p;
- // we need to run a layout here to get font sizes right :-(
ApplyStyle(&m_DefaultSetting, dc);
while(line)
{
p = line->GetPosition();
if(p.y <= pos.y && p.y+line->GetHeight() >= pos.y)
break;
+#if 0
+ // we need to run a layout here to get font sizes right :-(
+
+ // VZ: we can't call Layout() from here because it marks the line as
+ // clean and it is not refreshed when it's called from wxLayoutList::
+ // Layout() - if we really need to do this, we should introduce an
+ // extra argument to Layout() to prevent the line from MarkClean()ing
+ // itself here
line->Layout(dc, this);
+#endif
line = line->GetNextLine();
}
if(line == NULL)