X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/61b64bd92a02df762e59c368536b52d76516ce8c..6dfec4b8d901b13f11745a1371083a0b8c1c6980:/contrib/src/canvas/canvas.cpp diff --git a/contrib/src/canvas/canvas.cpp b/contrib/src/canvas/canvas.cpp index 14bdeb0fe4..1be997526a 100644 --- a/contrib/src/canvas/canvas.cpp +++ b/contrib/src/canvas/canvas.cpp @@ -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,12 +126,520 @@ void wxCanvasObject::WriteSVG( wxTextOutputStream &stream ) { } +//---------------------------------------------------------------------------- +// wxCanvasObjectGroup +//---------------------------------------------------------------------------- + +wxCanvasObjectGroup::wxCanvasObjectGroup() +{ + m_validbounds = FALSE; +} + +wxCanvasObjectGroup::~wxCanvasObjectGroup() +{ +} + +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(double x, double 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 ) +{ + // 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 (wxCanvasObject*) NULL; +} + +//---------------------------------------------------------------------------- +// 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(double x, double 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 ) +{ + xabs += m_area.x; + yabs += m_area.y; + + 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 ) +{ + m_x = x; + m_y = y; + + int old_area_x = m_area.x; + int old_area_y = m_area.y; + + m_area.x=m_owner->GetDeviceX( m_x + m_minx ); + m_area.y=m_owner->GetDeviceY( m_y + m_miny ); + + int leftu,rightu,bottomu,topu ; + leftu = wxMin (m_area.x, old_area_x ) ; + rightu = wxMax (old_area_x + m_area.width, m_area.x + m_area.width) ; + topu = wxMin (m_area.y,old_area_y) ; + bottomu = wxMax (old_area_y + m_area.height, m_area.y + m_area.height) ; + + if ( rightu - leftu < 2*m_area.width && bottomu - topu < 2*m_area.height ) + { + m_owner->Update(leftu,topu,rightu - leftu,bottomu - topu); + } + else + { + m_owner->Update(old_area_x, old_area_y, m_area.width, m_area.height ); + m_owner->Update( m_area.x, m_area.y, m_area.width, m_area.height ); + } +} + +//---------------------------------------------------------------------------- +// wxCanvasPolyline +//---------------------------------------------------------------------------- + +wxCanvasPolyline::wxCanvasPolyline( int n, wxPoint2DDouble points[]) + : wxCanvasObject() +{ + m_n = n; + m_points = points; + m_pen = *wxBLACK_PEN; +} + +wxCanvasPolyline::~wxCanvasPolyline() +{ + delete m_points; +} + +void wxCanvasPolyline::ExtendArea(double x, double 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 wxCanvasPolyline::Recreate() +{ + + m_validbounds=FALSE; + int i; + for (i=0; i < m_n;i++) + { + ExtendArea(m_points[i].m_x,m_points[i].m_y); + } + + //include the pen width also + ExtendArea(m_minx -m_pen.GetWidth(),m_miny-m_pen.GetWidth()); + ExtendArea(m_maxx+m_pen.GetWidth()*2,m_maxy+m_pen.GetWidth()*2); + + //set the area in pixels relative to the parent + SetArea( m_owner->GetDeviceX(m_minx ), + m_owner->GetDeviceY(m_miny ), + m_owner->GetDeviceWidth( m_maxx-m_minx ), + m_owner->GetDeviceHeight( m_maxy-m_miny ) ); +} + +void wxCanvasPolyline::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_y = m_owner->GetBufferY(); + + int start_y = clip_y - buffer_y; + int end_y = clip_y+clip_height - buffer_y; + + int start_x = clip_x - buffer_x; + int end_x = clip_x+clip_width - buffer_x; + +#if IMAGE_CANVAS +#else + wxPoint *cpoints = new wxPoint[m_n]; + int i; + for (i = 0; i < m_n; i++) + { + cpoints[i].x = m_owner->GetDeviceX(m_points[i].m_x+xabs); + cpoints[i].y = m_owner->GetDeviceY(m_points[i].m_y+yabs); + } + wxMemoryDC *dc = m_owner->GetDC(); + dc->SetClippingRegion(start_x,start_y,end_x-start_x,end_y-start_y); + dc->SetPen(m_pen); + dc->DrawLines(m_n, cpoints, 0,0); + delete [] cpoints; + dc->SetPen(wxNullPen); + dc->DestroyClippingRegion(); +#endif +} + +void wxCanvasPolyline::WriteSVG( wxTextOutputStream &stream ) +{ +} + +//---------------------------------------------------------------------------- +// wxCanvasPolygon +//---------------------------------------------------------------------------- + +wxCanvasPolygon::wxCanvasPolygon( int n, wxPoint2DDouble points[]) + : wxCanvasObject() +{ + m_n = n; + m_points = points; + m_brush = *wxBLACK_BRUSH; + m_pen = *wxTRANSPARENT_PEN; +} + +wxCanvasPolygon::~wxCanvasPolygon() +{ + delete m_points; +} + +void wxCanvasPolygon::ExtendArea(double x, double 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 wxCanvasPolygon::Recreate() +{ + + m_validbounds=FALSE; + int i; + for (i=0; i < m_n;i++) + { + ExtendArea(m_points[i].m_x,m_points[i].m_y); + } + + //include the pen width also + ExtendArea(m_minx -m_pen.GetWidth(),m_miny-m_pen.GetWidth()); + ExtendArea(m_maxx+m_pen.GetWidth()*2,m_maxy+m_pen.GetWidth()*2); + + //set the area in pixels relative to the parent + SetArea( m_owner->GetDeviceX( m_minx ), + m_owner->GetDeviceY( m_miny ), + m_owner->GetDeviceWidth( m_maxx-m_minx ), + m_owner->GetDeviceHeight( m_maxy-m_miny ) ); +} + +void wxCanvasPolygon::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_y = m_owner->GetBufferY(); + + int start_y = clip_y - buffer_y; + int end_y = clip_y+clip_height - buffer_y; + + int start_x = clip_x - buffer_x; + int end_x = clip_x+clip_width - buffer_x; + +#if IMAGE_CANVAS +#else + wxPoint *cpoints = new wxPoint[m_n]; + int i; + for (i = 0; i < m_n; i++) + { + cpoints[i].x = m_owner->GetDeviceX(m_points[i].m_x+xabs); + cpoints[i].y = m_owner->GetDeviceY(m_points[i].m_y+yabs); + } + wxMemoryDC *dc = m_owner->GetDC(); + dc->SetClippingRegion(start_x,start_y,end_x-start_x,end_y-start_y); + dc->SetBrush(m_brush); + dc->SetPen(m_pen); + dc->DrawPolygon(m_n, cpoints, 0,0,wxWINDING_RULE); + delete [] cpoints; + dc->SetBrush(wxNullBrush); + dc->SetPen(wxNullPen); + dc->DestroyClippingRegion(); +#endif +} + +void wxCanvasPolygon::WriteSVG( wxTextOutputStream &stream ) +{ +} + + + //---------------------------------------------------------------------------- // wxCanvasRect //---------------------------------------------------------------------------- -wxCanvasRect::wxCanvasRect( double x, double y, double w, double h, - unsigned char red, unsigned char green, unsigned char blue ) +wxCanvasRect::wxCanvasRect( double x, double y, double w, double h ) : wxCanvasObject() { m_x = x; @@ -139,9 +647,8 @@ wxCanvasRect::wxCanvasRect( double x, double y, double w, double h, m_width = w; m_height = h; - m_red = red; - m_green = green; - m_blue = blue; + m_brush = *wxBLACK_BRUSH; + m_pen = *wxTRANSPARENT_PEN; } void wxCanvasRect::Recreate() @@ -152,22 +659,30 @@ void wxCanvasRect::Recreate() 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(); int buffer_x = m_owner->GetBufferX(); int buffer_y = m_owner->GetBufferY(); + +#if IMAGE_CANVAS + wxImage *image = m_owner->GetBuffer(); int start_y = clip_y - buffer_y; int end_y = clip_y+clip_height - buffer_y; - + int start_x = clip_x - buffer_x; int end_x = clip_x+clip_width - buffer_x; - + // speed up later for (int y = start_y; y < end_y; y++) for (int x = start_x; x < end_x; x++) image->SetRGB( x, y, m_red, m_green, m_blue ); +#else + wxMemoryDC *dc = m_owner->GetDC(); + dc->SetPen( m_pen ); + dc->SetBrush( m_brush ); + dc->DrawRectangle( clip_x-buffer_x, clip_y-buffer_y, clip_width, clip_height ); +#endif } void wxCanvasRect::WriteSVG( wxTextOutputStream &stream ) @@ -178,8 +693,7 @@ void wxCanvasRect::WriteSVG( wxTextOutputStream &stream ) // wxCanvasLine //---------------------------------------------------------------------------- -wxCanvasLine::wxCanvasLine( double x1, double y1, double x2, double y2, - unsigned char red, unsigned char green, unsigned char blue ) +wxCanvasLine::wxCanvasLine( double x1, double y1, double x2, double y2 ) : wxCanvasObject() { m_x1 = x1; @@ -187,9 +701,7 @@ wxCanvasLine::wxCanvasLine( double x1, double y1, double x2, double y2, m_x2 = x2; m_y2 = y2; - m_red = red; - m_green = green; - m_blue = blue; + m_pen = *wxBLACK_PEN; } void wxCanvasLine::Recreate() @@ -213,23 +725,24 @@ void wxCanvasLine::Recreate() 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(); int buffer_x = m_owner->GetBufferX(); int buffer_y = m_owner->GetBufferY(); - + + int x1 = xabs + m_owner->GetDeviceX( m_x1 ); + int y1 = yabs + m_owner->GetDeviceY( m_y1 ); + int x2 = xabs + m_owner->GetDeviceX( m_x2 ); + int y2 = yabs + m_owner->GetDeviceY( m_y2 ); + +#if IMAGE_CANVAS + wxImage *image = m_owner->GetBuffer(); 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 ); } else { - int x1 = m_owner->GetDeviceX( m_x1 ); - int y1 = m_owner->GetDeviceY( m_y1 ); - int x2 = m_owner->GetDeviceX( m_x2 ); - int y2 = m_owner->GetDeviceY( m_y2 ); - wxInt32 d, ii, jj, di, ai, si, dj, aj, sj; di = x1 - x2; ai = abs(di) << 1; @@ -284,6 +797,14 @@ void wxCanvasLine::Render( int clip_x, int clip_y, int clip_width, int clip_heig } } } +#else + wxMemoryDC *dc = m_owner->GetDC(); + dc->SetClippingRegion( clip_x-buffer_x, clip_y-buffer_y, clip_width, clip_height ); + dc->SetPen( m_pen ); + dc->DrawLine( x1-buffer_x, y1-buffer_y, x2-buffer_x, y2-buffer_y ); + + dc->DestroyClippingRegion(); +#endif } void wxCanvasLine::WriteSVG( wxTextOutputStream &stream ) @@ -314,20 +835,38 @@ void wxCanvasImage::Recreate() m_owner->GetDeviceWidth( m_width ), m_owner->GetDeviceHeight( m_height ) ); +#if IMAGE_CANVAS if ((m_area.width == m_image.GetWidth()) && (m_area.width == m_image.GetWidth())) + { m_tmp = m_image; + } else + { m_tmp = m_image.Scale( m_area.width, m_area.height ); + } +#else + if ((m_area.width == m_image.GetWidth()) && + (m_area.width == m_image.GetWidth())) + { + m_tmp = m_image.ConvertToBitmap(); + } + else + { + wxImage tmp( m_image.Scale( m_area.width, m_area.height ) ); + m_tmp = tmp.ConvertToBitmap(); + } +#endif } -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_y = m_owner->GetBufferY(); - - if ((clip_x == m_area.x) && - (clip_y == m_area.y) && + +#if IMAGE_CANVAS + if ((clip_x == xabs + m_area.x) && + (clip_y == yabs + m_area.y) && (clip_width == m_area.width) && (clip_height == m_area.height)) { @@ -336,13 +875,35 @@ void wxCanvasImage::Render( int clip_x, int clip_y, int clip_width, int clip_hei else { // local coordinates - int start_x = clip_x - m_area.x; - int start_y = clip_y - m_area.y; + int start_x = clip_x - (xabs + m_area.x); + int start_y = clip_y - (yabs + m_area.y); wxRect rect( start_x, start_y, clip_width, clip_height ); wxImage sub_image( m_tmp.GetSubImage( rect ) ); m_owner->GetBuffer()->Paste( sub_image, clip_x-buffer_x, clip_y-buffer_y ); } +#else + wxMemoryDC *dc = m_owner->GetDC(); + + if ((clip_x == xabs + m_area.x) && + (clip_y == yabs + m_area.y) && + (clip_width == m_area.width) && + (clip_height == m_area.height)) + { + dc->DrawBitmap( m_tmp, clip_x-buffer_x, clip_y-buffer_y, TRUE ); + } + else + { + // local coordinates + int start_x = clip_x - (xabs + m_area.x); + int start_y = clip_y - (yabs + m_area.y); + + // Clipping region faster ? + wxRect rect( start_x, start_y, clip_width, clip_height ); + wxBitmap sub_bitmap( m_tmp.GetSubBitmap( rect ) ); + dc->DrawBitmap( sub_bitmap, clip_x-buffer_x, clip_y-buffer_y, TRUE ); + } +#endif } void wxCanvasImage::WriteSVG( wxTextOutputStream &stream ) @@ -415,7 +976,7 @@ wxCanvasText::wxCanvasText( const wxString &text, double x, double y, const wxSt m_fontFileName, 0, &(data->m_face) ); - + error = FT_Set_Char_Size( data->m_face, 0, m_size*64, @@ -426,7 +987,7 @@ wxCanvasText::wxCanvasText( const wxString &text, double x, double y, const wxSt wxCanvasText::~wxCanvasText() { -#if wxUSE_FREETYPE +#if wxUSE_FREETYPE wxFaceData *data = (wxFaceData*) m_faceData; delete data; #endif @@ -446,20 +1007,22 @@ void wxCanvasText::SetFlag( int 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; - - wxImage *image = m_owner->GetBuffer(); + int buffer_x = m_owner->GetBufferX(); int buffer_y = m_owner->GetBufferY(); + +#if IMAGE_CANVAS + wxImage *image = m_owner->GetBuffer(); // local coordinates int start_x = clip_x - m_area.x; int end_x = clip_width + start_x; int start_y = clip_y - m_area.y; int end_y = clip_height + start_y; - + for (int y = start_y; y < end_y; y++) for (int x = start_x; x < end_x; x++) { @@ -484,10 +1047,57 @@ void wxCanvasText::Render( int clip_x, int clip_y, int clip_width, int clip_heig red2 = (red2 * alpha) / 255; green2 = (green2 * alpha) / 255; blue2 = (blue2 * alpha) / 255; - + image->SetRGB( image_x, image_y, red1+red2, green1+green2, blue1+blue2 ); } } +#else + wxBitmap *bitmap = m_owner->GetBuffer(); + wxRect sub_rect( clip_x-buffer_x, clip_y-buffer_y, clip_width, clip_height ); + wxBitmap sub_bitmap( bitmap->GetSubBitmap( sub_rect ) ); + + wxImage image( sub_bitmap ); + + // local coordinates + int start_x = clip_x - m_area.x; + int end_x = clip_width + start_x; + int start_y = clip_y - m_area.y; + int end_y = clip_height + start_y; + + for (int y = start_y; y < end_y; y++) + for (int x = start_x; x < end_x; x++) + { + int alpha = m_alpha[y*m_area.width + x]; + if (alpha) + { + int image_x = x - start_x; + int image_y = y - start_y; + if (alpha == 255) + { + image.SetRGB( image_x, image_y, m_red, m_green, m_blue ); + continue; + } + int red1 = (m_red * alpha) / 255; + int green1 = (m_green * alpha) / 255; + int blue1 = (m_blue * alpha) / 255; + + alpha = 255-alpha; + int red2 = image.GetRed( image_x, image_y ); + int green2 = image.GetGreen( image_x, image_y ); + int blue2 = image.GetBlue( image_x, image_y ); + red2 = (red2 * alpha) / 255; + green2 = (green2 * alpha) / 255; + blue2 = (blue2 * alpha) / 255; + + image.SetRGB( image_x, image_y, red1+red2, green1+green2, blue1+blue2 ); + } + } + + sub_bitmap = image.ConvertToBitmap(); + + wxMemoryDC *dc = m_owner->GetDC(); + dc->DrawBitmap( sub_bitmap, clip_x-buffer_x, clip_y-buffer_y ); +#endif } void wxCanvasText::WriteSVG( wxTextOutputStream &stream ) @@ -501,27 +1111,27 @@ void wxCanvasText::Recreate() m_area.x = m_owner->GetDeviceX( m_x ); m_area.y = m_owner->GetDeviceY( m_y ); - m_area.width = 100; // TODO, calculate length - m_area.height = m_size; - m_alpha = new unsigned char[100*m_size]; + m_area.width = 100; // TODO calculate length + m_area.height = m_size + (m_size/2); // TODO space for sub-baseline (pgypq) + m_alpha = new unsigned char[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_GlyphSlot slot = face->glyph; int pen_x = 0; int pen_y = m_size; - + for (int n = 0; n < (int)m_text.Len(); n++) { FT_UInt index = FT_Get_Char_Index( face, m_text[n] ); int error = FT_Load_Glyph( face, index, FT_LOAD_DEFAULT ); if (error) continue; - + error = FT_Render_Glyph( face->glyph, ft_render_mode_normal ); if (error) continue; - + FT_Bitmap *bitmap = &slot->bitmap; unsigned char* buffer = bitmap->buffer; for (int y = 0; y < bitmap->rows; y++) @@ -534,10 +1144,10 @@ void wxCanvasText::Recreate() int yy = pen_y - slot->bitmap_top + y; m_alpha[ yy * m_area.width + xx ] = alpha; } - + pen_x += slot->advance.x >> 6; pen_y += slot->advance.y >> 6; - } + } #endif } @@ -565,14 +1175,19 @@ wxCanvas::wxCanvas( wxWindow *parent, wxWindowID id, m_bufferX = 0; m_bufferY = 0; m_needUpdate = FALSE; - m_objects.DeleteContents( TRUE ); m_red = 0; m_green = 0; m_blue = 0; m_lastMouse = (wxCanvasObject*)NULL; m_captureMouse = (wxCanvasObject*)NULL; m_frozen = TRUE; - m_requestNewBuffer = TRUE; + m_oldDeviceX = 0; + m_oldDeviceY = 0; + + //root group always at 0,0 + m_root = new wxCanvasObjectGroup(); + m_root->DeleteContents( TRUE ); + m_root->SetOwner(this); } wxCanvas::~wxCanvas() @@ -602,6 +1217,7 @@ void wxCanvas::SetColour( unsigned char red, unsigned char green, unsigned char if (m_frozen) return; +#if IMAGE_CANVAS unsigned char *data = m_buffer.GetData(); for (int y = 0; y < m_buffer.GetHeight(); y++) @@ -614,6 +1230,15 @@ void wxCanvas::SetColour( unsigned char red, unsigned char green, unsigned char data[0] = blue; data++; } +#else + wxMemoryDC dc; + dc.SelectObject( m_buffer ); + dc.SetPen( *wxTRANSPARENT_PEN ); + wxBrush brush( wxColour( red,green,blue), wxSOLID ); + dc.SetBrush( brush ); + dc.DrawRectangle( 0, 0, m_buffer.GetWidth(), m_buffer.GetHeight() ); + dc.SelectObject( wxNullBitmap ); +#endif } void wxCanvas::SetCaptureMouse( wxCanvasObject *obj ) @@ -654,34 +1279,36 @@ void wxCanvas::Thaw() void wxCanvas::Update( int x, int y, int width, int height, bool blit ) { - if (m_frozen) return; + CalcScrolledPosition( 0, 0, &m_oldDeviceX, &m_oldDeviceY ); + if (m_frozen) return; + // clip to buffer if (x < m_bufferX) { width -= m_bufferX-x; x = m_bufferX; } - if (width < 0) return; + if (width <= 0) return; if (y < m_bufferY) { height -= m_bufferY-y; y = m_bufferY; } - if (height < 0) return; + if (height <= 0) return; if (x+width > m_bufferX+m_buffer.GetWidth()) { width = m_bufferX+m_buffer.GetWidth() - x; } - if (width < 0) return; + if (width <= 0) return; if (y+height > m_bufferY+m_buffer.GetHeight()) { height = m_bufferY+m_buffer.GetHeight() - y; } - if (height < 0) return; + if (height <= 0) return; // update is within the buffer m_needUpdate = TRUE; @@ -693,6 +1320,7 @@ void wxCanvas::Update( int x, int y, int width, int height, bool blit ) (wxObject*) new wxRect( x,y,width,height ) ); } +#if IMAGE_CANVAS // speed up with direct access, maybe add wxImage::Clear(x,y,w,h,r,g,b) int start_y = y - m_bufferY; int end_y = y+height - m_bufferY; @@ -702,52 +1330,20 @@ void wxCanvas::Update( int x, int y, int width, int height, bool blit ) for (int xx = start_x; xx < end_x; xx++) m_buffer.SetRGB( xx, yy, m_red, m_green, m_blue ); - // 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 = 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; + m_root->Render(0,0, x, y, width, height ); +#else + wxMemoryDC dc; + dc.SelectObject( m_buffer ); + dc.SetPen( *wxTRANSPARENT_PEN ); + wxBrush brush( wxColour( m_red,m_green,m_blue), wxSOLID ); + dc.SetBrush( brush ); + dc.DrawRectangle( x-m_bufferX, y-m_bufferY, width, height ); - if (clip_height > 0) - obj->Render( clip_x, clip_y, clip_width, clip_height ); - } - } - } - } + m_renderDC = &dc; + m_root->Render(0,0, x, y, width, height ); - node = node->Next(); - } + dc.SelectObject( wxNullBitmap ); +#endif } void wxCanvas::BlitBuffer( wxDC &dc ) @@ -760,9 +1356,10 @@ void wxCanvas::BlitBuffer( wxDC &dc ) wxRect sub_rect( *rect ); sub_rect.x -= m_bufferX; sub_rect.y -= m_bufferY; - - wxImage sub_image( m_buffer.GetSubImage( sub_rect ) ); +#if IMAGE_CANVAS + + wxImage sub_image( m_buffer.GetSubImage( sub_rect ) ); #ifdef __WXGTK__ int bpp = wxDisplayDepth(); if (bpp > 8) @@ -789,13 +1386,19 @@ void wxCanvas::BlitBuffer( wxDC &dc ) wxBitmap bitmap( sub_image.ConvertToBitmap() ); dc.DrawBitmap( bitmap, rect->x, rect->y ); } -#endif - -#ifndef __WXGTK__ +#else wxBitmap bitmap( sub_image.ConvertToBitmap() ); dc.DrawBitmap( bitmap, rect->x, rect->y ); #endif +#else // IMAGE_CANVAS + + // Maybe clipping use SetClipping() is faster than + // getting the subrect first and drawing it then? + wxBitmap sub_bitmap( m_buffer.GetSubBitmap( sub_rect ) ); + dc.DrawBitmap( sub_bitmap, rect->x, rect->y ); + +#endif delete rect; m_updateRects.DeleteNode( node ); node = m_updateRects.First(); @@ -838,23 +1441,15 @@ int wxCanvas::GetDeviceHeight( double height ) void wxCanvas::Recreate() { - wxNode *node = m_objects.First(); - while (node) - { - wxCanvasObject *obj = (wxCanvasObject*) node->Data(); - - obj->Recreate(); - - node = node->Next(); - } + m_root->Recreate(); } void wxCanvas::Prepend( wxCanvasObject* obj ) { - m_objects.Insert( obj ); + m_root->Prepend( obj ); + obj->SetOwner(this); - obj->SetOwner( this ); - obj->Recreate(); + m_root->Recreate(); if (!obj->IsControl()) Update( obj->GetX(), obj->GetY(), obj->GetWidth(), obj->GetHeight() ); @@ -862,10 +1457,10 @@ void wxCanvas::Prepend( wxCanvasObject* obj ) void wxCanvas::Append( wxCanvasObject* obj ) { - m_objects.Append( obj ); + m_root->Append( obj ); + obj->SetOwner(this); - obj->SetOwner( this ); - obj->Recreate(); + m_root->Recreate(); if (!obj->IsControl()) Update( obj->GetX(), obj->GetY(), obj->GetWidth(), obj->GetHeight() ); @@ -873,10 +1468,10 @@ void wxCanvas::Append( 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 ); - obj->Recreate(); + m_root->Recreate(); if (!obj->IsControl()) Update( obj->GetX(), obj->GetY(), obj->GetWidth(), obj->GetHeight() ); @@ -890,7 +1485,7 @@ void wxCanvas::Remove( wxCanvasObject* obj ) int h = obj->GetHeight(); bool ic = obj->IsControl(); - m_objects.DeleteObject( obj ); + m_root->Remove( obj ); if (!ic) Update( x, y, w, h ); @@ -903,6 +1498,8 @@ void wxCanvas::OnPaint(wxPaintEvent &event) if (!m_buffer.Ok()) return; + if (m_frozen) return; + m_needUpdate = TRUE; wxRegionIterator it( GetUpdateRegion() ); @@ -934,15 +1531,19 @@ void wxCanvas::OnPaint(wxPaintEvent &event) void wxCanvas::ScrollWindow( int dx, int dy, const wxRect* rect ) { // If any updates are pending, do them now since they will - // expect the previous m_bufferX and m_bufferY values. - UpdateNow(); + // expect the previous m_bufferX and m_bufferY as well as + // the previous device origin values. + wxClientDC dc( this ); + dc.SetDeviceOrigin( m_oldDeviceX, m_oldDeviceY ); + BlitBuffer( dc ); // The buffer always starts at the top left corner of the // client area. Indeed, it is the client area. CalcUnscrolledPosition( 0, 0, &m_bufferX, &m_bufferY ); +#if IMAGE_CANVAS unsigned char* data = m_buffer.GetData(); - + if (dy != 0) { if (dy > 0) @@ -951,7 +1552,7 @@ void wxCanvas::ScrollWindow( int dx, int dy, const wxRect* rect ) unsigned char *dest = data + (dy * m_buffer.GetWidth() * 3); size_t count = (size_t) (m_buffer.GetWidth() * 3 * (m_buffer.GetHeight()-dy)); memmove( dest, source, count ); - + // We update the new buffer area, but there is no need to // blit (last param FALSE) since the ensuing paint event will // do that anyway. @@ -963,14 +1564,14 @@ void wxCanvas::ScrollWindow( int dx, int dy, const wxRect* rect ) unsigned char *source = data + (-dy * m_buffer.GetWidth() * 3); size_t count = (size_t) (m_buffer.GetWidth() * 3 * (m_buffer.GetHeight()+dy)); memmove( dest, source, count ); - + // We update the new buffer area, but there is no need to // blit (last param FALSE) since the ensuing paint event will // do that anyway. Update( m_bufferX, m_bufferY+m_buffer.GetHeight()+dy, m_buffer.GetWidth(), -dy, FALSE ); } } - + if (dx != 0) { if (dx > 0) @@ -982,7 +1583,7 @@ void wxCanvas::ScrollWindow( int dx, int dy, const wxRect* rect ) memmove( dest, source, (m_buffer.GetWidth()-dx) * 3 ); source += m_buffer.GetWidth()*3; } - + // We update the new buffer area, but there is no need to // blit (last param FALSE) since the ensuing paint event will // do that anyway. @@ -997,13 +1598,17 @@ void wxCanvas::ScrollWindow( int dx, int dy, const wxRect* rect ) memmove( dest, source, (m_buffer.GetWidth()+dx) * 3 ); dest += m_buffer.GetWidth()*3; } - + // We update the new buffer area, but there is no need to // blit (last param FALSE) since the ensuing paint event will // do that anyway. Update( m_bufferX+m_buffer.GetWidth()+dx, m_bufferY, -dx, m_buffer.GetHeight(), FALSE ); } } +#else + // Update everything, TODO: scrolling + Update( m_bufferX, m_bufferY, m_buffer.GetWidth(), m_buffer.GetHeight(), FALSE ); +#endif wxWindow::ScrollWindow( dx, dy, rect ); } @@ -1029,54 +1634,49 @@ void wxCanvas::OnMouse(wxMouseEvent &event) child_event.m_shiftDown = event.m_shiftDown; child_event.m_altDown = event.m_altDown; child_event.m_metaDown = event.m_metaDown; + m_captureMouse->ProcessEvent( child_event ); + return; } else { - wxNode *node = m_objects.Last(); - while (node) - { - wxCanvasObject *obj = (wxCanvasObject*) node->Data(); + wxCanvasObject *obj = m_root->IsHitObject(x,y,0); - if (!obj->IsControl()) + if (obj && !obj->IsControl()) + { + 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 != m_lastMouse) && (m_lastMouse != NULL)) { - if (obj->IsHit(x,y)) - { - 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 != m_lastMouse) && (m_lastMouse != NULL)) - { - child_event.SetEventType( wxEVT_LEAVE_WINDOW ); - 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 ); - - m_lastMouse = obj; - child_event.SetEventType( wxEVT_ENTER_WINDOW ); - 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; - } + child_event.SetEventType( wxEVT_LEAVE_WINDOW ); + 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 ); + + m_lastMouse = obj; + child_event.SetEventType( wxEVT_ENTER_WINDOW ); + 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 ); } - node = node->Previous(); + + obj->ProcessEvent( child_event ); + return; } } if (m_lastMouse) @@ -1098,32 +1698,80 @@ void wxCanvas::OnMouse(wxMouseEvent &event) return; } } + else + { + if (m_captureMouse) //no matter what go to this one + { + wxMouseEvent child_event( event.GetEventType() ); + child_event.SetEventObject(m_captureMouse); + child_event.m_x = x - m_captureMouse->GetX(); + child_event.m_y = y - m_captureMouse->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; + m_captureMouse->ProcessEvent( child_event ); + } + else + { + wxCanvasObject *obj = m_root->IsHitObject(x,y,0); + + if (obj && !obj->IsControl()) + { + wxMouseEvent child_event( event.GetEventType() ); + 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; + + obj->ProcessEvent( child_event ); + return; + } + } + } + event.Skip(); } void wxCanvas::OnSize(wxSizeEvent &event) { - m_requestNewBuffer = TRUE; - Freeze(); + int w,h; + GetClientSize( &w, &h ); +#if IMAGE_CANVAS + m_buffer = wxImage( w, h ); +#else + m_buffer = wxBitmap( w, h ); +#endif + + CalcUnscrolledPosition( 0, 0, &m_bufferX, &m_bufferY ); + + wxNode *node = m_updateRects.First(); + while (node) + { + wxRect *rect = (wxRect*) node->Data(); + delete rect; + m_updateRects.DeleteNode( node ); + node = m_updateRects.First(); + } + + m_frozen = FALSE; + + Update( m_bufferX, m_bufferY, m_buffer.GetWidth(), m_buffer.GetHeight(), FALSE ); event.Skip(); } void wxCanvas::OnIdle(wxIdleEvent &event) { - if (m_requestNewBuffer) - { - m_requestNewBuffer = FALSE; - - int w,h; - GetClientSize( &w, &h ); - m_buffer = wxImage( w, h ); - - CalcUnscrolledPosition( 0, 0, &m_bufferX, &m_bufferY ); - - Thaw(); - } - UpdateNow(); event.Skip(); }