#include "mathutils.h" #include "canvas.h" #include "CMUgraphics.h" #include "image.h" #include "auxil.h" #include "canvasiterator.h" #include #include #include #include Box::Box(int xul, int yul, int xlr, int ylr) : myLeft(xul, yul), myRight(xlr, ylr) { } Box::Box(const Point& ul, const Point& lr) : myLeft(ul), myRight(lr) { } Box::Box() : myLeft(0,0), myRight(0,0) { } const Box& Box::operator += (const Box& rhs) { myLeft.x = min(myLeft.x, rhs.myLeft.x); myLeft.y = min(myLeft.y, rhs.myLeft.y); myRight.x = max(myRight.x, rhs.myRight.x); myRight.y = max(myRight.y, rhs.myRight.y); return *this; } Box operator + (const Box& lhs, const Box& rhs) { Box copy(lhs); copy += rhs; return copy; } Point Box::getUL() const { return myLeft; } Point Box::getLR() const { return myRight; } double Box::width() const { return myRight.x - myLeft.x; } double Box::height() const { return myRight.y - myLeft.y; } bool Box::contains(const Point& p) const { Point ul = getUL(); Point ur = getLR(); return ul.x <= p.x && p.x <= ur.x && ul.y <= p.y && p.y <= ur.y; } bool Box::intersects(const Box& b) const { Point LL = b.getUL(); LL.y = b.getLR().y; Point UR = b.getLR(); LL.x = b.getUL().x; Point myLL = getUL(); myLL.y = getLR().y; Point myUR = getLR(); myUR.x = getUL().x; return contains(LL) || contains(UR) || contains(b.getUL()) || contains(b.getLR()) || b.contains(myLL) || b.contains(myUR) || b.contains(myLeft) || b.contains(myRight); } string Box::tostring() const { ostringstream out; out << "[ " << getUL() << ", " << getLR() << " ]"; return out.str(); } ostream& operator << (ostream& os, const Box& b) { // os << "[ " << b.getUL() << ", " << b.getLR() << " ]"; os << b.tostring(); return os; } int BaseCanvas::ourCount = 0; const int BaseCanvas::BBARHEIGHT = 20; BaseCanvas::BaseCanvas(int w, int h, int x, int y) : myWindow(new window(w,h,x,y)), myHeight(h), myFilled(true), myCoords(BaseCanvas::top_origin) { myWindow->SetBuffering(false); myWindow->ChangeTitle("Tapestry Canvas"); myCount = ourCount; ourCount++; if (myCount == 0) { SetColor(CanvasColor::BLACK); DrawString("click with mouse to begin",Point(0,h/2)); int x,y; myWindow->WaitMouseClick(x,y); Clear(); SetColor(CanvasColor::BLACK); } } double BaseCanvas::ycoord(double d) { if (myCoords == BaseCanvas::top_origin) { return d; } else { return height() - d; } } Point BaseCanvas::ycoord(const Point& p) { return Point(p.x,ycoord(p.y)); } void BaseCanvas::MakeBBar() { SetColor(CanvasColor::BLACK); DrawLine(Point(0,height()-BBARHEIGHT),Point(width(),height()-BBARHEIGHT)); SetColor(myColor); myHeight = height() - BBARHEIGHT; } BaseCanvas::~BaseCanvas() { // delete myBackground; ourCount--; // delete myWindow; } int BaseCanvas::height() { return myHeight; // myWindow->GetHeight(); } int BaseCanvas::width() { return myWindow->GetWidth(); } void BaseCanvas::Print() { myWindow->Print(); } AnimatedCanvas::AnimatedCanvas(int w, int h, int x, int y, bool isBuffered) : BaseCanvas(w,h,x,y), myShapes(), myShapeCount(0), myButtonCount(0), myBackground(0), myClickPoint(-1,-1), myKey(0), myIsBuffered(isBuffered), myIsRunning(false) { myShapes.reserve(8); // space for some shapes to start myWindow->SetBuffering(myIsBuffered); } AnimatedCanvas::~AnimatedCanvas() { int k; for(k=0; k < myShapes.size(); k++) { // delete myShapes[k]; } } void AnimatedCanvas::repaint() { if (myIsBuffered) { Clear(); if (myBackground != 0) { myWindow->DrawImage(myBackground,0,0,width(),height()); } } int k; poll(); Point p = getClick(); if( ! myKey.isnothing()) { for(k=0; k < myShapeCount; k++) { Keyable * ks = dynamic_cast(myShapes[k]); if (ks != 0) { ks->processKey(myKey,*this); } } } if (p.x != -1) { for(k=0; k < myShapeCount; k++) { Mouseable * ms = dynamic_cast(myShapes[k]); if (ms != 0) { ms->processClick(p,*this); } } } for(k=0; k < myShapeCount; k++) { myShapes[k]->draw(*this); } myIsRunning = false; int limit = myDeadShapes.size(); for(k=0; k < limit; k++) { removeShape(myDeadShapes[k]); } myDeadShapes.clear(); limit = myLiveShapes.size(); for(k=0; k < limit; k++) { addShape(myLiveShapes[k]); } myLiveShapes.clear(); myIsRunning = true; myWindow->UpdateBuffer(); } void AnimatedCanvas::setBackground(image& im) { myBackground= &im; } void AnimatedCanvas::addShape(Shape * s) { if (myIsRunning) { myLiveShapes.push_back(s); return; } myShapes.push_back(s); myShapeCount++; } void AnimatedCanvas::addShape(Shape& s) { addShape(s.clone()); } void AnimatedCanvas::addShape(Button& b) { addShape((Button *) b.clone()); } void AnimatedCanvas::addShape(Button * b) { addShape((Shape *) b); if (myButtonCount == 0) { MakeBBar(); } b->setLocation(Point(myButtonCount, ycoord(height()))); myButtonCount += b->bbox().width() + 5; } void AnimatedCanvas::removeShape(Shape * s) { if (myIsRunning) { myDeadShapes.push_back(s); return; } int k; for(k=0; k < myShapeCount; k++) { if (myShapes[k]->id() == s->id()) { myShapes[k] = myShapes[myShapeCount-1]; myShapes.pop_back(); myShapeCount--; return; } } } void AnimatedCanvas::removeShape(Shape& s) { removeShape(&s); } void BaseCanvas::SetFrame() { myFilled = false; SetColor(myColor); } void BaseCanvas::SetFilled() { myFilled = true; SetColor(myColor); } void BaseCanvas::SetColor(const color&c ) { myColor = c; myWindow->SetPen(c,0); if (myFilled) { myWindow->SetBrush(c); } else { myWindow->SetBrush(WHITE); } } void BaseCanvas::Clear() { SetColor(WHITE); myWindow->DrawRectangle(0,0,width(),height()); } void BaseCanvas::DrawPixel(int x, int y) { DrawPixel(Point(x,y)); } void BaseCanvas::DrawPixel(const Point& p) { myWindow->DrawPixel(p.x,p.y); } CanvasColor BaseCanvas::GetPixel(const Point& p) const { return CanvasColor(myWindow->GetColor(static_cast(p.x), static_cast(p.y))); } void BaseCanvas::DrawLine(int x1, int y1, int x2, int y2) { DrawLine(Point(x1,y1), Point(x2,y2)); } void BaseCanvas::DrawLine(const Point& p1, const Point& p2) { //myWindow->DrawLine(p1.x, p1.y, p2.x+1, p2.y+1); Process(); myWindow->DrawLine(p1.x,p1.y,p2.x,p2.y); } void BaseCanvas::DrawRectangle(int x1, int y1, int x2, int y2) { DrawRectangle(Point(x1,y1),Point(x2,y2)); } void BaseCanvas::DrawRectangle(const Point& p1, const Point& p2) { Process(); myWindow->DrawRectangle(p1.x,p1.y,p2.x,p2.y); } void BaseCanvas::DrawCircle(int x, int y, int radius) { DrawCircle(Point(x,y),radius); } void BaseCanvas::DrawCircle(const Point& center, int radius) { Process(); myWindow->DrawCircle(center.x,center.y,radius); } void BaseCanvas::DrawEllipse(int x1, int y1, int x2, int y2) { DrawEllipse(Point(x1,y1),Point(x2,y2)); } void BaseCanvas::DrawEllipse(const Point& p1, const Point& p2) { Process(); myWindow->DrawEllipse(p1.x,p1.y,p2.x,p2.y); } void BaseCanvas::DrawTriangle(const Point& p1, const Point& p2, const Point& p3) { tvector t; t.push_back(p1); t.push_back(p2); t.push_back(p3); DrawPolygon(t,3); } void BaseCanvas::DrawPolygon(const tvector& a, int numPoints) { const int SIZE = 100; static int MAX = SIZE; static int x[SIZE]; static int y[SIZE]; static int * xp = x; static int * yp = y; Process(); if (numPoints > MAX) { xp = new int[numPoints]; yp = new int[numPoints]; MAX = numPoints; } int k; for(k=0; k < numPoints; k++) { xp[k] = a[k].x; yp[k] = a[k].y; } myWindow->DrawPolygon(xp,yp,numPoints); } void BaseCanvas::DrawImage(image& im, int x, int y, double scale) { Process(); myWindow->DrawImage(im,x,y, im.GetWidth()*scale, im.GetHeight()*scale); } void BaseCanvas::DrawImage(image& im, const Point& p, double scale) { DrawImage(im,p.x,p.y,scale); } void BaseCanvas::DrawPieWedge(const Point& p, int radius, double startRad, double endRad) { myWindow->DrawArc(p.x, p.y, p.x+2*radius, p.y+2*radius, startRad,endRad, myFilled ? FILLED : FRAME,RADIANS); } void BaseCanvas::DrawString(const string& s, int x, int y, int fontsize) { Process(); myWindow->SetFont(fontsize,BOLD,SWISS); myWindow->DrawString(x,y,s); } void BaseCanvas::DrawString(const string& s, const Point& p, int fontsize) { DrawString(s,p.x,p.y,fontsize); } void BaseCanvas::GetStringSize(int & w, int & h, const string& s) { myWindow->GetStringSize(w,h,s.c_str()); } void BaseCanvas::SetTitle(const string& s) { myWindow->ChangeTitle(const_cast(s.c_str())); } void BaseCanvas::Process() { } IteratorRef * AnimatedCanvas::makeIterator() { return new CanvasIterator(myShapes,myShapeCount); } void AnimatedCanvas::poll() { clicktype click; keytype press; //myWindow->FlushMouseQueue(); int x,y; char ch; click = myWindow->GetMouseClick(x,y); Point p(x,y); press = myWindow->GetKeyPress(ch); if (click != NO_CLICK) { myClickPoint = p; } else { myClickPoint = Point(-1,-1); } if (press == NO_KEYPRESS) { myKey = Key(ch,Key::none); } else { switch(press) { case ESCAPE: myKey = Key(ch,Key::escape); break; case ASCII: myKey = Key(ch,Key::ascii); break; case FUNCTION: myKey = Key(ch,Key::function); break; case ARROW: myKey = Key(ch,Key::arrow); break; default: myKey = Key(ch,Key::ascii); break; } } } void AnimatedCanvas::run(int steps,int pause) { myIsRunning = true; for(int k=0; k < steps; k++) { repaint(); Pause(pause); } myIsRunning = false; } void AnimatedCanvas::runUntilEscape(int pause) { myIsRunning = true; while (true) { repaint(); if (myKey.isescape()) break; Pause(pause); } myIsRunning = false; } Point AnimatedCanvas::getClick() { return myClickPoint; } int Shape::ourCount = 0; Shape::Shape() { myCount = ourCount; ourCount++; } bool Shape::contains(const Point& p) const { return bbox().contains(p); } bool Shape::overlaps(const Shape& s) const { return bbox().intersects(s.bbox()); } Shape * Shape::clone() { cerr << "error, called Shape::clone()" << endl; return 0; // intentionally return NULL/0, clients should override } string Shape::tostring() const { ostringstream out; out << typeid(*this).name() << " " << id() << " " << bbox(); return out.str(); } CircleShape::CircleShape(const Point& p, double r, color c) : myPoint(p), myRadius(r), myColor(c) { } CircleShape::CircleShape(const CircleShape& c) : myPoint(c.myPoint), myRadius(c.myRadius), myColor(c.myColor) { } Box CircleShape::bbox() const { return Box (myPoint.x - myRadius, myPoint.y - myRadius, myPoint.x + myRadius, myPoint.y + myRadius); } void CircleShape::draw(AnimatedCanvas& c) { c.SetColor(myColor); c.DrawCircle(myPoint.x, myPoint.y, myRadius); } Shape * CircleShape::clone() { CircleShape * c = new CircleShape(*this); return c; } void CircleShape::setLocation(const Point& p) { myPoint = p; } Point CircleShape::getLocation() const { return myPoint; } string CircleShape::tostring() const { return string("circle ") + bbox().tostring(); } EllipseShape::EllipseShape(const Point& ul, const Point& lr, color c) : myPoint(ul), myBox(ul,lr), myColor(c) { } void EllipseShape::draw(AnimatedCanvas& c) { c.SetColor(myColor); Point ul = myBox.getUL(); Point lr = myBox.getLR(); c.DrawEllipse(ul.x,ul.y,lr.x,lr.y); } void EllipseShape::setLocation(const Point& p) { Point ul = myBox.getUL(); Point lr = myBox.getLR(); //myBox = Box(p,Point(lr.x + (p.x - ul.x), lr.y + (p.y - ul.y))); myBox = Box(p,Point(p.x+myBox.width(),p.y+myBox.height())); myPoint = p; } Point EllipseShape::getLocation() const { return myPoint; } Box EllipseShape::bbox() const { return myBox; } Shape * EllipseShape::clone() { EllipseShape * e = new EllipseShape(myBox.getUL(),myBox.getLR(),myColor); return e; } string EllipseShape::tostring() const { return string("ellipse ") + bbox().tostring(); } RectangleShape::RectangleShape(const Point& p, double w, double h, color c) : myPoint(p), myWidth(w), myHeight(h), myColor(c) { // note: + 1 ?? is because of how rectangles are drawn in // graphics.h, they go from xul,yul to xlr-1,ylr-1 } void RectangleShape::draw(AnimatedCanvas& c) { c.SetColor(myColor); c.DrawRectangle(myPoint.x,myPoint.y, myPoint.x + myWidth, myPoint.y + myHeight); } Box RectangleShape::bbox() const { return Box(myPoint.x, myPoint.y, myPoint.x + myWidth, myPoint.y + myHeight); } Shape * RectangleShape::clone() { RectangleShape * r = new RectangleShape(myPoint,myWidth,myHeight,myColor); return r; } void RectangleShape::setLocation(const Point& p) { myPoint = p; } Point RectangleShape::getLocation() const { return myPoint; } string RectangleShape::tostring() const { return string("rectangle ") + bbox().tostring(); } TriangleShape::TriangleShape(const Point& p1, const Point& p2, const Point& p3, color c) { tvector p(3); p[0] = p1; p[1] = p2; p[2] = p3; myShape = new PolygonShape(p,3,c); myShape->setLocation(myShape->getLocation()); } void TriangleShape::setLocation(const Point& p) { myShape->setLocation(p); } Point TriangleShape::getLocation() const { return myShape->getLocation(); } TriangleShape::TriangleShape(const TriangleShape& ts) { myShape = dynamic_cast (ts.myShape->clone()); myShape->setLocation(myShape->getLocation()); } const TriangleShape& TriangleShape::operator =(const TriangleShape& ts) { if (this != &ts) { // delete myShape; myShape = dynamic_cast (ts.myShape->clone()); } return *this; } TriangleShape::~TriangleShape() { // delete myShape; myShape = 0; } void TriangleShape::draw(AnimatedCanvas& c) { myShape->draw(c); } Box TriangleShape::bbox() const { return myShape->bbox(); } Shape * TriangleShape::clone() { return new TriangleShape(*this); } string TriangleShape::tostring() const { return string("triangle ") + bbox().tostring(); } PolygonShape::PolygonShape(const tvector& a, int numPoints, color c) : myXdeltas(numPoints), myYdeltas(numPoints), myColor(c) { Point minp = a[0]; Point maxp = a[0]; double miny = a[0].y; double maxy = a[0].y; int k; for(k=1; k < numPoints; k++) { minp = min(minp,a[k]); maxp = max(maxp,a[k]); miny = min(miny,a[k].y); maxy = max(maxy,a[k].y); } myMin = myPoint = minp; for(k=0; k < numPoints; k++) { myXdeltas[k] = a[k].x - minp.x; myYdeltas[k] = a[k].y - minp.y; } // create bounding box myBox = Box(minp.x,miny,maxp.x,maxy); myPoint = myBox.getUL(); } void PolygonShape::setLocation(const Point& p) { double dx = p.x - myPoint.x; double dy = p.y - myPoint.y; myPoint = p; //myMin.x += dx; //myMin.y += dy; int k; for(k=0; k < myXdeltas.size(); k++) { myXdeltas[k] += dx; myYdeltas[k] += dy; } Point ul = myBox.getUL(); Point lr = myBox.getLR(); // myBox = Box(ul.x + dx, ul.y + dy, lr.x + dx, lr.y + dy); myBox = Box(myPoint.x, myPoint.y, myPoint.x + myBox.width(), myPoint.y + myBox.height()); } Point PolygonShape::getLocation() const { return myPoint; // return myBox.getUL(); } void PolygonShape::draw(AnimatedCanvas& c) { tvector p(myXdeltas.capacity()); //static int * xa = new int[myXdeltas.length()]; //static int * ya = new int[myXdeltas.length()]; int k; int len = myXdeltas.capacity(); for(k=0; k < len; k++) { // xa[k] = myMin.x + myXdeltas[k]; // ya[k] = myMin.y + myYdeltas[k]; p[k].x = myMin.x + myXdeltas[k]; p[k].y = myMin.y + myYdeltas[k]; } c.SetColor(myColor); c.DrawPolygon(p,len); } Box PolygonShape::bbox() const { return myBox; } Shape * PolygonShape::clone() { tvector p(myXdeltas.size()); int k; for(k=0; k < myXdeltas.size(); k++) { p[k] = Point(myMin.x + myXdeltas[k], myMin.y + myYdeltas[k]); } PolygonShape * ps = new PolygonShape(p, myXdeltas.size(),myColor); return ps; } string PolygonShape::tostring() const { return string("polygon ") + bbox().tostring(); } ImageShape::ImageShape(const Point& p, const string& filename,double scale) : myPoint(p), myScale(scale) { ifstream in(filename.c_str()); if (in.fail()) { cerr << "could not access " << filename << "in ImageShape" << endl; exit(1); } in.close(); myImage = new image((char *)filename.c_str(),JPEG); } ImageShape::ImageShape(const ImageShape& is) : myPoint(is.getLocation()), myImage(is.myImage), myScale(is.myScale) { } void ImageShape::draw(AnimatedCanvas& c) { c.DrawImage(*myImage,myPoint.x,myPoint.y, myScale); } Box ImageShape::bbox() const { return Box(myPoint.x, myPoint.y, myPoint.x + myImage->GetWidth()*myScale, myPoint.y + myImage->GetHeight()*myScale); } Shape * ImageShape::clone() { ImageShape * im = new ImageShape(*this); return im; } void ImageShape::setLocation(const Point& p) { myPoint = p; } Point ImageShape::getLocation() const { return myPoint; } string ImageShape::tostring() const { return string("image ") + bbox().tostring(); } TextShape::TextShape( const Point& p, const string& s, color c) : myPoint(p), myString(s), myColor(c), myBox(p,Point(p.x+s.length()*4,p.y+5)), myInitialized(false) { // to get real box dimensions we need a canvas // so this is a gross approximation } void TextShape::changeText(const string& s) { myString = s; myInitialized = false; } void TextShape::draw(AnimatedCanvas& c) { if (! myInitialized) { int w,h; c.GetStringSize(w,h,myString.c_str()); myBox = Box(myPoint.x,myPoint.y, myPoint.x+w, myPoint.y+h); myInitialized = true; } c.SetColor(myColor), c.DrawString(myString,myPoint.x,myPoint.y); } Box TextShape::bbox() const { return myBox; } Shape * TextShape::clone() { TextShape * t = new TextShape(myPoint,myString,myColor); return t; } void TextShape::setLocation(const Point& p) { myPoint = p; } Point TextShape::getLocation() const { return myPoint; } string TextShape::tostring() const { return string("text ") + myString + " " + bbox().tostring(); } Mover::Mover(Shape& cs) : Shape(), myShape(&cs) { } void Mover::draw(AnimatedCanvas& c) { myShape->draw(c); } Box Mover::bbox() const { return myShape->bbox(); } void Mover::moveTo(const Point& p) { myShape->setLocation(p); } void Mover::moveBy(double dx, double dy) { Point p = myShape->getLocation(); p.x += dx; p.y += dy; myShape->setLocation(p); } Shape * Mover::clone() { return myShape->clone(); } void Mover::setLocation(const Point& p) { myShape->setLocation(p); } Point Mover::getLocation() const { return myShape->getLocation(); } CompositeShape::CompositeShape() : myShapes(), myBox(0,0,0,0) { } void CompositeShape::draw(AnimatedCanvas& c) { int k; for(k=0; k < myShapes.size(); k++) { myShapes[k]->draw(c); } } void CompositeShape::add(Shape& sh) { add(sh.clone()); } void CompositeShape::add(Shape* sh) { myShapes.push_back(sh); if (myShapes.size() == 1) { myBox = sh->bbox(); myPoint = sh->bbox().getUL(); // setLocation(sh->bbox().getUL()); } else { myBox += sh->bbox(); // myPoint = min(getLocation(),sh->bbox().getUL()); myPoint = myBox.getUL(); } } Point CompositeShape::getLocation() const { return myPoint; } void CompositeShape::setLocation(const Point& p) { Point old = getLocation(); double dx = p.x - old.x; double dy = p.y - old.y; for(int k=0; k < myShapes.size(); k++) { old = myShapes[k]->getLocation(); old.x += dx; old.y += dy; myShapes[k]->setLocation(old); } myPoint = p; } Box CompositeShape::bbox() const { return Box(myPoint.x,myPoint.y, myPoint.x + myBox.width(), myPoint.y + myBox.height()); } Shape* CompositeShape::clone() { CompositeShape * c = new CompositeShape; int k; for(k=0; k < myShapes.size(); k++) { Shape * s = myShapes[k]->clone(); if (s != 0) { c->add(s); } } return c; } string CompositeShape::tostring() const { string s = string("composite ") + bbox().tostring(); int k; for(k=0; k < myShapes.size(); k++) { s += myShapes[k]->tostring(); } return s; } Bouncer::Bouncer(Shape * cs, double angle, double v) : Shape(), myShape(cs), myAngle(angle), myVelocity(v) { } Bouncer::Bouncer(Shape& cs, double angle, double v) : Shape(), myShape(cs.clone()), myAngle(angle), myVelocity(v) { } Bouncer::Bouncer(const Bouncer& b) : Shape(), myShape(b.myShape->clone()), myAngle(b.myAngle), myVelocity(b.myVelocity) { } Shape * Bouncer::clone() { return new Bouncer(*this); } void Bouncer::updatetop(AnimatedCanvas& c, Point& p) { myAngle = 2*PI - myAngle; p.y -= bbox().getUL().y; } void Bouncer::updatebottom(AnimatedCanvas& c, Point& p) { myAngle = 2*PI - myAngle; p.y += c.height() - bbox().getLR().y; } void Bouncer::updateleft(AnimatedCanvas& c, Point& p) { myAngle = PI - myAngle; p.x -= bbox().getUL().x; } void Bouncer::updateright(AnimatedCanvas& c, Point& p) { myAngle = PI - myAngle; p.x += c.width() - bbox().getLR().x; } void Bouncer::update(AnimatedCanvas& c) { Box b = bbox(); Point p = myShape->getLocation(); Point newP = p; double xchange = myVelocity*cos(myAngle); double ychange = myVelocity*sin(myAngle); bool didChangeX = false,didChangeY=false; if (b.getUL().x + xchange < 0) { updateleft(c,p); didChangeX = true; } else if (b.getLR().x + xchange > c.width()) { updateright(c,p); didChangeX = true; } else if (b.getUL().y + ychange < 0) { updatetop(c,p); didChangeY = true; } else if (b.getLR().y + ychange > c.height()) { updatebottom(c,p); didChangeY = true; } else { p.x += xchange; p.y += ychange; } setLocation(p); } void Bouncer::draw(AnimatedCanvas& c) { update(c); myShape->draw(c); // c.DrawRectangle(bbox().getUL(),bbox().getLR()); } Box Bouncer::bbox() const { return myShape->bbox(); } void Bouncer::setLocation(const Point& p) { myShape->setLocation(p); } Point Bouncer::getLocation() const { return myShape->getLocation(); } double Bouncer::getAngle() const { return myAngle; } double Bouncer::getVelocity() const { return myVelocity; } Mouseable::~Mouseable() { } Keyable::~Keyable() { } MKAdapter::MKAdapter() { } void MKAdapter::processClick(const Point& p, AnimatedCanvas& c) { } void MKAdapter::processKey(const Key& k, AnimatedCanvas& c) { } CanvasAble::~CanvasAble() { } EmptyShape::EmptyShape() { } void EmptyShape::draw(AnimatedCanvas& c) { // do nothing } Box EmptyShape::bbox() const { return Box(Point(0,0),Point(0,0)); } Shape * EmptyShape::clone() { return this; } void EmptyShape::setLocation(const Point& p) { } Point EmptyShape::getLocation() const { return Point(0,0); } PrintWatcher::PrintWatcher(const Key& key) : myKey(key) { } void PrintWatcher::processKey(const Key& key, AnimatedCanvas& c) { if (key == myKey) c.Print(); } Button::Button(const string& label) : myLabel(label) { myShape = new TextShape(Point(0,0),label,CanvasColor::DARKBLUE); } Button::Button(const string& label,const color& c) : myLabel(label) { myShape = new TextShape(Point(0,0),label,c); } void Button::draw(AnimatedCanvas& c) { c.SetColor(CanvasColor::KHAKI); Point p = getLocation(); c.DrawRectangle(p.x,c.ycoord(p.y+1),p.x + bbox().width()-1, c.ycoord(p.y + bbox().height() - 1)); myShape->draw(c); } void Button::setLocation(const Point& p) { myShape->setLocation(p); } Box Button::bbox() const { return myShape->bbox(); } Point Button::getLocation() const { return myShape->getLocation(); } void Button::execute(AnimatedCanvas& c) { } void Button::processClick(const Point& p, AnimatedCanvas& c) { if (contains(p)) { execute(c); } } Shape * Button::clone() { return this; }