added groups of canvasobject and references to groups

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@8307 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Kevin Hock 2000-09-08 18:42:57 +00:00
parent afdefa8e84
commit fcbb6b37bf
3 changed files with 586 additions and 155 deletions

View File

@ -41,7 +41,7 @@ public:
// These are for screen output only therefore use // These are for screen output only therefore use
// int as coordinates. // int as coordinates.
virtual bool IsHit( int x, int y, int margin = 0 ); virtual bool IsHit( int x, int y, int margin = 0 );
virtual void Render( int clip_x, int clip_y, int clip_width, int clip_height ); virtual void Render(int xabs, int yabs, int clip_x, int clip_y, int clip_width, int clip_height );
// use doubles later // use doubles later
virtual void Move( int x, int y ); virtual void Move( int x, int y );
@ -55,7 +55,7 @@ public:
virtual void WriteSVG( wxTextOutputStream &stream ); virtual void WriteSVG( wxTextOutputStream &stream );
wxCanvas *GetOwner() { return m_owner; } wxCanvas *GetOwner() { return m_owner; }
void SetOwner( wxCanvas *owner ) { m_owner = owner; } virtual void SetOwner( wxCanvas *owner ) { m_owner = owner; }
bool IsControl() { return m_isControl; } bool IsControl() { return m_isControl; }
bool IsVector() { return m_isVector; } bool IsVector() { return m_isVector; }
@ -74,11 +74,99 @@ protected:
bool m_isControl; bool m_isControl;
bool m_isVector; bool m_isVector;
bool m_isImage; bool m_isImage;
//relative boundingbox in parent in pixels
wxRect m_area; wxRect m_area;
friend class wxCanvas; friend class wxCanvas;
}; };
//----------------------------------------------------------------------------
// wxCanvasObjectGroup
//----------------------------------------------------------------------------
class wxCanvasObjectGroup
{
public:
wxCanvasObjectGroup();
void SetOwner(wxCanvas* canvas);
wxCanvas *GetOwner() { return m_owner; }
virtual void Prepend( wxCanvasObject* obj );
virtual void Append( wxCanvasObject* obj );
virtual void Insert( size_t before, wxCanvasObject* obj );
virtual void Remove( wxCanvasObject* obj );
virtual void Recreate();
void DeleteContents( bool );
virtual void Render(int xabs, int yabs,int x, int y, int width, int height );
virtual void WriteSVG( wxTextOutputStream &stream );
virtual bool IsHit( int x, int y, int margin );
virtual wxCanvasObject* IsHitObject( int x, int y, int margin );
void ExtendArea(int x, int y);
inline int GetXMin() { return m_minx; }
inline int GetYMin() { return m_miny; }
inline int GetXMax() { return m_maxx; }
inline int GetYMax() { return m_maxy; }
protected:
wxCanvas *m_owner;
//bounding box
double m_minx;
double m_miny;
double m_maxx;
double m_maxy;
bool m_validbounds;
wxList m_objects;
friend class wxCanvas;
};
//----------------------------------------------------------------------------
// wxCanvasObjectGroupRef
//----------------------------------------------------------------------------
class wxCanvasObjectGroupRef: public wxCanvasObject
{
public:
wxCanvasObjectGroupRef(double x, double y,wxCanvasObjectGroup* group);
void SetOwner(wxCanvas* canvas);
virtual void Recreate();
virtual void Render(int xabs, int yabs,int x, int y, int width, int height );
virtual void WriteSVG( wxTextOutputStream &stream );
virtual bool IsHit( int x, int y, int margin );
void Move( int x, int y );
inline int GetPosX() { return m_x; }
inline int GetPosY() { return m_y; }
void ExtendArea(int x, int y);
virtual wxCanvasObject* IsHitObject( int x, int y, int margin );
protected:
//position of the group
double m_x;
double m_y;
//reference to the group
wxCanvasObjectGroup* m_group;
//bounding box
double m_minx;
double m_miny;
double m_maxx;
double m_maxy;
bool m_validbounds;
};
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// wxCanvasRect // wxCanvasRect
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -91,7 +179,7 @@ public:
virtual void Recreate(); virtual void Recreate();
virtual void Render( int clip_x, int clip_y, int clip_width, int clip_height ); virtual void Render(int xabs, int yabs, int clip_x, int clip_y, int clip_width, int clip_height );
virtual void WriteSVG( wxTextOutputStream &stream ); virtual void WriteSVG( wxTextOutputStream &stream );
private: private:
@ -117,7 +205,7 @@ public:
virtual void Recreate(); virtual void Recreate();
virtual void Render( int clip_x, int clip_y, int clip_width, int clip_height ); virtual void Render(int xabs, int yabs, int clip_x, int clip_y, int clip_width, int clip_height );
virtual void WriteSVG( wxTextOutputStream &stream ); virtual void WriteSVG( wxTextOutputStream &stream );
private: private:
@ -142,7 +230,7 @@ public:
virtual void Recreate(); virtual void Recreate();
virtual void Render( int clip_x, int clip_y, int clip_width, int clip_height ); virtual void Render(int xabs, int yabs, int clip_x, int clip_y, int clip_width, int clip_height );
virtual void WriteSVG( wxTextOutputStream &stream ); virtual void WriteSVG( wxTextOutputStream &stream );
private: private:
@ -185,7 +273,7 @@ public:
void Recreate(); void Recreate();
virtual void Render( int clip_x, int clip_y, int clip_width, int clip_height ); virtual void Render(int xabs, int yabs, int clip_x, int clip_y, int clip_width, int clip_height );
virtual void WriteSVG( wxTextOutputStream &stream ); virtual void WriteSVG( wxTextOutputStream &stream );
void SetRGB( unsigned char red, unsigned char green, unsigned char blue ); void SetRGB( unsigned char red, unsigned char green, unsigned char blue );
@ -264,7 +352,8 @@ private:
int m_bufferY; int m_bufferY;
bool m_needUpdate; bool m_needUpdate;
wxList m_updateRects; wxList m_updateRects;
wxList m_objects; wxCanvasObjectGroup* m_root;
unsigned char m_green,m_red,m_blue; unsigned char m_green,m_red,m_blue;
bool m_frozen; bool m_frozen;
bool m_requestNewBuffer; bool m_requestNewBuffer;

