]> git.saurik.com Git - wxWidgets.git/blobdiff - samples/richedit/wxlwindow.cpp
wxWINE fixes.
[wxWidgets.git] / samples / richedit / wxlwindow.cpp
index 44a575d665e812f78b0b23e948b38e8824a19140..0745527116c6e1a093e9865d14652494cb8bfaf9 100644 (file)
@@ -6,9 +6,9 @@
  * $Id$
  *******************************************************************/
 
-// ===========================================================================
+// ============================================================================
 // declarations
-// ===========================================================================
+// ============================================================================
 
 // ----------------------------------------------------------------------------
 // headers
@@ -84,12 +84,15 @@ static const int Y_SCROLL_PAGE = 20;
 // ----------------------------------------------------------------------------
 
 BEGIN_EVENT_TABLE(wxLayoutWindow,wxScrolledWindow)
+   EVT_SIZE    (wxLayoutWindow::OnSize)
+
    EVT_PAINT    (wxLayoutWindow::OnPaint)
 
    EVT_CHAR     (wxLayoutWindow::OnChar)
    EVT_KEY_UP   (wxLayoutWindow::OnKeyUp)
 
-   EVT_LEFT_DOWN(wxLayoutWindow::OnLeftMouseClick)
+   EVT_LEFT_DOWN(wxLayoutWindow::OnLeftMouseDown)
+   EVT_LEFT_UP(wxLayoutWindow::OnLeftMouseUp)
    EVT_RIGHT_DOWN(wxLayoutWindow::OnRightMouseClick)
    EVT_LEFT_DCLICK(wxLayoutWindow::OnMouseDblClick)
    EVT_MOTION    (wxLayoutWindow::OnMouseMove)
@@ -103,9 +106,16 @@ BEGIN_EVENT_TABLE(wxLayoutWindow,wxScrolledWindow)
    EVT_KILL_FOCUS(wxLayoutWindow::OnKillFocus)
 END_EVENT_TABLE()
 
-// ===========================================================================
+// ----------------------------------------------------------------------------
+// function prototypes
+// ----------------------------------------------------------------------------
+
+/// returns TRUE if keyCode is one of arrows/home/end/page{up|down} keys
+static bool IsDirectionKey(long keyCode);
+
+// ============================================================================
 // implementation
-// ===========================================================================
+// ============================================================================
 
 /* LEAVE IT HERE UNTIL WXGTK WORKS AGAIN!!! */
 #ifdef __WXGTK__
@@ -151,6 +161,11 @@ wxLayoutWindow::wxLayoutWindow(wxWindow *parent)
    EnableScrolling(true, true);
    m_maxx = max.x + X_SCROLL_PAGE;
    m_maxy = max.y + Y_SCROLL_PAGE;
+
+   // no scrollbars initially (BTW, why then we do all the stuff above?)
+   m_hasHScrollbar =
+   m_hasVScrollbar = false;
+
    m_Selecting = false;
 
 #ifdef WXLAYOUT_USE_CARET
@@ -212,8 +227,10 @@ wxLayoutWindow::OnMouse(int eventId, wxMouseEvent& event)
    findPos.x -= WXLO_XOFFSET;
    findPos.y -= WXLO_YOFFSET;
 
-   if(findPos.x < 0) findPos.x = 0;
-   if(findPos.y < 0) findPos.y = 0;
+   if(findPos.x < 0)
+       findPos.x = 0;
+   if(findPos.y < 0)
+       findPos.y = 0;
 
    m_ClickPosition = wxPoint(event.GetX(), event.GetY());
 
@@ -223,98 +240,120 @@ wxLayoutWindow::OnMouse(int eventId, wxMouseEvent& event)
                                                    &cursorPos, &found);
    wxLayoutObject::UserData *u = obj ? obj->GetUserData() : NULL;
 
