ThinkC QuadWindows - going a bit beyond [Study Group 1] with event detection

Relating to ThinkC Development

Mu0n

Active Tinkerer
Oct 29, 2021
609
560
93
Quebec
www.youtube.com
I have a question about detecting mouse-over event management. There's no MacTrap function destined for it so you have to poll the mouse location with GetMouse (gets you local coordinates) and compare it to something related to the GrafPort you're using (window, whole screen, etc.). My question is, how can I not make it so dang awkward! The only way I found forces me to do a lot of prep and I wonder if I'm just missing a useful helper function or two here.


Problem #1:
Can't seem to shake off a few lines of the bottom right window whenever you switch ink color, despite calling a FillRect to get rid of the old stuff

Problem #2:
You have to slow down your drawing, otherwise you only get a bunch of separated squares. I wish it would mimick mac paint more and produce continuous lines/curves.

Problem #3:
In order to detect a mouse-over a particular window, I have to:
1) GetMouse the mouse coordinates in local coordinates
2) Transform them into global coordinates
3) SetPort into an individual window where I want to detect a mouse-over situation
4) transform the mouse coordinates into that local coordinates
5) Use PtInRegion with the local->global->second local mouse Point with the (WindowPtr->visRgn) region

No matter what I tried (portRect, GrafPort.portBits.bounds or others, all of these retangles seem to work in local coordinates, forcing me to wrangle my info to the specific local coordinates I wanted to check. I'd love to have a way to de-convert a local rect to global rect.


I didn't want to add to the week 1 thread of the THINK C programming club here https://tinkerdifferent.com/threads/study-group-1-drawing-on-the-macintosh.1811/
since I tried my own thing with multiple windows, attempting and mostly succeeding at:

-Load and display 4 small windows from a resource file
-Deal with mouse-over events (this has to be done manually by comparing an old mouse position that's polled frequently and seeing if the mouse's Point data is inside a region with the PtInRegion function
-Allow to paint with the mouse in one window
-Do the FlyingLines demo in one window
-Allow pen color changes by simply mousing over the remaining two other windows

Here it is in action:



See attached .SIT file for Symantec THINK C v6 project, source code and executable.

Here's the full code source

C:
#define kBaseResID            128

#define kTopLeftWin            kBaseResID
#define kTopRighttWin        kBaseResID+1
#define kBottomLeftWin        kBaseResID+2
#define kBottomRighttWin    kBaseResID+3

#define    kNumLines            20              // used in the flyingLines window
#define kMoveToFront        (WindowPtr)-1L // used when spawning the windows
#define kRandomUpperLimit    32768            // used in the flyingLines window
#define kEmptyString        "\p"           // used in every Pascal-type string
#define kEmptyTitle         kEmptyString   // used in windows without a title
#define kVisible            true           // used when spawning the windows
#define kNoGoAway            false           // used for windows without a close button
#define kNilRefCon            (long)nil       // used when spawning windows, no record wanted

#define mFile                 kBaseResID
#define iQuit                1

// GLOBALS

Rect            gLines[kNumLines];                   // used in the flyingLines window
short            gDeltaTop = 3, gDeltaBottom = 3;   // used in the flyingLines window
short            gDeltaLeft = 2, gDeltaRight = 6;   // used in the flyingLines window
WindowPtr       gTLwin, gTRwin, gBLwin, gBRwin;       // tracks all 4 window pointers for later detections
short           gCurrentInk;                        // current Pattern for the pen
PatPtr          gOldPattern;               // detects color changes for single triggers during changes

//FUNCTIONS

void  ToolBoxInit(void);                       // runs once at the start, initializes Mac managers
void  WindowInit(void);                           // runs once at the start, initializes all 4 windows
void  LinesInit(void);                           // runs once at the start, initializes the lines for flyingLines
void  MenuBarInit(void);                        // runs once at the start, initializes the menu
void  HandleMenuChoice(long menuChoice);       // handles menu choices
void  HandleFileChoice(short item);               // handles file menu choice
void  HandleMouseDown(EventRecord *eventPtr);  // handles mouse down event
void  MainLoop(void);                           // runs constantly until quitting, main loop
void  UpdateLinesInLoop(void);                   // runs once per loop to do the lines
void  DetectInkChangeInLoop(WindowPtr theWindow, short tMode, PatPtr color);                   // runs once per loop to see if a new ink has to be chosen
void  DetectPenDrag(void);                       // runs once per loop to see if a pen drag has to be drawn
void  RandomRect(Rect *rectPtr);               // is used by flyingLines
short Randomize(short range);                   // is used by flyingLines
void  RecalcLine(short i);                     // is used by flyingLines
void  DrawLine(short i);                         // is used by flyingLines
void  DetectPainting(Point *oldMousePoint, Point *newMousePoint);   //runs once per loop to see if painting should occur in the top right window

// TOOLBOXINIT

void ToolBoxInit()
    {
    InitGraf(&thePort);
    InitFonts();
    InitWindows();
    InitMenus();
    TEInit();
    InitDialogs(nil);
    InitCursor();
    }
    
// MENUBARINIT
void MenuBarInit()
    {
    Handle menuBar;
    MenuHandle menu;
    
    menuBar = GetNewMBar( kBaseResID);
    SetMenuBar(menuBar);
    
    DrawMenuBar();
    }

//HANDLEMENUCHOICE
void HandleMenuChoice(long menuChoice)
    {
    short menu;
    short item;
    
    if(menuChoice != 0)
        {
        menu = HiWord(menuChoice);
        item = LoWord(menuChoice);
        
        switch(menu)
            {
            case mFile:
                HandleFileChoice(item);
                break;
            }
        HiliteMenu(0);
        }
    }   

// HANDLEFILECHOICE
void HandleFileChoice(short item)
    {
    switch(item)
        {
        case iQuit:
            ExitToShell();
            break;
        }
    }

// HANDLEMOUSEDOWN
void HandleMouseDown(EventRecord *eventPtr)
    {
    WindowPtr whichWindow;
    short thePart;
    long menuChoice;
    
    thePart = FindWindow(eventPtr->where, &whichWindow);
    switch(thePart)
        {
        case inMenuBar:
            menuChoice = MenuSelect(eventPtr->where);
            HandleMenuChoice(menuChoice);
            break;
        }
    }

// WINDOWINIT
// Will initialize all 4 windows and keep the pointers for future updating
// TOP LEFT: BLACK INK - if you mouse over it, the pattern will change to black
// TOP RIGHT: CANVAS - if you mouse over it, it will draw a pen over the window in the chosen ink
// BOTTOM LEFT: WHITE INK - if you mouse over it, the pattern will change to white
// BOTTOM RIGHT: FLYING LINES - a screensaver like random line pattern is continually updated in the loop

void WindowInit(void)         
    {
    WindowPtr window;
    
    //TOP LEFT
    gTLwin = GetNewWindow(kTopLeftWin, nil, kMoveToFront);
    if(gTLwin == nil)
        {
        SysBeep(10); //can't load window resource
        ExitToShell();
        }
    ShowWindow(gTLwin);
    SetPort(gTLwin);
    PenPat(white);
    FillRect(&(gTLwin->portRect),black);
    
    //TOP RIGHT
    gTRwin = GetNewWindow(kTopRighttWin, nil, kMoveToFront);
    if(gTRwin == nil)
        {
        SysBeep(10); //can't load window resource
        ExitToShell();
        }
    ShowWindow(gTRwin);
    SetPort(gTRwin);
    PenPat(black);
    PenSize(5,5);
    FillRect(&(gTRwin->portRect),white);
    
    //BOTTOM LEFT
    gBLwin = GetNewWindow(kBottomLeftWin, nil, kMoveToFront);
    if(gBLwin == nil)
        {
        SysBeep(10); //can't load window resource
        ExitToShell();
        }
    ShowWindow(gBLwin);
    SetPort(gBLwin);
    PenPat(black);
    
    
    //BOTTOM RIGHT
    gBRwin = GetNewWindow(kBottomRighttWin, nil, kMoveToFront);
    if(gBRwin == nil)
        {
        SysBeep(10); //can't load window resource
        ExitToShell();
        }
    ShowWindow(gBRwin);
    SetPort(gBRwin);
    PenMode(patXor);
    }
    
// LINESINIT

void LinesInit(void)
    {
    short i;
    WindowPtr currentWin;
    
    GetPort(&currentWin);
    HideCursor();
    
    SetPort(gTLwin);
    GetDateTime((unsigned long *)(&randSeed));
    SetPort(gTRwin);
    GetDateTime((unsigned long *)(&randSeed));
    SetPort(gBLwin);
    GetDateTime((unsigned long *)(&randSeed));
    SetPort(gBRwin);
    GetDateTime((unsigned long *)(&randSeed));
    
    RandomRect(&(gLines[0]));
    DrawLine(0);
    
    for(i=1; i<kNumLines; i++)
        {
        gLines[i] = gLines[i-1];
        RecalcLine(i);
        DrawLine(i);
        }
    ShowCursor();
    SetPort(currentWin);
    }   
    
//MAIN

void main(void)
    {
    ToolBoxInit();
    MenuBarInit();
    WindowInit();
    LinesInit();
    MainLoop();
    }
    
    
    // MAINLOOP

void MainLoop(void)
    {
    EventRecord wutup;
    Boolean exitFlag = false;
    Point oldMousePoint;
    GetMouse(&oldMousePoint);
    LocalToGlobal(&oldMousePoint);
    
    while(exitFlag == false)       //exit condition as part of the while loop
        {
        Point newMousePoint;
        GetMouse(&newMousePoint);
        LocalToGlobal(&newMousePoint);

            
        GetNextEvent(everyEvent, &wutup);
        
        UpdateLinesInLoop();  //updates the flying lines
        DetectInkChangeInLoop(gTLwin, srcBic, &black);
        DetectInkChangeInLoop(gBLwin, srcOr, &white);
        DetectPainting(&oldMousePoint, &newMousePoint);   
        
        if(wutup.what==keyDown)
            {
            char theChar;
            theChar = wutup.message & charCodeMask;
            if((wutup.modifiers & cmdKey) != 0)
                {
                HandleMenuChoice(MenuKey(theChar));
                }
            }
        if(wutup.what==mouseDown)
            {
            HandleMouseDown(&wutup);
            }
            
        GetMouse(&oldMousePoint);
        LocalToGlobal(&oldMousePoint);
        }
    }

// MOUSE PAINTING

void DetectPainting(Point *oldMousePoint, Point *newMousePoint)
    {
    WindowPtr currentWin;
    
    GetPort(&currentWin);
    SetPort(gTRwin);
    GlobalToLocal(newMousePoint);
    GlobalToLocal(oldMousePoint);
    
    if(PtInRgn(*newMousePoint, gTRwin->visRgn) && Button())
        {
        MoveTo(newMousePoint->h, newMousePoint->v);
        LineTo(oldMousePoint->h, oldMousePoint->v);
        }
    LocalToGlobal(newMousePoint);
    LocalToGlobal(oldMousePoint);
    SetPort(currentWin);
    }

// INK CHANGING SECTION
void DetectInkChangeInLoop(WindowPtr theWindow, short tMode, PatPtr color)
    {
    Point currentMousePoint;
    WindowPtr currentWin;
    
    GetPort(&currentWin);
    GetMouse(&currentMousePoint);
    LocalToGlobal(&currentMousePoint);
    
    SetPort(theWindow);
    GlobalToLocal(&currentMousePoint);
    if(PtInRgn(currentMousePoint, theWindow->visRgn))
        {
        TextMode(tMode);
        MoveTo(theWindow->portRect.left, (theWindow->portRect.bottom-theWindow->portRect.top)/2);
        DrawString("\p   Your pen is now this color");
        
        if(*color==black && *gOldPattern != black)
            {
            SetPort(gBRwin);
            FillRect(&(gBRwin->portRect),white);
            PenMode(patXor);
            PenPat(*color);
            gOldPattern = color;
            }
        else if(*color == white && *gOldPattern != white)
            {
            SetPort(gBRwin);
            FillRect(&(gBRwin->portRect),black);
            PenMode(notPatXor);
            PenPat(*color);
            gOldPattern = color;
            }
        
        SetPort(gTRwin);
        PenPat(*color);
        }
    else
        {
        FillRect(&(theWindow->portRect),*color);
        }
    SetPort(currentWin);
    }


// FLYING LINES SECTION



// UPDATELINESINLOOP
void UpdateLinesInLoop(void)
    {
    WindowPtr currentWin;  //temporary keepsake of the active window so it can update the other ones
    short currentPenMode;  //temporary keepsake of the penMode
    short i;
    
    GetPort(&currentWin);    //backup the current window
    currentPenMode = thePort -> pnMode;
    
    SetPort(gBRwin);                //bottom right, update flying lines
    DrawLine(kNumLines - 1);         
    for(i=kNumLines-1; i>0; i--)
        gLines[i] = gLines[i-1];
    RecalcLine(0);
    DrawLine(0);
        
    SetPort(currentWin);            //go back to previous active window
    PenMode(currentPenMode);        //go back to previous pen mode
    }
    
    
// RANDOMRECT

void RandomRect(Rect *rectPtr)
    {
    rectPtr->left =   Randomize(gBRwin->portRect.right - gBRwin->portRect.left);
    rectPtr->right =  Randomize(gBRwin->portRect.right - gBRwin->portRect.left);
    rectPtr->top =    Randomize(gBRwin->portRect.bottom - gBRwin->portRect.top);
    rectPtr->bottom = Randomize(gBRwin->portRect.bottom - gBRwin->portRect.top);
    }
    
// RANDOMIZE

short Randomize(short range)
    {
    long randomNumber;
    
    randomNumber = Random();
    if(randomNumber < 0) randomNumber *=-1;
    
    return((randomNumber * range) / kRandomUpperLimit);
    }
    
// RECALCLINE

void RecalcLine(short i)
    {   
    gLines[i].top += gDeltaTop;
    if( (gLines[i].top < gBRwin->portRect.top) ||
        (gLines[i].top > gBRwin->portRect.bottom) )
        {
        gDeltaTop *= -1;
        gLines[i].top += 2*gDeltaTop;   
        }
    gLines[i].bottom += gDeltaBottom;
    if( (gLines[i].bottom < gBRwin->portRect.top) ||
        (gLines[i].bottom > gBRwin->portRect.bottom))
        {
        gDeltaBottom *= -1;
        gLines[i].bottom += 2*gDeltaBottom;
        }
    gLines[i].left += gDeltaLeft;
    if( (gLines[i].left < gBRwin->portRect.left) ||
        (gLines[i].left > gBRwin->portRect.right))
        {
        gDeltaLeft *= -1;
        gLines[i].left += 2*gDeltaLeft;
        }
    gLines[i].right += gDeltaRight;
    if( (gLines[i].right < gBRwin->portRect.left) ||
        (gLines[i].right > gBRwin->portRect.right))
        {
        gDeltaRight *= -1;
        gLines[i].right += 2* gDeltaRight;
        }
    }
    
// DRAWLINE

void DrawLine(short i) // no need to set the port here, it's only called by UpdateLinesInLoop and the port is set to the bottom right window
    {   
    MoveTo(gLines[i].left, gLines[i].top);
    LineTo(gLines[i].right,gLines[i].bottom);
    }
 

Attachments

  • QuadWindows.sit
    29.7 KB · Views: 113
  • Like
Reactions: pfuentes69

Crutch

Tinkerer
Jul 10, 2022
293
228
43
Chicago
It looks like you are just trying to check if the user moused over a window? You already know how to do that … call FindWindow(). It’s not just for mouse clicks!

C:
Point p;
WindowPtr w;

GetMouse(&p);
LocalToGlobal(&p);

if (FindWindow(p, &w) == inContent)
{
    if (w == firstWindow)
        ;  // user moused over firstWindow
    else if (w == secondWindow)
        ;  // user moused over secondWindow
}
 
  • Like
Reactions: Mu0n and pfuentes69

Crutch

Tinkerer
Jul 10, 2022
293
228
43
Chicago
Problem #1 - you are getting those residual lines because your line-drawing loop “erases” the old lines by drawing them using penmode patXor. However when you change colors, your FillRect() call instantly erases all the old lines. So when you later ”erase” all of the oldest lines one at a time by “drawing” them in patXor on an already-erased background, you are actually drawing the N oldest lines one last time, then they get stuck.

One instant solution would be to use InvertRect() instead of FillRect(), but only do so when the user mouseovers the color-changing window that corresponds to the color not already in use.
 
  • Like
Reactions: Mu0n

Crutch

Tinkerer
Jul 10, 2022
293
228
43
Chicago
Final observation: there is only one QD global randSeed for your whole A5 world. You don’t need to set it for all 4 GrafPorts.

So just one GetDateTime(&randSeed) or randSeed = TickCount() will do.
 
Last edited:

Mu0n

Active Tinkerer
Oct 29, 2021
609
560
93
Quebec
www.youtube.com
@Crutch Thanks a lot! It all worked. Here's the revised version

I have to set PenMode(patXor) when it's black lines on white background and notPatXor when it's white lines on a black background.




New Code:


C:
#define kBaseResID            128

#define kTopLeftWin            kBaseResID
#define kTopRighttWin        kBaseResID+1
#define kBottomLeftWin        kBaseResID+2
#define kBottomRighttWin    kBaseResID+3

#define    kNumLines            20              // used in the flyingLines window
#define kMoveToFront        (WindowPtr)-1L // used when spawning the windows
#define kRandomUpperLimit    32768            // used in the flyingLines window
#define kEmptyString        "\p"           // used in every Pascal-type string
#define kEmptyTitle         kEmptyString   // used in windows without a title
#define kVisible            true           // used when spawning the windows
#define kNoGoAway            false           // used for windows without a close button
#define kNilRefCon            (long)nil       // used when spawning windows, no record wanted

#define mFile                 kBaseResID
#define iQuit                1

// GLOBALS

Rect            gLines[kNumLines];                   // used in the flyingLines window
short            gDeltaTop = 3, gDeltaBottom = 3;   // used in the flyingLines window
short            gDeltaLeft = 2, gDeltaRight = 6;   // used in the flyingLines window
WindowPtr       gTLwin, gTRwin, gBLwin, gBRwin;       // tracks all 4 window pointers for later detections
short           gCurrentInk;                        // current Pattern for the pen
PatPtr          gOldPattern;               // detects color changes for single triggers during changes

//FUNCTIONS

void  ToolBoxInit(void);                       // runs once at the start, initializes Mac managers
void  WindowInit(void);                           // runs once at the start, initializes all 4 windows
void  LinesInit(void);                           // runs once at the start, initializes the lines for flyingLines
void  MenuBarInit(void);                        // runs once at the start, initializes the menu
void  HandleMenuChoice(long menuChoice);       // handles menu choices
void  HandleFileChoice(short item);               // handles file menu choice
void  HandleMouseDown(EventRecord *eventPtr);  // handles mouse down event
void  MainLoop(void);                           // runs constantly until quitting, main loop
void  UpdateLinesInLoop(void);                   // runs once per loop to do the lines
void  DetectInkChangeInLoop(WindowPtr theWindow, PatPtr color);                   // runs once per loop to see if a new ink has to be chosen
void  DetectPenDrag(void);                       // runs once per loop to see if a pen drag has to be drawn
void  RandomRect(Rect *rectPtr);               // is used by flyingLines
short Randomize(short range);                   // is used by flyingLines
void  RecalcLine(short i);                     // is used by flyingLines
void  DrawLine(short i);                         // is used by flyingLines
void  DetectPainting(Point *oldMousePoint, Point *newMousePoint);   //runs once per loop to see if painting should occur in the top right window

// TOOLBOXINIT

void ToolBoxInit()
    {
    InitGraf(&thePort);
    InitFonts();
    InitWindows();
    InitMenus();
    TEInit();
    InitDialogs(nil);
    InitCursor();
    }
    
// MENUBARINIT
void MenuBarInit()
    {
    Handle menuBar;
    MenuHandle menu;
    
    menuBar = GetNewMBar( kBaseResID);
    SetMenuBar(menuBar);
    
    DrawMenuBar();
    }

//HANDLEMENUCHOICE
void HandleMenuChoice(long menuChoice)
    {
    short menu;
    short item;
    
    if(menuChoice != 0)
        {
        menu = HiWord(menuChoice);
        item = LoWord(menuChoice);
        
        switch(menu)
            {
            case mFile:
                HandleFileChoice(item);
                break;
            }
        HiliteMenu(0);
        }
    }   

// HANDLEFILECHOICE
void HandleFileChoice(short item)
    {
    switch(item)
        {
        case iQuit:
            ExitToShell();
            break;
        }
    }

// HANDLEMOUSEDOWN
void HandleMouseDown(EventRecord *eventPtr)
    {
    WindowPtr whichWindow;
    short thePart;
    long menuChoice;
    
    thePart = FindWindow(eventPtr->where, &whichWindow);
    switch(thePart)
        {
        case inMenuBar:
            menuChoice = MenuSelect(eventPtr->where);
            HandleMenuChoice(menuChoice);
            break;
        }
    }

// WINDOWINIT
// Will initialize all 4 windows and keep the pointers for future updating
// TOP LEFT: BLACK INK - if you mouse over it, the pattern will change to black
// TOP RIGHT: CANVAS - if you mouse over it, it will draw a pen over the window in the chosen ink
// BOTTOM LEFT: WHITE INK - if you mouse over it, the pattern will change to white
// BOTTOM RIGHT: FLYING LINES - a screensaver like random line pattern is continually updated in the loop

void WindowInit(void)         
    {
    WindowPtr window;
    
    //TOP LEFT
    gTLwin = GetNewWindow(kTopLeftWin, nil, kMoveToFront);
    if(gTLwin == nil)
        {
        SysBeep(10); //can't load window resource
        ExitToShell();
        }
    ShowWindow(gTLwin);
    SetPort(gTLwin);
    TextMode(srcBic);
    PenPat(white);
    FillRect(&(gTLwin->portRect),black);
    
    //TOP RIGHT
    gTRwin = GetNewWindow(kTopRighttWin, nil, kMoveToFront);
    if(gTRwin == nil)
        {
        SysBeep(10); //can't load window resource
        ExitToShell();
        }
    ShowWindow(gTRwin);
    SetPort(gTRwin);
    PenPat(black);
    PenSize(5,5);
    FillRect(&(gTRwin->portRect),white);
    
    //BOTTOM LEFT
    gBLwin = GetNewWindow(kBottomLeftWin, nil, kMoveToFront);
    if(gBLwin == nil)
        {
        SysBeep(10); //can't load window resource
        ExitToShell();
        }
    ShowWindow(gBLwin);
    SetPort(gBLwin);
    TextMode(srcOr);
    PenPat(black);
    FillRect(&(gBLwin->portRect),white);
    
    
    //BOTTOM RIGHT
    gBRwin = GetNewWindow(kBottomRighttWin, nil, kMoveToFront);
    if(gBRwin == nil)
        {
        SysBeep(10); //can't load window resource
        ExitToShell();
        }
    ShowWindow(gBRwin);
    SetPort(gBRwin);
    PenMode(patXor);
    }
    
// LINESINIT

void LinesInit(void)
    {
    short i;
    WindowPtr currentWin;
    
    GetPort(&currentWin);

    GetDateTime((unsigned long *)(&randSeed));  //initializes the random seed in this app's A5 world
    SetPort(gBRwin); // Preps to draw the initial lines
    
    RandomRect(&(gLines[0]));
    DrawLine(0);
    
    for(i=1; i<kNumLines; i++)
        {
        gLines[i] = gLines[i-1];
        RecalcLine(i);
        DrawLine(i);
        }
    SetPort(currentWin);
    }   
    
//MAIN

void main(void)
    {
    ToolBoxInit();
    MenuBarInit();
    WindowInit();
    LinesInit();
    MainLoop();
    }
    
    
    // MAINLOOP

void MainLoop(void)
    {
    EventRecord wutup;
    Boolean exitFlag = false;
    Point oldMousePoint;
    GetMouse(&oldMousePoint);
    LocalToGlobal(&oldMousePoint);
    
    while(exitFlag == false)       //exit condition as part of the while loop
        {
        Point newMousePoint;
        GetMouse(&newMousePoint);
        LocalToGlobal(&newMousePoint);

            
        GetNextEvent(everyEvent, &wutup);
        
        UpdateLinesInLoop();  //updates the flying lines
        DetectInkChangeInLoop(gTLwin, &black);
        DetectInkChangeInLoop(gBLwin, &white);
        DetectPainting(&oldMousePoint, &newMousePoint);   
        
        if(wutup.what==keyDown)
            {
            char theChar;
            theChar = wutup.message & charCodeMask;
            if((wutup.modifiers & cmdKey) != 0)
                {
                HandleMenuChoice(MenuKey(theChar));
                }
            }
        if(wutup.what==mouseDown)
            {
            HandleMouseDown(&wutup);
            }
            
        GetMouse(&oldMousePoint);
        LocalToGlobal(&oldMousePoint);
        }
    }

// MOUSE PAINTING

void DetectPainting(Point *oldMousePoint, Point *newMousePoint)
    {
    WindowPtr currentWin;
    
    GetPort(&currentWin);
    SetPort(gTRwin);
    GlobalToLocal(newMousePoint);
    GlobalToLocal(oldMousePoint);
    
    if(PtInRgn(*newMousePoint, gTRwin->visRgn) && Button())
        {
        MoveTo(newMousePoint->h, newMousePoint->v);
        LineTo(oldMousePoint->h, oldMousePoint->v);
        }
    LocalToGlobal(newMousePoint);
    LocalToGlobal(oldMousePoint);
    SetPort(currentWin);
    }

// INK CHANGING SECTION
void DetectInkChangeInLoop(WindowPtr theWindow, PatPtr color)
    {
    Point currentMousePoint;
    WindowPtr w, savedWindow;
    
    GetPort(&savedWindow); //safeguard the current port, assume nothing about the current active window
    GetMouse(&currentMousePoint);
    LocalToGlobal(&currentMousePoint);
    
    if(FindWindow(currentMousePoint, &w) == inContent && w == theWindow)    //checks if the converted-to-local mouse coordinates are detected in the chosen window
        {
        SetPort(theWindow);
        MoveTo(theWindow->portRect.left, (theWindow->portRect.bottom-theWindow->portRect.top)/2);
        DrawString("\p   Your pen is now this color");
        
        if(*color==black && *gOldPattern != black)
            {
            SetPort(gBRwin);
            InvertRect(&(gBRwin->portRect));
            PenPat(*color);
            gOldPattern = color;
            PenMode(patXor);
            }
        else if(*color == white && *gOldPattern != white)
            {
            SetPort(gBRwin);
            InvertRect(&(gBRwin->portRect));
            PenPat(*color);
            gOldPattern = color;
            PenMode(notPatXor);
            }
        
        SetPort(gTRwin);
        PenPat(*color);
        }
    else
        {
        SetPort(theWindow);
        FillRect(&(theWindow->portRect),*color);
        }
    SetPort(savedWindow); //restore the active window to clean up this operation
    }


// FLYING LINES SECTION



// UPDATELINESINLOOP
void UpdateLinesInLoop(void)
    {
    WindowPtr currentWin;  //temporary keepsake of the active window so it can update the other ones
    short i;
    
    GetPort(&currentWin);    //backup the current window
    
    SetPort(gBRwin);                //bottom right, update flying lines
    DrawLine(kNumLines - 1);         
    for(i=kNumLines-1; i>0; i--)
        gLines[i] = gLines[i-1];
    RecalcLine(0);
    DrawLine(0);
        
    SetPort(currentWin);            //go back to previous active window
    }
    
    
// RANDOMRECT

void RandomRect(Rect *rectPtr)
    {
    rectPtr->left =   Randomize(gBRwin->portRect.right - gBRwin->portRect.left);
    rectPtr->right =  Randomize(gBRwin->portRect.right - gBRwin->portRect.left);
    rectPtr->top =    Randomize(gBRwin->portRect.bottom - gBRwin->portRect.top);
    rectPtr->bottom = Randomize(gBRwin->portRect.bottom - gBRwin->portRect.top);
    }
    
// RANDOMIZE

short Randomize(short range)
    {
    long randomNumber;
    
    randomNumber = Random();
    if(randomNumber < 0) randomNumber *=-1;
    
    return((randomNumber * range) / kRandomUpperLimit);
    }
    
// RECALCLINE

void RecalcLine(short i)
    {   
    gLines[i].top += gDeltaTop;
    if( (gLines[i].top < gBRwin->portRect.top) ||
        (gLines[i].top > gBRwin->portRect.bottom) )
        {
        gDeltaTop *= -1;
        gLines[i].top += 2*gDeltaTop;   
        }
    gLines[i].bottom += gDeltaBottom;
    if( (gLines[i].bottom < gBRwin->portRect.top) ||
        (gLines[i].bottom > gBRwin->portRect.bottom))
        {
        gDeltaBottom *= -1;
        gLines[i].bottom += 2*gDeltaBottom;
        }
    gLines[i].left += gDeltaLeft;
    if( (gLines[i].left < gBRwin->portRect.left) ||
        (gLines[i].left > gBRwin->portRect.right))
        {
        gDeltaLeft *= -1;
        gLines[i].left += 2*gDeltaLeft;
        }
    gLines[i].right += gDeltaRight;
    if( (gLines[i].right < gBRwin->portRect.left) ||
        (gLines[i].right > gBRwin->portRect.right))
        {
        gDeltaRight *= -1;
        gLines[i].right += 2* gDeltaRight;
        }
    }
    
// DRAWLINE

void DrawLine(short i) // no need to set the port here, it's only called by UpdateLinesInLoop and the port is set to the bottom right window
    {   
    MoveTo(gLines[i].left, gLines[i].top);
    LineTo(gLines[i].right,gLines[i].bottom);
    }
 

Attachments

  • QuadWindows2.sit
    29.8 KB · Views: 106
  • Like
  • Love
Reactions: Crutch and eric