TweetFollow Us on Twitter

Resize Objects
Volume Number:7
Issue Number:4
Column Tag:Jörg's Folder

Related Info: Quickdraw

Getting A Handle On Objects

By Jörg Langowski, MacTutor Editorial Board

Note: Source code files accompanying article are located on MacTech CD-ROM or source code disks.

“C++/MacApp - resizing objects”

As promised last month, this time we’ll start adding some code to our MacApp drawing program to change the basic shapes once they’ve been drawn. I have chosen to implement a resize operation; other functions, like changing colors and patterns, manipulating the order of objects, etc., will follow later.

We are going to use an interface similar to MacDraw, where a selected object has a number of small black squares connected with itself that can be used to change its shape. We’ll call them ‘tags’ in the following. Objects that can be circumscribed by a rectangle have eight tags: four on the corners and four on the centers of the edges. Dragging a corner tag will move the two sides of the rectangle adjacent to the corner, while dragging the edge tag will only move the side of the rectangle that contains the tag.

We’ll need code to display the tags, determine whether the mouse was clicked in one of them, and take action (track the mouse) depending on what tag it was clicked in. Of course, all operations should be undoable, but that’s almost implicit in MacApp.

Detecting the mouse click will proceed in two stages: first, we’ll check whether the mouse has been clicked in any one of the eight tags. If so, we’ll create a new command object of class TSizer, which then does the mouse tracking and track feedback. The command object determines where the mouse was clicked exactly, and the tracking and action will depend on the tag.

For the first phase - determining whether the mouse was clicked in one of the tags at all - it is convenient to create a region that consists of all the eight tags. This region is stored in a new instance variable of TBox, fTagRgn, and created when an object is selected and redrawn (see changes to the TBox::DrawShape method in listing 3). Also, the eight tags are stored individually as Rect instance variables.

The changes to the mouse down command handler are shown in listing 2. We shall now create a TSketcher, a TDragger, or a TSizer command object, depending on where the mouse was clicked - outside any object, inside a selected object, or inside one of the tags of a selected object.

In the TSizer::TrackMouse method we determine which of the eight tags was clicked in, and allow for changes in the top, bottom, left and right coordinates of the object (flags pT, pB, pL, pR). While those coordinates are continuously changed in the TrackMove phase of the TrackMouse method, the TrackFeedback method simply redraws the object rectangle in XOR mode. Undoing can be implemented very simply by remembering the old coordinates of the object.

Sounds simple? It is, and again the modifications are only to a very limited part of the total code - one of MacApp’s great advantages. We still have to add one more ‘Buzzword’ to the list of commands that appear after the Undo/Redo menu item (Listing 4), and extend the Make file a little. By now our code has grown too big to fit into one segment (compiling in Debug mode). Thus, you’ll also see how to segment a MacApp program.

I have put the code that is supposed to go into the new segment into the file TBox.cp, containing TSizer and all the Box/Shape classes. We then have to tell the MacApp builder that this file should be linked in under a different segment name. The necessary changes are shown in listing 5. We add the name of the new source file (TBox.cp) to the list of OtherInterfaces, and the corresponding object file (TBox.cp.o) to the list of OtherLinkFiles. Last, we add the dependency rule for generating the object file (also containing a comment line showing the build progress).

The drawing example will certainly still be extended over the next few months, but we’ll also take up some Forth again soon. Until then.

Listing 1: Changes to TEDrag.h

class TBox : public TObject {
public:
 Rect fLocation;
 BooleanfSelected;
 RgnHandlefTagRgn;
 Rect fTL,fTR,fBL,fBR,
 fT,fB,fL,fR;
 virtual pascal void IBox(Rect *itsLocation);
 virtual pascal void DrawShape();
 virtual pascal void NeedDiskSpace(long *data);
 virtual pascal void Read(short aRefNum);
 virtual pascal void Write(short aRefNum);
#ifdef qDebug
 virtual pascal void Fields(pascal void (*DoToField) 
 (StringPtr fieldName, Ptr fieldAddr, 
 short fieldType, void *link), void *link);
#endif
};