-   //has the mouse only been moved?
-   if(eventId == WXLOWIN_MENU_MOUSEMOVE)
+   // has the mouse only been moved?
+   switch ( eventId )
    {
-      // found is only true if we are really over an object, not just
-      // behind it
-      if(found && u && ! m_Selecting)
-      {
-         if(!m_HandCursor)
-            SetCursor(wxCURSOR_HAND);
-         m_HandCursor = TRUE;
-         if(m_StatusBar && m_StatusFieldLabel != -1)
+      case WXLOWIN_MENU_MOUSEMOVE:
+         // found is only true if we are really over an object, not just
+         // behind it
+         if(found && u && ! m_Selecting)
          {
-            const wxString &label = u->GetLabel();
-            if(label.Length())
-               m_StatusBar->SetStatusText(label,
-                                          m_StatusFieldLabel);
+            if(!m_HandCursor)
+               SetCursor(wxCURSOR_HAND);
+            m_HandCursor = TRUE;
+            if(m_StatusBar && m_StatusFieldLabel != -1)
+            {
+               const wxString &label = u->GetLabel();
+               if(label.Length())
+                  m_StatusBar->SetStatusText(label,
+                                             m_StatusFieldLabel);
+            }
          }
-      }
-      else
-      {
-         if(m_HandCursor)
-            SetCursor(wxCURSOR_IBEAM);
-         m_HandCursor = FALSE;
-         if(m_StatusBar && m_StatusFieldLabel != -1)
-            m_StatusBar->SetStatusText("", m_StatusFieldLabel);
-      }
-      if(event.LeftIsDown())
-      {
-         if(! m_Selecting)
+         else
          {
-            m_llist->StartSelection(wxPoint(-1, -1), m_ClickPosition);
-            m_Selecting = true;
-            DoPaint();  // TODO: we don't have to redraw everything!
+            if(m_HandCursor)
+               SetCursor(wxCURSOR_IBEAM);
+            m_HandCursor = FALSE;
+            if(m_StatusBar && m_StatusFieldLabel != -1)
+               m_StatusBar->SetStatusText("", m_StatusFieldLabel);
          }
-         else
+
+         // selecting?
+         if ( event.LeftIsDown() )
          {
+            wxASSERT_MSG( m_Selecting, "should be set in OnMouseLeftDown" );
+
             m_llist->ContinueSelection(cursorPos, m_ClickPosition);
             DoPaint();  // TODO: we don't have to redraw everything!
          }
-      }
-      if(m_Selecting && ! event.LeftIsDown())
-      {
-         m_llist->EndSelection(cursorPos, m_ClickPosition);
-         m_Selecting = false;
-         DoPaint();     // TODO: we don't have to redraw everything!
-      }
 
-      if ( u )
-      {
-         u->DecRef();
-         u = NULL;
-      }
-   }
-   else if(eventId == WXLOWIN_MENU_LCLICK)
-   {
-      // always move cursor to mouse click:
-      m_llist->MoveCursorTo(cursorPos);
+         if ( u )
+         {
+            u->DecRef();
+            u = NULL;
+         }
+         break;
 
-      // clicking a mouse removes the selection
-      if ( m_llist->HasSelection() )
-      {
-         m_llist->DiscardSelection();
-         DoPaint();     // TODO: we don't have to redraw everything!
-      }
+      case WXLOWIN_MENU_LDOWN:
+         {
+             // always move cursor to mouse click:
+             m_llist->MoveCursorTo(cursorPos);
+
+             // clicking a mouse removes the selection
+             if ( m_llist->HasSelection() )
+             {
+                m_llist->DiscardSelection();
+                DoPaint();     // TODO: we don't have to redraw everything!
+             }
+
+             // Calculate where the top of the visible area is:
+             int x0, y0;
+             ViewStart(&x0,&y0);
+             int dx, dy;
+             GetScrollPixelsPerUnit(&dx, &dy);
+             x0 *= dx; y0 *= dy;
+
+             wxPoint offset(-x0+WXLO_XOFFSET, -y0+WXLO_YOFFSET);
+
+             if(m_CursorVisibility == -1)
+                m_CursorVisibility = 1;
+
+             if(m_CursorVisibility != 0)
+             {
+                // draw a thick cursor for    editable windows with focus
+                m_llist->DrawCursor(dc, m_HaveFocus && IsEditable(), offset);
+             }
+
+             // VZ: this should be unnecessary because mouse can only click on a
+             //     visible part of the canvas
+#if 0
+             ScrollToCursor();
+#endif // 0
 
-      // Calculate where the top of the visible area is:
-      int x0, y0;
-      ViewStart(&x0,&y0);
-      int dx, dy;
-      GetScrollPixelsPerUnit(&dx, &dy);
-      x0 *= dx; y0 *= dy;
+#ifdef __WXGTK__
+             DoPaint(); // DoPaint suppresses flicker under GTK
+#endif // wxGTK
 
-      wxPoint offset(-x0+WXLO_XOFFSET, -y0+WXLO_YOFFSET);
+             // start selection
+             m_llist->StartSelection(wxPoint(-1, -1), m_ClickPosition);
+             m_Selecting = true;
+         }
+         break;
 
-      if(m_CursorVisibility == -1)
-         m_CursorVisibility = 1;
+      case WXLOWIN_MENU_LUP:
+         if ( m_Selecting )
+         {
+            m_llist->EndSelection();
+            m_Selecting = false;
 
-      if(m_CursorVisibility != 0)
-      {
-         // draw a thick cursor for    editable windows with focus
-         m_llist->DrawCursor(dc, m_HaveFocus && IsEditable(), offset);
-      }
+            DoPaint();     // TODO: we don't have to redraw everything!
+         }
+         break;
 
-      // VZ: this should be unnecessary because mouse can only click on a
-      //     visible part of the canvas
-#if 0
-      ScrollToCursor();
-#endif // 0
+      case WXLOWIN_MENU_RCLICK:
+         // remove the selection if mouse click is outside it (TODO)
+         break;
 
-#ifdef __WXGTK__
-      DoPaint(); // DoPaint suppresses flicker under GTK
-#endif // wxGTK
+      case WXLOWIN_MENU_DBLCLICK:
+         // select a word under cursor
+         m_llist->MoveCursorTo(cursorPos);
+         m_llist->MoveCursorWord(-1);
+         m_llist->StartSelection();
+         m_llist->MoveCursorWord(1, false);
+         m_llist->EndSelection();
+
+         DoPaint();     // TODO: we don't have to redraw everything!
+         break;
    }
 
    // notify about mouse events?
