// $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)); // 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()); // Create a selection and set it to the empty selection. TTilesSelection* selection = (TTilesSelection*) model->CreateSelection (); selection->DeselectAll(); // Call MGUIBundle's AdoptCurrentModelSelection to pass ownership of the // selection* to MGUIBundle. This sets the initial current selection to // the empty selection. AdoptCurrentModelSelection (selection); } // 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()); // Get a pointer to the current selection. May receive a 0 pointer if there // is no current selection. const TTilesSelection* currentSelection = GetTilesSelection(); 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. bool inCurrentSelection = false; int numTiles = model->GetNumTiles(); for (int i = 0; i < numTiles; i++) { const TTile* tile = model->GetTileForReading(i); // Check if the current selection exists. If it does, see if the // current selection contains the tile to be drawn. if (currentSelection && currentSelection->ContainsTile(i)) { inCurrentSelection = true; } else { inCurrentSelection = false; } DrawTile(port, tile, inCurrentSelection); } } bool TTilesView::MouseDown (TMouseDownEvent& mouseDownEvent) { TRGBColor newColor; TileIndex whichTile; // Get the position of the mouse down TGPoint mousePoint = mouseDownEvent.GetEventPosition(); // 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; } } // Create a selection and set it to the tile chosen or to an empty selection. TTilesSelection* selection = (TTilesSelection*) model->CreateSelection (); if (whichTile >= 0) { // A TTile was clicked on. selection->SelectTile (whichTile); // Call MGUIBundle's AdoptCurrentModelSelection to pass ownership of the // selection* to MGUIBundle. DrawContents() will // highlight the Tiles in the current selection. The current selection will // also be used by TCommandControlStateOn, which will perform its command on // the current selection. AdoptCurrentModelSelection (selection); } else { // No TTile was hit. Set the selection to be empty to deselect whatever // the previous current selection was. selection->DeselectAll(); // Call MGUIBundle's AdoptCurrentModelSelection to pass ownership of the // selection* to MGUIBundle. AdoptCurrentModelSelection (selection); } return true; } // A convenience function which calls MGUIBundle's GetCurrentModelSelection and // safely downcasts the TModelSelection to a TTilesSelection*. The user should // always check for a 0 pointer after calling this function. const TTilesSelection * TTilesView::GetTilesSelection () const { // Get a pointer to the current selection, if any. const TModelSelection* modelSelection = GetCurrentModelSelection(); if (modelSelection) { // Attempt to safely downcast the TModelSelection to a TTileSelection. // IsA will return 0 if the downcast is not safe. TTilesSelection* tilesSelection; DynamicCastTo(tilesSelection, modelSelection); return tilesSelection; } else { return 0; } } // Draw an individual TTile into the port. Hilight the TTile if it is in the current selection. void TTilesView::DrawTile (TGrafPort& port, const TTile* tile, bool inCurrentSelection) const { // Create a graph bundle specifying color frame and fill properties. If the TTile // is in the current selection then frame and fill to hilight, otherwise just fill. TGrafBundle* bundle = new TGrafBundle (new TColorPaint(tile->GetColor()), new TColorPaint(TColorPaint::GetBlack()), inCurrentSelection ? TGrafBundle::kFillAndFrame : TGrafBundle::kFill); // Set the pen width for the graph bundle. bundle->AdoptFramePen(new TSolidPen(3.0, TPen::kOutsetFrame)); // 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;