TweetFollow Us on Twitter

Mouse in MacApp
Volume Number:6
Issue Number:12
Column Tag:Jörg's Folder

Related Info: Event Manager

MacApp-Tracking the Mouse

By Jörg Langowski, MacTutor Editorial Board

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

As promised, I will show you this month how to add code that handles mouse tracking to our last example. In the code as it was given in V6#11, we had no explicit mouse tracking routine defined; in that case MacApp uses the default routine, which simply draws the rectangle defined by the mouse starting point and the current mouse position. For dragging an object, this default behavior is quite inconvenient, because you don’t see the exact outline of the object being dragged and can’t position it exactly where you want it.

We would like dragged objects to behave like they do in MacDraw, where an outline of the object follows the mouse. How can one implement this?

All the changes we have do to are to the TDragger class. Specifically, we need to define a TrackFeedback method in this class. This method is called by MacApp’s TApplication.TrackMouse routine while it tracks the mouse. You may draw some shape here, which is then ‘dragged around’ with the mouse: TrackMouse will set the pen to patXOR mode before any calls to the feedback routine. When you move the mouse, the shape is first redrawn at the old position (erasing it that way), then drawn at the new position. All this is handled automatically by TrackMouse; you only need to provide the drawing routine.

So all we would have to do is write a TrackFeedback method that draws the shape at the current mouse position, maybe like this:

/* 1 */

pascal void TDragger::TrackFeedback(VPoint *anchorPoint,
 VPoint *nextPoint, Boolean turnItOn, Boolean mouseDidMove)
{
 Point  delta;

 if (mouseDidMove) {
 delta = fTextView->ViewToQDPt(nextPoint);
 SubPt(fTextView->ViewToQDPt(previousPoint), &delta);
 OffsetRect(&fBox->fLocation,delta.h,delta.v);
 fBox->DrawShape();
 }
}

In the call to the routine, anchorPoint and nextPoint are the starting point of the mouse drag and the current mouse position. mouseDidMove is true when the mouse actually did move since the last call to this routine; and turnItOn is a variable that controls whether feedback should be turned on or off; we don’t use it. To draw the shape at the new mouse position, we calculate the difference between the two coordinates (SubPt) and offset the shape rectangle accordingly; then we draw the shape.

This method should work without problems when you add it to last month’s example (try it, and don’t forget to include the method in the class definition in the header file). Since we change the location rectangle of fBox as we go, we may even simplify the code that changes oldLocation and newLocation at the end of the TDragger.TrackMouse routine; fBox->fLocation is already at its final value when the mouse is released.

However, I would like to show you a different way to do the feedback which can later be used in a much more general way, for instance if we want to drag an outline of a group of different shapes, change the aspect of the shape being dragged around, etc. The principle is taken from an example in the excellent book Programming with MacApp by David Wilson, Larry Rosenstein, and Dan Shafer (Addison-Wesley). We call the routines that we want to use for drawing the shape(s) to be dragged only once, when the mouse is first clicked or at its first movement. At that point, we create a picture, calling all the drawing routines, and store its handle in an instance variable. The TrackFeedback routine will then take this picture handle and call DrawPicture with it.

Creation of the picture, and destruction when we’re done with the dragging, is handled by the TrackMouse routine. When this routine is called, one parameter indicated what track phase we are in: whether the mouse button was just pressed (trackPress), is being held down (trackMove), or has just been released (trackRelease).

The track phase tells us what to do (see listing): when we are in trackPress, we create the picture and save its handle; when we are in trackMove, we offset the picture’s bounds rectangle by the distance the mouse has traveled; finally, in trackRelease, we change the shape’s coordinates to the mouse position and dispose of the picture. If we find out that the shape has not been moved at all out of its old position, we return gNoChanges.

Note that the mouse tracking routine does not do any drawing at all; drawing the dragged shape is done by the TrackFeedback routine, and the final draw of the shape at its new position is of course done when the window is updated automatically. Another point to remember is that you have to set the pen state to PenNormal and patXor when you create the picture (see listing). The current pen state is part of the picture information, so when the picture is created, that pen state will be remembered. The pen state in the TrackMouse routine in the trackPress phase is not the one we want; if you don’t set it to patXor yourself, it will be patCopy (I guess) when the picture is drawn by the feedback routine. That means you will create copies of your shape all over the screen when you drag it. Try it out.

Final words

This was a short Christmas column; next time will be longer, because we’ll add code for different shapes and for dragging a selection of shapes. Also, it might be that my test copy of MacFortran II comes in until then, so that we can finally see those comprehensive benchmarks. Absoft, I want my M F Two...

Listing 1: Changes to the V6#9 example to support track feedback