@@ -344,9 +383,10 @@ wxLayoutWindow::OnMouse(int eventId, wxMouseEvent& event)
       u->DecRef();
 }
 
-/*
- * Some simple keyboard handling.
- */
+// ----------------------------------------------------------------------------
+// keyboard handling.
+// ----------------------------------------------------------------------------
+
 void
 wxLayoutWindow::OnChar(wxKeyEvent& event)
 {
@@ -360,24 +400,32 @@ wxLayoutWindow::OnChar(wxKeyEvent& event)
    }
 #endif
 
-   if(! m_Selecting && event.ShiftDown())
+   wxASSERT_MSG( !m_Selecting || event.ShiftDown(),
+                 "m_Selecting is normally reset in OnKeyUp() when Shift "
+                 "goes up!" );
+
+   if ( !m_Selecting && m_llist->HasSelection() )
    {
-      switch(keyCode)
+      // pressing any non-arrow key replaces the selection
+      if ( !IsDirectionKey(keyCode) )
+      {
+         m_llist->DeleteSelection();
+      }
+      else if ( !event.ShiftDown() )
+      {
+         m_llist->DiscardSelection();
+      }
+   }
+
+   // <Shift>+<arrow> starts selection
+   if ( event.ShiftDown() && IsDirectionKey(keyCode) )
+   {
+      if ( !m_Selecting )
       {
-      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:
-         ;
       }
+      //else: just continue the old selection
    }
 
    // If needed, make cursor visible:
@@ -505,7 +553,8 @@ wxLayoutWindow::OnChar(wxKeyEvent& event)
                   m_llist->Delete(1);
                break;
             case WXK_BACK: // backspace
-               if(m_llist->MoveCursorHorizontally(-1)) m_llist->Delete(1);
+               if(m_llist->MoveCursorHorizontally(-1))
+                  m_llist->Delete(1);
                break;
             case WXK_RETURN:
                if(m_WrapMargin > 0)
@@ -528,15 +577,11 @@ wxLayoutWindow::OnChar(wxKeyEvent& event)
          SetModified();
       }// if(IsEditable())
    }// first switch()
-   if(m_Selecting)
+
+   if ( m_Selecting )
    {
-      if(event.ShiftDown())
-         m_llist->ContinueSelection();
-      else
-      {
-         m_llist->EndSelection();
-         m_Selecting = false;
-      }
+      // continue selection to the current (new) cursor position
+      m_llist->ContinueSelection();
    }
 
    // we must call ResizeScrollbars() before ScrollToCursor(), otherwise the
@@ -551,11 +596,12 @@ wxLayoutWindow::OnChar(wxKeyEvent& event)
 void
 wxLayoutWindow::OnKeyUp(wxKeyEvent& event)
 {
-   if(event.KeyCode() == WXK_SHIFT && m_llist->IsSelecting())
+   if ( event.KeyCode() == WXK_SHIFT && m_Selecting )
    {
       m_llist->EndSelection();
       m_Selecting = false;
    }
+
    event.Skip();
 }
 
