From a5e13868ca700aa39bae26b8fb13c640f466d9f0 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Karsten=20Ball=C3=BCder?= Date: Fri, 30 Oct 1998 10:14:58 +0000 Subject: [PATCH] fixes git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@938 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- user/wxLayout/README | 3 +- user/wxLayout/kbList.h | 4 +- user/wxLayout/wxllist.cpp | 280 ++++++++++++++++++++++++++++++------ user/wxLayout/wxllist.h | 23 ++- user/wxLayout/wxlwindow.cpp | 80 ++++++++++- 5 files changed, 338 insertions(+), 52 deletions(-) diff --git a/user/wxLayout/README b/user/wxLayout/README index ae32c3be24..5539268bc7 100644 --- a/user/wxLayout/README +++ b/user/wxLayout/README @@ -3,7 +3,8 @@ README for wxLayout classes --------------------------- All the source in this directory is copyrighted under the -LGPL (GNU LIBRARY PUBLIC LICENSE), by Karsten Ballueder . +GPL (GNU GENERAL PUBLIC LICENSE), version 2, +by Karsten Ballueder . This is still work in progress, so if you want to make any significant diff --git a/user/wxLayout/kbList.h b/user/wxLayout/kbList.h index fea12a9032..0ee29a39ac 100644 --- a/user/wxLayout/kbList.h +++ b/user/wxLayout/kbList.h @@ -161,7 +161,9 @@ public: void *pop_front(void); /** Insert an element into the list. - @param i an iterator pointing to the element, before which the new one should be inserted + @param i an iterator pointing to the element, before which the + new one should be inserted. After the insert operation i will + point to the newly inserted element. @param element the element data */ void insert(iterator & i, void *element); diff --git a/user/wxLayout/wxllist.cpp b/user/wxLayout/wxllist.cpp index abba142b08..d44ee4bcbd 100644 --- a/user/wxLayout/wxllist.cpp +++ b/user/wxLayout/wxllist.cpp @@ -11,16 +11,29 @@ - the list is responsible for calculating positions - the draw coordinates for each object are the top left corner - coordinates only get calculated when things get redrawn - - during redraw each line gets iterated over twice, first just - calculating baselines and positions, second to actually draw it - - the cursor position is the position before an object, i.e. if the + - The cursor position is the position before an object, i.e. if the buffer starts with a text-object, cursor 0,0 is just before the - first character + first character. For all non-text objects, the cursor positions + are 0==before or 1==behind. So that all non-text objects count as + one cursor position. +*/ + +/* + TODO: - - the cursor position and size must be decided at layout/draw time - or the fonts will be wrong + - new cursor movement calculations + - moving lines and moving across linebreaks still broken + + - blinking cursor + - mouse click positions cursor + - selection (SetMark(), GetSelection()) + - DND acceptance of text + + - wxlwindow: formatting menu: problem with checked/unchecked consistency gtk bug? */ +#define USE_NEW_CURSORCODE 1 + /* Known wxGTK bugs: - MaxX()/MaxY() don't get set @@ -242,7 +255,7 @@ void wxLayoutList::LineBreak(void) { Insert(new wxLayoutObjectLineBreak); - m_CursorPosition.x = 0; m_CursorPosition.y++; + m_CursorPos.x = 0; m_CursorPos.y++; } void @@ -391,10 +404,10 @@ wxLayoutList::Layout(wxDC &dc, wxLayoutMargins *margins) headOfLine++; position_HeadOfLine = position; } - if(cursorObject == NULL && cursorPos.y == m_CursorPosition.y) // look for cursor + if(cursorObject == NULL && cursorPos.y == m_CursorPos.y) // look for cursor { - if(cursorPos.x >= m_CursorPosition.x && - m_CursorPosition.x-cursorPos.x+(**i).CountPositions()) // cursor is in current object + if(cursorPos.x >= m_CursorPos.x && + m_CursorPos.x-cursorPos.x+(**i).CountPositions()) // cursor is in current object { cursorObject = *i; CalculateCursor(dc); @@ -472,6 +485,14 @@ wxLayoutList::CalculateCursor(wxDC &dc) CoordType baseLineSkip = 20; //FIXME CoordType offset; + if( FindCurrentObject() == iterator(NULL)) // empty list + { + DrawCursor(dc,true); // erase it + m_CursorCoords = wxPoint(0,0); + m_CursorSize = wxPoint(2,baseLineSkip); + m_CursorMoved = false; // coords are valid + return; + } wxLayoutObjectBase &obj = **FindCurrentObject(&offset); WXL_VAR(offset); @@ -511,6 +532,9 @@ wxLayoutList::CalculateCursor(wxDC &dc) void wxLayoutList::DrawCursor(wxDC &dc, bool erase) { + if(! m_Editable) + return; + if(erase) { //dc.SetBrush(*wxWHITE_BRUSH); @@ -581,9 +605,6 @@ wxLayoutList::ShowCurrentObject() CoordType offs; wxLayoutObjectList::iterator i = FindCurrentObject(&offs); - wxLayoutDebug("Cursor is at (%d, %d)", - m_CursorPosition.x, m_CursorPosition.y); - i = FindCurrentObject(&offs); wxLogDebug(" Line length: %d", GetLineLength(i)); @@ -598,6 +619,10 @@ wxLayoutList::ShowCurrentObject() ((wxLayoutObjectText *)(*i))->GetText().c_str(), offs); else wxLogDebug(" %s", TypeString((*i)->GetType())); + wxLayoutDebug("CursorPos (%d, %d)", (int) m_CursorPos.x, (int) m_CursorPos.y); + wxLayoutDebug("CursorOffset = %d", (int) m_CursorOffset); + wxLayoutDebug("CursorObject = %p", m_CursorObject); + } #endif @@ -703,9 +728,10 @@ wxLayoutList::FindObjectCursor(wxPoint *cpos, CoordType *offset) wxLayoutObjectList::iterator wxLayoutList::FindCurrentObject(CoordType *offset) { +#if ! defined( USE_NEW_CURSORCODE ) wxLayoutObjectList::iterator obj = end(); - obj = FindObjectCursor(&m_CursorPosition, offset); + obj = FindObjectCursor(&m_CursorPos, offset); if(obj == end()) // not ideal yet { obj = tail(); @@ -713,8 +739,15 @@ wxLayoutList::FindCurrentObject(CoordType *offset) *offset = (*obj)->CountPositions(); // at the end of it } return obj; +#else + if(offset) + *offset = m_CursorOffset; + return m_CursorObject; +#endif } +#if ! defined( USE_NEW_CURSORCODE ) + bool wxLayoutList::MoveCursor(int dx, int dy) { @@ -725,18 +758,19 @@ wxLayoutList::MoveCursor(int dx, int dy) bool rc = true; // have we moved? - if(dy > 0 && m_CursorPosition.y < m_MaxLine) - m_CursorPosition.y += dy; - else if(dy < 0 && m_CursorPosition.y > 0) - m_CursorPosition.y += dy; // dy is negative - if(m_CursorPosition.y < 0) + //FIXME calculate cursor object & offset for y movements + if(dy > 0 && m_CursorPos.y < m_MaxLine) + m_CursorPos.y += dy; + else if(dy < 0 && m_CursorPos.y > 0) + m_CursorPos.y += dy; // dy is negative + if(m_CursorPos.y < 0) { - m_CursorPosition.y = 0; + m_CursorPos.y = 0; rc = false; } - else if (m_CursorPosition.y > m_MaxLine) + else if (m_CursorPos.y > m_MaxLine) { - m_CursorPosition.y = m_MaxLine; + m_CursorPos.y = m_MaxLine; rc = false; } @@ -744,18 +778,18 @@ wxLayoutList::MoveCursor(int dx, int dy) { i = FindCurrentObject(&offs); lineLength = GetLineLength(i,offs); - if(m_CursorPosition.x < lineLength) + if(m_CursorPos.x < lineLength) { - m_CursorPosition.x ++; + m_CursorPos.x ++; dx--; continue; } else { - if(m_CursorPosition.y < m_MaxLine) + if(m_CursorPos.y < m_MaxLine) { - m_CursorPosition.y++; - m_CursorPosition.x = 0; + m_CursorPos.y++; + m_CursorPos.x = 0; dx--; } else @@ -767,20 +801,20 @@ wxLayoutList::MoveCursor(int dx, int dy) } while(dx < 0) { - if(m_CursorPosition.x > 0) + if(m_CursorPos.x > 0) { - m_CursorPosition.x --; + m_CursorPos.x --; dx++; } else { - if(m_CursorPosition.y > 0) + if(m_CursorPos.y > 0) { - m_CursorPosition.y --; - m_CursorPosition.x = 0; + m_CursorPos.y --; + m_CursorPos.x = 0; i = FindCurrentObject(&offs); lineLength = GetLineLength(i,offs); - m_CursorPosition.x = lineLength; + m_CursorPos.x = lineLength; dx++; continue; } @@ -794,9 +828,9 @@ wxLayoutList::MoveCursor(int dx, int dy) // final adjustment: i = FindCurrentObject(&offs); lineLength = GetLineLength(i,offs); - if(m_CursorPosition.x > lineLength) + if(m_CursorPos.x > lineLength) { - m_CursorPosition.x = lineLength; + m_CursorPos.x = lineLength; rc = false; } #ifdef WXLAYOUT_DEBUG @@ -805,6 +839,115 @@ wxLayoutList::MoveCursor(int dx, int dy) return rc; } +#else + +bool +wxLayoutList::MoveCursor(int dx, int dy) +{ + CoordType diff; + + m_CursorMoved = true; + + enum { up, down} direction; + + wxPoint newPos = wxPoint(m_CursorPos.x + dx, + m_CursorPos.y + dy); + + // check for bounds + if(newPos.x < 0) newPos.x = 0; + if(newPos.y < 0) newPos.y = 0; + else if(newPos.y > m_MaxLine) newPos.y = m_MaxLine; + + if(newPos.y > m_CursorPos.y || + newPos.y == m_CursorPos.y && + newPos.x >= m_CursorPos.x) + direction = up; + else + direction = down; + + // now move cursor forwards until at the new position: + + // first, go to the right line: + while(newPos.y != m_CursorPos.y) + { + if(direction == up) + { + m_CursorPos.x += + (**m_CursorObject).CountPositions() - m_CursorOffset; + if(m_CursorObject == tail()) + break; // can't go any further + if((**m_CursorObject).GetType() == WXLO_TYPE_LINEBREAK + && m_CursorOffset == 1) + { + m_CursorPos.y++; m_CursorPos.x = 0; + } + m_CursorObject ++; m_CursorOffset = 0; + } + else // down + { + m_CursorPos.x -= m_CursorOffset; + if(m_CursorObject == begin()) + break; // can't go any further + if((**m_CursorObject).GetType() == WXLO_TYPE_LINEBREAK && + m_CursorOffset == 0) + { + m_CursorPos.y--; + m_CursorPos.x = GetLineLength(m_CursorObject); + } + m_CursorObject --; m_CursorOffset = (**m_CursorObject).CountPositions(); + } + } + if(newPos.y != m_CursorPos.y) // reached begin/end of list, + newPos.y = m_CursorPos.y; // exited by break + + // now line is right, go to right column: + direction = newPos.x >= m_CursorPos.x ? up : down; + while(newPos.x != m_CursorPos.x) + { + if(direction == up) + { + diff = newPos.x - m_CursorPos.x; + if(diff >= (**m_CursorObject).CountPositions()) + { + m_CursorPos.x += (**m_CursorObject).CountPositions(); + if(m_CursorObject == tail()) + { + m_CursorOffset = (**m_CursorObject).CountPositions(); + break; // cannot go further + } + m_CursorObject++; m_CursorOffset = 0; + } + else + { + m_CursorPos.x += diff; + m_CursorOffset += diff; + } + } + else // down + { + diff = m_CursorPos.x - newPos.x; + if(diff >= m_CursorOffset) + { + if(m_CursorObject == begin()) + { + m_CursorOffset = 0; + m_CursorPos.x = 0; + break; // cannot go further + } + m_CursorObject--; + m_CursorOffset = (**m_CursorObject).CountPositions(); + } + else + { + m_CursorPos.x -= diff; + m_CursorOffset -= diff; + } + } + } + return true; // FIXME: when return what? +} +#endif + void wxLayoutList::Delete(CoordType count) { @@ -835,6 +978,8 @@ wxLayoutList::Delete(CoordType count) { m_MaxLine--; erase(i); + m_CursorObject = i; // new i! + m_CursorOffset = 0; // Pos unchanged count--; continue; // we're done } @@ -861,12 +1006,15 @@ wxLayoutList::Delete(CoordType count) { count -= len; erase(i); + m_CursorObject = i; + m_CursorOffset = 0; continue; } else { len = count; tobj->GetText().erase(offs,len); + // cursor unchanged return; // we are done } } @@ -878,7 +1026,10 @@ wxLayoutList::Delete(CoordType count) if(offs == 0) { count = count > len ? count -= len : 0; - erase(i); // after this, i is the iterator for the following object + erase(i); // after this, i is the iterator for the + // following object + m_CursorObject = i; + m_CursorOffset = 0; continue; } else // delete the following object @@ -905,9 +1056,15 @@ wxLayoutList::Insert(wxLayoutObjectBase *obj) // WXL_TRACE(Insert(obj)); if(i == end()) + { push_back(obj); + m_CursorObject = tail(); + } else if(offs == 0) + { insert(i,obj); + m_CursorObject = i; + } // do we have to split a text object? else if((*i)->GetType() == WXLO_TYPE_TEXT && offs != (*i)->CountPositions()) { @@ -929,12 +1086,19 @@ wxLayoutList::Insert(wxLayoutObjectBase *obj) wxLayoutObjectList::iterator j = i; // we want to apend after this object j++; if(j != end()) + { insert(j, obj); + m_CursorObject = j; + } else + { push_back(obj); + m_CursorObject = tail(); + } } + m_CursorPos.x += obj->CountPositions(); + m_CursorOffset = obj->CountPositions(); - m_CursorPosition.x += obj->CountPositions(); if(obj->GetType() == WXLO_TYPE_LINEBREAK) m_MaxLine++; m_CursorMoved = true; @@ -970,6 +1134,9 @@ wxLayoutList::Insert(String const &text) tobj = (wxLayoutObjectText *)*i ; wxASSERT(tobj); tobj->GetText().insert(offs,text); + m_CursorObject = i; + m_CursorOffset = offs + text.length(); + m_CursorPos.x += text.length(); break; case WXLO_TYPE_LINEBREAK: default: @@ -981,29 +1148,51 @@ wxLayoutList::Insert(String const &text) { tobj = (wxLayoutObjectText *)*j; tobj->GetText()+=text; + m_CursorObject = j; + m_CursorOffset = (**j).CountPositions(); + m_CursorPos.x += text.length(); } else + { insert(i,new wxLayoutObjectText(text)); + m_CursorObject = i; + m_CursorOffset = (**i).CountPositions(); + m_CursorPos.x += m_CursorOffset; + } } - else // cursor after linebreak + else // offset == 1 : cursor after linebreak { j++; + m_CursorPos.x ++; + m_CursorObject = j; + m_CursorOffset = 0; if(j != end() && (**j).GetType() == WXLO_TYPE_TEXT) { tobj = (wxLayoutObjectText *)*j; tobj->GetText()=text+tobj->GetText(); + m_CursorOffset = text.length(); + m_CursorPos.x += m_CursorOffset; } else { if(j == end()) + { push_back(new wxLayoutObjectText(text)); + m_CursorObject = tail(); + m_CursorOffset = (**m_CursorObject).CountPositions(); + m_CursorPos.x += text.length(); + } else + { insert(j,new wxLayoutObjectText(text)); + m_CursorObject = j; + m_CursorOffset = (**j).CountPositions(); + m_CursorPos.x += text.length(); + } } } break; } - m_CursorPosition.x += strlen(text.c_str()); m_CursorMoved = true; } @@ -1060,7 +1249,10 @@ wxLayoutList::Clear(int family, int size, int style, int weight, if(! m_ColourBG) m_ColourBG = wxWHITE; m_Position = wxPoint(0,0); - m_CursorPosition = wxPoint(0,0); + m_CursorPos = wxPoint(0,0); + m_CursorObject = iterator(NULL); + m_CursorOffset = 0; + m_MaxLine = 0; m_LineHeight = (BASELINESTRETCH*m_FontPtSize)/10; m_MaxX = 0; m_MaxY = 0; @@ -1106,6 +1298,14 @@ wxLayoutList::Find(wxPoint coords) const /******************** printing stuff ********************/ +wxLayoutPrintout::wxLayoutPrintout(wxLayoutList &llist, + wxString const & title) +:wxPrintout(title) +{ + m_llist = &llist; + m_title = title; +} + bool wxLayoutPrintout::OnPrintPage(int page) { wxDC *dc = GetDC(); diff --git a/user/wxLayout/wxllist.h b/user/wxLayout/wxllist.h index 6693df64f5..faa0fcfa15 100644 --- a/user/wxLayout/wxllist.h +++ b/user/wxLayout/wxllist.h @@ -280,6 +280,13 @@ public: int weight=-1, int underline = -1, char const *fg = NULL, char const *bg = NULL); + /// changes to the next larger font size + inline void SetFontLarger(void) + { SetFont(-1,(12*m_FontPtSize)/10); } + /// changes to the next smaller font size + inline void SetFontSmaller(void) + { SetFont(-1,(10*m_FontPtSize)/12); } + /// set font family inline void SetFontFamily(int family) { SetFont(family); } /// set font size @@ -345,11 +352,11 @@ public: bool IsEditable(void) const { return m_Editable; } /// move cursor, returns true if it could move to the desired position bool MoveCursor(int dx = 0, int dy = 0); - void SetCursor(wxPoint const &p) { m_CursorPosition = p; } + void SetCursor(wxPoint const &p) { m_CursorPos = p; } void DrawCursor(wxDC &dc, bool erase = false); /// Get current cursor position cursor coords - wxPoint GetCursor(void) const { return m_CursorPosition; } + wxPoint GetCursor(void) const { return m_CursorPos; } /// Gets graphical coordinates of cursor wxPoint GetCursorCoords(void) const { return m_CursorCoords; } @@ -404,12 +411,16 @@ protected: //---- this is needed for editing: /// where is the text cursor (column,line): - wxPoint m_CursorPosition; + wxPoint m_CursorPos; /// where to draw the cursor wxPoint m_CursorCoords; /// how large to draw it wxPoint m_CursorSize; - + /// object iterator for current cursor position: + iterator m_CursorObject; + /// position of cursor within m_CursorObject: + int m_CursorOffset; + /// to store content overwritten by cursor wxMemoryDC m_CursorMemDC; @@ -435,9 +446,7 @@ class wxLayoutPrintout: public wxPrintout { public: wxLayoutPrintout(wxLayoutList &llist, wxString const & title = - "wxLayout Printout") - :wxPrintout(title) - { m_llist = &llist; m_title = title;} + "wxLayout Printout"); bool OnPrintPage(int page); bool HasPage(int page); bool OnBeginDocument(int startPage, int endPage); diff --git a/user/wxLayout/wxlwindow.cpp b/user/wxLayout/wxlwindow.cpp index 828ac67a71..73a2d28e8f 100644 --- a/user/wxLayout/wxlwindow.cpp +++ b/user/wxLayout/wxlwindow.cpp @@ -39,6 +39,14 @@ BEGIN_EVENT_TABLE(wxLayoutWindow,wxScrolledWindow) EVT_LEFT_DOWN(wxLayoutWindow::OnLeftMouseClick) EVT_RIGHT_DOWN(wxLayoutWindow::OnRightMouseClick) EVT_LEFT_DCLICK(wxLayoutWindow::OnMouseDblClick) + 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_ROMAN, wxLayoutWindow::OnMenu) + EVT_MENU(WXLOWIN_MENU_TYPEWRITER, wxLayoutWindow::OnMenu) + EVT_MENU(WXLOWIN_MENU_SANSSERIF, wxLayoutWindow::OnMenu) END_EVENT_TABLE() wxLayoutWindow::wxLayoutWindow(wxWindow *parent) @@ -49,8 +57,9 @@ wxLayoutWindow::wxLayoutWindow(wxWindow *parent) m_ScrollbarsSet = 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); @@ -90,7 +99,7 @@ wxLayoutWindow::OnMouse(int eventId, wxMouseEvent& event) wxPaintDC dc( this ); PrepareDC( dc ); SetFocus(); - + wxPoint findPos; findPos.x = dc.DeviceToLogicalX(event.GetX()); findPos.y = dc.DeviceToLogicalY(event.GetY()); @@ -98,6 +107,13 @@ wxLayoutWindow::OnMouse(int eventId, wxMouseEvent& event) TRACEMESSAGE(("wxLayoutWindow::OnMouse: (%d, %d) -> (%d, %d)", event.GetX(), event.GetY(), findPos.x, findPos.y)); + if(eventId == WXLOWIN_MENU_RCLICK && m_DoPopupMenu && m_llist.IsEditable()) + { + // when does this menu get freed? + // how do we handle toggling? FIXME + PopupMenu(MakeFormatMenu(), event.GetX(), event.GetY()); + return; + } // find the object at this position wxLayoutObjectBase *obj = m_llist.Find(findPos); if(obj) @@ -290,3 +306,61 @@ wxLayoutWindow::Print(void) dc.EndDoc(); } } + +wxMenu * +wxLayoutWindow::MakeFormatMenu() +{ + if(m_PopupMenu) + return m_PopupMenu; + + wxMenu *m = new wxMenu(); + + 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->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; +} + +void wxLayoutWindow::OnMenu(wxCommandEvent& event) +{ + if(! m_llist.IsEditable()) + return; + + switch (event.GetId()) + { + case WXLOWIN_MENU_LARGER: + 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; + case WXLOWIN_MENU_ROMAN: + m_llist.SetFontFamily(wxROMAN); break; + case WXLOWIN_MENU_TYPEWRITER: + m_llist.SetFontFamily(wxFIXED); break; + case WXLOWIN_MENU_SANSSERIF: + m_llist.SetFontFamily(wxSWISS); break; + } +} -- 2.47.2