// Dragging support with custom mouse track feedback
// © JL/MT 10/90
pascal void 
 TDragger::IDragger(TBox *itsBox, 
 TTEDocument *itsDocument, TTextView *itsView)
{
 TScroller *aScroller;

 aScroller = itsView->GetScroller(true);
 ICommand(cDragBox, itsDocument, itsView, aScroller);
 fTEDocument = itsDocument;
 fTextView = itsView;
 fBox = itsBox;
 oldLocation = fBox->fLocation;
 newLocation = fBox->fLocation;
}

pascal struct TCommand 
 *TDragger::TrackMouse(TrackPhase aTrackPhase,
 VPoint *anchorPoint, VPoint *previousPoint, 
 VPoint *nextPoint, Boolean mouseDidMove)
{
 Point  delta;
 Rect   r;
 RgnHandleoldClip;
 PenState oldState;
 
 if (aTrackPhase == trackPress) {
 r = fBox->fLocation;
 oldClip = MakeNewRgn();  // MacApp routine
 
// get the old environment for later restore
 GetClip(oldClip);
 GetPenState(&oldState);
// and open a new picture
 fFeedbackPicture = OpenPicture(&r);
 FailNIL(fFeedbackPicture); // be safe
 ClipRect(&r);
// the following lines ARE necessary since the picture 
// remembers the pen state that was in effect when this 
// routine was called.
// Since we are in trackPress, the pen has NOT yet been 
// set to patXOR. Comment out the next two lines, 
// you’ll see interesting effects -- JL
 PenNormal();
 PenMode(patXor);
// draw the shape
 fBox->DrawShape();
 ClosePicture();
 fPictureBounds = r;

// restore old environment
 SetClip(oldClip);
 DisposeRgn(oldClip);
 SetPenState(&oldState);
 
 if (EmptyRect(&(*fFeedbackPicture)->picFrame)) {
 KillPicture(fFeedbackPicture);
 fFeedbackPicture = nil;
 FailNIL(fFeedbackPicture);
 }
 }

 if ((aTrackPhase == trackMove) && mouseDidMove) {
 delta = fTextView->ViewToQDPt(nextPoint);
 SubPt(fTextView->ViewToQDPt(previousPoint), &delta);
// we don’t actually move the shape here, only its picture.
// the move is done in the last phase
 OffsetRect(&fPictureBounds,delta.h,delta.v);
 }

 if ((aTrackPhase == trackRelease) && mouseDidMove) {
 if (fFeedbackPicture != nil)  {
// being paranoid: normally we should never get here if the 
// picture couldn’t be created, but who knows
 KillPicture(fFeedbackPicture);
 fFeedbackPicture = nil; }

 delta = fTextView->ViewToQDPt(nextPoint);
 SubPt(fTextView->ViewToQDPt(anchorPoint), &delta);
 newLocation = oldLocation;
 if ((delta.h == 0) && (delta.v == 0))
 { return gNoChanges;}
// if we get here, something has been changed. 
// move the shape to its new location
 OffsetRect(&newLocation,delta.h,delta.v);
 fBox->fLocation = newLocation;    
 }
 return this;
}

pascal void 
 TDragger::TrackFeedback(VPoint *anchorPoint, 
 VPoint *nextPoint,
 Boolean turnItOn, Boolean mouseDidMove)
{
 Rect r;
 
 if (mouseDidMove && (fFeedbackPicture != nil)) {
 r = fPictureBounds;
 DrawPicture(fFeedbackPicture,&r); // that’s all!! 
 }
}

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

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

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

