X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/a5e13868ca700aa39bae26b8fb13c640f466d9f0..8c0d01c876f3e792e33a331dfe9b1749242662af:/user/wxLayout/wxlwindow.cpp?ds=inline diff --git a/user/wxLayout/wxlwindow.cpp b/user/wxLayout/wxlwindow.cpp index 73a2d28e8f..83cbefdc5c 100644 --- a/user/wxLayout/wxlwindow.cpp +++ b/user/wxLayout/wxlwindow.cpp @@ -1,7 +1,7 @@ /*-*- c++ -*-******************************************************** * wxLwindow.h : a scrolled Window for displaying/entering rich text* * * - * (C) 1998 by Karsten Ballüder (Ballueder@usa.net) * + * (C) 1998, 1999 by Karsten Ballüder (Ballueder@usa.net) * * * * $Id$ *******************************************************************/ @@ -16,80 +16,82 @@ # ifndef USE_PCH # include "Mcommon.h" # include "gui/wxMenuDefs.h" +# include "gui/wxMApp.h" # endif // USE_PCH # include "gui/wxlwindow.h" #else # ifdef __WXMSW__ # include - # undef FindWindow # undef GetCharWidth # undef StartDoc # endif - # include "wxlwindow.h" -# define TRACEMESSAGE(x) #endif -# define WXL_VAR(x) cerr << #x " = " << x ; BEGIN_EVENT_TABLE(wxLayoutWindow,wxScrolledWindow) EVT_PAINT (wxLayoutWindow::OnPaint) EVT_CHAR (wxLayoutWindow::OnChar) - EVT_LEFT_DOWN(wxLayoutWindow::OnLeftMouseClick) EVT_RIGHT_DOWN(wxLayoutWindow::OnRightMouseClick) EVT_LEFT_DCLICK(wxLayoutWindow::OnMouseDblClick) + EVT_MENU_RANGE(WXLOWIN_MENU_FIRST, WXLOWIN_MENU_LAST, wxLayoutWindow::OnMenu) + EVT_SET_FOCUS(wxLayoutWindow::OnSetFocus) + EVT_KILL_FOCUS(wxLayoutWindow::OnKillFocus) +END_EVENT_TABLE() + /* + EVT_MENU(WXLOWIN_MENU_LARGER, wxLayoutWindow::OnMenu) EVT_MENU(WXLOWIN_MENU_SMALLER, wxLayoutWindow::OnMenu) - EVT_MENU(WXLOWIN_MENU_UNDERLINE, wxLayoutWindow::OnMenu) - EVT_MENU(WXLOWIN_MENU_BOLD, wxLayoutWindow::OnMenu) - EVT_MENU(WXLOWIN_MENU_ITALICS, wxLayoutWindow::OnMenu) + EVT_MENU(WXLOWIN_MENU_UNDERLINE_ON, wxLayoutWindow::OnMenu) + EVT_MENU(WXLOWIN_MENU_UNDERLINE_OFF, wxLayoutWindow::OnMenu) + EVT_MENU(WXLOWIN_MENU_BOLD_ON, wxLayoutWindow::OnMenu) + EVT_MENU(WXLOWIN_MENU_BOLD_OFF, wxLayoutWindow::OnMenu) + EVT_MENU(WXLOWIN_MENU_ITALICS_ON, wxLayoutWindow::OnMenu) + EVT_MENU(WXLOWIN_MENU_ITALICS_OFF, wxLayoutWindow::OnMenu) EVT_MENU(WXLOWIN_MENU_ROMAN, wxLayoutWindow::OnMenu) EVT_MENU(WXLOWIN_MENU_TYPEWRITER, wxLayoutWindow::OnMenu) EVT_MENU(WXLOWIN_MENU_SANSSERIF, wxLayoutWindow::OnMenu) -END_EVENT_TABLE() + */ wxLayoutWindow::wxLayoutWindow(wxWindow *parent) : wxScrolledWindow(parent, -1, wxDefaultPosition, wxDefaultSize, wxHSCROLL | wxVSCROLL | wxBORDER) { - m_ScrollbarsSet = false; + m_Editable = false; m_doSendEvents = false; m_ViewStartX = 0; m_ViewStartY = 0; m_DoPopupMenu = true; - m_PopupMenu = NULL; - - CoordType - max_x, max_y, lineHeight; - m_llist.GetSize(&max_x, &max_y, &lineHeight); - SetScrollbars(10, lineHeight, max_x/10+1, max_y/lineHeight+1); + m_PopupMenu = MakeFormatMenu(); + m_memDC = new wxMemoryDC; + m_bitmap = new wxBitmap(4,4); + m_bitmapSize = wxPoint(4,4); + m_llist = new wxLayoutList(); + wxPoint max = m_llist->GetSize(); + SetScrollbars(10, 20 /*lineHeight*/, max.x/10+1, max.y/20+1); EnableScrolling(true,true); + m_maxx = max.x; m_maxy = max.y; + SetDirty(); +} + +wxLayoutWindow::~wxLayoutWindow() +{ + delete m_memDC; // deletes bitmap automatically (?) + delete m_bitmap; + delete m_llist; + delete m_PopupMenu; } #ifdef __WXMSW__ long wxLayoutWindow::MSWGetDlgCode() { - // if we don't return this, we won't get OnChar() events + // if we don't return this, we won't get OnChar() events for TABs and ENTER return DLGC_WANTCHARS | DLGC_WANTARROWS | DLGC_WANTMESSAGE; } #endif //MSW -void -wxLayoutWindow::Update(void) -{ - wxClientDC dc(this); - PrepareDC(dc); - if(IsDirty()) - { - DoPaint(dc); - UpdateScrollbars(); - ResetDirty(); - } - m_llist.DrawCursor(dc); -} - void wxLayoutWindow::OnMouse(int eventId, wxMouseEvent& event) { @@ -104,21 +106,35 @@ wxLayoutWindow::OnMouse(int eventId, wxMouseEvent& event) findPos.x = dc.DeviceToLogicalX(event.GetX()); findPos.y = dc.DeviceToLogicalY(event.GetY()); - TRACEMESSAGE(("wxLayoutWindow::OnMouse: (%d, %d) -> (%d, %d)", - event.GetX(), event.GetY(), findPos.x, findPos.y)); +#ifdef WXLAYOUT_DEBUG + wxLogDebug("wxLayoutWindow::OnMouse: (%d, %d) -> (%d, %d)", + event.GetX(), event.GetY(), findPos.x, findPos.y); +#endif + + m_ClickPosition = findPos; + wxLayoutObject *obj = m_llist->FindObject(findPos); - if(eventId == WXLOWIN_MENU_RCLICK && m_DoPopupMenu && m_llist.IsEditable()) +#ifdef WXLAYOUT_DEBUG + if(obj) + wxLogDebug("wxLayoutWindow::OnMouse: Found object of type %d.", + obj->GetType()); + else + wxLogDebug("wxLayoutWindow::OnMouse: Found no object."); +#endif + + // only do the menu if activated, editable and not on a clickable object + if(eventId == WXLOWIN_MENU_RCLICK + && IsEditable() + && (! obj || (obj && obj->GetUserData() == NULL)) + ) { - // when does this menu get freed? - // how do we handle toggling? FIXME - PopupMenu(MakeFormatMenu(), event.GetX(), event.GetY()); + PopupMenu(m_PopupMenu, event.GetX(), event.GetY()); return; } // find the object at this position - wxLayoutObjectBase *obj = m_llist.Find(findPos); if(obj) { - wxCommandEvent commandEvent(wxEVENT_TYPE_MENU_COMMAND, eventId); + wxCommandEvent commandEvent(wxEVT_COMMAND_MENU_SELECTED, eventId); commandEvent.SetEventObject( this ); commandEvent.SetClientData((char *)obj); GetEventHandler()->ProcessEvent(commandEvent); @@ -126,241 +142,273 @@ wxLayoutWindow::OnMouse(int eventId, wxMouseEvent& event) } /* - * some simple keyboard handling + * Some simple keyboard handling. */ void wxLayoutWindow::OnChar(wxKeyEvent& event) { - if(! m_llist.IsEditable()) // do nothing + if(!IsEditable()) // do nothing { event.Skip(); return; } long keyCode = event.KeyCode(); - wxPoint p; - CoordType help; - - switch(event.KeyCode()) - { - case WXK_RIGHT: - m_llist.MoveCursor(1); - break; - case WXK_LEFT: - m_llist.MoveCursor(-1); - break; - case WXK_UP: - m_llist.MoveCursor(0,-1); - break; - case WXK_DOWN: - m_llist.MoveCursor(0,1); - break; - case WXK_PRIOR: - m_llist.MoveCursor(0,-20); - break; - case WXK_NEXT: - m_llist.MoveCursor(0,20); - break; - case WXK_HOME: - p = m_llist.GetCursor(); - p.x = 0; - m_llist.SetCursor(p); - break; - case WXK_END: - p = m_llist.GetCursor(); - p.x = m_llist.GetLineLength(m_llist.FindCurrentObject(NULL)); - m_llist.SetCursor(p); - break; - case WXK_DELETE : - if(event.ControlDown()) // delete to end of line - { - help = m_llist.GetLineLength( - m_llist.FindCurrentObject(NULL)) - - m_llist.GetCursor().x; - m_llist.Delete(help ? help : 1); - } - else - m_llist.Delete(1); - break; - case WXK_BACK: // backspace - if(m_llist.MoveCursor(-1)) { - m_llist.Delete(1); - } - break; - case WXK_RETURN: - m_llist.LineBreak(); - break; -#ifdef WXLAYOUT_DEBUG - case WXK_F1: - m_llist.Debug(); - break; -#endif - - default: - if(keyCode < 256 && keyCode >= 32) + /* First, handle control keys */ + if(event.ControlDown() && ! event.AltDown()) + { + switch(event.KeyCode()) { - String tmp; - tmp += keyCode; - m_llist.Insert(tmp); + 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; + default: + ; } - break; } - - /** Scroll so that cursor is visible! */ - int x0,y0,x1,y1,ux,uy; - ViewStart(&x0,&y0); - GetScrollPixelsPerUnit(&ux,&uy); - x0*=ux; y0*=uy; - GetClientSize(&x1,&y1); - - wxPoint cc = m_llist.GetCursorCoords(); - int nx = x0, ny = y0; - // when within 10% of borders, scroll to center - if(cc.y > y0+(9*y1)/10) - ny = cc.y - y1/5; - else if (cc.y < y0+y1/10) + // ALT only: + else if( event.AltDown() && ! event.ControlDown() ) { - ny = cc.y-y1/2; - if(ny < 0) ny = 0; + switch(event.KeyCode()) + { + case WXK_DELETE: + case 'd': + m_llist->DeleteWord(); + break; + default: + ; + } } - if(cc.x > x0+(9*x1)/10) - nx = cc.x - x1/5; - else if (cc.x < x0+x1/10) + // no control keys: + else if ( ! event.AltDown() && ! event.ControlDown()) { - nx = cc.x-x1/2; - if(nx < 0) nx = 0; + switch(event.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; + 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: + m_llist->LineBreak(); + break; + default: + if((!(event.ControlDown() || event.AltDown() || event.MetaDown())) + && (keyCode < 256 && keyCode >= 32) + ) + { + wxString tmp; + tmp += keyCode; + m_llist->Insert(tmp); +//// m_llist->WrapLine(); + } + break; + } } - Scroll(nx,ny); - - Update(); + SetDirty(); + DoPaint(true); // paint and scroll to cursor } void wxLayoutWindow::OnPaint( wxPaintEvent &WXUNUSED(event)) // or: OnDraw(wxDC& dc) +{ + DoPaint(); +} + +void +wxLayoutWindow::DoPaint(bool scrollToCursor) { wxPaintDC dc( this ); PrepareDC( dc ); - DoPaint(dc); + int x0,y0,x1,y1, dx, dy; -// wxGTK: wxMemoryDC broken? -#if 0 - int x0,y0,x1,y1; + // Calculate where the top of the visible area is: ViewStart(&x0,&y0); - GetSize(&x1,&y1); - WXL_VAR(x0); WXL_VAR(y0); - WXL_VAR(x1); WXL_VAR(y1); - - wxMemoryDC(memdc); - wxBitmap bm(x1,y1); - memdc.SelectObject(bm); - - // make temporary copy and edit this - memdc.SetDeviceOrigin(x0,y0); - memdc.Blit(x0,y0,x1,y1,&dc,x0,y0,wxCOPY,FALSE); - DoPaint(memdc); - // blit it back - dc.Blit(x0,y0,x1,y1,&memdc,x0,y0,wxCOPY,FALSE); -#endif - -} + GetScrollPixelsPerUnit(&dx, &dy); + x0 *= dx; y0 *= dy; -// does the actual painting -void -wxLayoutWindow::DoPaint(wxDC &dc) -{ - m_llist.EraseAndDraw(dc); - m_llist.DrawCursor(dc); - // FIXME: not strictly correct, this does only work for changes behind - // the cursor position, not complete redraws + // Get the size of the visible window: + GetClientSize(&x1,&y1); + wxASSERT(x1 > 0); + + wxASSERT(y1 > 0); - if(! m_ScrollbarsSet) + // Maybe we need to change the scrollbar sizes or positions, + // so layout the list and check: + if(IsDirty() || scrollToCursor) + m_llist->Layout(dc); + 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! */ + if(IsEditable() && scrollToCursor) { - m_ScrollbarsSet = true; // avoid recursion - UpdateScrollbars(); + wxPoint cc = m_llist->GetCursorScreenPos(); + 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) + { + wxASSERT(m_bitmapSize.x > 0); + wxASSERT(m_bitmapSize.y > 0); + + m_memDC->SelectObject(wxNullBitmap); + delete m_bitmap; + m_bitmapSize = wxPoint(x1,y1); + 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->Clear(); + + // The +4 give the window a tiny border on the left and top, looks nice. + wxPoint offset(-x0+4,-y0+4); + m_llist->Draw(*m_memDC,offset); + if(IsEditable()) + m_llist->DrawCursor(*m_memDC,m_HaveFocus,offset); + // Now copy everything to the screen: + dc.Blit(x0,y0,x1,y1,m_memDC,0,0,wxCOPY,FALSE); -void -wxLayoutWindow::UpdateScrollbars(void) -{ - CoordType - max_x, max_y, lineHeight; - - ViewStart(&m_ViewStartX, &m_ViewStartY); - m_llist.GetSize(&max_x, &max_y, &lineHeight); - SetScrollbars(10, lineHeight, max_x/10+1, max_y/lineHeight+1,m_ViewStartX,m_ViewStartY,true); - //EnableScrolling(true,true); - //Scroll(m_ViewStartX, m_ViewStartY); + + ResetDirty(); } +// change the range and position of scroll bars void -wxLayoutWindow::Print(void) +wxLayoutWindow::ResizeScrollbars(bool exact) { - wxPostScriptDC dc("layout.ps",true,this); - if (dc.Ok() && dc.StartDoc((char *)_("Printing message..."))) + wxPoint max = m_llist->GetSize(); + + if(max.x > m_maxx || max.y > m_maxy + || max.x < (7*m_maxx)/10 || max.y << (7*m_maxy)/10 + || exact) { - //dc.SetUserScale(1.0, 1.0); - m_llist.Draw(dc); - dc.EndDoc(); + if(! exact) // add an extra 20% to the sizes to avoid future updates + { + max.x = (12*max.x)/10; // 12/20 = 120% + max.y = (12*max.y)/10; + } + ViewStart(&m_ViewStartX, &m_ViewStartY); + SetScrollbars(10, 20, max.x/10+1,max.y/20+1,m_ViewStartX,m_ViewStartY,true); + m_maxx = max.x; m_maxy = max.y; } } + wxMenu * wxLayoutWindow::MakeFormatMenu() { - if(m_PopupMenu) - return m_PopupMenu; - - wxMenu *m = new wxMenu(); + wxMenu *m = new wxMenu(_("Layout Menu")); m->Append(WXLOWIN_MENU_LARGER ,_("&Larger"),_("Switch to larger font."), false); m->Append(WXLOWIN_MENU_SMALLER ,_("&Smaller"),_("Switch to smaller font."), false); m->AppendSeparator(); - m->Append(WXLOWIN_MENU_UNDERLINE,_("&Underline"),_("Toggle underline mode."), true); - m->Append(WXLOWIN_MENU_BOLD ,_("&Bold"),_("Toggle bold mode."), true); - m->Append(WXLOWIN_MENU_ITALICS ,_("&Italics"),_("Toggle italics mode."), true); + m->Append(WXLOWIN_MENU_UNDERLINE_ON, _("&Underline on"),_("Activate underline mode."), false); + m->Append(WXLOWIN_MENU_UNDERLINE_OFF,_("&Underline off"),_("Deactivate underline mode."), false); + m->Append(WXLOWIN_MENU_BOLD_ON ,_("&Bold on"),_("Activate bold mode."), false); + m->Append(WXLOWIN_MENU_BOLD_OFF ,_("&Bold off"),_("Deactivate bold mode."), false); + m->Append(WXLOWIN_MENU_ITALICS_ON ,_("&Italics on"),_("Activate italics mode."), false); + m->Append(WXLOWIN_MENU_ITALICS_OFF ,_("&Italics off"),_("Deactivate italics mode."), false); m->AppendSeparator(); - m->Append(WXLOWIN_MENU_ROMAN ,_("&Roman"),_("Toggle underline mode."), false); - m->Append(WXLOWIN_MENU_TYPEWRITER,_("&Typewriter"),_("Toggle bold mode."), false); - m->Append(WXLOWIN_MENU_SANSSERIF ,_("&Sans Serif"),_("Toggle italics mode."), false); - - return m_PopupMenu = m; + m->Append(WXLOWIN_MENU_ROMAN ,_("&Roman"),_("Switch to roman font."), false); + m->Append(WXLOWIN_MENU_TYPEWRITER,_("&Typewriter"),_("Switch to typewriter font."), false); + m->Append(WXLOWIN_MENU_SANSSERIF ,_("&Sans Serif"),_("Switch to sans serif font."), false); + return m; } void wxLayoutWindow::OnMenu(wxCommandEvent& event) { - if(! m_llist.IsEditable()) - return; - switch (event.GetId()) { case WXLOWIN_MENU_LARGER: - m_llist.SetFontLarger(); - break; + m_llist->SetFontLarger(); break; case WXLOWIN_MENU_SMALLER: - m_llist.SetFontSmaller(); - break; - case WXLOWIN_MENU_UNDERLINE: - m_llist.SetFontUnderline( - m_PopupMenu->IsChecked(WXLOWIN_MENU_UNDERLINE) ? false : true - ); - break; - case WXLOWIN_MENU_BOLD: - m_llist.SetFontWeight( - m_PopupMenu->IsChecked(WXLOWIN_MENU_BOLD) ? wxNORMAL : wxBOLD - ); - case WXLOWIN_MENU_ITALICS: - m_llist.SetFontStyle( - m_PopupMenu->IsChecked(WXLOWIN_MENU_ITALICS) ? wxNORMAL : wxITALIC - ); - break; + m_llist->SetFontSmaller(); break; + case WXLOWIN_MENU_UNDERLINE_ON: + m_llist->SetFontUnderline(true); break; + case WXLOWIN_MENU_UNDERLINE_OFF: + m_llist->SetFontUnderline(false); break; + case WXLOWIN_MENU_BOLD_ON: + m_llist->SetFontWeight(wxBOLD); break; + case WXLOWIN_MENU_BOLD_OFF: + m_llist->SetFontWeight(wxNORMAL); break; + case WXLOWIN_MENU_ITALICS_ON: + m_llist->SetFontStyle(wxITALIC); break; + case WXLOWIN_MENU_ITALICS_OFF: + m_llist->SetFontStyle(wxNORMAL); break; case WXLOWIN_MENU_ROMAN: - m_llist.SetFontFamily(wxROMAN); break; + m_llist->SetFontFamily(wxROMAN); break; case WXLOWIN_MENU_TYPEWRITER: - m_llist.SetFontFamily(wxFIXED); break; + m_llist->SetFontFamily(wxFIXED); break; case WXLOWIN_MENU_SANSSERIF: - m_llist.SetFontFamily(wxSWISS); break; + m_llist->SetFontFamily(wxSWISS); break; } } + +void +wxLayoutWindow::OnSetFocus(wxFocusEvent &ev) +{ + m_HaveFocus = true; + DoPaint(); // to repaint the cursor +} + +void +wxLayoutWindow::OnKillFocus(wxFocusEvent &ev) +{ + m_HaveFocus = true; + DoPaint(); // to repaint the cursor +}