View File

@ -76,6 +76,53 @@ void MywxCanvasImage::OnMouse(wxMouseEvent &event)
} }
} }
class MywxCanvasObjectGroupRef: public wxCanvasObjectGroupRef
{
public:
MywxCanvasObjectGroupRef(double x, double y, wxCanvasObjectGroup* group);
void OnMouse(wxMouseEvent &event);
DECLARE_EVENT_TABLE()
};
BEGIN_EVENT_TABLE(MywxCanvasObjectGroupRef,wxCanvasObjectGroupRef)
EVT_MOUSE_EVENTS( MywxCanvasObjectGroupRef::OnMouse )
END_EVENT_TABLE()
MywxCanvasObjectGroupRef::MywxCanvasObjectGroupRef(double x, double y,wxCanvasObjectGroup* group)
:wxCanvasObjectGroupRef(x,y,group)
{
}
void MywxCanvasObjectGroupRef::OnMouse(wxMouseEvent &event)
{
static bool first=false;
static dx=0;
static dy=0;
//new position of object
int x = m_owner->GetDeviceX( event.GetX());
int y = m_owner->GetDeviceY( event.GetY());
if (event.m_leftDown)
{ if (!first)
{
first=true;
dx=x;
dy=y;
}
Move(m_x+x-dx,m_y+y-dy);
CaptureMouse();
}
else if (IsCapturedMouse())
{
ReleaseMouse();
first=false;
dx=0;dy=0;
}
}
class MyFrame; class MyFrame;
class MyApp; class MyApp;
@ -97,6 +144,10 @@ public:
wxCanvasObject *m_sm2; wxCanvasObject *m_sm2;
wxCanvasObject *m_sm3; wxCanvasObject *m_sm3;
wxCanvasObject *m_sm4; wxCanvasObject *m_sm4;
MywxCanvasObjectGroupRef *m_ref;
MywxCanvasObjectGroupRef *m_ref2;
wxTimer *m_timer; wxTimer *m_timer;
wxTextCtrl *m_log; wxTextCtrl *m_log;
@ -137,7 +188,7 @@ END_EVENT_TABLE()
MyFrame::MyFrame() MyFrame::MyFrame()
: wxFrame( (wxFrame *)NULL, -1, "wxCanvas sample", : wxFrame( (wxFrame *)NULL, -1, "wxCanvas sample",
wxPoint(20,20), wxSize(470,460) ) wxPoint(20,20), wxSize(470,860) )
{ {
wxMenu *file_menu = new wxMenu(); wxMenu *file_menu = new wxMenu();
file_menu->Append( ID_ABOUT, "&About..."); file_menu->Append( ID_ABOUT, "&About...");
@ -158,12 +209,13 @@ MyFrame::MyFrame()
m_canvas->SetArea( 1400, 600 ); m_canvas->SetArea( 1400, 600 );
m_canvas->SetColour( 255, 255, 255 ); m_canvas->SetColour( 255, 255, 255 );
wxBitmap bitmap( smile_xpm ); wxBitmap bitmap( smile_xpm );
wxImage image( bitmap ); wxImage image( bitmap );
m_sm1 = new wxCanvasImage( image, 0,70,16,16 ); m_sm1 = new wxCanvasImage( image, 0,70,16,16 );
m_canvas->Append( m_sm1 ); m_canvas->Append( m_sm1 );
int i; int i;
for (i = 10; i < 300; i+=10) for (i = 10; i < 300; i+=10)
m_canvas->Append( new wxCanvasRect( i,50,3,140, 255,0,0 ) ); m_canvas->Append( new wxCanvasRect( i,50,3,140, 255,0,0 ) );
@ -189,9 +241,35 @@ MyFrame::MyFrame()
m_sm4 = new MywxCanvasImage( image, 0,270,64,32 ); m_sm4 = new MywxCanvasImage( image, 0,270,64,32 );
m_canvas->Append( m_sm4 ); m_canvas->Append( m_sm4 );
// m_canvas->Append( new wxCanvasLine( 10,-1500e6,50,300000e6, 0,255,0 ) ); // m_canvas->Append( new wxCanvasLine( 10,-1500e6,50,300000e6, 0,255,0 ) );
// m_canvas->Append( new wxCanvasLine( 10,-150000,50,300000, 0,255,0 ) ); // m_canvas->Append( new wxCanvasLine( 10,-150000,50,300000, 0,255,0 ) );
//make a group of wxCanvasObjects
wxCanvasObjectGroup* group1 = new wxCanvasObjectGroup();
group1->Prepend( new wxCanvasLine( 10,-35,50,190,100,255,0 ) );
group1->Prepend( new wxCanvasImage( image, 4,38,32,32 ) );
group1->Prepend( new wxCanvasRect(20,-20,50,170,0,20,240 ) );
group1->Prepend( new wxCanvasRect(10,20,104,52,0,240,240 ) );
//make another group of wxCanvasObjects
wxCanvasObjectGroup* group2 = new wxCanvasObjectGroup();
group2->Prepend( new wxCanvasImage( image, 60,38,52,32 ) );
group2->Prepend( new wxCanvasRect(10,20,104,52,10,40,10 ) );
//this a reference to group2 put into group1
wxCanvasObjectGroupRef* m_subref = new wxCanvasObjectGroupRef(60,50, group2);
group1->Prepend( m_subref );
//now make two refrences to group1 into root group of the canvas
m_ref = new MywxCanvasObjectGroupRef(40,200, group1);
m_canvas->Prepend( m_ref );
m_ref2 = new MywxCanvasObjectGroupRef(80,350, group1);
m_canvas->Prepend( m_ref2 );
m_log = new wxTextCtrl( this, -1, "", wxPoint(0,0), wxSize(100,100), wxTE_MULTILINE ); m_log = new wxTextCtrl( this, -1, "", wxPoint(0,0), wxSize(100,100), wxTE_MULTILINE );
wxLog *old_log = wxLog::SetActiveTarget( new wxLogTextCtrl( m_log ) ); wxLog *old_log = wxLog::SetActiveTarget( new wxLogTextCtrl( m_log ) );
delete old_log; delete old_log;
@ -220,11 +298,13 @@ void MyFrame::OnQuit( wxCommandEvent &WXUNUSED(event) )
void MyFrame::OnTimer( wxTimerEvent &WXUNUSED(event) ) void MyFrame::OnTimer( wxTimerEvent &WXUNUSED(event) )
{ {
m_sm1->Move( m_sm1->GetX()+1, m_sm1->GetY() ); m_sm1->Move( m_sm1->GetX()+1, m_sm1 ->GetY() );
m_sm2->Move( m_sm2->GetX()+1, m_sm2->GetY() ); m_sm2->Move( m_sm2->GetX()+1, m_sm2->GetY() );
m_sm3->Move( m_sm3->GetX()+1, m_sm3->GetY() ); m_sm3->Move( m_sm3->GetX()+1, m_sm3->GetY() );
m_sm4->Move( m_sm4->GetX()+1, m_sm4->GetY() ); m_sm4->Move( m_sm4->GetX()+2, m_sm4->GetY() );
m_ref->Move( m_ref->GetPosX()+1, m_ref->GetPosY() );
m_ref2->Move( m_ref2->GetPosX()+2, m_ref2->GetPosY() );
wxWakeUpIdle(); wxWakeUpIdle();
} }
@ -242,6 +322,7 @@ void MyFrame::OnAbout( wxCommandEvent &WXUNUSED(event) )
bool MyApp::OnInit() bool MyApp::OnInit()
{ {
m_fontpath = getenv("TRUETYPE"); m_fontpath = getenv("TRUETYPE");
m_fontpath = "c:\WINNT\Fonts\times.ttf";
if ( !m_fontpath ) if ( !m_fontpath )
{ {
wxLogError("Please set env var TRUETYPE to the path where times.ttf lives."); wxLogError("Please set env var TRUETYPE to the path where times.ttf lives.");

View File

@ -114,7 +114,7 @@ bool wxCanvasObject::IsCapturedMouse()
} }
void wxCanvasObject::Render( int clip_x, int clip_y, int clip_width, int clip_height ) void wxCanvasObject::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_width, int clip_height )
{ {
} }
@ -126,6 +126,322 @@ void wxCanvasObject::WriteSVG( wxTextOutputStream &stream )
{ {
} }
//----------------------------------------------------------------------------
// wxCanvasObjectGroup
//----------------------------------------------------------------------------
wxCanvasObjectGroup::wxCanvasObjectGroup()
{
m_validbounds=false;
}
void wxCanvasObjectGroup::SetOwner(wxCanvas* canvas)
{
m_owner=canvas;
wxNode *node = m_objects.First();
while (node)
{
wxCanvasObject *obj = (wxCanvasObject*) node->Data();
obj->SetOwner(canvas);
node = node->Next();
}
}
void wxCanvasObjectGroup::ExtendArea(int x, int y)
{
if (m_validbounds)
{
if ( x < m_minx ) m_minx = x;
if ( y < m_miny ) m_miny = y;
if ( x > m_maxx ) m_maxx = x;
if ( y > m_maxy ) m_maxy = y;
}
else
{
m_validbounds = true;
m_minx = x;
m_miny = y;
m_maxx = x;
m_maxy = y;
}
}
void wxCanvasObjectGroup::DeleteContents( bool flag)
{
m_objects.DeleteContents( flag );
m_validbounds=false;
}
void wxCanvasObjectGroup::Prepend( wxCanvasObject* obj )
{
m_objects.Insert( obj );
m_validbounds=false;
}
void wxCanvasObjectGroup::Append( wxCanvasObject* obj )
{
m_objects.Append( obj );
m_validbounds=false;
}
void wxCanvasObjectGroup::Insert( size_t before, wxCanvasObject* obj )
{
m_objects.Insert( before, obj );
m_validbounds=false;
}
void wxCanvasObjectGroup::Remove( wxCanvasObject* obj )
{
m_objects.DeleteObject( obj );
m_validbounds=false;
}
void wxCanvasObjectGroup::Recreate()
{
m_validbounds=false;
wxNode *node = m_objects.First();
while (node)
{
wxCanvasObject *obj = (wxCanvasObject*) node->Data();
obj->Recreate();
ExtendArea(obj->GetX(),obj->GetY());
ExtendArea(obj->GetX()+obj->GetWidth(),obj->GetY()+obj->GetHeight());
node = node->Next();
}
}
void wxCanvasObjectGroup::Render(int xabs, int yabs, int x, int y, int width, int height )
{
wxImage *image = m_owner->GetBuffer();
// cycle through all objects
wxNode *node = m_objects.First();
while (node)
{
wxCanvasObject *obj = (wxCanvasObject*) node->Data();
if (!obj->IsControl())
{
// If we have 10.000 objects, we will go through
// this 10.000 times for each update, so we have
// to optimise carefully.
int clip_x = xabs + obj->GetX();
int clip_width = obj->GetWidth();
if (clip_x < x)
{
clip_width -= x-clip_x;
clip_x = x;
}
if (clip_width > 0)
{
if (clip_x + clip_width > x + width)
clip_width = x+width-clip_x;
if (clip_width > 0)
{
int clip_y = yabs + obj->GetY();
int clip_height = obj->GetHeight();
if (clip_y < y)
{
clip_height -= y-clip_y;
clip_y = y;
}
if (clip_height > 0)
{
if (clip_y + clip_height > y + height)
clip_height = y+height-clip_y;
if (clip_height > 0)
obj->Render(xabs,yabs, clip_x, clip_y, clip_width, clip_height );
}
}
}
}
node = node->Next();
}
}
void wxCanvasObjectGroup::WriteSVG( wxTextOutputStream &stream )
{
}
bool wxCanvasObjectGroup::IsHit( int x, int y, int margin )
{
wxNode *node = m_objects.Last();
while (node)
{
wxCanvasObject *obj = (wxCanvasObject*) node->Data();
if (!obj->IsControl())
{
if (obj->IsHit(x,y,margin))
{
return true;
}
}
node = node->Previous();
}
return false;
}
wxCanvasObject* wxCanvasObjectGroup::IsHitObject( int x, int y, int margin )
{
wxCanvasObject *obj=0;
wxNode *node = m_objects.Last();
while (node)
{
obj=(wxCanvasObject*) node->Data();
if (!obj->IsControl())
{
if (obj->IsHit(x,y,margin))
{
return obj;
}
}
node = node->Previous();
}
return 0;
}
//----------------------------------------------------------------------------
// wxCanvasObjectGroupRef
//----------------------------------------------------------------------------
wxCanvasObjectGroupRef::wxCanvasObjectGroupRef(double x, double y, wxCanvasObjectGroup* group)
: wxCanvasObject()
{
m_x = x;
m_y = y;
m_validbounds=false;
m_group=group;
}
void wxCanvasObjectGroupRef::SetOwner(wxCanvas* canvas)
{
m_owner=canvas;
m_group->SetOwner(canvas);
}
void wxCanvasObjectGroupRef::ExtendArea(int x, int y)
{
if (m_validbounds)
{
if ( x < m_minx ) m_minx = x;
if ( y < m_miny ) m_miny = y;
if ( x > m_maxx ) m_maxx = x;
if ( y > m_maxy ) m_maxy = y;
}
else
{
m_validbounds = true;
m_minx = x;
m_miny = y;
m_maxx = x;
m_maxy = y;
}
}
void wxCanvasObjectGroupRef::Recreate()
{
m_validbounds=false;
m_group->Recreate();
ExtendArea(m_group->GetXMin(),m_group->GetYMin());
ExtendArea(m_group->GetXMax(),m_group->GetYMax());
//set the area in pixels relative to the parent
SetArea( m_owner->GetDeviceX( m_x + m_minx ),
m_owner->GetDeviceY( m_y + m_miny ),
m_owner->GetDeviceWidth( m_maxx-m_minx ),
m_owner->GetDeviceHeight( m_maxy-m_miny ) );
}
void wxCanvasObjectGroupRef::Render(int xabs, int yabs, int x, int y, int width, int height )
{
wxImage *image = m_owner->GetBuffer();
xabs+=m_owner->GetDeviceX(GetPosX());
yabs+=m_owner->GetDeviceY(GetPosY());
int clip_x = xabs + m_group->GetXMin();
int clip_width = m_group->GetXMax()-m_group->GetXMin();
if (clip_x < x)
{
clip_width -= x-clip_x;
clip_x = x;
}
if (clip_width > 0)
{
if (clip_x + clip_width > x + width)
clip_width = x+width-clip_x;
if (clip_width > 0)
{
int clip_y = yabs + m_group->GetYMin();
int clip_height = m_group->GetYMax()-m_group->GetYMin();
if (clip_y < y)
{
clip_height -= y-clip_y;
clip_y = y;
}
if (clip_height > 0)
{
if (clip_y + clip_height > y + height)
clip_height = y+height-clip_y;
if (clip_height > 0)
m_group->Render(xabs,yabs, clip_x, clip_y, clip_width, clip_height );
}
}
}
}
void wxCanvasObjectGroupRef::WriteSVG( wxTextOutputStream &stream )
{
}
bool wxCanvasObjectGroupRef::IsHit( int x, int y, int margin )
{
return m_group->IsHit(x-GetPosX(),y-GetPosY(),margin);
}
wxCanvasObject* wxCanvasObjectGroupRef::IsHitObject( int x, int y, int margin )
{
return m_group->IsHitObject(x-GetPosX(),y-GetPosY(),margin);
}
void wxCanvasObjectGroupRef::Move( int x, int y )
{
int old_x = m_x;
int old_y = m_y;
m_x = x;
m_y = y;
if (!m_isControl)
{
// TODO: sometimes faster to merge into 1 Update or
// to break up into four
m_owner->Update(m_area.x, m_area.y, m_area.width, m_area.height );
//calculate the new area in pixels relative to the parent
SetArea( m_owner->GetDeviceX( m_x + m_minx ),
m_owner->GetDeviceY( m_y + m_miny ),
m_owner->GetDeviceWidth( m_maxx-m_minx ),
m_owner->GetDeviceHeight( m_maxy-m_miny ) );
m_owner->Update( m_area.x, m_area.y, m_area.width, m_area.height );
}
}
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// wxCanvasRect // wxCanvasRect
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -152,18 +468,18 @@ void wxCanvasRect::Recreate()
m_owner->GetDeviceHeight( m_height ) ); m_owner->GetDeviceHeight( m_height ) );
} }
void wxCanvasRect::Render( int clip_x, int clip_y, int clip_width, int clip_height ) void wxCanvasRect::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_width, int clip_height )
{ {
wxImage *image = m_owner->GetBuffer(); wxImage *image = m_owner->GetBuffer();
int buffer_x = m_owner->GetBufferX(); int buffer_x = m_owner->GetBufferX();
int buffer_y = m_owner->GetBufferY(); int buffer_y = m_owner->GetBufferY();
int start_y = clip_y - buffer_y; int start_y = clip_y - buffer_y;
int end_y = clip_y+clip_height - buffer_y; int end_y = clip_y+clip_height - buffer_y;
int start_x = clip_x - buffer_x; int start_x = clip_x - buffer_x;
int end_x = clip_x+clip_width - buffer_x; int end_x = clip_x+clip_width - buffer_x;
// speed up later // speed up later
for (int y = start_y; y < end_y; y++) for (int y = start_y; y < end_y; y++)
for (int x = start_x; x < end_x; x++) for (int x = start_x; x < end_x; x++)
@ -213,22 +529,22 @@ void wxCanvasLine::Recreate()
SetArea( x1, y1, x2-x1+1, y2-y1+1 ); SetArea( x1, y1, x2-x1+1, y2-y1+1 );
} }
void wxCanvasLine::Render( int clip_x, int clip_y, int clip_width, int clip_height ) void wxCanvasLine::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_width, int clip_height )
{ {
wxImage *image = m_owner->GetBuffer(); wxImage *image = m_owner->GetBuffer();
int buffer_x = m_owner->GetBufferX(); int buffer_x = m_owner->GetBufferX();
int buffer_y = m_owner->GetBufferY(); int buffer_y = m_owner->GetBufferY();
if ((m_area.width == 0) && (m_area.height == 0)) if ((m_area.width == 0) && (m_area.height == 0))
{ {
image->SetRGB( m_area.x-buffer_x, m_area.y-buffer_y, m_red, m_green, m_blue ); image->SetRGB( m_area.x-buffer_x, m_area.y-buffer_y, m_red, m_green, m_blue );
} }
else else
{ {
int x1 = m_owner->GetDeviceX( m_x1 ); int x1 = xabs + m_owner->GetDeviceX( m_x1 );
int y1 = m_owner->GetDeviceY( m_y1 ); int y1 = yabs + m_owner->GetDeviceY( m_y1 );
int x2 = m_owner->GetDeviceX( m_x2 ); int x2 = xabs + m_owner->GetDeviceX( m_x2 );
int y2 = m_owner->GetDeviceY( m_y2 ); int y2 = yabs + m_owner->GetDeviceY( m_y2 );
wxInt32 d, ii, jj, di, ai, si, dj, aj, sj; wxInt32 d, ii, jj, di, ai, si, dj, aj, sj;
di = x1 - x2; di = x1 - x2;
@ -321,13 +637,13 @@ void wxCanvasImage::Recreate()
m_tmp = m_image.Scale( m_area.width, m_area.height ); m_tmp = m_image.Scale( m_area.width, m_area.height );
} }
void wxCanvasImage::Render( int clip_x, int clip_y, int clip_width, int clip_height ) void wxCanvasImage::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_width, int clip_height )
{ {
int buffer_x = m_owner->GetBufferX(); int buffer_x = m_owner->GetBufferX();
int buffer_y = m_owner->GetBufferY(); int buffer_y = m_owner->GetBufferY();
if ((clip_x == m_area.x) && if ((clip_x == xabs + m_area.x) &&
(clip_y == m_area.y) && (clip_y == yabs + m_area.y) &&
(clip_width == m_area.width) && (clip_width == m_area.width) &&
(clip_height == m_area.height)) (clip_height == m_area.height))
{ {
@ -336,8 +652,8 @@ void wxCanvasImage::Render( int clip_x, int clip_y, int clip_width, int clip_hei
else else
{ {
// local coordinates // local coordinates
int start_x = clip_x - m_area.x; int start_x = clip_x - (xabs + m_area.x);
int start_y = clip_y - m_area.y; int start_y = clip_y - (yabs + m_area.y);
wxRect rect( start_x, start_y, clip_width, clip_height ); wxRect rect( start_x, start_y, clip_width, clip_height );
wxImage sub_image( m_tmp.GetSubImage( rect ) ); wxImage sub_image( m_tmp.GetSubImage( rect ) );
@ -426,7 +742,7 @@ wxCanvasText::wxCanvasText( const wxString &text, double x, double y, const wxSt
wxCanvasText::~wxCanvasText() wxCanvasText::~wxCanvasText()
{ {
#if wxUSE_FREETYPE #if wxUSE_FREETYPE
wxFaceData *data = (wxFaceData*) m_faceData; wxFaceData *data = (wxFaceData*) m_faceData;
delete data; delete data;
#endif #endif
@ -446,10 +762,10 @@ void wxCanvasText::SetFlag( int flag )
m_flag = flag; m_flag = flag;
} }
void wxCanvasText::Render( int clip_x, int clip_y, int clip_width, int clip_height ) void wxCanvasText::Render(int xabs, int yabs, int clip_x, int clip_y, int clip_width, int clip_height )
{ {
if (!m_alpha) return; if (!m_alpha) return;
wxImage *image = m_owner->GetBuffer(); wxImage *image = m_owner->GetBuffer();
int buffer_x = m_owner->GetBufferX(); int buffer_x = m_owner->GetBufferX();
int buffer_y = m_owner->GetBufferY(); int buffer_y = m_owner->GetBufferY();
@ -459,7 +775,7 @@ void wxCanvasText::Render( int clip_x, int clip_y, int clip_width, int clip_heig
int end_x = clip_width + start_x; int end_x = clip_width + start_x;
int start_y = clip_y - m_area.y; int start_y = clip_y - m_area.y;
int end_y = clip_height + start_y; int end_y = clip_height + start_y;
for (int y = start_y; y < end_y; y++) for (int y = start_y; y < end_y; y++)
for (int x = start_x; x < end_x; x++) for (int x = start_x; x < end_x; x++)
{ {
@ -484,7 +800,7 @@ void wxCanvasText::Render( int clip_x, int clip_y, int clip_width, int clip_heig
red2 = (red2 * alpha) / 255; red2 = (red2 * alpha) / 255;
green2 = (green2 * alpha) / 255; green2 = (green2 * alpha) / 255;
blue2 = (blue2 * alpha) / 255; blue2 = (blue2 * alpha) / 255;
image->SetRGB( image_x, image_y, red1+red2, green1+green2, blue1+blue2 ); image->SetRGB( image_x, image_y, red1+red2, green1+green2, blue1+blue2 );
} }
} }
@ -505,23 +821,23 @@ void wxCanvasText::Recreate()
m_area.height = m_size; m_area.height = m_size;
m_alpha = new unsigned char[100*m_size]; m_alpha = new unsigned char[100*m_size];
memset( m_alpha, 0, m_area.width*m_area.height ); memset( m_alpha, 0, m_area.width*m_area.height );
#if wxUSE_FREETYPE #if wxUSE_FREETYPE
FT_Face face = ((wxFaceData*)m_faceData)->m_face; FT_Face face = ((wxFaceData*)m_faceData)->m_face;
FT_GlyphSlot slot = face->glyph; FT_GlyphSlot slot = face->glyph;
int pen_x = 0; int pen_x = 0;
int pen_y = m_size; int pen_y = m_size;
for (int n = 0; n < (int)m_text.Len(); n++) for (int n = 0; n < (int)m_text.Len(); n++)
{ {
FT_UInt index = FT_Get_Char_Index( face, m_text[n] ); FT_UInt index = FT_Get_Char_Index( face, m_text[n] );
int error = FT_Load_Glyph( face, index, FT_LOAD_DEFAULT ); int error = FT_Load_Glyph( face, index, FT_LOAD_DEFAULT );
if (error) continue; if (error) continue;
error = FT_Render_Glyph( face->glyph, ft_render_mode_normal ); error = FT_Render_Glyph( face->glyph, ft_render_mode_normal );
if (error) continue; if (error) continue;
FT_Bitmap *bitmap = &slot->bitmap; FT_Bitmap *bitmap = &slot->bitmap;
unsigned char* buffer = bitmap->buffer; unsigned char* buffer = bitmap->buffer;
for (int y = 0; y < bitmap->rows; y++) for (int y = 0; y < bitmap->rows; y++)
@ -534,10 +850,10 @@ void wxCanvasText::Recreate()
int yy = pen_y - slot->bitmap_top + y; int yy = pen_y - slot->bitmap_top + y;
m_alpha[ yy * m_area.width + xx ] = alpha; m_alpha[ yy * m_area.width + xx ] = alpha;
} }
pen_x += slot->advance.x >> 6; pen_x += slot->advance.x >> 6;
pen_y += slot->advance.y >> 6; pen_y += slot->advance.y >> 6;
} }
#endif #endif
} }
@ -565,7 +881,6 @@ wxCanvas::wxCanvas( wxWindow *parent, wxWindowID id,
m_bufferX = 0; m_bufferX = 0;
m_bufferY = 0; m_bufferY = 0;
m_needUpdate = FALSE; m_needUpdate = FALSE;
m_objects.DeleteContents( TRUE );
m_red = 0; m_red = 0;
m_green = 0; m_green = 0;
m_blue = 0; m_blue = 0;
@ -573,6 +888,11 @@ wxCanvas::wxCanvas( wxWindow *parent, wxWindowID id,
m_captureMouse = (wxCanvasObject*)NULL; m_captureMouse = (wxCanvasObject*)NULL;
m_frozen = TRUE; m_frozen = TRUE;
m_requestNewBuffer = TRUE; m_requestNewBuffer = TRUE;
//root group always at 0,0
m_root = new wxCanvasObjectGroup();
m_root->DeleteContents( TRUE );
m_root->SetOwner(this);
} }
wxCanvas::~wxCanvas() wxCanvas::~wxCanvas()
@ -655,7 +975,7 @@ void wxCanvas::Thaw()
void wxCanvas::Update( int x, int y, int width, int height, bool blit ) void wxCanvas::Update( int x, int y, int width, int height, bool blit )
{ {
if (m_frozen) return; if (m_frozen) return;
// clip to buffer // clip to buffer
if (x < m_bufferX) if (x < m_bufferX)
{ {
@ -702,52 +1022,8 @@ void wxCanvas::Update( int x, int y, int width, int height, bool blit )
for (int xx = start_x; xx < end_x; xx++) for (int xx = start_x; xx < end_x; xx++)
m_buffer.SetRGB( xx, yy, m_red, m_green, m_blue ); m_buffer.SetRGB( xx, yy, m_red, m_green, m_blue );
// cycle through all objects m_root->Render(0,0, x, y, width, height );
wxNode *node = m_objects.First();
while (node)
{
wxCanvasObject *obj = (wxCanvasObject*) node->Data();
if (!obj->IsControl())
{
// If we have 10.000 objects, we will go through
// this 10.000 times for each update, so we have
// to optimise carefully.
int clip_x = obj->GetX();
int clip_width = obj->GetWidth();
if (clip_x < x)
{
clip_width -= x-clip_x;
clip_x = x;
}
if (clip_width > 0)
{
if (clip_x + clip_width > x + width)
clip_width = x+width-clip_x;
if (clip_width > 0)
{
int clip_y = obj->GetY();
int clip_height = obj->GetHeight();
if (clip_y < y)
{
clip_height -= y-clip_y;
clip_y = y;
}
if (clip_height > 0)
{
if (clip_y + clip_height > y + height)
clip_height = y+height-clip_y;
if (clip_height > 0)
obj->Render( clip_x, clip_y, clip_width, clip_height );
}
}
}
}
node = node->Next();
}
} }
void wxCanvas::BlitBuffer( wxDC &dc ) void wxCanvas::BlitBuffer( wxDC &dc )
@ -760,7 +1036,7 @@ void wxCanvas::BlitBuffer( wxDC &dc )
wxRect sub_rect( *rect ); wxRect sub_rect( *rect );
sub_rect.x -= m_bufferX; sub_rect.x -= m_bufferX;
sub_rect.y -= m_bufferY; sub_rect.y -= m_bufferY;
wxImage sub_image( m_buffer.GetSubImage( sub_rect ) ); wxImage sub_image( m_buffer.GetSubImage( sub_rect ) );
#ifdef __WXGTK__ #ifdef __WXGTK__
@ -838,23 +1114,15 @@ int wxCanvas::GetDeviceHeight( double height )
void wxCanvas::Recreate() void wxCanvas::Recreate()
{ {
wxNode *node = m_objects.First(); m_root->Recreate();
while (node)
{
wxCanvasObject *obj = (wxCanvasObject*) node->Data();
obj->Recreate();
node = node->Next();
}
} }
void wxCanvas::Prepend( wxCanvasObject* obj ) void wxCanvas::Prepend( wxCanvasObject* obj )
{ {
m_objects.Insert( obj ); m_root->Prepend( obj );
obj->SetOwner(this);
obj->SetOwner( this ); m_root->Recreate();
obj->Recreate();
if (!obj->IsControl()) if (!obj->IsControl())
Update( obj->GetX(), obj->GetY(), obj->GetWidth(), obj->GetHeight() ); Update( obj->GetX(), obj->GetY(), obj->GetWidth(), obj->GetHeight() );
@ -862,10 +1130,10 @@ void wxCanvas::Prepend( wxCanvasObject* obj )
void wxCanvas::Append( wxCanvasObject* obj ) void wxCanvas::Append( wxCanvasObject* obj )
{ {
m_objects.Append( obj ); m_root->Append( obj );
obj->SetOwner(this);
obj->SetOwner( this ); m_root->Recreate();
obj->Recreate();
if (!obj->IsControl()) if (!obj->IsControl())
Update( obj->GetX(), obj->GetY(), obj->GetWidth(), obj->GetHeight() ); Update( obj->GetX(), obj->GetY(), obj->GetWidth(), obj->GetHeight() );
@ -873,10 +1141,10 @@ void wxCanvas::Append( wxCanvasObject* obj )
void wxCanvas::Insert( size_t before, wxCanvasObject* obj ) void wxCanvas::Insert( size_t before, wxCanvasObject* obj )
{ {
m_objects.Insert( before, obj ); m_root->Insert( before, obj );
obj->SetOwner(this);
obj->SetOwner( this ); m_root->Recreate();
obj->Recreate();
if (!obj->IsControl()) if (!obj->IsControl())
Update( obj->GetX(), obj->GetY(), obj->GetWidth(), obj->GetHeight() ); Update( obj->GetX(), obj->GetY(), obj->GetWidth(), obj->GetHeight() );
@ -890,7 +1158,7 @@ void wxCanvas::Remove( wxCanvasObject* obj )
int h = obj->GetHeight(); int h = obj->GetHeight();
bool ic = obj->IsControl(); bool ic = obj->IsControl();
m_objects.DeleteObject( obj ); m_root->Remove( obj );
if (!ic) if (!ic)
Update( x, y, w, h ); Update( x, y, w, h );
@ -902,7 +1170,7 @@ void wxCanvas::OnPaint(wxPaintEvent &event)
PrepareDC( dc ); PrepareDC( dc );
if (!m_buffer.Ok()) return; if (!m_buffer.Ok()) return;
if (m_frozen) return; if (m_frozen) return;
m_needUpdate = TRUE; m_needUpdate = TRUE;
@ -944,7 +1212,7 @@ void wxCanvas::ScrollWindow( int dx, int dy, const wxRect* rect )
CalcUnscrolledPosition( 0, 0, &m_bufferX, &m_bufferY ); CalcUnscrolledPosition( 0, 0, &m_bufferX, &m_bufferY );
unsigned char* data = m_buffer.GetData(); unsigned char* data = m_buffer.GetData();
if (dy != 0) if (dy != 0)
{ {
if (dy > 0) if (dy > 0)
@ -953,7 +1221,7 @@ void wxCanvas::ScrollWindow( int dx, int dy, const wxRect* rect )
unsigned char *dest = data + (dy * m_buffer.GetWidth() * 3); unsigned char *dest = data + (dy * m_buffer.GetWidth() * 3);
size_t count = (size_t) (m_buffer.GetWidth() * 3 * (m_buffer.GetHeight()-dy)); size_t count = (size_t) (m_buffer.GetWidth() * 3 * (m_buffer.GetHeight()-dy));
memmove( dest, source, count ); memmove( dest, source, count );
// We update the new buffer area, but there is no need to // We update the new buffer area, but there is no need to
// blit (last param FALSE) since the ensuing paint event will // blit (last param FALSE) since the ensuing paint event will
// do that anyway. // do that anyway.
@ -965,14 +1233,14 @@ void wxCanvas::ScrollWindow( int dx, int dy, const wxRect* rect )
unsigned char *source = data + (-dy * m_buffer.GetWidth() * 3); unsigned char *source = data + (-dy * m_buffer.GetWidth() * 3);
size_t count = (size_t) (m_buffer.GetWidth() * 3 * (m_buffer.GetHeight()+dy)); size_t count = (size_t) (m_buffer.GetWidth() * 3 * (m_buffer.GetHeight()+dy));
memmove( dest, source, count ); memmove( dest, source, count );
// We update the new buffer area, but there is no need to // We update the new buffer area, but there is no need to
// blit (last param FALSE) since the ensuing paint event will // blit (last param FALSE) since the ensuing paint event will
// do that anyway. // do that anyway.
Update( m_bufferX, m_bufferY+m_buffer.GetHeight()+dy, m_buffer.GetWidth(), -dy, FALSE ); Update( m_bufferX, m_bufferY+m_buffer.GetHeight()+dy, m_buffer.GetWidth(), -dy, FALSE );
} }
} }
if (dx != 0) if (dx != 0)
{ {
if (dx > 0) if (dx > 0)
@ -984,7 +1252,7 @@ void wxCanvas::ScrollWindow( int dx, int dy, const wxRect* rect )
memmove( dest, source, (m_buffer.GetWidth()-dx) * 3 ); memmove( dest, source, (m_buffer.GetWidth()-dx) * 3 );
source += m_buffer.GetWidth()*3; source += m_buffer.GetWidth()*3;
} }
// We update the new buffer area, but there is no need to // We update the new buffer area, but there is no need to
// blit (last param FALSE) since the ensuing paint event will // blit (last param FALSE) since the ensuing paint event will
// do that anyway. // do that anyway.
@ -999,7 +1267,7 @@ void wxCanvas::ScrollWindow( int dx, int dy, const wxRect* rect )
memmove( dest, source, (m_buffer.GetWidth()+dx) * 3 ); memmove( dest, source, (m_buffer.GetWidth()+dx) * 3 );
dest += m_buffer.GetWidth()*3; dest += m_buffer.GetWidth()*3;
} }
// We update the new buffer area, but there is no need to // We update the new buffer area, but there is no need to
// blit (last param FALSE) since the ensuing paint event will // blit (last param FALSE) since the ensuing paint event will
// do that anyway. // do that anyway.
@ -1035,50 +1303,42 @@ void wxCanvas::OnMouse(wxMouseEvent &event)
} }
else else
{ {
wxNode *node = m_objects.Last(); wxCanvasObject *obj = m_root->IsHitObject(x,y,0);
while (node)
if (obj && !obj->IsControl())
{ {
wxCanvasObject *obj = (wxCanvasObject*) node->Data(); wxMouseEvent child_event( wxEVT_MOTION );
child_event.SetEventObject( obj );
child_event.m_x = x - obj->GetX();
child_event.m_y = y - obj->GetY();
child_event.m_leftDown = event.m_leftDown;
child_event.m_rightDown = event.m_rightDown;
child_event.m_middleDown = event.m_middleDown;
child_event.m_controlDown = event.m_controlDown;
child_event.m_shiftDown = event.m_shiftDown;
child_event.m_altDown = event.m_altDown;
child_event.m_metaDown = event.m_metaDown;
if (!obj->IsControl()) if ((obj != m_lastMouse) && (m_lastMouse != NULL))
{ {
if (obj->IsHit(x,y)) child_event.SetEventType( wxEVT_LEAVE_WINDOW );
{ child_event.SetEventObject( m_lastMouse );
wxMouseEvent child_event( wxEVT_MOTION ); child_event.m_x = x - m_lastMouse->GetX();
child_event.SetEventObject( obj ); child_event.m_y = y - m_lastMouse->GetY();
child_event.m_x = x - obj->GetX(); m_lastMouse->ProcessEvent( child_event );
child_event.m_y = y - obj->GetY();
child_event.m_leftDown = event.m_leftDown;
child_event.m_rightDown = event.m_rightDown;
child_event.m_middleDown = event.m_middleDown;
child_event.m_controlDown = event.m_controlDown;
child_event.m_shiftDown = event.m_shiftDown;
child_event.m_altDown = event.m_altDown;
child_event.m_metaDown = event.m_metaDown;
if ((obj != m_lastMouse) && (m_lastMouse != NULL)) m_lastMouse = obj;
{ child_event.SetEventType( wxEVT_ENTER_WINDOW );
child_event.SetEventType( wxEVT_LEAVE_WINDOW ); child_event.SetEventObject( m_lastMouse );
child_event.SetEventObject( m_lastMouse ); child_event.m_x = x - m_lastMouse->GetX();
child_event.m_x = x - m_lastMouse->GetX(); child_event.m_y = y - m_lastMouse->GetY();
child_event.m_y = y - m_lastMouse->GetY(); m_lastMouse->ProcessEvent( child_event );
m_lastMouse->ProcessEvent( child_event );
m_lastMouse = obj; child_event.SetEventType( wxEVT_MOTION );
child_event.SetEventType( wxEVT_ENTER_WINDOW ); child_event.SetEventObject( obj );
child_event.SetEventObject( m_lastMouse );
child_event.m_x = x - m_lastMouse->GetX();
child_event.m_y = y - m_lastMouse->GetY();
m_lastMouse->ProcessEvent( child_event );
child_event.SetEventType( wxEVT_MOTION );
child_event.SetEventObject( obj );
}
obj->ProcessEvent( child_event );
return;
}
} }
node = node->Previous(); obj->ProcessEvent( child_event );
return;
} }
} }
if (m_lastMouse) if (m_lastMouse)
@ -1100,6 +1360,7 @@ void wxCanvas::OnMouse(wxMouseEvent &event)
return; return;
} }
} }
event.Skip(); event.Skip();
} }
@ -1108,9 +1369,9 @@ void wxCanvas::OnSize(wxSizeEvent &event)
int w,h; int w,h;
GetClientSize( &w, &h ); GetClientSize( &w, &h );
m_buffer = wxImage( w, h ); m_buffer = wxImage( w, h );
CalcUnscrolledPosition( 0, 0, &m_bufferX, &m_bufferY ); CalcUnscrolledPosition( 0, 0, &m_bufferX, &m_bufferY );
wxNode *node = m_updateRects.First(); wxNode *node = m_updateRects.First();
while (node) while (node)
{ {