#ifdef qDebug
pascal void TDragger::Fields(pascal void (*DoToField) 
 (StringPtr fieldName, Ptr fieldAddr, short fieldType, 
 void *link), void *link)
{
 DoToField(“\pTDragger”, 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(“\pfFeedbackPicture”, 
 (Ptr) &fFeedbackPicture, bHandle, link);
 DoToField(“\pfPictureBounds”, 
 (Ptr) &fPictureBounds, bRect, link);
 inherited::Fields(DoToField, link);
}
#endif

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Latest Forum Discussions

See All

Tokkun Studio unveils alpha trailer for...
We are back on the MMORPG news train, and this time it comes from the sort of international developers Tokkun Studio. They are based in France and Japan, so it counts. Anyway, semantics aside, they have released an alpha trailer for the upcoming... | Read more »
Win a host of exclusive in-game Honor of...
To celebrate its latest Jujutsu Kaisen crossover event, Honor of Kings is offering a bounty of login and achievement rewards kicking off the holiday season early. [Read more] | Read more »
Miraibo GO comes out swinging hard as it...
Having just launched what feels like yesterday, Dreamcube Studio is wasting no time adding events to their open-world survival Miraibo GO. Abyssal Souls arrives relatively in time for the spooky season and brings with it horrifying new partners to... | Read more »
Ditch the heavy binders and high price t...
As fun as the real-world equivalent and the very old Game Boy version are, the Pokemon Trading Card games have historically been received poorly on mobile. It is a very strange and confusing trend, but one that The Pokemon Company is determined to... | Read more »
Peace amongst mobile gamers is now shatt...
Some of the crazy folk tales from gaming have undoubtedly come from the EVE universe. Stories of spying, betrayal, and epic battles have entered history, and now the franchise expands as CCP Games launches EVE Galaxy Conquest, a free-to-play 4x... | Read more »
Lord of Nazarick, the turn-based RPG bas...
Crunchyroll and A PLUS JAPAN have just confirmed that Lord of Nazarick, their turn-based RPG based on the popular OVERLORD anime, is now available for iOS and Android. Starting today at 2PM CET, fans can download the game from Google Play and the... | Read more »
Digital Extremes' recent Devstream...
If you are anything like me you are impatiently waiting for Warframe: 1999 whilst simultaneously cursing the fact Excalibur Prime is permanently Vault locked. To keep us fed during our wait, Digital Extremes hosted a Double Devstream to dish out a... | Read more »
The Frozen Canvas adds a splash of colou...
It is time to grab your gloves and layer up, as Torchlight: Infinite is diving into the frozen tundra in its sixth season. The Frozen Canvas is a colourful new update that brings a stylish flair to the Netherrealm and puts creativity in the... | Read more »
Back When AOL WAS the Internet – The Tou...
In Episode 606 of The TouchArcade Show we kick things off talking about my plans for this weekend, which has resulted in this week’s show being a bit shorter than normal. We also go over some more updates on our Patreon situation, which has been... | Read more »
Creative Assembly's latest mobile p...
The Total War series has been slowly trickling onto mobile, which is a fantastic thing because most, if not all, of them are incredibly great fun. Creative Assembly's latest to get the Feral Interactive treatment into portable form is Total War:... | Read more »

Price Scanner via MacPrices.net

Early Black Friday Deal: Apple’s newly upgrad...
Amazon has Apple 13″ MacBook Airs with M2 CPUs and 16GB of RAM on early Black Friday sale for $200 off MSRP, only $799. Their prices are the lowest currently available for these newly upgraded 13″ M2... Read more
13-inch 8GB M2 MacBook Airs for $749, $250 of...
Best Buy has Apple 13″ MacBook Airs with M2 CPUs and 8GB of RAM in stock and on sale on their online store for $250 off MSRP. Prices start at $749. Their prices are the lowest currently available for... Read more
Amazon is offering an early Black Friday $100...
Amazon is offering early Black Friday discounts on Apple’s new 2024 WiFi iPad minis ranging up to $100 off MSRP, each with free shipping. These are the lowest prices available for new minis anywhere... Read more
Price Drop! Clearance 14-inch M3 MacBook Pros...
Best Buy is offering a $500 discount on clearance 14″ M3 MacBook Pros on their online store this week with prices available starting at only $1099. Prices valid for online orders only, in-store... Read more
Apple AirPods Pro with USB-C on early Black F...
A couple of Apple retailers are offering $70 (28%) discounts on Apple’s AirPods Pro with USB-C (and hearing aid capabilities) this weekend. These are early AirPods Black Friday discounts if you’re... Read more
Price drop! 13-inch M3 MacBook Airs now avail...
With yesterday’s across-the-board MacBook Air upgrade to 16GB of RAM standard, Apple has dropped prices on clearance 13″ 8GB M3 MacBook Airs, Certified Refurbished, to a new low starting at only $829... Read more
Price drop! Apple 15-inch M3 MacBook Airs now...
With yesterday’s release of 15-inch M3 MacBook Airs with 16GB of RAM standard, Apple has dropped prices on clearance Certified Refurbished 15″ 8GB M3 MacBook Airs to a new low starting at only $999.... Read more
Apple has clearance 15-inch M2 MacBook Airs a...
Apple has clearance, Certified Refurbished, 15″ M2 MacBook Airs now available starting at $929 and ranging up to $410 off original MSRP. These are the cheapest 15″ MacBook Airs for sale today at... Read more
Apple drops prices on 13-inch M2 MacBook Airs...
Apple has dropped prices on 13″ M2 MacBook Airs to a new low of only $749 in their Certified Refurbished store. These are the cheapest M2-powered MacBooks for sale at Apple. Apple’s one-year warranty... Read more
Clearance 13-inch M1 MacBook Airs available a...
Apple has clearance 13″ M1 MacBook Airs, Certified Refurbished, now available for $679 for 8-Core CPU/7-Core GPU/256GB models. Apple’s one-year warranty is included, shipping is free, and each... Read more

Jobs Board

Seasonal Cashier - *Apple* Blossom Mall - J...
Seasonal Cashier - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Seasonal Fine Jewelry Commission Associate -...
…Fine Jewelry Commission Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) Read more
Seasonal Operations Associate - *Apple* Blo...
Seasonal Operations Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Read more
Hair Stylist - *Apple* Blossom Mall - JCPen...
Hair Stylist - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Blossom Read more
Cashier - *Apple* Blossom Mall - JCPenney (...
Cashier - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Blossom Mall Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.