* $Id$
*******************************************************************/
-/*
-
- */
-
#ifdef __GNUG__
#pragma implementation "wxllist.h"
#endif
/// Use this character to estimate a cursor size when none is available.
#define WXLO_CURSORCHAR "E"
-
-/// Helper function, allows me to compare to wxPoints
+/** @name Helper functions */
+//@{
+/// allows me to compare to wxPoints
bool operator ==(wxPoint const &p1, wxPoint const &p2)
{
return p1.x == p2.x && p1.y == p2.y;
}
-/// Helper function, allows me to compare to wxPoints
+/// allows me to compare to wxPoints
bool operator !=(wxPoint const &p1, wxPoint const &p2)
{
return p1.x != p2.x || p1.y != p2.y;
}
+/// grows a wxRect so that it includes the given point
+
+static void GrowRect(wxRect &r, const wxPoint & p)
+{
+ if(r.x > p.x)
+ r.x = p.x;
+ else if(r.x + r.width < p.x)
+ r.width = p.x - r.x;
+
+ if(r.y > p.y)
+ r.y = p.y;
+ else if(r.y + r.height < p.y)
+ r.height = p.y - r.y;
+}
+//@}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
wxLayoutLine::FindObjectScreen(wxDC &dc, CoordType xpos, CoordType *cxpos) const
{
wxASSERT(cxpos);
- wxASSERT(xpos);
+ wxASSERT(cxpos);
wxLayoutObjectList::iterator i;
CoordType x = 0, cx = 0, width;
if(m_Next && objHeight != oldHeight)
m_Next->RecalculatePositions();
+ // We need to check whether we found a valid cursor size:
if(cursorPos)
{
// this might be the case if the cursor is at the end of the
{
do
{
- if( isspace(((wxLayoutObjectText*)*i)->GetText()[offset]))
+ if( isspace(((wxLayoutObjectText*)*i)->GetText()[(size_t)offset]))
return column;
else
{
{
m_DefaultSetting = NULL;
m_FirstLine = NULL;
+ InvalidateUpdateRect();
Clear();
}
if(bottom != -1 && line->GetPosition().y > bottom) break;
line = line->GetNextLine();
}
+
+///FIXME: disabled for now
+#if 0
// can only be 0 if we are on the first line and have no next line
wxASSERT(m_CursorSize.x != 0 || (m_CursorLine &&
m_CursorLine->GetNextLine() == NULL &&
m_CursorLine == m_FirstLine));
+#endif
}
void
Layout(dc, bottom);
m_DefaultSetting->Draw(dc, wxPoint(0,0));
+ wxBrush *brush = new wxBrush(*m_ColourBG, wxSOLID);
+ dc.SetBrush(*brush);
+ delete brush;
+
while(line)
{
// only draw if between top and bottom:
if((top == -1 || line->GetPosition().y >= top))
line->Draw(dc, offset);
// little condition to speed up redrawing:
- if(bottom != -1 && line->GetPosition().y > bottom) break;
+ if(bottom != -1 && line->GetPosition().y + line->GetHeight() > bottom) break;
line = line->GetNextLine();
}
// can only be 0 if we are on the first line and have no next line
if(! line)
return wxPoint(0,0);
- wxPoint max(0,0);
+ wxPoint maxPoint(0,0);
// find last line:
while(line)
{
- if(line->GetWidth() > max.x) max.x = line->GetWidth();
+ if(line->GetWidth() > maxPoint.x)
+ maxPoint.x = line->GetWidth();
last = line;
line = line->GetNextLine();
}
- max.y = last->GetPosition().y + last->GetHeight();
- return max;
+ maxPoint.y = last->GetPosition().y + last->GetHeight();
+ return maxPoint;
}
void
dc.SetBrush(*wxBLACK_BRUSH);
dc.SetLogicalFunction(wxXOR);
dc.SetPen(wxPen(*wxBLACK,1,wxSOLID));
- dc.SetLogicalFunction(wxXOR);
if(active)
dc.DrawRectangle(coords.x, coords.y, m_CursorSize.x,
m_CursorSize.y);
dc.DrawLine(coords.x, coords.y+m_CursorSize.y-1,
coords.x+m_CursorSize.x, coords.y+m_CursorSize.y-1);
dc.SetLogicalFunction(wxCOPY);
- dc.SetBrush(wxNullBrush);
+ //dc.SetBrush(wxNullBrush);
}
+/** Called by the objects to update the update rectangle.
+ @param p a point to include in it
+*/
+void
+wxLayoutList::SetUpdateRect(const wxPoint &p)
+{
+ if(m_UpdateRectValid)
+ GrowRect(m_UpdateRect, p);
+ else
+ {
+ m_UpdateRect.x = p.x;
+ m_UpdateRect.y = p.y;
+ m_UpdateRect.width = 4; // large enough to avoid surprises from
+ m_UpdateRect.height = 4;// wxGTK :-)
+ m_UpdateRectValid = true;
+ }
+}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
m_PrintoutHeight = (int)( m_PrintoutHeight / scale); // we want to use the real paper height
- m_NumOfPages = (int)( m_llist->GetSize().y / (float)(m_PrintoutHeight) + 0.5);
+ m_NumOfPages = 1 +
+ (int)( m_llist->GetSize().y / (float)(m_PrintoutHeight));
- // This is a crude hack to get it right for very small
- // printouts. No idea why this is required, I thought +0.5 would do
- // the job. :-(
- if(m_NumOfPages == 0 && m_llist->GetSize().y > 0)
- m_NumOfPages = 1;
*minPage = 1;
*maxPage = m_NumOfPages;
/** Makes a copy of this object.
*/
virtual wxLayoutObject *Copy(void) = 0;
-private:
+protected:
/// optional data for application's use
UserData *m_UserData;
};
wxPoint const pos,
wxPoint *cursorPos = NULL);
+ /** Called by the objects to update the update rectangle.
+ @param p a point to include in it
+ */
+ void SetUpdateRect(const wxPoint &p);
+ /// Invalidates the update rectangle.
+ void InvalidateUpdateRect(void) { m_UpdateRectValid = false; }
+ /// Returns the update rectangle.
+ const wxRect *GetUpdateRect(void) const { return &m_UpdateRect; }
//@}
/**@name For exporting one object after another. */
/// The list of lines.
wxLayoutLine *m_FirstLine;
+ /// The update rectangle which needs to be refreshed:
+ wxRect m_UpdateRect;
+ /// Is the update rectangle valid?
+ bool m_UpdateRectValid;
/**@name Cursor Management */
//@{
/// Where the text cursor (column,line) is.
// in addition to Unix EOL convention we also (but not instead) understand
// the DOS one under Windows
return
- ((mode & WXLO_EXPORT_WITH_MASK) == WXLO_EXPORT_WITH_CRLF) ?
+ (mode == WXLO_EXPORT_WITH_CRLF) ?
((*p == '\r') && (*(p + 1) == '\n'))
:
(((*p == '\r') && (*(p + 1) == '\n'))||(*p == '\n'));
#define WXLO_IS_TEXT(type) \
( type == WXLO_TYPE_TEXT \
|| (type == WXLO_TYPE_CMD \
- && (mode & WXLO_EXPORT_AS_MASK) == WXLO_EXPORT_AS_HTML))
+ && mode == WXLO_EXPORT_AS_HTML))
wxLayoutExportObject *wxLayoutExport(wxLayoutExportStatus *status,
- int mode)
+ int mode, int flags)
{
wxASSERT(status);
wxLayoutExportObject * export;
if(status->m_iterator == NULLIT) // end of line
{
- if(!status->m_line || status->m_line->GetNextLine() == NULL) // reached end of list
+ if(!status->m_line || status->m_line->GetNextLine() == NULL)
+ // reached end of list
return NULL;
- else
+ }
+ export = new wxLayoutExportObject();
+ wxLayoutObjectType type;
+ if(status->m_iterator != NULLIT)
+ {
+ type = (** status->m_iterator).GetType();
+ if( mode == WXLO_EXPORT_AS_OBJECTS || ! WXLO_IS_TEXT(type)) // simple case
{
- status->m_line = status->m_line->GetNextLine();
- status->m_iterator = status->m_line->GetFirstObject();
- export = new wxLayoutExportObject();;
- if( (mode & WXLO_EXPORT_AS_MASK) == WXLO_EXPORT_AS_OBJECTS) // simple case
- {
- export->type = WXLO_EXPORT_OBJECT;
- export->content.object = *status->m_iterator;
- status->m_iterator++;
- return export;
- }
- //else: text object:
- export->type = ((mode & WXLO_EXPORT_AS_MASK) == WXLO_EXPORT_AS_HTML)
- ? WXLO_EXPORT_HTML : WXLO_EXPORT_TEXT;
- if((mode & WXLO_EXPORT_WITH_CRLF) == WXLO_EXPORT_WITH_CRLF)
- export->content.text = new wxString("\r\n");
- else
- export->content.text = new wxString("\n");
+ export->type = WXLO_EXPORT_OBJECT;
+ export->content.object = *status->m_iterator;
+ status->m_iterator++;
return export;
}
}
-
- export = new wxLayoutExportObject();
- wxLayoutObjectType type = (** status->m_iterator).GetType();
- if( (mode & WXLO_EXPORT_AS_MASK) == WXLO_EXPORT_AS_OBJECTS || ! WXLO_IS_TEXT(type)) // simple case
- {
- export->type = WXLO_EXPORT_OBJECT;
- export->content.object = *status->m_iterator;
- status->m_iterator++;
- return export;
+ else
+ { // iterator == NULLIT
+ if(mode == WXLO_EXPORT_AS_OBJECTS)
+ {
+ export->type = WXLO_EXPORT_EMPTYLINE;
+ export->content.object = NULL; //empty line
+ status->m_line = status->m_line->GetNextLine();
+ if(status->m_line)
+ status->m_iterator = status->m_line->GetFirstObject();
+ return export;
+ }
+ else
+ type = WXLO_TYPE_TEXT;
}
- // else: must be text
wxString *str = new wxString();
// text must be concatenated
- do
+ int testf = WXLO_EXPORT_WITH_CRLF;
+ for(;;)
{
+ while(status->m_iterator == NULLIT)
+ {
+ if(flags & WXLO_EXPORT_AS_HTML)
+ *str += "<br>";
+ if(flags & WXLO_EXPORT_WITH_CRLF)
+ *str += "\r\n";
+ else
+ *str += '\n';
+
+ status->m_line = status->m_line->GetNextLine();
+ if(status->m_line)
+ status->m_iterator = status->m_line->GetFirstObject();
+ else
+ break; // end of list
+ }
+ if(! status->m_line) // reached end of list, fall through
+ break;
+ type = (** status->m_iterator).GetType();
+ if(type == WXLO_TYPE_ICON)
+ break;
switch(type)
{
case WXLO_TYPE_TEXT:
*str += ((wxLayoutObjectText *)*status->m_iterator)->GetText();
break;
case WXLO_TYPE_CMD:
- wxASSERT_MSG( (mode&WXLO_EXPORT_AS_MASK) == WXLO_EXPORT_AS_HTML,
+ wxASSERT_MSG( mode == WXLO_EXPORT_AS_HTML,
"reached cmd object in text mode" );
*str += wxLayoutExportCmdAsHTML(*(wxLayoutObjectCmd const
;
}
status->m_iterator++;
- if(status->m_iterator == NULLIT) // end of line!
- {
- if((mode & WXLO_EXPORT_AS_MASK) == WXLO_EXPORT_AS_HTML)
- *str += "<br>";
- if((mode & WXLO_EXPORT_WITH_CRLF) == WXLO_EXPORT_WITH_CRLF)
- *str += "\r\n";
- else
- *str += '\n';
- status->m_line = status->m_line->GetNextLine();
- if(status->m_line)
- status->m_iterator = status->m_line->GetFirstObject();
- else
- status->m_iterator = NULLIT;
- }
- if(status->m_iterator != NULLIT)
- type = (** status->m_iterator).GetType();
- else
- break;
}
- while(WXLO_IS_TEXT(type));
- export->type = ((mode & WXLO_EXPORT_AS_MASK) == WXLO_EXPORT_AS_HTML)
+ export->type = (mode == WXLO_EXPORT_AS_HTML)
? WXLO_EXPORT_HTML : WXLO_EXPORT_TEXT;
export->content.text = str;
return export;
{
WXLO_EXPORT_TEXT,
WXLO_EXPORT_HTML,
- WXLO_EXPORT_OBJECT
+ WXLO_EXPORT_OBJECT,
+ // this can be caused by empty lines:
+ WXLO_EXPORT_EMPTYLINE
};
enum wxLayoutExportMode
{
- WXLO_EXPORT_AS_MASK = 0x0f,
WXLO_EXPORT_AS_TEXT = 0x00,
WXLO_EXPORT_AS_TEXT_AND_COMMANDS = 0x01,
WXLO_EXPORT_AS_HTML = 0x02,
WXLO_EXPORT_AS_OBJECTS = 0x03,
-
- WXLO_EXPORT_WITH_MASK = 0xf0,
- WXLO_EXPORT_WITH_CRLF = 0x00,
- WXLO_EXPORT_WITH_LF_ONLY = 0x10
+
+ // non 0:
+ WXLO_EXPORT_WITH_CRLF = 0x10,
+ WXLO_EXPORT_WITH_LF_ONLY = 0x20
};
struct wxLayoutExportObject
int withflag = WXLO_EXPORT_WITH_CRLF);
wxLayoutExportObject *wxLayoutExport(wxLayoutExportStatus *status,
- int mode = WXLO_EXPORT_AS_TEXT|WXLO_EXPORT_WITH_CRLF);
+ int mode = WXLO_EXPORT_AS_TEXT,
+ int flags = WXLO_EXPORT_WITH_CRLF);
#else
/// import text into a wxLayoutList (including linefeeds):
void wxLayoutImportText(wxLayoutList *list, wxString const &str,
int withflag = WXLO_EXPORT_WITH_LF_ONLY);
-/// export text in a given format FIXME-MT: not thread safe, uses static variable
+/// export text in a given format
wxLayoutExportObject *wxLayoutExport(wxLayoutExportStatus *status,
- int mode = WXLO_EXPORT_AS_TEXT|WXLO_EXPORT_WITH_LF_ONLY
+ int mode = WXLO_EXPORT_AS_TEXT,
+ int flags = WXLO_EXPORT_WITH_LF_ONLY
);
#endif
# include "gui/wxMenuDefs.h"
# include "gui/wxMApp.h"
# endif // USE_PCH
+
# include "gui/wxlwindow.h"
+# include "gui/wxlparser.h"
#else
# ifdef __WXMSW__
# include <windows.h>
# undef GetCharWidth
# undef StartDoc
# endif
+
# include "wxlwindow.h"
# include "wxlparser.h"
#endif
-#include <ctype.h>
#include <wx/clipbrd.h>
+#include <wx/dataobj.h>
+
+#include <ctype.h>
+/// offsets to put a nice frame around text
#define WXLO_XOFFSET 4
#define WXLO_YOFFSET 4
+/// offset to the right and bottom for when to redraw scrollbars
+#define WXLO_ROFFSET 20
+#define WXLO_BOFFSET 20
+
BEGIN_EVENT_TABLE(wxLayoutWindow,wxScrolledWindow)
EVT_PAINT (wxLayoutWindow::OnPaint)
EVT_CHAR (wxLayoutWindow::OnChar)
m_bitmap = new wxBitmap(4,4);
m_bitmapSize = wxPoint(4,4);
m_llist = new wxLayoutList();
+ m_BGbitmap = NULL;
SetWrapMargin(0);
wxPoint max = m_llist->GetSize();
SetScrollbars(10, 20 /*lineHeight*/, max.x/10+1, max.y/20+1);
delete m_memDC; // deletes bitmap automatically (?)
delete m_bitmap;
delete m_llist;
- delete m_PopupMenu;
+ delete m_PopupMenu;
+ SetBackgroundBitmap(NULL);
}
#ifdef __WXMSW__
wxPaintDC dc( this );
PrepareDC( dc );
SetFocus();
+
wxPoint findPos;
findPos.x = dc.DeviceToLogicalX(event.GetX());
if(findPos.x < 0) findPos.x = 0;
if(findPos.y < 0) findPos.y = 0;
-
+
+ m_ClickPosition = wxPoint(event.GetX(), event.GetY());
#ifdef WXLAYOUT_DEBUG
wxLogDebug("wxLayoutWindow::OnMouse: (%d, %d) -> (%d, %d)",
event.GetX(), event.GetY(), findPos.x, findPos.y);
#endif
- m_ClickPosition = findPos;
wxPoint cursorPos;
wxLayoutObject *obj = m_llist->FindObjectScreen(dc, findPos, &cursorPos);
&& (! obj || (obj && obj->GetUserData() == NULL))
)
{
- PopupMenu(m_PopupMenu, event.GetX(), event.GetY());
+ PopupMenu(m_PopupMenu, m_ClickPosition.x, m_ClickPosition.y);
return;
}
// find the object at this position
}
}
SetDirty();
+ SetModified();
DoPaint(true); // paint and scroll to cursor
}
#ifdef __WXGTK__
InternalPaint();
#else
- Refresh();
+ Refresh(FALSE); // Causes bad flicker under wxGTK!!!
#endif
}
// Get the size of the visible window:
GetClientSize(&x1,&y1);
wxASSERT(x1 > 0);
-
wxASSERT(y1 > 0);
+ // As we have the values anyway, use them to avoid unnecessary
+ // scrollbar updates.
+ if(x1 > m_maxx) m_maxx = x1;
+ if(y1 > m_maxy) m_maxy = y1;
// Maybe we need to change the scrollbar sizes or positions,
// so layout the list and check:
// Device origins on the memDC are suspect, we translate manually
// with the translate parameter of Draw().
m_memDC->SetDeviceOrigin(0,0);
- m_memDC->Clear();
+ 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->SetLogicalFunction(wxCOPY);
+ if(m_BGbitmap)
+ {
+ CoordType
+ y, x,
+ w = m_BGbitmap->GetWidth(),
+ h = m_BGbitmap->GetHeight();
+ for(y = 0; y < y1; y+=h)
+ for(x = 0; x < x1; x+=w)
+ m_memDC->DrawBitmap(*m_BGbitmap, x, y);
+ }
+ else
+ m_memDC->DrawRectangle(0,0,x1, y1);
// The offsets give the window a tiny border on the left and top, looks nice.
wxPoint offset(-x0+WXLO_XOFFSET,-y0+WXLO_YOFFSET);
m_llist->Draw(*m_memDC,offset);
if(IsEditable())
m_llist->DrawCursor(*m_memDC,m_HaveFocus,offset);
+
// Now copy everything to the screen:
- dc.Blit(x0,y0,x1,y1,m_memDC,0,0,wxCOPY,FALSE);
+ wxRegionIterator ri ( GetUpdateRegion() );
+ if(ri)
+ while(ri)
+ {
+ dc.Blit(x0+ri.GetX(),y0+ri.GetY(),ri.GetW(),ri.GetH(),
+ m_memDC,ri.GetX(),ri.GetY(),wxCOPY,FALSE);
+ ri++;
+ }
+ else
+ // 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
+ // all. The wxLayoutList could handle this, creating a list or
+ // at least one large rectangle of changes. FIXME
+ dc.Blit(x0,y0,x1,y1,m_memDC,0,0,wxCOPY,FALSE);
-
ResetDirty();
}
wxLayoutWindow::ResizeScrollbars(bool exact)
{
wxPoint max = m_llist->GetSize();
-
+
if(max.x > m_maxx || max.y > m_maxy
- || max.x < (7*m_maxx)/10 || max.y << (7*m_maxy)/10
+ || max.x > m_maxx-WXLO_ROFFSET || max.y > m_maxy-WXLO_BOFFSET
|| exact)
{
- if(! exact) // add an extra 20% to the sizes to avoid future updates
+ if(! exact)
{
- max.x = (12*max.x)/10; // 12/20 = 120%
- max.y = (12*max.y)/10;
+ // add an extra bit to the sizes to avoid future updates
+ max.x = max.x+WXLO_ROFFSET;
+ max.y = max.y+WXLO_BOFFSET;
}
ViewStart(&m_ViewStartX, &m_ViewStartY);
SetScrollbars(10, 20, max.x/10+1,max.y/20+1,m_ViewStartX,m_ViewStartY,true);
{
GetLayoutList()->Clear(family,size,style,weight,underline,fg,bg);
SetBackgroundColour(*GetLayoutList()->GetDefaults()->GetBGColour());
+ ResizeScrollbars(true);
SetDirty();
+ SetModified(false);
DoPaint();
}
-
+ /** Sets a background image, only used on screen, not on printouts.
+ @param bitmap a pointer to a wxBitmap or NULL to remove it
+ */
+ void SetBackgroundBitmap(wxBitmap *bitmap = NULL)
+ {
+ if(m_BGbitmap) delete m_BGbitmap;
+ m_BGbitmap = bitmap;
+ }
/// Enable or disable editing, i.e. processing of keystrokes.
void SetEditable(bool toggle) { m_Editable = toggle; }
/// Query whether list can be edited by user.
//@}
/// Redraws the window, used by DoPaint() or OnPaint().
void InternalPaint(void);
+
+ /// Has list been modified/edited?
+ bool IsModified(void) const { return m_Modified; }
+ /// Mark list as modified or unchanged.
+ void SetModified(bool modified = true) { m_Modified = modified; }
+
protected:
/// generic function for mouse events processing
void OnMouse(int eventId, wxMouseEvent& event);
private:
/// The layout list to be displayed.
wxLayoutList *m_llist;
-
/// Can user edit the window?
bool m_Editable;
/// wrap margin
CoordType m_WrapMargin;
- /// Is list dirty?
+ /// Is list dirty (for redraws, internal use)?
bool m_Dirty;
+ /// Has list been edited?
+ bool m_Modified;
wxMemoryDC *m_memDC;
wxBitmap *m_bitmap;
wxPoint m_bitmapSize;
-
+ /// a pointer to a bitmap for the background
+ wxBitmap *m_BGbitmap;
DECLARE_EVENT_TABLE()
};