wxColour *fg,
wxColour *bg)
{
- family = ifamily; size = isize;
- style = istyle; weight = iweight;
+ family = ifamily;
+ size = isize;
+ style = istyle;
+ weight = iweight;
underline = iul != 0;
- if(fg)
- {
- m_fg = *fg;
- m_fg_valid = TRUE;
- }
- else
- m_fg = *wxBLACK;
- if(bg)
- {
- m_bg = *bg;
- m_bg_valid = TRUE;
- }
- else
- m_bg = *wxWHITE;
+
+ m_fg_valid = fg != 0;
+ m_bg_valid = bg != 0;
+ m_fg = m_fg_valid ? *fg : *wxBLACK;
+ m_bg = m_bg_valid ? *bg : *wxWHITE;
}
#define COPY_SI_(what) if(right.what != -1) what = right.what;
wxLayoutLine::wxLayoutLine(wxLayoutLine *prev, wxLayoutList *llist)
{
- m_LineNumber = 0;
m_Width = m_Height = 0;
m_Length = 0;
+
+ m_updateLeft = -1;
MarkDirty(0);
+
m_Previous = prev;
m_Next = NULL;
+
+ m_LineNumber = 0;
RecalculatePosition(llist);
+
if(m_Previous)
{
- m_LineNumber = m_Previous->GetLineNumber()+1;
+ m_LineNumber = m_Previous->GetLineNumber() + 1;
m_Next = m_Previous->GetNextLine();
m_Previous->m_Next = this;
}
+
if(m_Next)
{
m_Next->m_Previous = this;
m_Next->MoveLines(+1);
m_Next->RecalculatePositions(1,llist);
}
+
+ m_StyleInfo = llist->GetDefaultStyleInfo();
+
+ llist->IncNumLines();
}
wxLayoutLine::~wxLayoutLine()
}
wxLayoutObjectList::iterator
-wxLayoutLine::FindObjectScreen(wxDC &dc,
+wxLayoutLine::FindObjectScreen(wxDC &dc, wxLayoutList *llist,
CoordType xpos, CoordType *cxpos,
bool *found) const
{
wxASSERT(cxpos);
- wxASSERT(cxpos);
+
+ llist->ApplyStyle(GetStyleInfo(), dc);
+
wxLayoutObjectList::iterator i;
CoordType x = 0, cx = 0, width;
for(i = m_ObjectList.begin(); i != NULLIT; i++)
{
- width = (**i).GetWidth();
+ wxLayoutObject *obj = *i;
+ if ( obj->GetType() == WXLO_TYPE_CMD )
+ {
+ // this will set the correct font for the objects which follow
+ obj->Layout(dc, llist);
+ }
+
+ width = obj->GetWidth();
if( x <= xpos && xpos <= x + width )
{
- *cxpos = cx + (**i).GetOffsetScreen(dc, xpos-x);
- if(found) *found = true;
+ *cxpos = cx + obj->GetOffsetScreen(dc, xpos-x);
+
+ if ( found )
+ *found = true;
return i;
}
- x += (**i).GetWidth();
- cx += (**i).GetLength();
+
+ x += obj->GetWidth();
+ cx += obj->GetLength();
}
+
// behind last object:
*cxpos = cx;
- if(found) *found = false;
+
+ if (found)
+ *found = false;
return m_ObjectList.tail();
}
wxLayoutLine *
wxLayoutLine::DeleteLine(bool update, wxLayoutList *llist)
{
- if(m_Next) m_Next->m_Previous = m_Previous;
- if(m_Previous) m_Previous->m_Next = m_Next;
+ // maintain linked list integrity
+ if(m_Next)
+ m_Next->m_Previous = m_Previous;
+ if(m_Previous)
+ m_Previous->m_Next = m_Next;
+
+ wxLayoutLine *next = m_Next;
+ if ( next )
+ {
+ // get the line numbers right again
+ next->MoveLines(-1);
+ }
+
if(update)
{
- m_Next->MoveLines(-1);
- m_Next->RecalculatePositions(1, llist);
+ if ( next )
+ next->RecalculatePositions(1, llist);
+
/* We assume that if we have more than one object in the list,
this means that we have a command object, so we need to
update the following lines. */
)
MarkNextDirty(-1);
}
- wxLayoutLine *next = m_Next;
+
delete this;
+
+ llist->DecNumLines();
+
return next;
}
wxLayoutList *llist,
wxPoint *cursorPos,
wxPoint *cursorSize,
+ wxLayoutStyleInfo *cursorStyle,
int cx,
bool suppressSIupdate)
{
else
str = WXLO_CURSORCHAR;
dc.GetTextExtent(str, &width, &height, &descent);
- wxASSERT(cursorSize);
- // Just in case some joker inserted an empty string object:
- if(width == 0) width = WXLO_MINIMUM_CURSOR_WIDTH;
- if(height == 0) height = sizeObj.y;
- cursorSize->x = width;
- cursorSize->y = height;
+
+ if(cursorStyle) // set style info
+ *cursorStyle = llist->GetStyleInfo();
+ if ( cursorSize )
+ {
+ // Just in case some joker inserted an empty string object:
+ if(width == 0)
+ width = WXLO_MINIMUM_CURSOR_WIDTH;
+ if(height == 0)
+ height = sizeObj.y;
+ cursorSize->x = width;
+ cursorSize->y = height;
+ }
+
cursorFound = true; // no more checks
}
else
{
// on some other object
CoordType top, bottom; // unused
- *cursorSize = obj->GetSize(&top,&bottom);
+ if(cursorSize)
+ *cursorSize = obj->GetSize(&top,&bottom);
cursorPos->y = m_Position.y;
cursorFound = true; // no more checks
}
}
// We need to check whether we found a valid cursor size:
- if(cursorPos)
+ if(cursorPos && cursorSize)
{
// this might be the case if the cursor is at the end of the
// line or on a command object:
#endif // 0
}
+ llist->DecNumLines();
+
delete oldnext;
}
m_caret = NULL;
#endif // WXLAYOUT_USE_CARET
+ m_numLines = 0;
m_FirstLine = NULL;
InvalidateUpdateRect();
Clear();
wxLayoutList::~wxLayoutList()
{
InternalClear();
+ Empty();
m_FirstLine->DeleteLine(false, this);
+
+ wxASSERT_MSG( m_numLines == 0, "line count calculation broken" );
}
void
void
wxLayoutList::InternalClear(void)
{
- Empty();
m_Selection.m_selecting = false;
m_Selection.m_valid = false;
m_DefaultStyleInfo.m_bg = *wxWHITE;
m_CurrentStyleInfo = m_DefaultStyleInfo;
+ m_CursorStyleInfo = m_DefaultStyleInfo;
}
void
m_DefaultStyleInfo = wxLayoutStyleInfo(family, size, style, weight,
underline, fg, bg);
m_CurrentStyleInfo = m_DefaultStyleInfo;
+
+ // Empty() should be called after we set m_DefaultStyleInfo because
+ // otherwise the style info for the first line (created in Empty()) would be
+ // incorrect
+ Empty();
}
wxPoint
}
bool
-wxLayoutList::MoveCursorWord(int n)
+wxLayoutList::MoveCursorWord(int n, bool untilNext)
{
wxCHECK_MSG( m_CursorLine, false, "no current line" );
wxCHECK_MSG( n == -1 || n == +1, false, "not implemented yet" );
CoordType moveDistance = 0;
CoordType offset;
- for ( wxLOiterator i = m_CursorLine->FindObject(m_CursorPos.x, &offset);
+ wxLayoutLine *lineCur = m_CursorLine;
+ for ( wxLOiterator i = lineCur->FindObject(m_CursorPos.x, &offset);
n != 0;
n > 0 ? i++ : i-- )
{
if ( i == NULLIT )
- return false;
+ {
+ if ( n > 0 )
+ {
+ // moving forward, pass to the first object of the next line
+ moveDistance++;
+ lineCur = lineCur->GetNextLine();
+ if ( lineCur )
+ i = lineCur->GetFirstObject();
+ }
+ else
+ {
+ // moving backwards, pass to the last object of the prev line
+ moveDistance--;
+ lineCur = lineCur->GetPreviousLine();
+ if ( lineCur )
+ i = lineCur->GetLastObject();
+ }
+
+ if ( i == NULLIT )
+ {
+ // moved to the end/beginning of text
+ return false;
+ }
+
+ offset = -1;
+ }
wxLayoutObject *obj = *i;
+
+ if ( offset == -1 )
+ {
+ // calculate offset: we are either at the very beginning or the very
+ // end of the object, so it isn't very difficult (the only time when
+ // offset is != -1 is for the very first iteration when its value is
+ // returned by FindObject)
+ if ( n > 0 )
+ offset = 0;
+ else
+ offset = obj->GetLength();
+ }
+
if( obj->GetType() != WXLO_TYPE_TEXT )
{
- // any non text objects count as one word
- n > 0 ? n-- : n++;
+ // any visible non text objects count as one word
+ if ( obj->IsVisibleObject() )
+ {
+ n > 0 ? n-- : n++;
- moveDistance += obj->GetLength();
+ moveDistance += obj->GetLength();
+ }
}
- else
+ else // text object
{
- // text object
wxLayoutObjectText *tobj = (wxLayoutObjectText *)obj;
+ bool canAdvance = true;
+
if ( offset == tobj->GetLength() )
{
// at end of object
- n > 0 ? n-- : n++;
+ if ( n > 0 )
+ {
+ // can't move further in this text object
+ canAdvance = false;
+
+ // still should move over the object border
+ moveDistance++;
+ n--;
+ }
+ else if ( offset > 0 )
+ {
+ // offset is off by 1, make it a valid index
+ offset--;
+ }
}
- else
+
+ if ( canAdvance )
{
- const char *start = tobj->GetText().c_str();
+ const wxString& text = tobj->GetText();
+ const char *start = text.c_str();
+ const char *end = start + text.length();
const char *p = start + offset;
+ if ( n < 0 )
+ {
+ if ( offset > 0 )
+ p--;
+ }
+
// to the beginning/end of the next/prev word
- while ( isspace(*p) )
+ while ( p >= start && p < end && isspace(*p) )
{
n > 0 ? p++ : p--;
}
// go to the end/beginning of the word (in a broad sense...)
- while ( p >= start && !isspace(*p) )
+ while ( p >= start && p < end && !isspace(*p) )
{
n > 0 ? p++ : p--;
}
if ( n > 0 )
{
- // now advance to the beginning of the next word
- while ( isspace(*p) )
+ if ( untilNext )
+ {
+ // now advance to the beginning of the next word
+ while ( isspace(*p) && p < end )
+ p++;
+ }
+ }
+ else // backwards
+ {
+ // in these 2 cases we took 1 char too much
+ if ( (p < start) || isspace(*p) )
+ {
p++;
+ }
}
- n > 0 ? n-- : n++;
+ CoordType moveDelta = p - start - offset;
+ if ( (n < 0) && (offset == tobj->GetLength() - 1) )
+ {
+ // because we substracted 1 from offset in this case above, now
+ // compensate for it
+ moveDelta--;
+ }
+
+ if ( moveDelta != 0 )
+ {
+ moveDistance += moveDelta;
- moveDistance = p - start - offset;
+ n > 0 ? n-- : n++;
+ }
}
}
- // except for the first iteration, offset is 0
- offset = 0;
+ // except for the first iteration, offset is calculated in the beginning
+ // of the loop
+ offset = -1;
}
MoveCursorHorizontally(moveDistance);
wxLayoutList::LineBreak(void)
{
wxASSERT(m_CursorLine);
- bool setFirst = (m_CursorLine == m_FirstLine && m_CursorPos.x == 0);
AddCursorPosToUpdateRect();
height = m_CursorLine->GetHeight();
m_CursorLine = m_CursorLine->Break(m_CursorPos.x, this);
- if(setFirst) // we were at beginning of first line
- m_FirstLine = m_CursorLine->GetPreviousLine();
- if(m_CursorPos.x != 0)
+ if(m_CursorLine->GetPreviousLine() == NULL)
+ m_FirstLine = m_CursorLine;
+ if(m_CursorPos.x > 0)
m_CursorPos.y++;
m_CursorPos.x = 0;
+ // The following code will produce a height which is guaranteed to
+ // be too high: old lineheight + the height of both new lines.
+ // We can probably drop the old line height and start with height =
+ // 0. FIXME
wxLayoutLine *prev = m_CursorLine->GetPreviousLine();
- wxCHECK_MSG(prev, false, "just broke the line, where is the previous one?");
-
- height += prev->GetHeight();
+ if(prev)
+ height += prev->GetHeight();
+ height += m_CursorLine->GetHeight();
m_movedCursor = true;
}
}
-void
-wxLayoutList::UpdateCursorScreenPos(wxDC &dc,
- bool resetCursorMovedFlag,
- const wxPoint& translate)
-{
- wxCHECK_RET( m_CursorLine, "no cursor line" );
-
- if ( m_movedCursor )
- {
- // we need to save the current style, in case the layout() of
- // the line changes it
- wxLayoutStyleInfo SiBackup = m_CurrentStyleInfo;
- m_CursorLine->Layout(dc, this,
- &m_CursorScreenPos, &m_CursorSize,
- m_CursorPos.x,
- /* suppress update */ true);
- ApplyStyle(SiBackup, dc); // restore it
-
- if ( resetCursorMovedFlag )
- {
-#ifdef WXLAYOUT_USE_CARET
- // adjust the caret position
- wxPoint coords(m_CursorScreenPos);
- coords += translate;
-
- // and set it
- m_caret->Move(coords);
-#endif // WXLAYOUT_USE_CARET
-
- m_movedCursor = false;
- }
- }
-}
-
wxPoint
wxLayoutList::GetCursorScreenPos(wxDC &dc)
{
- // this function is called with wxMemoryDC argument from ScrollToCursor(),
- // for example, so it shouldn't clear "cursor moved" flag - or else the
- // cursor won't be moved when UpdateCursorScreenPos() is called with the
- // "real" (i.e. the one used for drawing) wxDC.
- UpdateCursorScreenPos(dc, false /* don't reset the flag */);
-
return m_CursorScreenPos;
}
*/
void
wxLayoutList::Layout(wxDC &dc, CoordType bottom, bool forceAll,
- wxPoint *cpos = NULL,
- wxPoint *csize = NULL)
+ wxPoint *cpos, wxPoint *csize)
{
// first, make sure everything is calculated - this might not be
// needed, optimise it later
// The following Layout() calls will update our
// m_CurrentStyleInfo if needed.
if(line == m_CursorLine)
+ {
line->Layout(dc, this,
(wxPoint *)&m_CursorScreenPos,
- (wxPoint *)&m_CursorSize, m_CursorPos.x);
- if(cpos && line->GetLineNumber() == cpos->y)
- line->Layout(dc, this,
- cpos,
- csize, cpos->x);
+ (wxPoint *)&m_CursorSize,
+ &m_CursorStyleInfo,
+ m_CursorPos.x);
+ // we cannot layout the line twice, so copy the coords:
+ if(cpos && line ->GetLineNumber() == cpos->y)
+ {
+ *cpos = m_CursorScreenPos;
+ if ( csize )
+ *csize = m_CursorSize;
+ }
+ }
+ else
+ if(cpos && line->GetLineNumber() == cpos->y)
+ line->Layout(dc, this,
+ cpos,
+ csize, NULL, cpos->x);
else
line->Layout(dc, this);
// little condition to speed up redrawing:
}
wxPoint
-wxLayoutList::GetScreenPos(wxDC &dc, const wxPoint &cpos, wxPoint *csize = NULL)
+wxLayoutList::GetScreenPos(wxDC &dc, const wxPoint &cpos, wxPoint *csize)
{
wxPoint pos = cpos;
Layout(dc, -1, false, &pos, csize);
{
wxLayoutLine *line = m_FirstLine;
+ if ( m_Selection.m_discarded )
+ {
+ // calculate them if we don't have them already
+ if ( !m_Selection.HasValidScreenCoords() )
+ {
+ m_Selection.m_ScreenA = GetScreenPos(dc, m_Selection.m_CursorA);
+ m_Selection.m_ScreenB = GetScreenPos(dc, m_Selection.m_CursorB);
+ }
+
+ // invalidate the area which was previousle selected - and which is not
+ // selected any more
+ SetUpdateRect(m_Selection.m_ScreenA);
+ SetUpdateRect(m_Selection.m_ScreenB);
+
+ m_Selection.m_discarded = false;
+ }
+
/* We need to re-layout all dirty lines to update styleinfos
etc. However, somehow we don't find all dirty lines... */
Layout(dc); //,-1,true); //FIXME
{
// only draw if between top and bottom:
if((top == -1 ||
- line->GetPosition().y + line->GetHeight() >= top))
+ line->GetPosition().y + line->GetHeight() > top))
{
// if(! style_set)
{
ApplyStyle(line->GetStyleInfo(), dc);
style_set = true;
}
+ // little condition to speed up redrawing:
+ if(bottom != -1
+ && line->GetPosition().y+line->GetHeight() >= bottom)
+ break;
line->Draw(dc, this, offset);
}
-#if 0
- else
- line->Layout(dc, this);
-#endif
- // little condition to speed up redrawing:
- if(bottom != -1 && line->GetPosition().y > bottom) break;
line = line->GetNextLine();
}
InvalidateUpdateRect();
bool *found)
{
// First, find the right line:
- wxLayoutLine *line = m_FirstLine;
+ wxLayoutLine
+ *line = m_FirstLine,
+ *lastline = m_FirstLine;
wxPoint p;
ApplyStyle(m_DefaultStyleInfo, dc);
p = line->GetPosition();
if(p.y <= pos.y && p.y+line->GetHeight() >= pos.y)
break;
-#if 0
- // we need to run a layout here to get font sizes right :-(
-
- // VZ: we can't call Layout() from here because it marks the line as
- // clean and it is not refreshed when it's called from wxLayoutList::
- // Layout() - if we really need to do this, we should introduce an
- // extra argument to Layout() to prevent the line from MarkClean()ing
- // itself here
- line->Layout(dc, this);
-#endif
+ lastline = line;
line = line->GetNextLine();
}
- if(line == NULL)
+
+ bool didFind = line != NULL;
+
+ if ( !line )
{
- if(found) *found = false;
- return NULL; // not found
+ // use the last line:
+ line = lastline;
}
- if(cursorPos) cursorPos->y = line->GetLineNumber();
+
+ if ( cursorPos )
+ cursorPos->y = line->GetLineNumber();
+
+ bool foundinline = true;
// Now, find the object in the line:
- wxLOiterator i = line->FindObjectScreen(dc, pos.x,
- cursorPos ? & cursorPos->x : NULL ,
- found);
+ wxLOiterator i = line->FindObjectScreen(dc, this,
+ pos.x,
+ cursorPos ? &cursorPos->x : NULL,
+ &foundinline);
+ if ( found )
+ *found = didFind && foundinline;
+
return (i == NULLIT) ? NULL : *i;
}
void
wxLayoutList::DrawCursor(wxDC &dc, bool active, wxPoint const &translate)
{
+ if ( m_movedCursor )
+ m_movedCursor = false;
+
wxPoint coords(m_CursorScreenPos);
coords += translate;
wxLogStatus("Cursor is at (%d, %d)", m_CursorPos.x, m_CursorPos.y);
#endif
-#ifndef WXLAYOUT_USE_CARET
- dc.SetBrush(*wxBLACK_BRUSH);
- dc.SetLogicalFunction(wxXOR);
+#ifdef WXLAYOUT_USE_CARET
+ m_caret->Move(coords);
+#else // !WXLAYOUT_USE_CARET
+ dc.SetBrush(*wxWHITE_BRUSH);
+ //FIXME: wxGTK XOR is borken at the moment!!!dc.SetLogicalFunction(wxXOR);
dc.SetPen(wxPen(*wxBLACK,1,wxSOLID));
if(active)
{
+ dc.SetLogicalFunction(wxXOR);
dc.DrawRectangle(coords.x, coords.y,
m_CursorSize.x, m_CursorSize.y);
SetUpdateRect(coords.x, coords.y);
}
else
{
+ dc.SetLogicalFunction(wxCOPY);
dc.DrawLine(coords.x, coords.y+m_CursorSize.y-1,
coords.x, coords.y);
SetUpdateRect(coords.x, coords.y+m_CursorSize.y-1);
m_Selection.m_valid =
m_Selection.m_selecting = false;
-
- // invalidate the area which was previousle selected - and which is not
- // selected any more
- if ( m_Selection.HasValidScreenCoords() )
- {
- SetUpdateRect(m_Selection.m_ScreenA);
- SetUpdateRect(m_Selection.m_ScreenB);
- }
- else
- {
- // TODO
- }
+ m_Selection.m_discarded = true;
}
bool
-wxLayoutList::IsSelecting(void)
+wxLayoutList::IsSelecting(void) const
{
return m_Selection.m_selecting;
}
bool
-wxLayoutList::IsSelected(const wxPoint &cursor)
+wxLayoutList::IsSelected(const wxPoint &cursor) const
{
if ( !HasSelection() )
return false;
return;
}
+ // We now know that the two lines are different:
wxLayoutLine
- * firstLine = NULL,
- * lastLine = NULL;
-
- for(firstLine = m_FirstLine;
- firstLine && firstLine->GetLineNumber() < m_Selection.m_CursorA.y;
- firstLine=firstLine->GetNextLine())
- ;
- if(!firstLine || firstLine->GetLineNumber() != m_Selection.m_CursorA.y)
- return;
-
-
- for(lastLine = m_FirstLine;
- lastLine && lastLine->GetLineNumber() < m_Selection.m_CursorB.y;
- lastLine=lastLine->GetNextLine())
- ;
- if(!lastLine || lastLine->GetLineNumber() != m_Selection.m_CursorB.y)
- return;
-
-
- // We now know that the two lines are different:
+ * firstLine = GetLine(m_Selection.m_CursorA.y),
+ * lastLine = GetLine(m_Selection.m_CursorB.y);
// First, delete what's left of this line:
MoveCursorTo(m_Selection.m_CursorA);
DeleteToEndOfLine();
- wxLayoutLine *nextLine = firstLine->GetNextLine();
+ wxLayoutLine *prevLine = firstLine->GetPreviousLine(),
+ *nextLine = firstLine->GetNextLine();
while(nextLine && nextLine != lastLine)
nextLine = nextLine->DeleteLine(false, this);
// Now nextLine = lastLine;
Delete(1); // This joins firstLine and nextLine
- Delete(m_Selection.m_CursorB.x); // This deletes the first x
- // positions
+ Delete(m_Selection.m_CursorB.x); // This deletes the first x positions
- /// Recalculate:
- firstLine->RecalculatePositions(1, this);
+ // Recalculate the line positions and numbers but notice that firstLine
+ // might not exist any more - it could be deleted by Delete(1) above
+ wxLayoutLine *firstLine2 = prevLine ? prevLine->GetNextLine() : m_FirstLine;
+ firstLine2->RecalculatePositions(1, this);
}
/// Starts highlighting the selection
int top, bottom;
top = (page - 1)*m_PrintoutHeight;
bottom = top + m_PrintoutHeight;
+
+ WXLO_DEBUG(("OnPrintPage(%d) printing from %d to %d", page, top,
+ bottom));
// SetDeviceOrigin() doesn't work here, so we need to manually
// translate all coordinates.
wxPoint translate(m_Offset.x,m_Offset.y-top);
float scale = ScaleDC(&psdc);
psdc.GetSize(&m_PageWidth, &m_PageHeight);
- // This sets a left/top origin of 15% and 20%:
- m_Offset = wxPoint((15*m_PageWidth)/100, m_PageHeight/20);
+
+ // This sets a left/top origin of 15% and 5%:
+ m_Offset = wxPoint((15*m_PageWidth)/100, (5*m_PageHeight)/100);
// This is the length of the printable area.
- m_PrintoutHeight = m_PageHeight - (int) (m_PageHeight * 0.15);
+ m_PrintoutHeight = m_PageHeight - 2*m_Offset.y;
m_PrintoutHeight = (int)( m_PrintoutHeight / scale); // we want to use the real paper height
-
+#if 0
+ // We should really use the margin settings of wxWindows somehow.
+ m_Offset = wxPoint(0,0);
+ // This is the length of the printable area.
+ m_PrintoutHeight = m_PageHeight;
+ m_PrintoutHeight = (int)( m_PrintoutHeight / scale); // we want to use the real paper height
+#endif
+
m_NumOfPages = 1 +
(int)( m_llist->GetSize().y / (float)(m_PrintoutHeight));