class TSizer : public TCommand {
public:
 TTEDocument   *fTEDocument;
 TTextView*fTextView;
 TBox   *fBox;   RectoldLocation;  RectnewLocation;      Point 
 fStart;  // mouse pressed here
 Point  fDelta;  // offset moved
 BooleanpT,pB,pL,pR; 
 // flags to indicate which coordinates to change
 pascal void ISizer(TBox *itsBox, 
 TTEDocument *itsDocument, TTextView *itsView);
 pascal struct TCommand *TrackMouse
 (TrackPhase aTrackPhase, VPoint *anchorPoint, 
 VPoint *previousPoint, VPoint *nextPoint, 
 Boolean mouseDidMove);
 pascal void TrackFeedback
 (VPoint *anchorPoint, VPoint *nextPoint,
 Boolean turnItOn, Boolean mouseDidMove);
 pascal void DoIt();
 pascal void RedoIt();
 pascal void UndoIt();
#ifdef qDebug
 virtual pascal void Fields(pascal void (*DoToField) 
 (StringPtr fieldName, Ptr fieldAddr, 
 short fieldType, void *link), void *link);
#endif
};
Listing 2: Change to TTextView::DoMouseCommand (file TEDrag.cp)
   
 if (aFindBoxStruct.myBox->fSelected)
 { if (info->theShiftKey) 
 { aFindBoxStruct.myBox->fSelected = false;
 InvalidRect (&aFindBoxStruct.myBox->fLocation);
 return inherited::DoMouseCommand
 (theMouse,info,hysteresis);   
 }
 else
 { if (PtInRgn(*theMouse,
 aFindBoxStruct.myBox->fTagRgn))
 { aSizer = new TSizer;
 FailNIL(aSizer);
 aSizer->ISizer (aFindBoxStruct.myBox,
  fTEDocument, this);
 return aSizer;   }
 else
 { aDragger = new TDragger;
 FailNIL(aDragger);
 aDragger->IDragger
 (aFindBoxStruct.myBox, fTEDocument, this);
 return aDragger;   }
 }
 }
 else
 {
 if (!info->theShiftKey) 
 { fTEDocument->ForEachShapeDo
 ((DoToObject)Deselect, &aSelectStruct); }
 aFindBoxStruct.myBox->fSelected = true;
 InvalidRect(&aFindBoxStruct.myBox-> fLocation);
 return inherited::DoMouseCommand
 (theMouse,info,hysteresis);
 }
   
Listing 3: TBox.cp
#include <UMacApp.h>
#include <UTEView.h>
#include <ToolUtils.h>
#include “TEDrag.h”

const int kBoxColor= redColor;
const int cSizer = 4001;
// Resizing support, JL 2/91
pascal void TSizer::ISizer(TBox *itsBox, 
 TTEDocument *itsDocument, TTextView *itsView)
{
 TScroller *aScroller;

 aScroller = itsView->GetScroller(true);
 ICommand(cSizer, itsDocument, itsView, aScroller);
 fTEDocument = itsDocument;
 fTextView = itsView;
 fBox = itsBox;  
 pT = false; pB = false; pL = false; pR = false;
 oldLocation = fBox->fLocation;
 newLocation = oldLocation;
}

