X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/0454d4ca74055e8b84ae8081df3f6958986f15bf..085b1c8b61d486f4c7c6d191fe8bc2fa19243bb2:/user/wxLayout/wxlwindow.cpp diff --git a/user/wxLayout/wxlwindow.cpp b/user/wxLayout/wxlwindow.cpp index fddc161486..a64e4286ae 100644 --- a/user/wxLayout/wxlwindow.cpp +++ b/user/wxLayout/wxlwindow.cpp @@ -16,14 +16,13 @@ #endif -//#include "Mpch.h" +#include "Mpch.h" #ifdef M_BASEDIR # ifndef USE_PCH # include "Mcommon.h" # include "gui/wxMenuDefs.h" # include "gui/wxMApp.h" # endif // USE_PCH - # include "gui/wxlwindow.h" # include "gui/wxlparser.h" #else @@ -44,6 +43,12 @@ #include +#ifdef WXLAYOUT_DEBUG +# define WXLO_DEBUG(x) wxLogDebug x +#else +# define WXLO_DEBUG(x) +#endif + /// offsets to put a nice frame around text #define WXLO_XOFFSET 4 #define WXLO_YOFFSET 4 @@ -55,6 +60,7 @@ BEGIN_EVENT_TABLE(wxLayoutWindow,wxScrolledWindow) EVT_PAINT (wxLayoutWindow::OnPaint) EVT_CHAR (wxLayoutWindow::OnChar) + EVT_KEY_UP (wxLayoutWindow::OnKeyUp) EVT_LEFT_DOWN(wxLayoutWindow::OnLeftMouseClick) EVT_RIGHT_DOWN(wxLayoutWindow::OnRightMouseClick) EVT_LEFT_DCLICK(wxLayoutWindow::OnMouseDblClick) @@ -115,7 +121,6 @@ wxLayoutWindow::OnMouse(int eventId, wxMouseEvent& event) PrepareDC( dc ); SetFocus(); - wxPoint findPos; findPos.x = dc.DeviceToLogicalX(event.GetX()); findPos.y = dc.DeviceToLogicalY(event.GetY()); @@ -127,26 +132,18 @@ wxLayoutWindow::OnMouse(int eventId, wxMouseEvent& event) if(findPos.y < 0) findPos.y = 0; m_ClickPosition = wxPoint(event.GetX(), event.GetY()); -#ifdef WXLAYOUT_DEBUG - wxLogDebug("wxLayoutWindow::OnMouse: (%d, %d) -> (%d, %d)", - event.GetX(), event.GetY(), findPos.x, findPos.y); -#endif wxPoint cursorPos; - wxLayoutObject *obj = m_llist->FindObjectScreen(dc, findPos, &cursorPos); - -#ifdef WXLAYOUT_DEBUG - if(obj) - wxLogDebug("wxLayoutWindow::OnMouse: Found object of type %d.", - obj->GetType()); - else - wxLogDebug("wxLayoutWindow::OnMouse: Found no object."); -#endif + bool found; + wxLayoutObject *obj = m_llist->FindObjectScreen(dc, findPos, + &cursorPos, &found); //has the mouse only been moved? if(eventId == WXLOWIN_MENU_MOUSEMOVE) { - if(obj && obj->GetUserData() != NULL) + // found is only true if we are really over an object, not just + // behind it + if(found && obj && obj->GetUserData() != NULL) { if(!m_HandCursor) SetCursor(wxCURSOR_HAND); @@ -165,7 +162,8 @@ wxLayoutWindow::OnMouse(int eventId, wxMouseEvent& event) if(obj && eventId == WXLOWIN_MENU_LCLICK) { m_llist->MoveCursorTo(cursorPos); - m_ScrollToCursor = true; //FIXME: needed? DoPaint(m_llist->GetUpdateRect()); + ScrollToCursor(); + Refresh(FALSE); // DoPaint suppresses flicker under GTK } if(!m_doSendEvents) // nothing to do return; @@ -195,133 +193,211 @@ wxLayoutWindow::OnMouse(int eventId, wxMouseEvent& event) void wxLayoutWindow::OnChar(wxKeyEvent& event) { - if(!IsEditable()) // do nothing +#ifdef WXLAYOUT_DEBUG + if(event.KeyCode() == WXK_F1) { - event.Skip(); + m_llist->Debug(); return; } +#endif long keyCode = event.KeyCode(); - if(event.ShiftDown()) - m_Selecting = true; - else + if(m_Selecting && ! event.ShiftDown()) { - if(m_Selecting) - m_llist->EndSelection(); + m_llist->EndSelection(); m_Selecting = false; } - /* First, handle control keys */ - if(event.ControlDown() && ! event.AltDown()) - { - switch(keyCode) - { - case WXK_DELETE : - case 'd': - m_llist->Delete(1); - break; - case 'y': - m_llist->DeleteLines(1); - break; - case 'h': // like backspace - if(m_llist->MoveCursorHorizontally(-1)) m_llist->Delete(1); - break; - case 'u': - m_llist->DeleteToBeginOfLine(); - break; - case 'k': - m_llist->DeleteToEndOfLine(); - break; -#ifdef WXLAYOUT_DEBUG - case WXK_F1: - m_llist->SetFont(-1,-1,-1,-1,true); // underlined - break; -#endif - default: - ; - } - } - // ALT only: - else if( event.AltDown() && ! event.ControlDown() ) - { - switch(keyCode) + else + if(! m_Selecting && event.ShiftDown()) { - case WXK_DELETE: - case 'd': - m_llist->DeleteWord(); - break; - default: - ; + switch(keyCode) + { + case WXK_UP: + case WXK_DOWN: + case WXK_RIGHT: + case WXK_LEFT: + case WXK_PRIOR: + case WXK_NEXT: + case WXK_HOME: + case WXK_END: + m_Selecting = true; + m_llist->StartSelection(); + break; + default: + ; + } } - } - // no control keys: - else if ( ! event.AltDown() && ! event.ControlDown()) + + /* These two nested switches work like this: + The first one processes all non-editing keycodes, to move the + cursor, etc. It's default will process all keycodes causing + modifications to the buffer, but only if editing is allowed. + */ + switch(keyCode) { - switch(keyCode) + case WXK_RIGHT: + m_llist->MoveCursorHorizontally(1); + break; + case WXK_LEFT: + m_llist->MoveCursorHorizontally(-1); + break; + case WXK_UP: + m_llist->MoveCursorVertically(-1); + break; + case WXK_DOWN: + m_llist->MoveCursorVertically(1); + break; + case WXK_PRIOR: + m_llist->MoveCursorVertically(-20); + break; + case WXK_NEXT: + m_llist->MoveCursorVertically(20); + break; + case WXK_HOME: + m_llist->MoveCursorToBeginOfLine(); + break; + case WXK_END: + m_llist->MoveCursorToEndOfLine(); + break; + default: + if(keyCode == 'c' && event.ControlDown()) + Copy(); + if( IsEditable() ) { - case WXK_RIGHT: - if(m_Selecting) m_llist->StartSelection(); - m_llist->MoveCursorHorizontally(1); - break; - case WXK_LEFT: - if(m_Selecting) m_llist->StartSelection(); - m_llist->MoveCursorHorizontally(-1); - break; - case WXK_UP: - if(m_Selecting) m_llist->StartSelection(); - m_llist->MoveCursorVertically(-1); - break; - case WXK_DOWN: - if(m_Selecting) m_llist->StartSelection(); - m_llist->MoveCursorVertically(1); - break; - case WXK_PRIOR: - if(m_Selecting) m_llist->StartSelection(); - m_llist->MoveCursorVertically(-20); - break; - case WXK_NEXT: - if(m_Selecting) m_llist->StartSelection(); - m_llist->MoveCursorVertically(20); - break; - case WXK_HOME: - if(m_Selecting) m_llist->StartSelection(); - m_llist->MoveCursorToBeginOfLine(); - break; - case WXK_END: - if(m_Selecting) m_llist->StartSelection(); - m_llist->MoveCursorToEndOfLine(); - break; - case WXK_DELETE : - m_llist->Delete(1); - break; - case WXK_BACK: // backspace - if(m_llist->MoveCursorHorizontally(-1)) m_llist->Delete(1); - break; - case WXK_RETURN: - if(m_WrapMargin > 0) - m_llist->WrapLine(m_WrapMargin); - m_llist->LineBreak(); - break; - default: - if((!(event.ControlDown() || event.AltDown() || event.MetaDown())) - && (keyCode < 256 && keyCode >= 32) - ) + /* First, handle control keys */ + if(event.ControlDown() && ! event.AltDown()) { - wxString tmp; - tmp += keyCode; - if(m_WrapMargin > 0 && isspace(keyCode)) - m_llist->WrapLine(m_WrapMargin); - m_llist->Insert(tmp); + switch(keyCode) + { + case WXK_DELETE : + case 'd': + m_llist->Delete(1); + break; + case 'y': + m_llist->DeleteLines(1); + break; + case 'h': // like backspace + if(m_llist->MoveCursorHorizontally(-1)) m_llist->Delete(1); + break; + case 'u': + m_llist->DeleteToBeginOfLine(); + break; + case 'k': + m_llist->DeleteToEndOfLine(); + break; + case 'v': + Paste(); + break; +#ifdef WXLAYOUT_DEBUG + case WXK_F1: + m_llist->SetFont(-1,-1,-1,-1,true); // underlined + break; +#endif + default: + ; + } } - break; - } - } - SetDirty(); - SetModified(); - m_ScrollToCursor = true; - //DoPaint(true); // paint and scroll to cursor + // ALT only: + else if( event.AltDown() && ! event.ControlDown() ) + { + switch(keyCode) + { + case WXK_DELETE: + case 'd': + m_llist->DeleteWord(); + break; + default: + ; + } + } + // no control keys: + else if ( ! event.AltDown() && ! event.ControlDown()) + { + switch(keyCode) + { + case WXK_INSERT: + if(event.ShiftDown()) + Paste(); + break; + case WXK_DELETE : + m_llist->Delete(1); + break; + case WXK_BACK: // backspace + if(m_llist->MoveCursorHorizontally(-1)) m_llist->Delete(1); + break; + case WXK_RETURN: + if(m_WrapMargin > 0) + m_llist->WrapLine(m_WrapMargin); + m_llist->LineBreak(); + break; + default: + if((!(event.ControlDown() || event.AltDown() || event.MetaDown())) + && (keyCode < 256 && keyCode >= 32) + ) + { + wxString tmp; + tmp += keyCode; + if(m_WrapMargin > 0 && isspace(keyCode)) + m_llist->WrapLine(m_WrapMargin); + m_llist->Insert(tmp); + } + break; + } + } + SetDirty(); + SetModified(); + }// if(IsEditable()) + }// first switch() + ScrollToCursor(); wxRect r = *m_llist->GetUpdateRect(); - r.x -= WXLO_XOFFSET; r.y -= WXLO_YOFFSET; - Refresh( FALSE, &r); + DoPaint(&r); +} + +void +wxLayoutWindow::OnKeyUp(wxKeyEvent& event) +{ + if(event.KeyCode() == WXK_SHIFT && m_llist->IsSelecting()) + m_llist->EndSelection(); + event.Skip(); +} + + +void +wxLayoutWindow::ScrollToCursor(void) +{ + wxClientDC dc( this ); + PrepareDC( dc ); + + int x0,y0,x1,y1, dx, dy; + + // Calculate where the top of the visible area is: + ViewStart(&x0,&y0); + GetScrollPixelsPerUnit(&dx, &dy); + x0 *= dx; y0 *= dy; + + // Get the size of the visible window: + GetClientSize(&x1,&y1); + wxASSERT(x1 > 0); + wxASSERT(y1 > 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; + /* Make sure that the scrollbars are at a position so that the + cursor is visible if we are editing. */ + /** Scroll so that cursor is visible! */ + WXLO_DEBUG(("m_ScrollToCursor = %d", (int) m_ScrollToCursor)); + wxPoint cc = m_llist->GetCursorScreenPos(*m_memDC); + if(cc.x < x0 || cc.y < y0 + || cc.x >= x0+(9*x1)/10 || cc.y >= y0+(9*y1/10)) // (9*x)/10 == 90% + { + int nx, ny; + nx = cc.x - x1/2; if(nx < 0) nx = 0; + ny = cc.y - y1/2; if(ny < 0) ny = 0; + Scroll(nx/dx,ny/dy); // new view start + x0 = nx; y0 = ny; + m_ScrollToCursor = false; // avoid recursion + } } void @@ -363,48 +439,14 @@ wxLayoutWindow::InternalPaint(const wxRect *updateRect) if(x1 > m_maxx) m_maxx = x1; if(y1 > m_maxy) m_maxy = y1; + WXLO_DEBUG(("Update rect: %ld,%ld / %ld,%ld", + updateRect->x, updateRect->y, + updateRect->x+updateRect->width, + updateRect->y+updateRect->height)); - m_llist->InvalidateUpdateRect(); - const wxRect *r = m_llist->GetUpdateRect(); - wxLogDebug("Update rect before calling Layout: %ld,%ld / %ld,%ld", - r->x, r->y, r->x+r->width, r->y+r->height); - -#if 0 - //FIXME: we should never need to call Layout at all because the - // list does it automatically. -// Maybe we need to change the scrollbar sizes or positions, - // so layout the list and check: - if(IsDirty()) - m_llist->Layout(dc); - wxLogDebug("Update rect after calling Layout: %ld,%ld / %ld,%ld", - r->x, r->y, r->x+r->width, r->y+r->height); - // this is needed even when only the cursor moved - m_llist->Layout(dc,y0+y1); - wxLogDebug("Update rect after calling Layout again: %ld,%ld / %ld,%ld", - r->x, r->y, r->x+r->width, r->y+r->height); -#endif - if(IsDirty()) ResizeScrollbars(); - /* Make sure that the scrollbars are at a position so that the - cursor is visible if we are editing. */ - /** Scroll so that cursor is visible! */ - wxLogDebug("m_ScrollToCursor = %d", (int) m_ScrollToCursor); - if(IsEditable() && m_ScrollToCursor) - { - wxPoint cc = m_llist->GetCursorScreenPos(*m_memDC); - if(cc.x < x0 || cc.y < y0 - || cc.x >= x0+(9*x1)/10 || cc.y >= y0+(9*y1/10)) // (9*x)/10 == 90% - { - int nx, ny; - nx = cc.x - x1/2; if(nx < 0) nx = 0; - ny = cc.y - y1/2; if(ny < 0) ny = 0; - Scroll(nx/dx,ny/dy); // new view start - x0 = nx; y0 = ny; - } - } - /* 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) @@ -418,13 +460,15 @@ wxLayoutWindow::InternalPaint(const wxRect *updateRect) m_bitmap = new wxBitmap(x1,y1); m_memDC->SelectObject(*m_bitmap); } - // Device origins on the memDC are suspect, we translate manually - // with the translate parameter of Draw(). + m_memDC->SetDeviceOrigin(0,0); - m_memDC->SetBackgroundMode(wxTRANSPARENT); - m_memDC->SetBrush(wxBrush(m_llist->GetDefaults()->GetBGColour(), wxSOLID)); - m_memDC->SetPen(wxPen(m_llist->GetDefaults()->GetBGColour(),0,wxTRANSPARENT)); + m_memDC->SetBrush(wxBrush(m_llist->GetDefaults()->GetBGColour(),wxSOLID)); + m_memDC->SetPen(wxPen(m_llist->GetDefaults()->GetBGColour(), + 0,wxTRANSPARENT)); m_memDC->SetLogicalFunction(wxCOPY); + + /* Either fill the background with the background bitmap, or clear + it. */ if(m_BGbitmap) { CoordType @@ -434,46 +478,68 @@ wxLayoutWindow::InternalPaint(const wxRect *updateRect) for(y = 0; y < y1; y+=h) for(x = 0; x < x1; x+=w) m_memDC->DrawBitmap(*m_BGbitmap, x, y); + m_memDC->SetBackgroundMode(wxTRANSPARENT); } else + { + // clear the background: (must not be done if we use the update rectangle!) + m_memDC->SetBackgroundMode(wxSOLID); m_memDC->DrawRectangle(0,0,x1, y1); + } - // The offsets give the window a tiny border on the left and top, looks nice. + + /* This is the important bit: we tell the list to draw itself: */ + WXLO_DEBUG(("Update rect: %ld,%ld / %ld,%ld", + updateRect->x, updateRect->y, + updateRect->x+updateRect->width, + updateRect->y+updateRect->height)); + + // Device origins on the memDC are suspect, we translate manually + // with the translate parameter of Draw(). wxPoint offset(-x0+WXLO_XOFFSET,-y0+WXLO_YOFFSET); - m_llist->Draw(*m_memDC,offset); - if(IsEditable()) - m_llist->DrawCursor(*m_memDC,m_HaveFocus,offset); - - // Now copy everything to the screen: + m_llist->Draw(*m_memDC,offset, y0, y0+y1); + + // We start calculating a new update rect before drawing the + // cursor, so that the cursor coordinates get included in the next + // update rectangle (although they are drawn on the memDC, this is + // needed to erase it): + m_llist->InvalidateUpdateRect(); + m_llist->DrawCursor(*m_memDC, + m_HaveFocus && IsEditable(), // draw a thick + // cursor for editable windows with focus + offset); + +// Now copy everything to the screen: #if 0 - //FIXME: - // 1. the update region as calculated by the list is wrong - // 2. we get wrong values here - // 3. how about the offset? + // This somehow doesn't work, but even the following bit with the + // whole rect at once is still a bit broken I think. wxRegionIterator ri ( GetUpdateRegion() ); if(ri) while(ri) { - wxLogDebug("UpdateRegion: %ld,%ld, %ld,%ld", - ri.GetX(),ri.GetY(),ri.GetW(),ri.GetH()); + WXLO_DEBUG(("UpdateRegion: %ld,%ld, %ld,%ld", + ri.GetX(),ri.GetY(),ri.GetW(),ri.GetH())); dc.Blit(x0+ri.GetX(),y0+ri.GetY(),ri.GetW(),ri.GetH(), m_memDC,ri.GetX(),ri.GetY(),wxCOPY,FALSE); ri++; } else #endif - // If there are no update rectangles, we got called to reflect - // a change in the list. Currently there is no mechanism to - // easily find out which bits need updating, so we update - // all. The wxLayoutList could handle this, creating a list or - // at least one large rectangle of changes. FIXME + { + // FIXME: Trying to copy only the changed parts, but it does not seem + // to work: +// x0 = updateRect->x; y0 = updateRect->y; +// if(updateRect->height < y1) +// y1 = updateRect->height; +// y1 += WXLO_YOFFSET; //FIXME might not be needed dc.Blit(x0,y0,x1,y1,m_memDC,0,0,wxCOPY,FALSE); + } ResetDirty(); m_ScrollToCursor = false; } -// change the range and position of scroll bars +// change the range and position of scrollbars void wxLayoutWindow::ResizeScrollbars(bool exact) { @@ -510,26 +576,47 @@ wxLayoutWindow::Paste(void) } wxTheClipboard->Close(); } -#ifdef __WXGTK__ - /* wxGTK's sophisticated multi-format copy/paste is not supported - by 99% of the X11 clients available. If there was no selection, - do the dumb thing, too: - */ #if 0 - /* Unfortunately, this little hack doesn't work. So I'll go back to - pure X11. */ + /* My attempt to get the primary selection, but it does not + work. :-( */ if(text.Length() == 0) { wxTextCtrl tmp_tctrl(this,-1); tmp_tctrl.Paste(); text += tmp_tctrl.GetValue(); } -#endif - #endif wxLayoutImportText( m_llist, text); } +bool +wxLayoutWindow::Copy(void) +{ + wxLayoutList *llist = m_llist->GetSelection(); + if(! llist) + return FALSE; + + wxString text; + wxLayoutExportObject *export; + wxLayoutExportStatus status(llist); + while((export = wxLayoutExport( &status, WXLO_EXPORT_AS_TEXT)) != NULL) + { + if(export->type == WXLO_EXPORT_TEXT) + text << *(export->content.text); + delete export; + } + delete llist; + + // Read some text + if (wxTheClipboard->Open()) + { + wxTextDataObject *data = new wxTextDataObject( text ); + bool rc = wxTheClipboard->SetData( data ); + wxTheClipboard->Close(); + return rc; + } + return FALSE; +} wxMenu * wxLayoutWindow::MakeFormatMenu() @@ -585,12 +672,12 @@ void wxLayoutWindow::OnSetFocus(wxFocusEvent &ev) { m_HaveFocus = true; -//FIXME DoPaint(); // to repaint the cursor +//FIXME: need argument DoPaint(); // to repaint the cursor } void wxLayoutWindow::OnKillFocus(wxFocusEvent &ev) { m_HaveFocus = false; -//FIXME DoPaint(); // to repaint the cursor +//FIXME: need argument DoPaint(); // to repaint the cursor }