DrawCode.c

/*
    File:       DrawCode.c
 
    Contains:   DragWindowGrid- a big nasty function to Drag a window along grid lines.  
                Note the elegant error handling.  You should change it to make your users happy.
    
                You can change the size of the 'grid rects' by changing the value of kIncrement.
 
    Written by:     
 
    Copyright:  Copyright © 1999 by Apple Computer, Inc., All Rights Reserved.
 
                You may incorporate this Apple sample source code into your program(s) without
                restriction. This Apple sample source code has been provided "AS IS" and the
                responsibility for its operation is yours. You are not permitted to redistribute
                this Apple sample source code as "Apple sample source code" after having made
                changes. If you're going to re-distribute the source, we require that you make
                it clear in the source that the code was descended from Apple sample source
                code, but that you've made changes.
 
    Change History (most recent first):
                8/5/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
                
 
*/
#include <Windows.h>
#include <QuickDraw.h>
#include <TextUtils.h>
#include <Fonts.h>
#include <Memory.h>
 
void DragWindowGrid(WindowPtr win, Point pt);
void DrawIt(WindowPtr win);
pascal void DrawWindowContent(short pixelDepth, short dFlags, GDHandle theDevice, long theWin);
void MyCreateNewWindow(void);
void PreEventLoop(void);
void DoUpdate(WindowPtr thisWindow);
void PostEventLoop(void);
 
void DragWindowGrid(WindowPtr win, Point pt)
{
    RgnHandle   dragRgn, lastDragRgn, insetGray;
    GrafPtr     oldPort, tmpPort;
    Point       currPt, firstMulPoint, lastMulPoint, currMulPoint;
    Boolean     frameHidden;
    enum        {kIncrement = 16, kBorderInset = 4};
 
    // Set up our regions - init our variables.
    dragRgn = NewRgn(); 
    lastDragRgn = NewRgn(); 
    insetGray = NewRgn();
    if ((dragRgn == NULL) || (lastDragRgn == NULL) || (insetGray == NULL)) {
        DebugStr("\pnot enough memory- bye!");
        return;
    }
    CopyRgn(GetGrayRgn(), insetGray);
    if (MemError() != noErr) {
        DebugStr("\pnot enough memory- bye!");
        return;
    }
 
    InsetRgn(insetGray, kBorderInset, kBorderInset);
    frameHidden = false;
 
    // Set up a port to draw into, and save off the old
    tmpPort = (GrafPtr)NewPtr(sizeof(GrafPort));
    if (tmpPort == NULL) {
        DebugStr("\pnot enough memory- bye!");
        return;
    }
    GetPort(&oldPort);
    OpenPort(tmpPort);
    CopyRgn(GetGrayRgn(), tmpPort->visRgn);
    if (MemError() != noErr) {
        DebugStr("\pnot enough memory- bye!");
        return;
    }
    tmpPort->portRect = (*GetGrayRgn())->rgnBBox;
    SetPort(tmpPort);
    
    PenMode(patXor);
    PenPat(&qd.gray);
 
    // Set the incoming point to be on a multiple of kIncrement,
    // to make later calculations easier.
    currMulPoint.h = pt.h + (kIncrement/2);
    currMulPoint.h /= kIncrement; currMulPoint.h *= kIncrement;
    currMulPoint.v = pt.v + (kIncrement/2);
    currMulPoint.v /= kIncrement; currMulPoint.v *= kIncrement;
 
    firstMulPoint = lastMulPoint = currMulPoint;
 
    CopyRgn(((WindowPeek)win)->strucRgn, dragRgn);
    if (MemError() != noErr) {
        DebugStr("\pnot enough memory- bye!");
        return;
    }
 
    CopyRgn(((WindowPeek)win)->strucRgn, lastDragRgn);
    if (MemError() != noErr) {
        DebugStr("\pnot enough memory- bye!");
        return;
    }
 
    // Draw the first framed region, which will follow the mouse
    // on the screen
    FrameRgn(lastDragRgn);
 
    while (WaitMouseUp() == true) {
        // Now track the mouse, and when it moves enough make the framed
        // region move as well.
        GetMouse(&currPt);
    
        // Set the new point to be on a multiple of kIncrement
        currMulPoint.h = currPt.h + (kIncrement/2);
        currMulPoint.h /= kIncrement; currMulPoint.h *= kIncrement;
        currMulPoint.v = currPt.v + (kIncrement/2);
        currMulPoint.v /= kIncrement; currMulPoint.v *= kIncrement;
 
        // Should we be showing the frame region ??
        if (PtInRgn(currPt, insetGray) == false) {
            // It's somewhere near the edges, so hide the frame
            if (frameHidden == false)
                // if it's not hidden already, hide it now
                FrameRgn(lastDragRgn);
            frameHidden = true;
        }
        else {
            // else, the frame should be shown if it's hidden
            if (frameHidden == true) {
                FrameRgn(lastDragRgn);
                frameHidden = false;
            }
        }
    
        // Has the mouse moved ?
        if (&currMulPoint != &lastMulPoint) {           
            // The mouse coordinates have changed enough to adjust the window,
            // so move the frame accordingly
            OffsetRgn(dragRgn, currMulPoint.h - lastMulPoint.h, currMulPoint.v - lastMulPoint.v);
 
            if (frameHidden == false) {
                // Only show the frame if we're allowed to.
                FrameRgn(dragRgn);      
                FrameRgn(lastDragRgn);
            }
            lastMulPoint = currMulPoint;
            CopyRgn(dragRgn, lastDragRgn);
            if (MemError() != noErr) {
                DebugStr("\pnot enough memory- bye!");
                return;
            }
        }   
    }
    
    if (frameHidden == false)
        // If frameHidden is true, there's no need to erase the final
        // frame.
        FrameRgn(lastDragRgn);
 
    if ((&lastMulPoint != &firstMulPoint) && (frameHidden == false)) {
        // The mouse has moved from its original position and is
        // somewhere on the screen, so move the window accordingly.
        Point   globalPt, diffPt, contPt = {0, 0};
 
        // Calculate the difference between the strucRgn's 0, 0 and
        // the window's content region 0, 0.  Remember that MoveWindow
        // moves the window's *content* to the coordinate specified, and
        // we want to move the window's structure to fit in the lastDragRgn
        SetPort(win);
        // LocalToGlobal works much better when the port is set up...
        LocalToGlobal(&contPt);
        SetPort(tmpPort);
        diffPt.h = contPt.h - (*((WindowPeek)win)->strucRgn)->rgnBBox.left;
        diffPt.v = contPt.v - (*((WindowPeek)win)->strucRgn)->rgnBBox.top;
        
        globalPt.h = (*lastDragRgn)->rgnBBox.left;
        globalPt.v = (*lastDragRgn)->rgnBBox.top;
        LocalToGlobal(&globalPt);
        globalPt.h += diffPt.h;
        globalPt.v += diffPt.v;
        MoveWindow(win, globalPt.h, globalPt.v, true);
    }
 
    // Close the port and tear everything down
    ClosePort(tmpPort);
    SetPort(oldPort);
    DisposeRgn(dragRgn);
    DisposeRgn(insetGray);
    DisposeRgn(lastDragRgn);
    
}
 
 
/*-------------------------------------------------------------------------------------*/
 