pascal struct TCommand *TSizer::TrackMouse
 (TrackPhase aTrackPhase, VPoint *anchorPoint, 
 VPoint *previousPoint,  VPoint *nextPoint, 
 Boolean mouseDidMove)
{
 fStart = fTextView->ViewToQDPt(anchorPoint);
 
 if (aTrackPhase == trackPress) {
 if (PtInRect(fStart,&fBox->fTR)) { pT = true; pR = true; }
 else if (PtInRect(fStart,&fBox->fTL))
 { pT = true; pL = true; }
 else if (PtInRect(fStart,&fBox->fBR))
 { pB = true; pR = true; }
 else if (PtInRect(fStart,&fBox->fBL))
 { pB = true; pL = true; }
 else if (PtInRect(fStart,&fBox->fT)) { pT = true; }
 else if (PtInRect(fStart,&fBox->fB)) { pB = true; }
 else if (PtInRect(fStart,&fBox->fL)) { pL = true; }
 else if (PtInRect(fStart,&fBox->fR)) { pR = true; }
 }

 if ((aTrackPhase == trackMove) && mouseDidMove) {
 fDelta = fTextView->ViewToQDPt(nextPoint);
 SubPt(fTextView->ViewToQDPt(anchorPoint), &fDelta);
 
 if ( !((fDelta.h == 0) && (fDelta.v == 0)) ) {                
 if (pT){ newLocation.top = 
 oldLocation.top + fDelta.v;  }
 if (pB){ newLocation.bottom = 
 oldLocation.bottom + fDelta.v; }
 if (pL){ newLocation.left = 
 oldLocation.left + fDelta.h; }
 if (pR){ newLocation.right = 
 oldLocation.right + fDelta.h; }
 }
 }

 if ((aTrackPhase == trackRelease) && mouseDidMove) {
 fDelta = fTextView->ViewToQDPt(nextPoint);
 SubPt(fTextView->ViewToQDPt(anchorPoint), &fDelta);
 if ((fDelta.h == 0) && (fDelta.v == 0))
 { return gNoChanges; }
 fBox->fLocation = newLocation;
 }
 return this;
}

pascal void TSizer::TrackFeedback
 (VPoint *anchorPoint, VPoint *nextPoint,
 Boolean turnItOn, Boolean mouseDidMove)
{
 PenState oldState;
 
 if (mouseDidMove) {
 GetPenState(&oldState);
 PenNormal();
 PenMode(patXor);
 FrameRect(&newLocation);
 SetPenState(&oldState);
 }
}

pascal void TSizer::DoIt()
{fTextView->InvalidRect(&newLocation);
 fTextView->InvalidRect(&oldLocation);   }

pascal void TSizer::RedoIt()  
{  fBox->fLocation = newLocation; DoIt();    }

pascal void TSizer::UndoIt()
{fBox->fLocation = oldLocation; DoIt();      }

#ifdef qDebug
pascal void TSizer::Fields(pascal void (*DoToField) 
 (StringPtr fieldName, Ptr fieldAddr, 
 short fieldType, void *link), void *link)
{
 DoToField(“\pTSizer”, nil, bClass, link);
 DoToField(“\pfTEDocument”, 
 (Ptr) &fTEDocument, bObject, link);
 DoToField(“\pfTextView”, (Ptr) &fTextView, bObject, link);
 DoToField(“\pfBox”, (Ptr) &fBox, bObject, link);
 DoToField(“\poldLocation”, (Ptr) &oldLocation, bRect, link);
 DoToField(“\pnewLocation”, (Ptr) &newLocation, bRect, link);
 DoToField(“\pfStart”, (Ptr) &fStart, bPoint, link);
 DoToField(“\pfDelta”, (Ptr) &fDelta, bPoint, link);
 DoToField(“\ppT”, (Ptr) &pT, bBoolean, link);
 DoToField(“\ppB”, (Ptr) &pB, bBoolean, link);
 DoToField(“\ppL”, (Ptr) &pL, bBoolean, link);
 DoToField(“\ppR”, (Ptr) &pR, bBoolean, link);
 inherited::Fields(DoToField, link);
}
#endif

pascal void TBox::IBox(Rect *itsLocation)
 {    fLocation = *itsLocation; fSelected = false; }

