diff --git a/samples/richedit/wxLayout.cpp b/samples/richedit/wxLayout.cpp index 265ead4ebc..d00d2a2186 100644 --- a/samples/richedit/wxLayout.cpp +++ b/samples/richedit/wxLayout.cpp @@ -33,19 +33,22 @@ IMPLEMENT_APP(MyApp) // 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) @@ -57,7 +60,7 @@ IMPLEMENT_DYNAMIC_CLASS( MyFrame, wxFrame ) EVT_MENU (-1, MyFrame::OnCommand) EVT_COMMAND (-1,-1, MyFrame::OnCommand) EVT_CHAR ( wxLayoutWindow::OnChar ) - END_EVENT_TABLE() +END_EVENT_TABLE() MyFrame::MyFrame(void) : @@ -119,8 +122,8 @@ 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; diff --git a/samples/richedit/wxllist.cpp b/samples/richedit/wxllist.cpp index ca7b2b7587..e2c3613977 100644 --- a/samples/richedit/wxllist.cpp +++ b/samples/richedit/wxllist.cpp @@ -622,20 +622,25 @@ wxLayoutObjectCmd::Layout(wxDC &dc, class wxLayoutList * llist) 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; @@ -736,30 +741,45 @@ wxLayoutLine::FindObject(CoordType xpos, CoordType *offset) const } 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(); } @@ -1012,10 +1032,18 @@ wxLayoutLine::DeleteLine(bool update, wxLayoutList *llist) 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. */ @@ -1025,7 +1053,7 @@ wxLayoutLine::DeleteLine(bool update, wxLayoutList *llist) ) MarkNextDirty(-1); } - wxLayoutLine *next = m_Next; + delete this; llist->DecNumLines(); @@ -1367,6 +1395,8 @@ wxLayoutLine::MergeNextLine(wxLayoutList *llist) #endif // 0 } + llist->DecNumLines(); + delete oldnext; } @@ -1531,6 +1561,7 @@ wxLayoutList::wxLayoutList() wxLayoutList::~wxLayoutList() { InternalClear(); + Empty(); m_FirstLine->DeleteLine(false, this); wxASSERT_MSG( m_numLines == 0, "line count calculation broken" ); @@ -1555,7 +1586,6 @@ wxLayoutList::Empty(void) void wxLayoutList::InternalClear(void) { - Empty(); m_Selection.m_selecting = false; m_Selection.m_valid = false; @@ -1620,6 +1650,11 @@ wxLayoutList::Clear(int family, int size, int style, int weight, 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 @@ -1787,14 +1822,51 @@ wxLayoutList::MoveCursorWord(int n, bool untilNext) 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 @@ -1817,9 +1889,11 @@ wxLayoutList::MoveCursorWord(int n, bool untilNext) 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 ) { @@ -1871,14 +1945,26 @@ wxLayoutList::MoveCursorWord(int n, bool untilNext) } } - 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--; + } - moveDistance = p - start - offset; + if ( moveDelta != 0 ) + { + moveDistance += moveDelta; + + n > 0 ? n-- : n++; + } } } - // except for the first iteration, offset is 0 - offset = 0; + // except for the first iteration, offset is calculated in the beginning + // of the loop + offset = -1; } MoveCursorHorizontally(moveDistance); @@ -1952,7 +2038,6 @@ bool wxLayoutList::LineBreak(void) { wxASSERT(m_CursorLine); - bool setFirst = (m_CursorLine == m_FirstLine && m_CursorPos.x == 0); AddCursorPosToUpdateRect(); @@ -1963,14 +2048,9 @@ wxLayoutList::LineBreak(void) 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 = @@ -2321,8 +2401,8 @@ wxLayoutList::FindObjectScreen(wxDC &dc, wxPoint const pos, 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; @@ -2575,44 +2655,29 @@ wxLayoutList::DeleteSelection(void) 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 diff --git a/samples/richedit/wxllist.h b/samples/richedit/wxllist.h index 9c70ecbf40..5874e64dac 100644 --- a/samples/richedit/wxllist.h +++ b/samples/richedit/wxllist.h @@ -520,12 +520,14 @@ public: /** 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 ; @@ -541,11 +543,18 @@ public: 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. */ @@ -600,13 +609,14 @@ public: 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; } //@} @@ -1123,6 +1133,26 @@ public: 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); diff --git a/samples/richedit/wxlparser.cpp b/samples/richedit/wxlparser.cpp index 316247bfc0..b3a961e374 100644 --- a/samples/richedit/wxlparser.cpp +++ b/samples/richedit/wxlparser.cpp @@ -41,10 +41,9 @@ void wxLayoutImportText(wxLayoutList *list, wxString const &str) if ( !str ) return; - // we change the string temporarily inside this function - wxString& s = (wxString &)str; // const_cast - - char * cptr = s.GetWriteBuf(s.Len()); + // we change the string only temporarily inside this function + // VZ: I still don't like it... the string data may be shared... + char * cptr = (char *)str.c_str(); // const_cast const char * begin = cptr; char backup; @@ -70,8 +69,6 @@ void wxLayoutImportText(wxLayoutList *list, wxString const &str) break; cptr++; } - - s.UngetWriteBuf(); } static diff --git a/samples/richedit/wxlwindow.cpp b/samples/richedit/wxlwindow.cpp index b8a8c12782..07e6e01cde 100644 --- a/samples/richedit/wxlwindow.cpp +++ b/samples/richedit/wxlwindow.cpp @@ -140,7 +140,8 @@ wxLayoutWindow::wxLayoutWindow(wxWindow *parent) wxDefaultPosition, wxDefaultSize, wxHSCROLL | wxVSCROLL | wxBORDER | - wxWANTS_CHARS) + wxWANTS_CHARS), + m_llist(NULL) { SetStatusBar(NULL); // don't use statusbar m_Editable = false; @@ -156,14 +157,18 @@ wxLayoutWindow::wxLayoutWindow(wxWindow *parent) 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; @@ -579,6 +584,18 @@ wxLayoutWindow::OnChar(wxKeyEvent& event) 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) @@ -640,19 +657,10 @@ wxLayoutWindow::ScrollToCursor(void) WXLO_DEBUG(("ScrollToCursor: ViewStart is %d/%d", x0, y0)); // Get the size of the visible window: - GetClientSize(&x1,&y1); + GetClientSize(&x1, &y1); - // notice that the client size may be (0, 0)... - wxASSERT(x1 >= 0 && y1 >= 0); - - // 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 @@ -860,9 +868,12 @@ wxLayoutWindow::InternalPaint(const wxRect *updateRect) void wxLayoutWindow::OnSize(wxSizeEvent &event) { - ResizeScrollbars(); + if ( m_llist ) + { + ResizeScrollbars(); + } - event.Skip(); + event.Skip(); } // change the range and position of scrollbars diff --git a/samples/richedit/wxlwindow.h b/samples/richedit/wxlwindow.h index c936477bfe..7ed9994c80 100644 --- a/samples/richedit/wxlwindow.h +++ b/samples/richedit/wxlwindow.h @@ -23,7 +23,7 @@ #endif -#define wxUSE_PRIVATE_CLIPBOARD_FORMAT 1 +#define wxUSE_PRIVATE_CLIPBOARD_FORMAT 0 enum {