// $Revision: 1.3 $ // Copyright (C) 1994, 1995 Taligent, Inc. All rights reserved. // TilesView.C #ifndef TaligentSample_TILESVIEW #include "TilesView.h" #endif #ifndef TaligentSample_TILESMODEL #include "TilesModel.h" #endif #ifndef TaligentSample_TILESCOMMANDS #include "TilesCommands.h" #endif // This macro call matches a macro call to VersionDeclarationsMacro // in the TTilesView class declaration. This macro defines the // versioning utility functions. VersionDefinitionsMacro(TTilesView, kOriginalVersion); // This is how the view is actually constructed, with a TGUIBundle*. TTilesView::TTilesView(TGUIBundle* bundle) : TDocumentComponentView (bundle) {} // Default constructor TTilesView::TTilesView() : TDocumentComponentView() {} // Copy constructor TTilesView::TTilesView(const TTilesView& copy) : TDocumentComponentView(copy) {} // Destructor TTilesView::~TTilesView() {} // HandleAfterConnectionToViewRoot is called by the Framework when the view is added // to the view hierachy. This usually happens just before the view is made // visible. Initialization routines are usually added here. void TTilesView::HandleAfterConnectionToViewRoot() { // Call the base class version TDocumentComponentView::HandleAfterConnectionToViewRoot (); // Build a map between the TTilesModel's tile types (enums) and the // actual graphics used to render them in the view. BuildTilesGraphicsMapToModel(); // Set default view size SetAllocatedArea (TGArea(TGRect(TGPoint(0,0), TGPoint(200, 100)))); // Return mouse events in local coordinates SetCoordinateView(TViewHandle(*this)); } // HandleBeforeDisconnectionFromViewRoot is called by the Framework when the view is removed // to the view hierachy. This usually happens just before the view is destroyed. // Cleanup routines are usually added here. void TTilesView::HandleBeforeDisconnectionFromViewRoot() { // call the base class version TDocumentComponentView::HandleBeforeDisconnectionFromViewRoot(); DestroyTilesGraphicsMapToModel(); } // Draw contents renders the data from the model. This is the primary method // of a content view. The TGrafPort is already clipped to the region which needs // to be redrawn, so DrawContents should re-render the entire view and rely on // the port to do any necessary clipping. void TTilesView::DrawContents(TGrafPort& port) const { // Create a smart pointer which will lock the model for reading, // and will release the lock on destruction of the pointer. const TModelPointerTo model(GetModelReference()); TGArea area; GetBounds(area); // Fill the background with white TGrafBundle whitebg (new TColorPaint(TRGBColor(.9,1,1)), TGrafBundle::kFill); port.Draw (area, whitebg); // Get each tile and draw it according to its type, color position and size. int numTiles = model->GetNumTiles(); for (int i = 0; i < numTiles; i++) { const TTile* tile = model->GetTileForReading(i); DrawTile(port, tile); } } bool TTilesView::MouseDown (TMouseDownEvent& mouseDownEvent) { TRGBColor newColor; TileIndex whichTile; TTilesCommandBinding* commandBinding = NIL; // Get the position of the mouse down TGPoint mousePoint = mouseDownEvent.GetEventPosition(); // Begin a new scope so that the TModelPointerTo<> will release at the // end of the scope. { // Create a smart pointer which will lock the model for reading, // and will release the lock on destruction of the pointer. const TModelPointerTo model(GetModelReference()); // Now see if any of the TTiles in the model contain the point which // was clicked on in the view. Count in the opposite direction in // which the TTiles were drawn in DrawContents in order to detect // hits on the frontmost TTiles first. for (whichTile = model->GetNumTiles() - 1; whichTile >= 0; whichTile--) { if (model->GetTileForReading(whichTile)->ContainsPoint(mousePoint)) { break; } } if (whichTile >= 0) { // A TTile was clicked on. // Create a selection and set it to the tile chosen or to an empty selection. TTilesSelection* selection = (TTilesSelection*) model->CreateSelection (); selection->SelectTile (whichTile); // Get the current color of the tile TRGBColor currentColor = model->GetTileForReading(whichTile)->GetColor() ; // Rotate the color if (currentColor == TRGBColor(1,0,0)) newColor = TRGBColor(0,1,0); else if (currentColor == TRGBColor(0,1,0)) newColor = TRGBColor(0,0,1); else if (currentColor == TRGBColor(0,0,1)) newColor = TRGBColor(1,0,0); // Create command to change to the new color. TChangeColorCommand* command = new TChangeColorCommand (newColor); // Create a command binding to bind command and selection // Pass the GUIBundle and a text string for the Undo/Redo menu item. commandBinding = new TTilesCommandBinding (command, selection, *GetGUIBundle(), TStandardText("Change Color")); } } // The scope above has ended. The read-only TModelPointerTo<> is released. A // read-only lock on the model must be release before a read/write lock can be // made. AdoptAndDo will attempt to do a read/write lock. // Access the document and have it adopt and do the command binding if (commandBinding) AdoptAndDo (commandBinding); return true; } // Draw an individual TTile into the port. void TTilesView::DrawTile (TGrafPort& port, const TTile* tile) const { // Create a graph bundle specifying color fill properties. TGrafBundle* bundle = new TGrafBundle (new TColorPaint(tile->GetColor()), new TColorPaint(TColorPaint::GetBlack()), TGrafBundle::kFill); // Copy the MGraphic from the table created by BuildTilesGraphicsMapToModel // Use ::Copy to get a polymorphic copy. MGraphic* tileGraphic = ::CopyPointer(fTilesGraphics[tile->GetType()]); // Scale and translate the graphic tileGraphic->ScaleBy(tile->GetSize()); tileGraphic->TranslateBy(tile->GetPosition()); // Have graphic adopt the drawing attributes tileGraphic->AdoptBundle(bundle); tileGraphic->Draw(port); delete tileGraphic; } // Build an array of MGraphics which maps the data in the model (kRock, // kPaper, kScissors) to drawable objects for use by DrawTile. void TTilesView::BuildTilesGraphicsMapToModel () { // Create a circle to represent the kRock, normalized to size 1.0 TEllipse* circle = new TEllipse(TGRect(TGPoint::kOrigin, TGPoint(1.0, 1.0))); // Create a square to represent the kPaper, normalized to size 1.0 TPolygon* square = new TPolygon(TGRect(TGPoint(0.0, 0.0), TGPoint(1.0, 1.0))); // Create a Triangle to represent the kScissors, normalized to size 1.0 TGPointArray pointArray (3); pointArray.SetPoint(0, TGPoint(0.5, 0.0)); pointArray.SetPoint(1, TGPoint(1.0, 1.0)); pointArray.SetPoint(2, TGPoint(0.0, 1.0)); TPolygon* triangle = new TPolygon(TGPolygon(pointArray)); // Place the MGraphics in the array fTilesGraphics[TTile::kRock] = circle; fTilesGraphics[TTile::kPaper] = square; fTilesGraphics[TTile::kScissors] = triangle; } void TTilesView::DestroyTilesGraphicsMapToModel () { delete fTilesGraphics[TTile::kRock]; delete fTilesGraphics[TTile::kPaper]; delete fTilesGraphics[TTile::kScissors]; } // Use static to force instantiation of a class template from the template class. // Future C++ syntax will support a template keyword for doing this. static TGUIModelViewStationeryFor theStationery;