pascal void TBox::DrawShape()
{
 if (fSelected) {
 short halfH, halfV;
 
 halfH = (fLocation.right-fLocation.left)/2;
 halfV = (fLocation.bottom-fLocation.top)/2;
 
 PenSize (1,1);
 ForeColor(blackColor);
 FrameRect(&fLocation);
 
 fTagRgn = MakeNewRgn();
 OpenRgn();
 
 fTL.top = fLocation.top;
 fTL.left = fLocation.left;
 fTL.bottom = fTL.top + 4;
 fTL.right = fTL.left + 4;
 FrameRect(&fTL);
 
 fT.top = fLocation.top;
 fT.bottom = fT.top + 4;
 fT.left = fLocation.left + halfH - 2;
 fT.right = fT.left + 4;
 FrameRect(&fT);
 
 fTR.top = fLocation.top;
 fTR.bottom = fTR.top + 4;
 fTR.right = fLocation.right;
 fTR.left = fTR.right - 4;
 FrameRect(&fTR);
 
 fBL.bottom = fLocation.bottom;
 fBL.top = fBL.bottom - 4;
 fBL.left = fLocation.left;
 fBL.right = fBL.left + 4;
 FrameRect(&fBL);
 
 fB.bottom = fLocation.bottom;
 fB.top = fB.bottom - 4;
 fB.left = fLocation.left + halfH - 2;
 fB.right = fB.left + 4;
 FrameRect(&fB);
 
 fBR.bottom = fLocation.bottom;
 fBR.top = fBR.bottom - 4;
 fBR.right = fLocation.right;
 fBR.left = fBR.right - 4;
 FrameRect(&fBR);
 
 fL.top = fLocation.top + halfV - 2;
 fL.bottom = fL.top + 4;
 fL.left = fLocation.left;
 fL.right = fL.left + 4;
 FrameRect(&fL);
 
 fR.top = fLocation.top + halfV - 2;
 fR.bottom = fR.top + 4;
 fR.right = fLocation.right;
 fR.left = fR.right - 4;
 FrameRect(&fR);
 
 CloseRgn(fTagRgn);
 FillRgn(fTagRgn,qd.black);
 ForeColor(kBoxColor);  }
}
   the rest of the file (TShape and following definitions) stays unchanged 
  
Listing 4: Change to TEDrag.r

#define cSizer   4001
resource ‘cmnu’ (128) {
 128, textMenuProc, allEnabled, enabled, “Buzzwords”,          /* these 
words appear after Undo in the Edit menu */
  {
 “Page Setup Change”, noIcon, noKey, 
 noMark, plain, cChangePrinterStyle;
 “Typing”, noIcon, noKey, noMark, plain, cTyping;
 “Drawing”,  noIcon, noKey, 
 noMark, plain, cDrawBox;
 “Dragging”,  noIcon, noKey, 
 noMark, plain, cDragBox;
 “Resize”,  noIcon, noKey, noMark, plain, cSizer
 }
};
Listing 5: TEDrag.MAMake
AppName = TEDrag
OtherInterfaces =  
 “{SrcApp}TBox.cp”
OtherLinkFiles = 
 “{ObjApp}TBox.cp.o”
“{ObjApp}TBox.cp.o”ƒ 
 “{SrcApp}TBox.cp” 
 “{SrcApp}TEDrag.MAMake” 
  {MacAppIntf} 
  {BuildingBlocksIntf}
 {MAEcho} {EchoOptions} “Compiling:     TBox.cp”
 {MACPlus} 
 {CPlusOptions} 
 -s TBox 
 -i “{SrcApp}” 
 -i “{MACIncludes}” 
 -o “{ObjApp}TBox.cp.o” 
 “{SrcApp}TBox.cp”
OtherRsrcFiles = 
 “{MAObj}Printing.rsrc” 
 “TEOther.rsrc”

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

