TODO
=====================================================================
-- replacement of llist in window
-- undo
-- Selections!!!
+RECENTLY FIXED (?)
+ - fix(simplify) cursor size calculation
+ - delete in empty line doesn't work
+ - fix horiz scrollbar size OK here, a Mahogany problem?
+
-- More optimisations:
-
-- let each line have a pointer to the last layoutcommand and let that
- one only store the settings that changed, then we no longer need to
- recalculate all the lines
-
- - update rectangle (needs support in wxllist and wxWindows)
-- fix(simplify) cursor size calculation: don't use icon cursor if there
- is no cursor object
+- update rectangle (needs support in wxllist and wxWindows)
+ --> needs a bit of fixing still
+ some code bits are commented out in wxlwindow.cpp
+ offset handling seems a bit dodgy, white shadow to top/left of cursor
+ - replacement of llist in window
+ - undo
+ - font optimisations(!)
- copy/cut/selections
+ - occasionally wraps lines wongly (twice) ??
- UNDO
+ later:
+ - DragNDrop ... broken in wxGTK at present
+ - cut&paste ... broken in wxGTK at present, Paste already implemented
+ - Selections
-- cut&paste (paste is there but broken in wxGTK)
- The current paste in wxGTK is broken, support is there.
- Once selections are there, add copy (trivial).
-
-- DragNDrop (waiting for wxGTK/gtk1.2 & GNOME 1.0 / Debian Slink)
+- More optimisations:
+ - let each line have a pointer to the last layoutcommand and let that
+ one only store the settings that changed, then we no longer need to
+ recalculate all the lines
+
#pragma implementation "wxllist.h"
#endif
+//#include "Mpch.h"
+
+
#include "wx/wxprec.h"
#ifdef __BORLANDC__
# pragma hdrstop
#endif
-//#include "Mpch.h"
#ifdef M_PREFIX
# include "gui/wxllist.h"
#else
return p1.x != p2.x || p1.y != p2.y;
}
+/// allows me to compare to wxPoints
+bool operator <=(wxPoint const &p1, wxPoint const &p2)
+{
+ return p1.y < p2.y || (p1.y == p2.y && p1.x <= p2.x);
+}
+
/// grows a wxRect so that it includes the given point
-static void GrowRect(wxRect &r, const wxPoint & p)
+static
+void GrowRect(wxRect &r, const wxPoint & p)
{
if(r.x > p.x)
r.x = p.x;
else if(r.y + r.height < p.y)
r.height = p.y - r.y;
}
+
+/// returns true if the point is in the rectangle
+static
+bool Contains(const wxRect &r, const wxPoint &p)
+{
+ return r.x <= p.x && r.y <= p.y && (r.x+r.width) >= p.x && (r.y + r.height) >= p.y;
+}
//@}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
wxLayoutObjectCmd::wxLayoutObjectCmd(int size, int family, int style, int
weight, bool underline,
- wxColour const *fg, wxColour const *bg)
+ wxColour &fg, wxColour &bg)
{
m_font = new wxFont(size,family,style,weight,underline);
si->underline = m_font->GetUnderlined();
si->weight = m_font->GetWeight();
- si->fg_red = m_ColourFG->Red();
- si->fg_green = m_ColourFG->Green();
- si->fg_blue = m_ColourFG->Blue();
- si->bg_red = m_ColourBG->Red();
- si->bg_green = m_ColourBG->Green();
- si->bg_blue = m_ColourBG->Blue();
+ si->fg_red = m_ColourFG.Red();
+ si->fg_green = m_ColourFG.Green();
+ si->fg_blue = m_ColourFG.Blue();
+ si->bg_red = m_ColourBG.Red();
+ si->bg_green = m_ColourBG.Green();
+ si->bg_blue = m_ColourBG.Blue();
}
void
{
wxASSERT(m_font);
dc.SetFont(*m_font);
- if(m_ColourFG)
- dc.SetTextForeground(*m_ColourFG);
- if(m_ColourBG)
- dc.SetTextBackground(*m_ColourBG);
+ dc.SetTextForeground(m_ColourFG);
+ dc.SetTextBackground(m_ColourBG);
}
void
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-wxLayoutLine::wxLayoutLine(wxLayoutLine *prev)
+wxLayoutLine::wxLayoutLine(wxLayoutLine *prev, wxLayoutList *llist)
{
m_LineNumber = 0;
m_Width = m_Height = 0;
m_Dirty = true;
m_Previous = prev;
m_Next = NULL;
- RecalculatePosition();
+ RecalculatePosition(llist);
if(m_Previous)
{
m_LineNumber = m_Previous->GetLineNumber()+1;
{
m_Next->m_Previous = this;
m_Next->MoveLines(+1);
- m_Next->RecalculatePositions(1);
+ m_Next->RecalculatePositions(1,llist);
}
}
}
wxPoint
-wxLayoutLine::RecalculatePosition(void)
+wxLayoutLine::RecalculatePosition(wxLayoutList *llist)
{
if(m_Previous)
m_Position = m_Previous->GetPosition() +
wxPoint(0,m_Previous->GetHeight());
else
m_Position = wxPoint(0,0);
+ llist->SetUpdateRect(m_Position);
return m_Position;
}
void
-wxLayoutLine::RecalculatePositions(int recurse)
+wxLayoutLine::RecalculatePositions(int recurse, wxLayoutList *llist)
{
wxASSERT(recurse >= 0);
wxPoint pos = m_Position;
CoordType height = m_Height;
// WXLO_TRACE("RecalculatePositions()");
- RecalculatePosition();
+ RecalculatePosition(llist);
if(m_Next)
{
if(recurse > 0)
- {
- if(m_Next) m_Next->RecalculatePositions(--recurse);
- }
+ m_Next->RecalculatePositions(--recurse, llist);
else if(pos != m_Position || m_Height != height)
- if(m_Next) m_Next->RecalculatePositions();
+ m_Next->RecalculatePositions(0, llist);
}
}
{
wxASSERT(xpos >= 0);
wxASSERT(offset);
- wxLayoutObjectList::iterator i;
+ wxLayoutObjectList::iterator
+ i,
+ found = NULLIT;
CoordType x = 0, len;
-
+ /* We search through the objects. As we don't like returning the
+ object that the cursor is behind, we just remember such an
+ object in "found" so we can return it if there is really no
+ further object following it. */
for(i = m_ObjectList.begin(); i != NULLIT; i++)
{
len = (**i).GetLength();
if( x <= xpos && xpos <= x + len )
{
*offset = xpos-x;
- return i;
+ if(xpos == x + len) // is there another object behind?
+ found = i;
+ else // we are really inside this object
+ return i;
}
x += (**i).GetLength();
}
- return NULLIT;
+ return found; // ==NULL if really none found
}
wxLayoutObjectList::iterator
}
wxLayoutLine *
-wxLayoutLine::DeleteLine(bool update)
+wxLayoutLine::DeleteLine(bool update, wxLayoutList *llist)
{
if(m_Next) m_Next->m_Previous = m_Previous;
if(m_Previous) m_Previous->m_Next = m_Next;
if(update)
{
m_Next->MoveLines(-1);
- m_Next->RecalculatePositions(1);
+ m_Next->RecalculatePositions(1, llist);
}
wxLayoutLine *next = m_Next;
delete this;
}
void
-wxLayoutLine::Draw(wxDC &dc, const wxPoint & offset) const
+wxLayoutLine::Draw(wxDC &dc,
+ wxLayoutList *llist,
+ const wxPoint & offset) const
{
wxLayoutObjectList::iterator i;
wxPoint pos = offset;
}
void
-wxLayoutLine::Layout(wxDC &dc, wxPoint *cursorPos,
+wxLayoutLine::Layout(wxDC &dc,
+ wxLayoutList *llist,
+ wxPoint *cursorPos,
wxPoint *cursorSize,
int cx)
{
if(cursorPos)
{
*cursorPos = m_Position;
+ if(cursorSize) *cursorSize = wxPoint(0,0);
}
for(i = m_ObjectList.begin(); i != NULLIT; i++)
// tell next line about coordinate change
if(m_Next && objHeight != oldHeight)
- m_Next->RecalculatePositions();
+ m_Next->RecalculatePositions(0, llist);
// We need to check whether we found a valid cursor size:
if(cursorPos)
// line or on a command object:
if(cursorSize->y < WXLO_MINIMUM_CURSOR_WIDTH)
{
- if(m_BaseLine > 0)
- {
- cursorSize->y = m_BaseLine;
- if(cursorSize->x < WXLO_MINIMUM_CURSOR_WIDTH) cursorSize->x = WXLO_MINIMUM_CURSOR_WIDTH;
- }
- else // empty line
- {
- CoordType width, height, descent;
- dc.GetTextExtent(WXLO_CURSORCHAR, &width, &height, &descent);
- cursorSize->x = width;
- cursorSize->y = height;
- }
+ CoordType width, height, descent;
+ dc.GetTextExtent(WXLO_CURSORCHAR, &width, &height, &descent);
+ cursorSize->x = width;
+ cursorSize->y = height;
}
if(m_BaseLine >= cursorSize->y) // the normal case anyway
cursorPos->y += m_BaseLine-cursorSize->y;
wxLayoutLine *
-wxLayoutLine::Break(CoordType xpos)
+wxLayoutLine::Break(CoordType xpos, wxLayoutList *llist)
{
wxASSERT(xpos >= 0);
if(xpos == 0)
{ // insert an empty line before this one
- wxLayoutLine *prev = new wxLayoutLine(m_Previous);
+ wxLayoutLine *prev = new wxLayoutLine(m_Previous, llist);
if(m_Previous == NULL)
{ // We were in first line, need to link in new empty line
// before this.
}
MoveLines(+1);
if(m_Next)
- m_Next->RecalculatePositions(1);
+ m_Next->RecalculatePositions(1, llist);
return this;
}
wxLOiterator i = FindObject(xpos, &offset);
if(i == NULLIT)
// must be at the end of the line then
- return new wxLayoutLine(this);
+ return new wxLayoutLine(this, llist);
// split this line:
- wxLayoutLine *newLine = new wxLayoutLine(this);
+ wxLayoutLine *newLine = new wxLayoutLine(this, llist);
// split object at i:
if((**i).GetType() == WXLO_TYPE_TEXT && offset != 0)
{
m_ObjectList.remove(i); // remove without deleting it
}
if(m_Next)
- m_Next->RecalculatePositions(2);
+ m_Next->RecalculatePositions(2, llist);
return newLine;
}
void
-wxLayoutLine::MergeNextLine(void)
+wxLayoutLine::MergeNextLine(wxLayoutList *llist)
{
wxASSERT(GetNextLine());
wxLayoutObjectList &list = GetNextLine()->m_ObjectList;
wxLayoutLine *oldnext = GetNextLine();
SetNext(GetNextLine()->GetNextLine());
delete oldnext;
- RecalculatePositions(1);
+ RecalculatePositions(1, llist);
}
CoordType
{
m_DefaultSetting = NULL;
m_FirstLine = NULL;
+ m_ColourFG = *wxBLACK;
+ m_ColourBG = *wxWHITE;
InvalidateUpdateRect();
Clear();
}
wxLayoutList::~wxLayoutList()
{
InternalClear();
- m_FirstLine->DeleteLine(false);
+ m_FirstLine->DeleteLine(false, this);
}
void
wxLayoutList::Empty(void)
{
while(m_FirstLine)
- m_FirstLine = m_FirstLine->DeleteLine(false);
+ m_FirstLine = m_FirstLine->DeleteLine(false, this);
m_CursorPos = wxPoint(0,0);
m_CursorScreenPos = wxPoint(0,0);
m_CursorSize = wxPoint(0,0);
- m_FirstLine = new wxLayoutLine(NULL); // empty first line
+ m_FirstLine = new wxLayoutLine(NULL, this); // empty first line
m_CursorLine = m_FirstLine;
+ InvalidateUpdateRect();
}
void
wxLayoutList::SetFont(int family, int size, int style, int weight,
- int underline, wxColour const *fg,
- wxColour const *bg)
+ int underline, wxColour *fg,
+ wxColour *bg)
{
if(family != -1) m_FontFamily = family;
if(size != -1) m_FontPtSize = size;
if(weight != -1) m_FontWeight = weight;
if(underline != -1) m_FontUnderline = underline != 0;
- if(fg != NULL) m_ColourFG = fg;
- if(bg != NULL) m_ColourBG = bg;
+ if(fg != NULL) m_ColourFG = *fg;
+ if(bg != NULL) m_ColourBG = *bg;
Insert(
new wxLayoutObjectCmd(m_FontPtSize,m_FontFamily,m_FontStyle,m_FontWeight,m_FontUnderline,
int underline, char const *fg, char const *bg)
{
- wxColour const
- * cfg = NULL,
- * cbg = NULL;
+ wxColour
+ *cfg = NULL,
+ *cbg = NULL;
if( fg )
cfg = wxTheColourDatabase->FindColour(fg);
void
wxLayoutList::Clear(int family, int size, int style, int weight,
- int /* underline */, char const *fg, char const *bg)
+ int /* underline */, wxColour *fg, wxColour *bg)
{
InternalClear();
m_FontFamily = family;
m_FontStyle = style;
m_FontWeight = weight;
- m_ColourFG = wxTheColourDatabase->FindColour(fg);
- m_ColourBG = wxTheColourDatabase->FindColour(bg);
+ if(fg) m_ColourFG = *fg;
+ if(bg) m_ColourBG = *bg;
- if(! m_ColourFG) m_ColourFG = wxBLACK;
- if(! m_ColourBG) m_ColourBG = wxWHITE;
+ m_ColourFG = *wxBLACK;
+ m_ColourBG = *wxWHITE;
if(m_DefaultSetting)
delete m_DefaultSetting;
bool
wxLayoutList::MoveCursorTo(wxPoint const &p)
{
+ SetUpdateRect(m_CursorScreenPos);
+ SetUpdateRect(m_CursorScreenPos+m_CursorSize);
wxLayoutLine *line = m_FirstLine;
while(line && line->GetLineNumber() != p.y)
line = line->GetNextLine();
bool
wxLayoutList::MoveCursorVertically(int n)
{
+ SetUpdateRect(m_CursorScreenPos);
+ SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+ bool rc;
if(n < 0) // move up
{
if(m_CursorLine == m_FirstLine) return false;
{
m_CursorLine = m_FirstLine;
m_CursorPos.y = 0;
- return false;
+ rc = false;
}
else
{
if(m_CursorPos.x > m_CursorLine->GetLength())
m_CursorPos.x = m_CursorLine->GetLength();
- return true;
+ rc = true;
}
}
else // move down
{
m_CursorLine = last;
m_CursorPos.y ++;
- return false;
+ rc = false;
}
else
{
if(m_CursorPos.x > m_CursorLine->GetLength())
m_CursorPos.x = m_CursorLine->GetLength();
- return true;
+ rc = true;
}
}
+ return rc;
}
bool
wxLayoutList::MoveCursorHorizontally(int n)
{
+ SetUpdateRect(m_CursorScreenPos);
+ SetUpdateRect(m_CursorScreenPos+m_CursorSize);
int move;
while(n < 0)
{
wxLayoutList::Insert(wxString const &text)
{
wxASSERT(m_CursorLine);
+ SetUpdateRect(m_CursorScreenPos);
+ SetUpdateRect(m_CursorScreenPos+m_CursorSize);
m_CursorLine->Insert(m_CursorPos.x, text);
m_CursorPos.x += text.Length();
return true;
wxLayoutList::Insert(wxLayoutObject *obj)
{
wxASSERT(m_CursorLine);
+ SetUpdateRect(m_CursorScreenPos);
+ SetUpdateRect(m_CursorScreenPos+m_CursorSize);
m_CursorLine->Insert(m_CursorPos.x, obj);
m_CursorPos.x += obj->GetLength();
return true;
wxLayoutList::LineBreak(void)
{
wxASSERT(m_CursorLine);
-
bool setFirst = (m_CursorLine == m_FirstLine && m_CursorPos.x == 0);
- m_CursorLine = m_CursorLine->Break(m_CursorPos.x);
+ SetUpdateRect(m_CursorScreenPos);
+ SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+ m_CursorLine = m_CursorLine->Break(m_CursorPos.x, this);
if(setFirst) // we were at beginning of first line
m_FirstLine = m_CursorLine->GetPreviousLine();
m_CursorPos.y++;
//else:
CoordType newpos = m_CursorPos.x - xpos - 1;
m_CursorPos.x = xpos;
+ SetUpdateRect(m_CursorScreenPos);
+ SetUpdateRect(m_CursorScreenPos+m_CursorSize);
LineBreak();
Delete(1); // delete the space
m_CursorPos.x = newpos;
wxLayoutList::Delete(CoordType npos)
{
wxASSERT(m_CursorLine);
+ SetUpdateRect(m_CursorScreenPos);
+ SetUpdateRect(m_CursorScreenPos+m_CursorSize);
CoordType left;
do
{
break; // cannot
else
{
- m_CursorLine->MergeNextLine();
+ m_CursorLine->MergeNextLine(this);
left--;
}
}
{
wxASSERT(m_CursorLine);
wxLayoutLine *line;
+ SetUpdateRect(m_CursorScreenPos);
+ SetUpdateRect(m_CursorScreenPos+m_CursorSize);
while(n > 0)
{
if(!m_CursorLine->GetNextLine())
}
//else:
line = m_CursorLine;
- m_CursorLine = m_CursorLine->DeleteLine(true);
+ m_CursorLine = m_CursorLine->DeleteLine(true, this);
n--;
if(line == m_FirstLine) m_FirstLine = m_CursorLine;
wxASSERT(m_FirstLine);
wxASSERT(m_CursorLine);
}
- m_CursorLine->RecalculatePositions(2);
+ m_CursorLine->RecalculatePositions(2, this);
return n;
}
void
-wxLayoutList::Recalculate(wxDC &dc, CoordType bottom) const
+wxLayoutList::Recalculate(wxDC &dc, CoordType bottom)
{
wxLayoutLine *line = m_FirstLine;
m_DefaultSetting->Layout(dc);
while(line)
{
- line->RecalculatePosition(); // so we don't need to do it all the time
+ line->RecalculatePosition(this); // so we don't need to do it all the time
// little condition to speed up redrawing:
if(bottom != -1 && line->GetPosition().y > bottom) break;
line = line->GetNextLine();
}
void
-wxLayoutList::Layout(wxDC &dc, CoordType bottom) const
+wxLayoutList::UpdateCursorScreenPos(wxDC &dc)
+{
+ wxASSERT(m_CursorLine);
+ m_CursorLine->Layout(dc, this, (wxPoint *)&m_CursorScreenPos, (wxPoint *)&m_CursorSize, m_CursorPos.x);
+}
+
+wxPoint
+wxLayoutList::GetCursorScreenPos(wxDC &dc)
+{
+ UpdateCursorScreenPos(dc);
+ return m_CursorScreenPos;
+}
+
+void
+wxLayoutList::Layout(wxDC &dc, CoordType bottom)
{
wxLayoutLine *line = m_FirstLine;
while(line)
{
if(line == m_CursorLine)
- line->Layout(dc, (wxPoint *)&m_CursorScreenPos, (wxPoint *)&m_CursorSize, m_CursorPos.x);
+ line->Layout(dc, this, (wxPoint *)&m_CursorScreenPos, (wxPoint *)&m_CursorSize, m_CursorPos.x);
else
- line->Layout(dc);
+ line->Layout(dc, this);
// little condition to speed up redrawing:
if(bottom != -1 && line->GetPosition().y > bottom) break;
line = line->GetNextLine();
m_CursorLine->GetNextLine() == NULL &&
m_CursorLine == m_FirstLine));
#endif
+ SetUpdateRect(m_CursorScreenPos);
+ SetUpdateRect(m_CursorScreenPos+m_CursorSize);
}
void
wxLayoutList::Draw(wxDC &dc, wxPoint const &offset,
- CoordType top, CoordType bottom) const
+ CoordType top, CoordType bottom)
{
wxLayoutLine *line = m_FirstLine;
Layout(dc, bottom);
m_DefaultSetting->Draw(dc, wxPoint(0,0));
- wxBrush *brush = new wxBrush(*m_ColourBG, wxSOLID);
- dc.SetBrush(*brush);
- delete brush;
+ wxBrush brush(m_ColourBG, wxSOLID);
+ dc.SetBrush(brush);
while(line)
{
// only draw if between top and bottom:
if((top == -1 || line->GetPosition().y >= top))
- line->Draw(dc, offset);
+ line->Draw(dc, this, offset);
// little condition to speed up redrawing:
if(bottom != -1 && line->GetPosition().y + line->GetHeight() > bottom) break;
line = line->GetNextLine();
wxASSERT(m_CursorSize.x != 0 || (m_CursorLine &&
m_CursorLine->GetNextLine() == NULL &&
m_CursorLine == m_FirstLine));
+ InvalidateUpdateRect();
}
wxLayoutObject *
p = line->GetPosition();
if(p.y <= pos.y && p.y+line->GetHeight() >= pos.y)
break;
- line->Layout(dc);
+ line->Layout(dc, this);
line = line->GetNextLine();
}
if(line == NULL) return NULL; // not found
}
}
+void
+wxLayoutList::StartSelection(void)
+{
+ wxLogDebug("Starting selection at %ld/%ld", m_CursorPos.x, m_CursorPos.y);
+ m_Selection.m_CursorA = m_CursorPos;
+}
+
+void
+wxLayoutList::EndSelection(void)
+{
+ wxLogDebug("Ending selection at %ld/%ld", m_CursorPos.x, m_CursorPos.y);
+ m_Selection.m_CursorB = m_CursorPos;
+}
+
+bool
+wxLayoutList::IsSelected(const wxPoint &cursor)
+{
+ return m_Selection.m_CursorA <= cursor
+ && cursor <= m_Selection.m_CursorB;
+}
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
virtual void Draw(wxDC &dc, wxPoint const &coords);
wxLayoutObjectCmd(int size, int family, int style, int weight,
bool underline,
- wxColour const *fg, wxColour const *bg);
+ wxColour &fg, wxColour &bg);
~wxLayoutObjectCmd();
/** Stores the current style in the styleinfo structure */
void GetStyle(wxLayoutStyleInfo *si) const;
/// return the background colour for setting colour of window
- wxColour const *GetBGColour(void) const { return m_ColourBG; }
+ wxColour &GetBGColour(void) { return m_ColourBG; }
/** Makes a copy of this object.
*/
virtual wxLayoutObject *Copy(void);
/// the font to use
wxFont *m_font;
/// foreground colour
- wxColour const *m_ColourFG;
+ wxColour m_ColourFG;
/// background colour
- wxColour const *m_ColourBG;
+ wxColour m_ColourBG;
};
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/// forward declaration
+class wxLayoutList;
+
/** This class represents a single line of objects to be displayed.
It knows its height and total size and whether it needs to be
redrawn or not.
/** Constructor.
@param prev pointer to previous line or NULL
@param next pointer to following line or NULL
+ @param llist pointer to layout list
*/
- wxLayoutLine(wxLayoutLine *prev);
+ wxLayoutLine(wxLayoutLine *prev, wxLayoutList *llist);
/** This function inserts a new object at cursor position xpos.
@param xpos where to insert new object
@param obj the object to insert
/** This function appens the next line to this, i.e. joins the two
lines into one.
*/
- void MergeNextLine(void);
+ void MergeNextLine(wxLayoutList *llist);
/** This function deletes npos cursor positions from position xpos.
@param xpos where to delete
@param xpos where to break it
@return pointer to the new line object replacing the old one
*/
- wxLayoutLine *Break(CoordType xpos);
+ wxLayoutLine *Break(CoordType xpos, wxLayoutList *llist);
/** Deletes the next word from this position, including leading
whitespace.
/** Deletes this line, returns pointer to next line.
@param update If true, update all following lines.
*/
- wxLayoutLine *DeleteLine(bool update);
+ wxLayoutLine *DeleteLine(bool update, wxLayoutList *llist);
/**@name Cursor Management */
//@{
//@{
/** Draws the line on a wxDC.
@param dc the wxDC to draw on
+ @param llist the wxLayoutList
@param offset an optional offset to shift printout
*/
- void Draw(wxDC &dc, const wxPoint &offset = wxPoint(0,0)) const;
+ void Draw(wxDC &dc,
+ wxLayoutList *llist,
+ const wxPoint &offset = wxPoint(0,0)) const;
/** Recalculates the positions of objects and the height of the
line.
@param dc the wxDC to draw on
+ @param llist th e wxLayoutList
@param cursorPos if not NULL, set cursor screen position in there
@param cursorSize if not cursorPos != NULL, set cursor size in there
@param cx if cursorPos != NULL, the cursor x position
*/
void Layout(wxDC &dc,
+ wxLayoutList *llist,
wxPoint *cursorPos = NULL,
wxPoint *cursorSize = NULL,
int cx = 0);
minimum(!) recursion level, continue with all lines till the end of
the list or until the coordinates no longer changed.
*/
- void RecalculatePositions(int recurse = 0);
+ void RecalculatePositions(int recurse, wxLayoutList *llist);
/// Recalculates the position of this line on the canvas.
- wxPoint RecalculatePosition(void);
+ wxPoint RecalculatePosition(wxLayoutList *llist);
private:
/// Destructor is private. Use DeleteLine() to remove it.
~wxLayoutLine();
dirty.
@param height new height
*/
- void SetHeight(CoordType height)
- { m_Height = height; RecalculatePositions(true); }
+ void SetHeight(CoordType height, wxLayoutList *llist)
+ { m_Height = height; RecalculatePositions(true, llist); }
/** Moves the linenumbers one on, because a line has been inserted
or deleted.
wxLayoutLine *m_Next;
/// Just to suppress gcc compiler warnings.
friend class dummy;
+private:
+ wxLayoutLine(const wxLayoutLine &);
};
int style=wxNORMAL,
int weight=wxNORMAL,
int underline=0,
- char const *fg="black",
- char const *bg="white");
+ wxColour *fg=NULL,
+ wxColour *bg=NULL);
/// Empty: clear the list but leave font settings.
void Empty(void);
{ MoveCursorHorizontally(-m_CursorPos.x); }
/// Returns current cursor position.
- wxPoint GetCursorPos(void) const { return m_CursorPos; }
+ wxPoint GetCursorPos(wxDC &dc) const { return m_CursorPos; }
//@}
/**@name Editing functions.
/// sets font parameters
void SetFont(int family, int size, int style,
int weight, int underline,
- wxColour const *fg,
- wxColour const *bg);
+ wxColour *fg,
+ wxColour *bg);
/// sets font parameters, colours by name
void SetFont(int family=-1, int size = -1, int style=-1,
int weight=-1, int underline = -1,
anywhere.
@return the default settings of the list
*/
- wxLayoutObjectCmd const *GetDefaults(void) const { return m_DefaultSetting ; }
+ wxLayoutObjectCmd *GetDefaults(void) { return m_DefaultSetting ; }
//@}
/**@name Drawing */
@param bottom optional y coordinate where to stop drawing
*/
void Draw(wxDC &dc, const wxPoint &offset = wxPoint(0,0),
- CoordType top = -1, CoordType bottom = -1) const;
+ CoordType top = -1, CoordType bottom = -1);
/** Calculates new layout for the list, like Draw() but does not
actually draw it.
@param dc the wxDC to draw on
@param bottom optional y coordinate where to stop calculating
*/
- void Layout(wxDC &dc, CoordType bottom = -1) const;
+ void Layout(wxDC &dc, CoordType bottom = -1);
/** Calculates new sizes for everything in the list, like Layout()
but this is needed after the list got changed.
@param dc the wxDC to draw on
@param bottom optional y coordinate where to stop calculating
*/
- void Recalculate(wxDC &dc, CoordType bottom = -1) const;
+ void Recalculate(wxDC &dc, CoordType bottom = -1);
/** Returns the size of the list in screen coordinates.
The return value only makes sense after the list has been
/** Returns the cursor position on the screen.
@return cursor position in pixels
*/
- wxPoint GetCursorScreenPos(void) const
- { return m_CursorScreenPos; }
+ wxPoint GetCursorScreenPos(wxDC &dc);
/** Draws the cursor.
@param active If true, draw a bold cursor to mark window as
return m_FirstLine;
}
//@}
+
+ void StartSelection(void);
+ void EndSelection(void);
+ bool IsSelected(const wxPoint &cursor);
+
private:
/// Clear the list.
void InternalClear(void);
+ /** Calculates the cursor position on the screen.
+ */
+ void UpdateCursorScreenPos(wxDC &dc);
/// The list of lines.
wxLayoutLine *m_FirstLine;
wxLayoutLine *m_CursorLine;
//@}
+ /// A structure for the selection.
+ struct
+ {
+ bool m_valid;
+ wxPoint m_CursorA, m_CursorB;
+ }m_Selection;
/** @name Font parameters. */
//@{
int m_FontFamily, m_FontStyle, m_FontWeight;
int m_FontPtSize;
bool m_FontUnderline;
/// colours:
- wxColour const * m_ColourFG;
- wxColour const * m_ColourBG;
+ wxColour m_ColourFG;
+ wxColour m_ColourBG;
/// the default setting:
wxLayoutObjectCmd *m_DefaultSetting;
//@}
m_bitmapSize = wxPoint(4,4);
m_llist = new wxLayoutList();
m_BGbitmap = NULL;
+ m_ScrollToCursor = false;
SetWrapMargin(0);
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;
+ m_Selecting = false;
SetCursor(wxCURSOR_IBEAM);
SetDirty();
}
if(obj && eventId == WXLOWIN_MENU_LCLICK)
{
m_llist->MoveCursorTo(cursorPos);
- DoPaint(false);
+ m_ScrollToCursor = true; //FIXME: needed? DoPaint(m_llist->GetUpdateRect());
}
if(!m_doSendEvents) // nothing to do
return;
}
long keyCode = event.KeyCode();
-
+ if(event.ShiftDown())
+ m_Selecting = true;
+ else
+ {
+ if(m_Selecting)
+ m_llist->EndSelection();
+ m_Selecting = false;
+ }
/* First, handle control keys */
if(event.ControlDown() && ! event.AltDown())
{
- switch(event.KeyCode())
+ switch(keyCode)
{
case WXK_DELETE :
case 'd':
// ALT only:
else if( event.AltDown() && ! event.ControlDown() )
{
- switch(event.KeyCode())
+ switch(keyCode)
{
case WXK_DELETE:
case 'd':
// no control keys:
else if ( ! event.AltDown() && ! event.ControlDown())
{
- switch(event.KeyCode())
+ switch(keyCode)
{
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 :
}
SetDirty();
SetModified();
- DoPaint(true); // paint and scroll to cursor
+ m_ScrollToCursor = true;
+ //DoPaint(true); // paint and scroll to cursor
+ wxRect r = *m_llist->GetUpdateRect();
+ r.x -= WXLO_XOFFSET; r.y -= WXLO_YOFFSET;
+ Refresh( FALSE, &r);
}
void
wxLayoutWindow::OnPaint( wxPaintEvent &WXUNUSED(event)) // or: OnDraw(wxDC& dc)
{
- m_ScrollToCursor = false;
- InternalPaint();
+ wxRect region = GetUpdateRegion().GetBox();
+ InternalPaint(& region);
}
void
-wxLayoutWindow::DoPaint(bool scrollToCursor)
+wxLayoutWindow::DoPaint(const wxRect *updateRect)
{
- m_ScrollToCursor = scrollToCursor;
#ifdef __WXGTK__
- InternalPaint();
+ InternalPaint(updateRect);
#else
- Refresh(FALSE); // Causes bad flicker under wxGTK!!!
+ Refresh(FALSE, updateRect); // Causes bad flicker under wxGTK!!!
#endif
}
void
-wxLayoutWindow::InternalPaint(void)
+wxLayoutWindow::InternalPaint(const wxRect *updateRect)
{
wxPaintDC dc( this );
PrepareDC( dc );
if(x1 > m_maxx) m_maxx = x1;
if(y1 > m_maxy) m_maxy = y1;
- // Maybe we need to change the scrollbar sizes or positions,
+
+ 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();
+ 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%
{
// 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);
if(m_BGbitmap)
{
m_llist->DrawCursor(*m_memDC,m_HaveFocus,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?
wxRegionIterator ri ( GetUpdateRegion() );
if(ri)
while(ri)
{
+ wxLogDebug("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
dc.Blit(x0,y0,x1,y1,m_memDC,0,0,wxCOPY,FALSE);
ResetDirty();
+ m_ScrollToCursor = false;
}
// change the range and position of scroll bars
wxLayoutWindow::OnSetFocus(wxFocusEvent &ev)
{
m_HaveFocus = true;
- DoPaint(); // to repaint the cursor
+//FIXME DoPaint(); // to repaint the cursor
}
void
wxLayoutWindow::OnKillFocus(wxFocusEvent &ev)
{
m_HaveFocus = false;
- DoPaint(); // to repaint the cursor
+//FIXME DoPaint(); // to repaint the cursor
}
int style=wxNORMAL,
int weight=wxNORMAL,
int underline=0,
- char const *fg="black",
- char const *bg="white")
+ wxColour *fg=NULL,
+ wxColour *bg=NULL)
{
GetLayoutList()->Clear(family,size,style,weight,underline,fg,bg);
- SetBackgroundColour(*GetLayoutList()->GetDefaults()->GetBGColour());
+ SetBackgroundColour(GetLayoutList()->GetDefaults()->GetBGColour());
ResizeScrollbars(true);
SetDirty();
SetModified(false);
- DoPaint();
+ wxRect r;
+ int w,h;
+ r.x = r.y = 0; GetSize(&w,&h);
+ r.width = w;
+ r.height = h;
+ DoPaint(&r);
}
/** Sets a background image, only used on screen, not on printouts.
@param bitmap a pointer to a wxBitmap or NULL to remove it
/** Redraws the window.
Internally, this stores the parameter and calls a refresh on
wxMSW, draws directly on wxGTK.
- @param scrollToCursor if true, scroll the window so that the
- cursor becomes visible
*/
- void DoPaint(bool scrollToCursor = false);
+ void DoPaint(const wxRect *updateRect);
#ifdef __WXMSW__
virtual long MSWGetDlgCode();
void ResetDirty(void) { m_Dirty = false; }
//@}
/// Redraws the window, used by DoPaint() or OnPaint().
- void InternalPaint(void);
+ void InternalPaint(const wxRect *updateRect);
/// Has list been modified/edited?
bool IsModified(void) const { return m_Modified; }
wxLayoutList *m_llist;
/// Can user edit the window?
bool m_Editable;
+ /// Are we currently building a selection with the keyboard?
+ bool m_Selecting;
/// wrap margin
CoordType m_WrapMargin;
/// Is list dirty (for redraws, internal use)?