@@ -633,10 +679,9 @@ wxLayoutWindow::OnPaint( wxPaintEvent &WXUNUSED(event))
 void
 wxLayoutWindow::DoPaint(const wxRect *updateRect)
 {
-   // Causes bad flicker under wxGTK!!!
 #ifdef __WXGTK__
    InternalPaint(updateRect);
-#else
+#else // Causes bad flicker under wxGTK!!!
    Refresh(FALSE); //, updateRect);
 
    if ( !::UpdateWindow(GetHwnd()) )
@@ -794,17 +839,35 @@ wxLayoutWindow::InternalPaint(const wxRect *updateRect)
    }
 }
 
+void
+wxLayoutWindow::OnSize(wxSizeEvent &event)
+{
+    ResizeScrollbars();
+
+    event.Skip();
+}
+
 // change the range and position of scrollbars
 void
 wxLayoutWindow::ResizeScrollbars(bool exact)
 {
    wxPoint max = m_llist->GetSize();
+   wxSize size = GetClientSize();
 
    WXLO_DEBUG(("ResizeScrollbars: max size = (%ld, %ld)",
                (long int)max.x, (long int) max.y));
 
+   // in the absence of scrollbars we should compare with the client size
+   if ( !m_hasHScrollbar )
+      m_maxx = size.x - WXLO_ROFFSET;
+   if ( !m_hasVScrollbar )
+      m_maxy = size.y - WXLO_BOFFSET;
+
+   // 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 )
    {
+      // text became too large
       if ( !exact )
       {
          // add an extra bit to the sizes to avoid future updates
@@ -818,11 +881,36 @@ wxLayoutWindow::ResizeScrollbars(bool exact)
                     m_ViewStartX, m_ViewStartY,
                     true);
 
+      m_hasHScrollbar =
+      m_hasVScrollbar = true;
+
       m_maxx = max.x + X_SCROLL_PAGE;
       m_maxy = max.y + Y_SCROLL_PAGE;
    }
+   else
+   {
+      // check if the window hasn't become too big, thus making the scrollbars
+      // unnecessary
+      if ( m_hasHScrollbar && (max.x < size.x) )
+      {
+         // remove the horizontal scrollbar
+         SetScrollbars(0, -1, 0, -1, 0, -1, true);
+         m_hasHScrollbar = false;
+      }
+
+      if ( m_hasVScrollbar && (max.y < size.y) )
+      {
+         // remove the vertical scrollbar
+         SetScrollbars(-1, 0, -1, 0, -1, 0, true);
+         m_hasVScrollbar = false;
+      }
+   }
 }
 
+// ----------------------------------------------------------------------------
+// clipboard operations
+// ----------------------------------------------------------------------------
+
 void
 wxLayoutWindow::Paste(void)
 {
@@ -927,6 +1015,11 @@ wxLayoutWindow::Cut(void)
    else
       return FALSE;
 }
+
+// ----------------------------------------------------------------------------
+// searching
+// ----------------------------------------------------------------------------
+
 bool
 wxLayoutWindow::Find(const wxString &needle,
                      wxPoint * fromWhere)
@@ -951,6 +1044,10 @@ wxLayoutWindow::Find(const wxString &needle,
    return false;
 }
 
+// ----------------------------------------------------------------------------
+// popup menu stuff
+// ----------------------------------------------------------------------------
+
 wxMenu *
 wxLayoutWindow::MakeFormatMenu()
 {
@@ -1015,6 +1112,10 @@ void wxLayoutWindow::OnMenu(wxCommandEvent& event)
    }
 }
 
+// ----------------------------------------------------------------------------
+// focus
+// ----------------------------------------------------------------------------
+
 void
 wxLayoutWindow::OnSetFocus(wxFocusEvent &ev)
 {
@@ -1028,3 +1129,26 @@ wxLayoutWindow::OnKillFocus(wxFocusEvent &ev)
    m_HaveFocus = false;
    ev.Skip();
 }
+
+// ----------------------------------------------------------------------------
+// private functions
+// ----------------------------------------------------------------------------
+
+static bool IsDirectionKey(long keyCode)
+{
+   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:
+         return true;
+
+      default:
+         return false;
+   }
+}