calibre 2.17 - Complete e-library manage...
Calibre is a complete e-book library manager. Organize your collection, convert your books to multiple formats, and sync with all of your devices. Let Calibre be your multi-tasking digital librarian... Read more
OmniGraffle Pro 6.1.2 - Create diagrams,...
OmniGraffle Pro helps you draw beautiful diagrams, family trees, flow charts, org charts, layouts, and (mathematically speaking) any other directed or non-directed graphs. We've had people use... Read more
OmniGraffle 6.1.2 - Create diagrams, flo...
OmniGraffle helps you draw beautiful diagrams, family trees, flow charts, org charts, layouts, and (mathematically speaking) any other directed or non-directed graphs. We've had people use Graffle to... Read more
RoboForm 2.0.2 - Password manager; syncs...
RoboForm is a password manager that offers one-click login, mobile syncing, easy form filling, and reliable security. Password Manager. RoboForm remembers your passwords so you don't have to! Just... Read more
Apple MainStage 3.1 - Live performance t...
Love the sound you got on your recording? MainStage 3 makes it easy to bring all the same instruments and effects to the stage. Everything from the Sound Library and Smart Controls you're familiar... Read more
Freeway Pro 7.0.2 - Drag-and-drop Web de...
Freeway Pro lets you build websites with speed and precision... without writing a line of code! With its user-oriented drag-and-drop interface, Freeway Pro helps you piece together the website of... Read more
A Better Finder Rename 9.44 - File, phot...
A Better Finder Rename is the most complete renaming solution available on the market today. That's why, since 1996, tens of thousands of hobbyists, professionals and businesses depend on A Better... Read more
Stacks 2.6.9 - New way to create pages i...
Stacks is a new way to create pages in RapidWeaver. It's a plugin designed to combine drag-and-drop simplicity with the power of fluid layout. Features: Fluid Layout: Stacks lets you build pages... Read more
Sid Meier's Civilization: Beyond Ea...
Sid Meier's Civilization: Beyond Earth is a new science-fiction-themed entry into the award-winning Civilization series. Set in the future, global events have destabilized the world leading to a... Read more
Logic Pro X 10.1 - Music creation and au...
Apple Logic Pro X is the most advanced version of Logic ever. Sophisticated new tools for professional songwriting, editing, and mixing are built around a modern interface that's designed to get... Read more

Choice Provisions is Set to Launch Destr...
Choice Provisions is Set to Launch Destructamundo on iOS This Month Posted by Tre Lawrence on January 23rd, 2015 [ permalink ] Choice Provisions – home stable to | Read more »
King of Thieves – An Interview With Zept...
Ahead of the release of ZeptoLab’s King of Thieves, we were able to ask ZeptoLab’s co-founder, Semyon Voinov, a few questions about the inspiration behind the game and what that means for the Cut the Rope franchise. | Read more »
Handle Review
Handle Review By Jennifer Allen on January 23rd, 2015 Our Rating: :: SPEEDY ORGANIZINGUniversal App - Designed for iPhone and iPad Handle is a very convenient way of juggling your emails, To Do list, and Calendar all through one... | Read more »
The New Disney Inquizitive App Offers a...
The New Disney Inquizitive App Offers a Place for Fans to Take Disney Quizzes Posted by Tre Lawrence on January 23rd, 2015 [ permalink ] | Read more »
Hands-On With Cut the Rope Developer Zep...
Marking quite a departure from ZeptoLab’s past successes, namely the Cut The Rope series, King of Thieves is shaping up to be quite promising. Due for release in February, we were lucky enough to have some time with a preview build to see exactly... | Read more »
Fast Fishing Review
Fast Fishing Review By Jennifer Allen on January 23rd, 2015 Our Rating: :: LIVES UP TO ITS NAMEUniversal App - Designed for iPhone and iPad Fishing is far from relaxing in Fast Fishing, but it is fun.   | Read more »
The LEGO Movie Video Game is Available N...
The LEGO Movie Video Game is Available Now for iOS Posted by Ellis Spice on January 23rd, 2015 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Satellina Review
Satellina Review By Jennifer Allen on January 23rd, 2015 Our Rating: :: TWITCHY BUT TACTICALUniversal App - Designed for iPhone and iPad Satellina requires quick thinking and twitchy fingers, and it’s pretty fun.   | Read more »
Tail Drift, the Crazy 360 Degree Flyer,...
Tail Drift, the Crazy 360 Degree Flyer, Has Gone Free-to-Play in a New Update Posted by Jessica Fisher on January 22nd, 2015 [ permalink ] | Read more »
PureSkate 2 Review
PureSkate 2 Review By Tre Lawrence on January 22nd, 2015 Our Rating: :: ALMOST ALL AIRUniversal App - Designed for iPhone and iPad PureSkate 2 lets one’s fingers do the skateboarding.   | Read more »

