X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/9ffdee8074b1581d2c8ad6e6b16f536a42e42dd1..34bbbc276dc470014c8d200cfbbf7f588076aeaf:/samples/richedit/wxlwindow.cpp diff --git a/samples/richedit/wxlwindow.cpp b/samples/richedit/wxlwindow.cpp index 43ec7781c4..1d5869b2a3 100644 --- a/samples/richedit/wxlwindow.cpp +++ b/samples/richedit/wxlwindow.cpp @@ -1,7 +1,7 @@ /*-*- c++ -*-******************************************************** * wxLwindow.h : a scrolled Window for displaying/entering rich text* * * - * (C) 1998, 1999 by Karsten Ballüder (karsten@phy.hw.ac.uk) * + * (C) 1998-2000 by Karsten Ballüder (ballueder@gmx.net) * * * * $Id$ *******************************************************************/ @@ -56,6 +56,7 @@ #include + // ---------------------------------------------------------------------------- // macros // ---------------------------------------------------------------------------- @@ -66,6 +67,13 @@ # define WXLO_DEBUG(x) #endif +// for profiling in debug mode: +WXLO_TIMER_DEFINE(UpdateTimer); +WXLO_TIMER_DEFINE(BlitTimer); +WXLO_TIMER_DEFINE(LayoutTimer); +WXLO_TIMER_DEFINE(TmpTimer); +WXLO_TIMER_DEFINE(DrawTimer); + // ---------------------------------------------------------------------------- // constants // ---------------------------------------------------------------------------- @@ -86,6 +94,8 @@ static const int X_SCROLL_PAGE = 10; static const int Y_SCROLL_PAGE = 20; + + // ---------------------------------------------------------------------------- // event tables // ---------------------------------------------------------------------------- @@ -158,6 +168,7 @@ wxLayoutWindow::wxLayoutWindow(wxWindow *parent) #ifndef __WXMSW__ m_FocusFollowMode = false; #endif + SetWordWrap(false); SetWrapMargin(0); // no scrollbars initially @@ -228,10 +239,11 @@ wxLayoutWindow::OnMouse(int eventId, wxMouseEvent& event) { wxClientDC dc( this ); PrepareDC( dc ); - if ( eventId != WXLOWIN_MENU_MOUSEMOVE + if ( (eventId != WXLOWIN_MENU_MOUSEMOVE #ifndef __WXMSW__ || m_FocusFollowMode #endif + ) && (wxWindow::FindFocus() != this) ) SetFocus(); @@ -254,7 +266,7 @@ wxLayoutWindow::OnMouse(int eventId, wxMouseEvent& event) { //WXLO_DEBUG(("selecting at : %d/%d", (int) event.GetX(), (int)event.GetY())); int left, top; - ViewStart(&left, &top); + GetViewStart(&left, &top); wxSize size = GetClientSize(); int xdelta, ydelta; @@ -361,7 +373,7 @@ wxLayoutWindow::OnMouse(int eventId, wxMouseEvent& event) // Calculate where the top of the visible area is: int x0, y0; - ViewStart(&x0,&y0); + GetViewStart(&x0,&y0); int dx, dy; GetScrollPixelsPerUnit(&dx, &dy); x0 *= dx; y0 *= dy; @@ -394,7 +406,9 @@ wxLayoutWindow::OnMouse(int eventId, wxMouseEvent& event) case WXLOWIN_MENU_LUP: if ( m_Selecting ) { - m_llist->EndSelection(); + // end selection at the cursor position corresponding to the + // current mouse position, but don´t move cursor there. + m_llist->EndSelection(cursorPos,m_ClickPosition); m_Selecting = false; RequestUpdate(); // TODO: we don't have to redraw everything! @@ -475,6 +489,7 @@ wxLayoutWindow::OnChar(wxKeyEvent& event) bool deletedSelection = false; // pressing any non-arrow key optionally replaces the selection: if(m_AutoDeleteSelection + && IsEditable() && !m_Selecting && m_llist->HasSelection() && ! IsDirectionKey(keyCode) @@ -490,21 +505,18 @@ wxLayoutWindow::OnChar(wxKeyEvent& event) if ( IsDirectionKey(keyCode) ) { // just continue the old selection - if ( m_Selecting ) + if ( m_Selecting && event.ShiftDown() ) + m_llist->ContinueSelection(); + else { + m_llist->DiscardSelection(); + m_Selecting = false; if( event.ShiftDown() ) - m_llist->ContinueSelection(); - else { - m_llist->DiscardSelection(); - m_Selecting = false; + m_Selecting = true; + m_llist->StartSelection(); } } - else if( event.ShiftDown() ) - { - m_Selecting = true; - m_llist->StartSelection(); - } } // If needed, make cursor visible: @@ -561,17 +573,17 @@ wxLayoutWindow::OnChar(wxKeyEvent& event) { case 'c': // this should work even in read-only mode - Copy(); + Copy(TRUE, TRUE); break; -#ifdef M_BASEDIR - case 's': // search + case 's': // search Find(""); break; case 't': // search again FindAgain(); break; -#endif - default: + default: + // we don't handle it, maybe an accelerator? + event.Skip(); ; } else if( IsEditable() ) @@ -611,15 +623,13 @@ wxLayoutWindow::OnChar(wxKeyEvent& event) SetDirty(); } break; -#ifdef M_BASEDIR case 's': // search Find(""); break; case 't': // search again FindAgain(); break; -#endif - case 'u': + case 'u': m_llist->DeleteToBeginOfLine(); SetDirty(); break; @@ -627,19 +637,34 @@ wxLayoutWindow::OnChar(wxKeyEvent& event) m_llist->DeleteToEndOfLine(); SetDirty(); break; + case 'c': + Copy(TRUE, TRUE); + break; case 'v': - Paste(); + Paste( TRUE ); break; case 'x': Cut(); break; + case 'w': + if(m_WrapMargin > 0) + m_llist->WrapLine(m_WrapMargin); + break; + case 'q': + if(m_WrapMargin > 0) + m_llist->WrapAll(m_WrapMargin); + break; #ifdef WXLAYOUT_DEBUG case WXK_F1: m_llist->SetFont(-1,-1,-1,-1,true); // underlined break; + case 'l': + Refresh(TRUE); + break; #endif default: - ; + // we don't handle it, maybe an accelerator? + event.Skip(); } } // ALT only: @@ -653,7 +678,8 @@ wxLayoutWindow::OnChar(wxKeyEvent& event) SetDirty(); break; default: - ; + // we don't handle it, maybe an accelerator? + event.Skip(); } } // no control keys: @@ -684,7 +710,9 @@ wxLayoutWindow::OnChar(wxKeyEvent& event) } break; case WXK_RETURN: - if(m_WrapMargin > 0) + if(m_DoWordWrap && + m_WrapMargin > 0 + && m_llist->GetCursorPos().x > m_WrapMargin) m_llist->WrapLine(m_WrapMargin); m_llist->LineBreak(); SetDirty(); @@ -702,26 +730,31 @@ wxLayoutWindow::OnChar(wxKeyEvent& event) SetDirty(); } break; - + default: if((!(event.ControlDown() || event.AltDown() -//#if 0 - ///FIXME: wxGTK reports MetaDown always - || event.MetaDown() -//#endif )) && (keyCode < 256 && keyCode >= 32) ) { - if(m_WrapMargin > 0 && isspace(keyCode)) + if(m_DoWordWrap + && m_WrapMargin > 0 + && m_llist->GetCursorPos().x > m_WrapMargin + && isspace(keyCode)) m_llist->WrapLine(m_WrapMargin); m_llist->Insert((char)keyCode); SetDirty(); } + else + // we don't handle it, maybe an accelerator? + event.Skip(); break; } } }// if(IsEditable()) + else + // we don't handle it, maybe an accelerator? + event.Skip(); }// first switch() if ( m_Selecting ) @@ -752,16 +785,19 @@ wxLayoutWindow::ScrollToCursor(void) { //is always needed to make sure we know where the cursor is //if(IsDirty()) - RequestUpdate(m_llist->GetUpdateRect()); + //RequestUpdate(m_llist->GetUpdateRect()); + + + ResizeScrollbars(); int x0,y0,x1,y1, dx, dy; // Calculate where the top of the visible area is: - ViewStart(&x0,&y0); + GetViewStart(&x0,&y0); GetScrollPixelsPerUnit(&dx, &dy); x0 *= dx; y0 *= dy; - WXLO_DEBUG(("ScrollToCursor: ViewStart is %d/%d", x0, y0)); + WXLO_DEBUG(("ScrollToCursor: GetViewStart is %d/%d", x0, y0)); // Get the size of the visible window: GetClientSize(&x1, &y1); @@ -789,7 +825,7 @@ wxLayoutWindow::ScrollToCursor(void) ny = 0; } - if ( nx != -1 || ny != -1 ) + if( nx != -1 || ny != -1 ) { // set new view start Scroll(nx == -1 ? -1 : (nx+dx-1)/dx, ny == -1 ? -1 : (ny+dy-1)/dy); @@ -823,6 +859,7 @@ wxLayoutWindow::RequestUpdate(const wxRect *updateRect) void wxLayoutWindow::InternalPaint(const wxRect *updateRect) { + wxPaintDC dc( this ); PrepareDC( dc ); @@ -834,7 +871,7 @@ wxLayoutWindow::InternalPaint(const wxRect *updateRect) int x0,y0,x1,y1, dx, dy; // Calculate where the top of the visible area is: - ViewStart(&x0,&y0); + GetViewStart(&x0,&y0); GetScrollPixelsPerUnit(&dx, &dy); x0 *= dx; y0 *= dy; @@ -850,20 +887,10 @@ wxLayoutWindow::InternalPaint(const wxRect *updateRect) updateRect->x+updateRect->width, updateRect->y+updateRect->height)); } - if(IsDirty()) - { - WXLO_DEBUG(("InternalPaint, isdirty, list size: %ld,%ld", - (unsigned long) m_llist->GetSize().x, - (unsigned long) m_llist->GetSize().y)); -// m_llist->ForceTotalLayout(); - m_llist->Layout(dc); - WXLO_DEBUG(("InternalPaint, isdirty, list size after layout: %ld,%ld", - (unsigned long) m_llist->GetSize().x, - (unsigned long) m_llist->GetSize().y)); - ResizeScrollbars(); - ResetDirty(); - } - + + ResizeScrollbars(true); + + WXLO_TIMER_START(TmpTimer); /* Check whether the window has grown, if so, we need to reallocate the bitmap to be larger. */ if(x1 > m_bitmapSize.x || y1 > m_bitmapSize.y) @@ -884,7 +911,8 @@ wxLayoutWindow::InternalPaint(const wxRect *updateRect) 0,wxTRANSPARENT)); m_memDC->SetLogicalFunction(wxCOPY); m_memDC->Clear(); - + WXLO_TIMER_STOP(TmpTimer); + // fill the background with the background bitmap if(m_BGbitmap) { @@ -919,7 +947,7 @@ wxLayoutWindow::InternalPaint(const wxRect *updateRect) // update rectangle (although they are drawn on the memDC, this is // needed to erase it): m_llist->InvalidateUpdateRect(); - if(m_CursorVisibility != 0) + if(m_CursorVisibility == 1) { // draw a thick cursor for editable windows with focus m_llist->DrawCursor(*m_memDC, @@ -927,6 +955,7 @@ wxLayoutWindow::InternalPaint(const wxRect *updateRect) offset); } + WXLO_TIMER_START(BlitTimer); // Now copy everything to the screen: #if 0 // This somehow doesn't work, but even the following bit with the @@ -952,6 +981,8 @@ wxLayoutWindow::InternalPaint(const wxRect *updateRect) // y1 += WXLO_YOFFSET; //FIXME might not be needed dc.Blit(x0,y0,x1,y1,m_memDC,0,0,wxCOPY,FALSE); } + WXLO_TIMER_STOP(BlitTimer); + #ifdef WXLAYOUT_USE_CARET // show the caret back after everything is redrawn @@ -976,6 +1007,10 @@ wxLayoutWindow::InternalPaint(const wxRect *updateRect) m_StatusBar->SetStatusText(label, m_StatusFieldCursor); } } + + WXLO_TIMER_PRINT(LayoutTimer); + WXLO_TIMER_PRINT(BlitTimer); + WXLO_TIMER_PRINT(TmpTimer); } void @@ -987,20 +1022,30 @@ wxLayoutWindow::OnSize(wxSizeEvent &event) event.Skip(); } -// change the range and position of scrollbars +/* +Change the range and position of scrollbars. Has evolved into a +generic Update function which will at some time later cause a repaint +as needed. +*/ + void wxLayoutWindow::ResizeScrollbars(bool exact) { + wxClientDC dc( this ); + PrepareDC( dc ); +// m_llist->ForceTotalLayout(); - if(IsDirty()) + if(! IsDirty()) { - wxClientDC dc( this ); - PrepareDC( dc ); -// m_llist->ForceTotalLayout(); - m_llist->Layout(dc); - ResetDirty(); - RequestUpdate(); + // we are laying out just the minimum, but always up to the + // cursor line, so the cursor position is updated. + m_llist->Layout(dc, 0); + return; } + WXLO_TIMER_START(LayoutTimer); + m_llist->Layout(dc, -1); + WXLO_TIMER_STOP(LayoutTimer); + ResetDirty(); wxPoint max = m_llist->GetSize(); wxSize size = GetClientSize(); @@ -1016,7 +1061,11 @@ wxLayoutWindow::ResizeScrollbars(bool exact) // check if the text hasn't become too big // TODO why do we set both at once? they're independent... - if( max.x > m_maxx - WXLO_ROFFSET || max.y > m_maxy - WXLO_BOFFSET || exact ) + if( max.x > m_maxx - WXLO_ROFFSET + || max.y > m_maxy - WXLO_BOFFSET + || (max.x < m_maxx - X_SCROLL_PAGE) + || (max.y < m_maxy - Y_SCROLL_PAGE) + || exact ) { // text became too large if ( !exact ) @@ -1026,91 +1075,107 @@ wxLayoutWindow::ResizeScrollbars(bool exact) max.y += WXLO_BOFFSET; } - ViewStart(&m_ViewStartX, &m_ViewStartY); - SetScrollbars(X_SCROLL_PAGE, Y_SCROLL_PAGE, - max.x / X_SCROLL_PAGE + 1, max.y / Y_SCROLL_PAGE + 1, - m_ViewStartX, m_ViewStartY, - true); - - m_hasHScrollbar = - m_hasVScrollbar = true; - - m_maxx = max.x + X_SCROLL_PAGE; - m_maxy = max.y + Y_SCROLL_PAGE; - } -#if 0 - //FIXME: this code is pretty broken, producing "arithmetic - //exception" crashes (div by 0??) - else - { - // check if the window hasn't become too big, thus making the scrollbars - // unnecessary - if ( !exact ) + bool done = FALSE; + if(max.x < X_SCROLL_PAGE && m_hasHScrollbar) { - // add an extra bit to the sizes to avoid future updates - max.x -= WXLO_ROFFSET; - max.y -= WXLO_BOFFSET; + SetScrollbars(0,-1,0,-1,0,-1,true); + m_hasHScrollbar = FALSE; + done = TRUE; } - - if ( m_hasHScrollbar && (max.x < m_maxx) ) + if(max.y < Y_SCROLL_PAGE && m_hasVScrollbar) { - // remove the horizontal scrollbar - SetScrollbars(0, -1, 0, -1, 0, -1, true); - m_hasHScrollbar = false; + SetScrollbars(-1,0,-1,0,-1,0,true); + m_hasVScrollbar = FALSE; + done = TRUE; } - - if ( m_hasVScrollbar && (max.y < m_maxy) ) + if(! done && +// (max.x > X_SCROLL_PAGE || max.y > Y_SCROLL_PAGE) + (max.x > size.x - X_SCROLL_PAGE|| max.y > size.y - Y_SCROLL_PAGE) + ) { - // remove the vertical scrollbar - SetScrollbars(-1, 0, -1, 0, -1, 0, true); - m_hasVScrollbar = false; + GetViewStart(&m_ViewStartX, &m_ViewStartY); + SetScrollbars(X_SCROLL_PAGE, + Y_SCROLL_PAGE, + max.x / X_SCROLL_PAGE + 2, + max.y / Y_SCROLL_PAGE + 2, + m_ViewStartX, + m_ViewStartY, + true); + m_hasHScrollbar = + m_hasVScrollbar = true; +// ScrollToCursor(); } + + m_maxx = max.x + X_SCROLL_PAGE; + m_maxy = max.y + Y_SCROLL_PAGE; } -#endif } // ---------------------------------------------------------------------------- +// // clipboard operations // // ---------------------------------------------------------------------------- void -wxLayoutWindow::Paste(bool primary) +wxLayoutWindow::Paste(bool usePrivate, bool primary) { + // this only has an effect under X11: + wxTheClipboard->UsePrimarySelection(primary); // Read some text if (wxTheClipboard->Open()) { -#if __WXGTK__ - if(primary) - wxTheClipboard->UsePrimarySelection(); -#endif -#if wxUSE_PRIVATE_CLIPBOARD_FORMAT - wxLayoutDataObject wxldo; - if (wxTheClipboard->IsSupported( wxldo.GetFormat() )) + if(usePrivate) { - wxTheClipboard->GetData(&wxldo); + wxLayoutDataObject wxldo; + if (wxTheClipboard->IsSupported( wxldo.GetFormat() )) { + if(wxTheClipboard->GetData(wxldo)) + { + wxTheClipboard->Close(); + wxString str = wxldo.GetLayoutData(); + m_llist->Read(str); + SetDirty(); + RequestUpdate(); + return; + } } - //FIXME: missing functionality m_llist->Insert(wxldo.GetList()); } - else -#endif + wxTextDataObject data; + if (wxTheClipboard->IsSupported( data.GetFormat() ) + && wxTheClipboard->GetData(data) ) + { + wxTheClipboard->Close(); + wxString text = data.GetText(); + wxLayoutImportText( m_llist, text); + SetDirty(); + RequestUpdate(); + return; + } + } + // if everything failed we can still try the primary: + wxTheClipboard->Close(); + if(! primary) // not tried before + { + wxTheClipboard->UsePrimarySelection(); + if (wxTheClipboard->Open()) { wxTextDataObject data; - if (wxTheClipboard->IsSupported( data.GetFormat() )) + if (wxTheClipboard->IsSupported( data.GetFormat() ) + && wxTheClipboard->GetData(data) ) { - wxTheClipboard->GetData(data); wxString text = data.GetText(); wxLayoutImportText( m_llist, text); SetDirty(); + RequestUpdate(); } + wxTheClipboard->Close(); } - wxTheClipboard->Close(); } } bool -wxLayoutWindow::Copy(bool invalidate) +wxLayoutWindow::Copy(bool invalidate, bool privateFormat, bool primary) { // Calling GetSelection() will automatically do an EndSelection() // on the list, but we need to take a note of it, too: @@ -1120,8 +1185,8 @@ wxLayoutWindow::Copy(bool invalidate) m_llist->EndSelection(); } - wxLayoutDataObject wldo; - wxLayoutList *llist = m_llist->GetSelection(&wldo, invalidate); + wxLayoutDataObject *wldo = new wxLayoutDataObject; + wxLayoutList *llist = m_llist->GetSelection(wldo, invalidate); if(! llist) return FALSE; // Export selection as text: @@ -1146,25 +1211,41 @@ wxLayoutWindow::Copy(bool invalidate) text = text.Mid(0,len-1); } +#if 0 +if(! primary) // always copy as text-only to primary selection + { + wxTheClipboard->UsePrimarySelection(); + if (wxTheClipboard->Open()) + { + wxTextDataObject *data = new wxTextDataObject( text ); + wxTheClipboard->SetData( data ); + wxTheClipboard->Close(); + } + } +#endif + wxTheClipboard->UsePrimarySelection(primary); if (wxTheClipboard->Open()) { wxTextDataObject *data = new wxTextDataObject( text ); - bool rc = wxTheClipboard->SetData( data ); -#if wxUSE_PRIVATE_CLIPBOARD_FORMAT - rc |= wxTheClipboard->AddData( &wldo ); -#endif + bool rc; + + rc = wxTheClipboard->SetData( data ); + if(privateFormat) + rc |= wxTheClipboard->SetData( wldo ); wxTheClipboard->Close(); return rc; } - + else + delete wldo; + return FALSE; } bool -wxLayoutWindow::Cut(void) +wxLayoutWindow::Cut(bool privateFormat, bool usePrimary) { - if(Copy(false)) // do not invalidate selection after copy + if(Copy(false, privateFormat, usePrimary)) // do not invalidate selection after copy { m_llist->DeleteSelection(); SetDirty(); @@ -1178,12 +1259,12 @@ wxLayoutWindow::Cut(void) // searching // ---------------------------------------------------------------------------- -#ifdef M_BASEDIR bool wxLayoutWindow::Find(const wxString &needle, wxPoint * fromWhere, const wxString &configPath) { +#ifdef M_BASEDIR wxPoint found; if(needle.Length() == 0) @@ -1215,6 +1296,7 @@ wxLayoutWindow::Find(const wxString &needle, RequestUpdate(); return true; } +#endif return false; } @@ -1225,7 +1307,6 @@ wxLayoutWindow::FindAgain(void) bool rc = Find(m_FindString); return rc; } -#endif // ---------------------------------------------------------------------------- // popup menu stuff