- 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
wxLayoutList::LineBreak(void)
{
Insert(new wxLayoutObjectLineBreak);
- m_CursorPosition.x = 0; m_CursorPosition.y++;
+ m_CursorPos.x = 0; m_CursorPos.y++;
}
void
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);
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);
void
wxLayoutList::DrawCursor(wxDC &dc, bool erase)
{
+ if(! m_Editable)
+ return;
+
if(erase)
{
//dc.SetBrush(*wxWHITE_BRUSH);
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));
((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
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();
*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)
{
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;
}
{
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
}
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;
}
// 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
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)
{
{
m_MaxLine--;
erase(i);
+ m_CursorObject = i; // new i!
+ m_CursorOffset = 0; // Pos unchanged
count--;
continue; // we're done
}
{
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
}
}
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
// 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())
{
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;
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:
{
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;
}
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;
/******************** 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();
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)
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);
wxPaintDC dc( this );
PrepareDC( dc );
SetFocus();
-
+
wxPoint findPos;
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));
+ 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)
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;
+ }
+}