Price Scanner via MacPrices.net

iPhone 6 and 6 Plus GIve Apple Half Of US Mob...
Chicago-based Consumer Intelligence Research Partners, LLC (CIRP) have released analysis of the results of its research on mobile phone manufacturers for the calendar quarter that ended December 31,... Read more
Save $100 on MacBook Airs with 256GB of stora...
B&H Photo has 256GB MacBook Airs on sale for $100 off MSRP. Shipping is free, and B&H charges NY sales tax only: - 11″ 1.4GHz/256GB MacBook Air: $999 $100 off MSRP - 13″ 1.4GHz/256GB MacBook... Read more
21-inch 2.7GHz iMac on sale for $1179, save $...
B&H Photo has the 21″ 2.7GHz iMac on sale for $1179 including free shipping plus NY sales tax only. Their price is $120 off MSRP, and it’s the lowest price available for this model from any... Read more
iPhone Usage Rates by State Correlate With Ed...
Chitika Insights notes that despite iPhones being the largest source of smartphone Internet traffic in North America, their latest study finds a relatively high degree of variation of iPhone usage... Read more
ProGearX Extendable Pole “Pov/Selfie Stick” M...
There’s something inescapably narcissistic about the concept of selfies as they’ve developed as a smartphone-driven social (particularly social media) phenomenon that rubs me the wrong way. However,... Read more
iPad Air 2 on sale for up to $100 off MSRP, 2...
 Best Buy has iPad Air 2s on sale for up to $100 off MSRP on their online store for the next two days. Choose free shipping or free local store pickup (if available). Sale prices available for online... Read more
Roundup of Apple refurbished MacBook Pros and...
The Apple Store has Apple Certified Refurbished 2014 MacBook Pros and MacBook Airs available for up to $400 off the cost of new models. An Apple one-year warranty is included with each model, and... Read more
Sale! 13-inch 2.8GHz Retina MacBook Pro for $...
 B&H Photo has the 13″ 2.8GHz Retina MacBook Pro on sale for $1599 including free shipping plus NY sales tax only. Their price is $200 off MSRP, and it’s the lowest price available for this model... Read more
Next OS X/iOS Version Upgrades Should Concent...
On stage at Apple’s World Wide Developers’ Conference in June 2009, Bertrand Serlet, the company’s Senior Vice President of Software Engineering at the time, announced that the forthcoming OS X... Read more
First National Bank to Offer Apple Pay Adds I...
First National Bank will make Apple Pay available to customers beginning in the first quarter of 2015. Apple Pay will enable customers to easily make secure mobile payments with their First National... Read more

Jobs Board

*Apple* Solutions Consultant (ASC)- Retail S...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
*Apple* Solutions Consultant - Retail Sales...
**Job Summary** As an Apple Solutions Consultant (ASC) you are the link between our customers and our products. Your role is to drive the Apple business in a retail Read more
*Apple* Lead Operator, GSOC - Apple (United...
**Job Summary** Apple is seeking an exceptional, customer service oriented and experienced persons to fulfill the role of Apple Lead Operator (ALO) as part of the Read more
Order Support Supervisor- *Apple* Online Sto...
**Job Summary** The Apple Online Store (AOS) Order Administration team is looking for an Order Support Supervisor to manage and lead a team of Specialists through the Read more
Senior Program Manager, *Apple* Online Supp...
**Job Summary** The Apple Online Support Planning team is looking for an experienced Senior Project Manager to lead key Quality program initiatives across the Online Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.