// MyFrame
//-----------------------------------------------------------------------------
- enum ids{ ID_ADD_SAMPLE = 1, ID_CLEAR, ID_PRINT,
- ID_PRINT_SETUP, ID_PAGE_SETUP, ID_PREVIEW, ID_PRINT_PS,
- ID_PRINT_SETUP_PS, ID_PAGE_SETUP_PS,ID_PREVIEW_PS,
- ID_WRAP, ID_NOWRAP, ID_PASTE, ID_COPY, ID_CUT,
- ID_PASTE_PRIMARY,
- ID_FIND,
- ID_WXLAYOUT_DEBUG, ID_QUIT, ID_CLICK, ID_HTML, ID_TEXT,
- ID_TEST, ID_LINEBREAKS_TEST, ID_LONG_TEST, ID_URL_TEST };
+enum ids
+{
+ ID_ADD_SAMPLE = 1, ID_CLEAR, ID_PRINT,
+ ID_PRINT_SETUP, ID_PAGE_SETUP, ID_PREVIEW, ID_PRINT_PS,
+ ID_PRINT_SETUP_PS, ID_PAGE_SETUP_PS,ID_PREVIEW_PS,
+ ID_WRAP, ID_NOWRAP, ID_PASTE, ID_COPY, ID_CUT,
+ ID_PASTE_PRIMARY,
+ ID_FIND,
+ ID_WXLAYOUT_DEBUG, ID_QUIT, ID_CLICK, ID_HTML, ID_TEXT,
+ ID_TEST, ID_LINEBREAKS_TEST, ID_LONG_TEST, ID_URL_TEST
+};
IMPLEMENT_DYNAMIC_CLASS( MyFrame, wxFrame )
- BEGIN_EVENT_TABLE(MyFrame,wxFrame)
+BEGIN_EVENT_TABLE(MyFrame,wxFrame)
EVT_MENU(ID_PRINT, MyFrame::OnPrint)
EVT_MENU(ID_PREVIEW, MyFrame::OnPrintPreview)
EVT_MENU(ID_PRINT_SETUP, MyFrame::OnPrintSetup)
EVT_MENU (-1, MyFrame::OnCommand)
EVT_COMMAND (-1,-1, MyFrame::OnCommand)
EVT_CHAR ( wxLayoutWindow::OnChar )
- END_EVENT_TABLE()
+END_EVENT_TABLE()
MyFrame::MyFrame(void) :
m_lwin->SetMouseTracking(true);
m_lwin->SetEditable(true);
m_lwin->SetWrapMargin(40);
- m_lwin->Clear(wxROMAN,16,wxNORMAL,wxNORMAL, false);
m_lwin->SetFocus();
+ Clear();
// create and set the background bitmap (this will result in a lattice)
static const int sizeBmp = 10;
wxLayoutLine::wxLayoutLine(wxLayoutLine *prev, wxLayoutList *llist)
{
- m_LineNumber = 0;
m_Width = m_Height = 0;
m_Length = 0;
+
m_updateLeft = -1;
MarkDirty(0);
+
m_Previous = prev;
m_Next = NULL;
+
+ m_LineNumber = 0;
RecalculatePosition(llist);
+
if(m_Previous)
{
- m_LineNumber = m_Previous->GetLineNumber()+1;
+ m_LineNumber = m_Previous->GetLineNumber() + 1;
m_Next = m_Previous->GetNextLine();
m_Previous->m_Next = this;
}
+
if(m_Next)
{
m_Next->m_Previous = this;
}
wxLayoutObjectList::iterator
-wxLayoutLine::FindObjectScreen(wxDC &dc,
+wxLayoutLine::FindObjectScreen(wxDC &dc, wxLayoutList *llist,
CoordType xpos, CoordType *cxpos,
bool *found) const
{
wxASSERT(cxpos);
- wxASSERT(cxpos);
+
+ llist->ApplyStyle(GetStyleInfo(), dc);
+
wxLayoutObjectList::iterator i;
CoordType x = 0, cx = 0, width;
for(i = m_ObjectList.begin(); i != NULLIT; i++)
{
- width = (**i).GetWidth();
+ wxLayoutObject *obj = *i;
+ if ( obj->GetType() == WXLO_TYPE_CMD )
+ {
+ // this will set the correct font for the objects which follow
+ obj->Layout(dc, llist);
+ }
+
+ width = obj->GetWidth();
if( x <= xpos && xpos <= x + width )
{
- *cxpos = cx + (**i).GetOffsetScreen(dc, xpos-x);
- if(found) *found = true;
+ *cxpos = cx + obj->GetOffsetScreen(dc, xpos-x);
+
+ if ( found )
+ *found = true;
return i;
}
- x += (**i).GetWidth();
- cx += (**i).GetLength();
+
+ x += obj->GetWidth();
+ cx += obj->GetLength();
}
+
// behind last object:
*cxpos = cx;
- if(found) *found = false;
+
+ if (found)
+ *found = false;
return m_ObjectList.tail();
}
if(m_Previous)
m_Previous->m_Next = m_Next;
+ wxLayoutLine *next = m_Next;
+ if ( next )
+ {
+ // get the line numbers right again
+ next->MoveLines(-1);
+ }
+
if(update)
{
- m_Next->MoveLines(-1);
- m_Next->RecalculatePositions(1, llist);
+ if ( next )
+ next->RecalculatePositions(1, llist);
+
/* We assume that if we have more than one object in the list,
this means that we have a command object, so we need to
update the following lines. */
)
MarkNextDirty(-1);
}
- wxLayoutLine *next = m_Next;
+
delete this;
llist->DecNumLines();
#endif // 0
}
+ llist->DecNumLines();
+
delete oldnext;
}
wxLayoutList::~wxLayoutList()
{
InternalClear();
+ Empty();
m_FirstLine->DeleteLine(false, this);
wxASSERT_MSG( m_numLines == 0, "line count calculation broken" );
void
wxLayoutList::InternalClear(void)
{
- Empty();
m_Selection.m_selecting = false;
m_Selection.m_valid = false;
m_DefaultStyleInfo = wxLayoutStyleInfo(family, size, style, weight,
underline, fg, bg);
m_CurrentStyleInfo = m_DefaultStyleInfo;
+
+ // Empty() should be called after we set m_DefaultStyleInfo because
+ // otherwise the style info for the first line (created in Empty()) would be
+ // incorrect
+ Empty();
}
wxPoint
CoordType moveDistance = 0;
CoordType offset;
- for ( wxLOiterator i = m_CursorLine->FindObject(m_CursorPos.x, &offset);
+ wxLayoutLine *lineCur = m_CursorLine;
+ for ( wxLOiterator i = lineCur->FindObject(m_CursorPos.x, &offset);
n != 0;
n > 0 ? i++ : i-- )
{
if ( i == NULLIT )
- return false;
+ {
+ if ( n > 0 )
+ {
+ // moving forward, pass to the first object of the next line
+ moveDistance++;
+ lineCur = lineCur->GetNextLine();
+ if ( lineCur )
+ i = lineCur->GetFirstObject();
+ }
+ else
+ {
+ // moving backwards, pass to the last object of the prev line
+ moveDistance--;
+ lineCur = lineCur->GetPreviousLine();
+ if ( lineCur )
+ i = lineCur->GetLastObject();
+ }
+
+ if ( i == NULLIT )
+ {
+ // moved to the end/beginning of text
+ return false;
+ }
+ }
wxLayoutObject *obj = *i;
+
+ if ( offset == -1 )
+ {
+ // calculate offset: we are either at the very beginning or the very
+ // end of the object, so it isn't very difficult (the only time when
+ // offset is != -1 is for the very first iteration when its value is
+ // returned by FindObject)
+ if ( n > 0 )
+ offset = 0;
+ else
+ offset = obj->GetLength();
+ }
+
if( obj->GetType() != WXLO_TYPE_TEXT )
{
// any visible non text objects count as one word
if ( n > 0 )
{
// can't move further in this text object
- n--;
-
canAdvance = false;
+
+ // still should move over the object border
+ moveDistance++;
+ n--;
}
else if ( offset > 0 )
{
}
}
- n > 0 ? n-- : n++;
+ CoordType moveDelta = p - start - offset;
+ if ( (n < 0) && (offset == tobj->GetLength() - 1) )
+ {
+ // because we substracted 1 from offset in this case above, now
+ // compensate for it
+ moveDelta--;
+ }
+
+ if ( moveDelta != 0 )
+ {
+ moveDistance += moveDelta;
- moveDistance = p - start - offset;
+ n > 0 ? n-- : n++;
+ }
}
}
- // except for the first iteration, offset is 0
- offset = 0;
+ // except for the first iteration, offset is calculated in the beginning
+ // of the loop
+ offset = -1;
}
MoveCursorHorizontally(moveDistance);
wxLayoutList::LineBreak(void)
{
wxASSERT(m_CursorLine);
- bool setFirst = (m_CursorLine == m_FirstLine && m_CursorPos.x == 0);
AddCursorPosToUpdateRect();
height = m_CursorLine->GetHeight();
m_CursorLine = m_CursorLine->Break(m_CursorPos.x, this);
- if(setFirst) // we were at beginning of first line
- m_FirstLine = m_CursorLine;
- wxASSERT(m_FirstLine);
- if(m_CursorPos.x != 0)
- m_CursorPos.y++;
+ m_CursorPos.y++;
m_CursorPos.x = 0;
-
// The following code will produce a height which is guaranteed to
// be too high: old lineheight + the height of both new lines.
// We can probably drop the old line height and start with height =
cursorPos->y = line->GetLineNumber();
// Now, find the object in the line:
- ApplyStyle(line->GetStyleInfo(), dc);
- wxLOiterator i = line->FindObjectScreen(dc, pos.x,
+ wxLOiterator i = line->FindObjectScreen(dc, this,
+ pos.x,
cursorPos ? &cursorPos->x : NULL,
found);
return (i == NULLIT) ? NULL : *i;
return;
}
+ // We now know that the two lines are different:
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:
+ * firstLine = GetLine(m_Selection.m_CursorA.y),
+ * lastLine = GetLine(m_Selection.m_CursorB.y);
// First, delete what's left of this line:
MoveCursorTo(m_Selection.m_CursorA);
DeleteToEndOfLine();
- wxLayoutLine *nextLine = firstLine->GetNextLine();
+ wxLayoutLine *prevLine = firstLine->GetPreviousLine(),
+ *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
+ Delete(m_Selection.m_CursorB.x); // This deletes the first x positions
- /// Recalculate:
- firstLine->RecalculatePositions(1, this);
+ // Recalculate the line positions and numbers but notice that firstLine
+ // might not exist any more - it could be deleted by Delete(1) above
+ wxLayoutLine *firstLine2 = prevLine ? prevLine->GetNextLine() : m_FirstLine;
+ firstLine2->RecalculatePositions(1, this);
}
/// Starts highlighting the selection
/** Finds the object which covers the screen position xpos in this
line.
@param dc the wxDC to use for calculations
+ @param llist the layout list to which this line belongs
@param xpos the screen x coordinate
@param offset where to store the difference between xpos and
the object's head
@return iterator to the object or NULLIT
*/
wxLayoutObjectList::iterator FindObjectScreen(wxDC &dc,
+ wxLayoutList *llist,
CoordType xpos,
CoordType *offset,
bool *found = NULL) const ;
functions to export the list.
@return iterator to the first object
*/
- wxLayoutObjectList::iterator GetFirstObject(void)
+ wxLayoutObjectList::iterator GetFirstObject(void) const
{
return m_ObjectList.begin();
}
+ /** Get the last object in the list.
+ */
+ wxLayoutObjectList::iterator GetLastObject(void) const
+ {
+ return m_ObjectList.tail();
+ }
+
/** Deletes this line, returns pointer to next line.
@param update If true, update all following lines.
*/
for that position
@return pointer to the object
*/
- wxLayoutObject * FindObjectScreen(wxDC &dc, CoordType xpos, bool
- *found = NULL);
+ wxLayoutObject * FindObjectScreen(wxDC &dc,
+ CoordType xpos,
+ bool *found = NULL);
/** This sets the style info for the beginning of this line.
@param si styleinfo structure
*/
void ApplyStyle(const wxLayoutStyleInfo &si)
- { m_StyleInfo = si; }
+ { m_StyleInfo = si; }
//@}
void IncNumLines() { m_numLines++; }
void DecNumLines() { m_numLines--; }
+ /// get the line by number
+ wxLayoutLine *GetLine(CoordType index) const
+ {
+ wxASSERT_MSG( (0 <= index) && (index < (CoordType)m_numLines),
+ "invalid index" );
+
+ wxLayoutLine *line;
+ CoordType n = index;
+ for ( line = m_FirstLine; line && n-- > 0; line = line->GetNextLine() )
+ ;
+
+ if ( line )
+ {
+ // should be the right one
+ wxASSERT( line->GetLineNumber() == index );
+ }
+
+ return line;
+ }
+
private:
/// Clear the list.
void InternalClear(void);
wxDefaultPosition, wxDefaultSize,
wxHSCROLL | wxVSCROLL |
wxBORDER |
- wxWANTS_CHARS)
+ wxWANTS_CHARS),
+ m_llist(NULL)
{
SetStatusBar(NULL); // don't use statusbar
m_Editable = false;
m_BGbitmap = NULL;
m_ScrollToCursor = false;
SetWrapMargin(0);
+
+ // initially the list is empty, so why would we need the scrollbars?
+#if 0
wxPoint max = m_llist->GetSize();
SetScrollbars(X_SCROLL_PAGE, Y_SCROLL_PAGE,
max.x / X_SCROLL_PAGE + 1, max.y / Y_SCROLL_PAGE + 1);
EnableScrolling(true, true);
m_maxx = max.x + X_SCROLL_PAGE;
m_maxy = max.y + Y_SCROLL_PAGE;
+#endif // 0
- // no scrollbars initially (BTW, why then we do all the stuff above?)
+ // no scrollbars initially
m_hasHScrollbar =
m_hasVScrollbar = false;
m_llist->WrapLine(m_WrapMargin);
m_llist->LineBreak();
break;
+
+ case WXK_TAB:
+ {
+ // TODO should be configurable
+ static const int tabSize = 8;
+
+ CoordType x = m_llist->GetCursorPos().x;
+ size_t numSpaces = tabSize - x % tabSize;
+ m_llist->Insert(wxString(' ', numSpaces));
+ }
+ break;
+
default:
if((!(event.ControlDown() || event.AltDown() || event.MetaDown()))
&& (keyCode < 256 && keyCode >= 32)
WXLO_DEBUG(("ScrollToCursor: ViewStart is %d/%d", x0, y0));
// Get the size of the visible window:
- GetClientSize(&x1,&y1);
-
- // notice that the client size may be (0, 0)...
- wxASSERT(x1 >= 0 && y1 >= 0);
+ GetClientSize(&x1, &y1);
- // VZ: I think this is false - if you do it here, ResizeScrollbars() won't
- // call SetScrollbars() later
-#if 0
- // As we have the values anyway, use them to avoid unnecessary scrollbar
- // updates.
- if(x1 > m_maxx) m_maxx = x1;
- if(y1 > m_maxy) m_maxy = y1;
-#endif // 0
+ // update the cursor screen position
+ m_llist->Layout(dc);
// Make sure that the scrollbars are at a position so that the cursor is
// visible if we are editing
void
wxLayoutWindow::OnSize(wxSizeEvent &event)
{
- ResizeScrollbars();
+ if ( m_llist )
+ {
+ ResizeScrollbars();
+ }
- event.Skip();
+ event.Skip();
}
// change the range and position of scrollbars