void DrawIt(WindowPtr win)
{
    short       origFont, origSize;
    
    origFont = win->txFont;
    origSize = win->txSize;
    TextFont(kFontIDCourier);
    TextSize(12);
 
    ForeColor(redColor);
    PaintRect(&(*win).portRect);
    ForeColor(blackColor);
 
    MoveTo(20, 20);
    DrawString("\pDrag this window.");
 
    TextFont(origFont);
    TextSize(origSize);
}
 
 
/*-------------------------------------------------------------------------------------*/
 
pascal void DrawWindowContent(short pixelDepth, short dFlags, GDHandle theDevice, long theWin)
{
#pragma unused (pixelDepth, dFlags, theDevice)
    GrafPtr     savePort;
 
    GetPort(&savePort);
    SetPort((GrafPtr)theWin);
 
    DrawIt((WindowPtr)theWin);
 
    SetPort(savePort);
}
 
 
/*-------------------------------------------------------------------------------------*/
 
void MyCreateNewWindow(void)
{
    Rect winDimension;
    
    SetRect(&winDimension, 60, 60, 460, 260);
    (void)NewCWindow(0L, &winDimension, "\pSample", true, noGrowDocProc,
                            (WindowPtr)-1L, true, 0L);
}
 
 
/*-------------------------------------------------------------------------------------*/
 
void PreEventLoop(void)
{
    MyCreateNewWindow();
}
 
 
/*-------------------------------------------------------------------------------------*/
 
void DoUpdate(WindowPtr thisWindow)
{
    static DeviceLoopDrawingUPP procForDeviceLoop = nil;
 
    SetPort(thisWindow);
 
    if ( procForDeviceLoop == nil )
        procForDeviceLoop = NewDeviceLoopDrawingProc(DrawWindowContent);    
    
    BeginUpdate(thisWindow);
    DeviceLoop(thisWindow->visRgn, procForDeviceLoop, (long)thisWindow, singleDevices);
    EndUpdate(thisWindow);
}
 
 
/*-------------------------------------------------------------------------------------*/
 
void PostEventLoop(void)
{
}