AmendHub

Download:

schrockwell

/

PopUp

/

amendments

/

1

Add initial PopUp library and README


schrockwell made amendment 1 5 days ago
--- PopUp.c Wed Oct 15 18:31:27 2025 +++ PopUp.c Wed Oct 15 18:31:27 2025 @@ -0,0 +1,182 @@ +#include "PopUp.h" + +PopUpPtr CreatePopUp(WindowPtr window, Rect *bounds, MenuHandle menu, short style) +{ + PopUpPtr popup; + + popup = (PopUpPtr)NewPtr(sizeof(PopUpRec)); + if (popup == nil) + return nil; + + InsertMenu(menu, -1L); + + popup->menu = menu; + popup->window = window; + popup->item = 1; + popup->bounds = *bounds; + popup->style = style; + + return popup; +} + +void DisposePopUp(PopUpPtr popup) +{ + if (popup == nil) + return; + + DisposPtr((Ptr)popup); +} + +void DrawPopUp(PopUpPtr popup) +{ + GrafPtr prevPort; + + GetPort(&prevPort); + SetPort(popup->window); + + // draw border + FrameRect(&popup->bounds); + + // draw shadow + MoveTo(popup->bounds.left + 1, popup->bounds.bottom); + LineTo(popup->bounds.right, popup->bounds.bottom); + LineTo(popup->bounds.right, popup->bounds.top + 1); + + // draw text and triangle + _DrawPopUpItem(popup); + + SetPort(prevPort); +} + +void _DrawPopUpItem(PopUpPtr popup) +{ + Str255 menuItem; + Rect bgRect; + RgnHandle prevClip; + + PolyHandle triangle; + Point pt1, pt2, pt3; + + if (popup->style & kPopUpStyleText) + { + // determine text + GetItem(popup->menu, popup->item, &menuItem); + + // fill bg with white + bgRect = popup->bounds; + InsetRect(&bgRect, 1, 1); + FillRect(&bgRect, white); + + // draw item text + MoveTo( + popup->bounds.left + 5, // left margin + popup->bounds.bottom - 5 // bottom margin + ); + TextFont(0); + DrawString(menuItem); + } + + if (popup->style & kPopUpStyleCaret) + { + // draw disclosure triangle + pt1.h = popup->bounds.right - 17; + pt1.v = popup->bounds.top + 6; + + pt2.h = popup->bounds.right - 5; + pt2.v = pt1.v; + + pt3.h = popup->bounds.right - 11; + pt3.v = popup->bounds.top + 13; + + triangle = OpenPoly(); + MoveTo(pt1.h, pt1.v); + LineTo(pt2.h, pt2.v); + LineTo(pt3.h, pt3.v); + LineTo(pt1.h, pt1.v); + ClosePoly(); + + FillPoly(triangle, black); + KillPoly(triangle); + } +} + +Boolean HandlePopUpEvent(PopUpPtr popup, EventRecord *eventPtr) +{ + WindowPtr window; + long thePart; + long menuChoice; + + if (eventPtr->what != mouseDown) + return false; + + thePart = FindWindow(eventPtr->where, &window); + + if (!(window == popup->window && thePart == inContent)) + return false; + + return _HandlePopUpMouseDownInContent(popup, eventPtr); +} + +Boolean _HandlePopUpMouseDownInContent(PopUpPtr popup, EventRecord *eventPtr) +{ + Point eventPoint, popUpPoint; + short choice; + Rect invertBounds; + GrafPtr prevPort; + + eventPoint = eventPtr->where; + GlobalToLocal(&eventPoint); + + if (PtInRect(eventPoint, &popup->bounds)) + { + GetPort(&prevPort); + SetPort(popup->window); + + invertBounds = popup->bounds; + InsetRect(&invertBounds, 1, 1); + + popUpPoint.v = popup->bounds.top + 1; + popUpPoint.h = popup->bounds.left + 1; + LocalToGlobal(&popUpPoint); + + InvertRect(&invertBounds); + + if (popup->style & kPopUpStyleCheck) + CheckItem(popup->menu, popup->item, true); + + choice = PopUpMenuSelect( + popup->menu, + popUpPoint.v, + popUpPoint.h, + popup->item + ); + + InvertRect(&invertBounds); + + if (popup->style & kPopUpStyleCheck) + CheckItem(popup->menu, popup->item, false); + + SetPort(prevPort); + + if (LoWord(choice) > 0) + { + SelectPopUpItem(popup, LoWord(choice)); + return true; + } + } + + return false; +} + +void SelectPopUpItem(PopUpPtr popup, short item) +{ + GrafPtr prevPort; + + GetPort(&prevPort); + SetPort(popup->window); + + popup->item = item; + _DrawPopUpItem(popup); + + SetPort(prevPort); +} --- PopUp.h Wed Oct 15 18:33:02 2025 +++ PopUp.h Wed Oct 15 18:33:02 2025 @@ -0,0 +1,38 @@ +#ifndef __POPUP_H__ +#define __POPUP_H__ + +#define kPopUpStyleText 0x01 // draw current item text +#define kPopUpStyleCaret 0x02 // draw disclosure triangle +#define kPopUpStyleCheck 0x04 // check current item in menu +#define kPopUpStyleAll 0xFF // all of the above + +typedef struct PopUpRec +{ + WindowPtr window; + MenuHandle menu; + Rect bounds; + short item; + short style; +} PopUpRec, *PopUpPtr, **PopUpHandle; + +// Returns a newly-allocated pointer to a PopUpRec +PopUpPtr CreatePopUp(WindowPtr window, Rect *bounds, MenuHandle menu, short style); + +// Frees memory +void DisposePopUp(PopUpPtr popup); + +// Paints the control frame, text, and other elements. Must be called +// during the window update cycle, between BeginUpdate() and EndUpdate() +void DrawPopUp(PopUpPtr popup); + +// Hook to handle mouse-down events that trigger the menu. Must be called +// in the main event loop. Returns true if the event was handled. +Boolean HandlePopUpEvent(PopUpPtr popup, EventRecord *eventPtr); + +// Changes the currently-selected item index and repaints the control +void SelectPopUpItem(PopUpPtr popup, short item); + +// Library use only +void _DrawPopUpItem(PopUpPtr popup); +Boolean _HandlePopUpMouseDownInContent(PopUpPtr popup, EventRecord *eventPtr); +#endif --- README Wed Oct 15 18:35:43 2025 +++ README Wed Oct 15 18:35:43 2025 @@ -0,0 +1,79 @@ + Easy Pop-Up Menus for System 6! + Rockwell Schrock <rockwell@schrock.me> + https://schrockwell.com + +This library makes it more convenient to add pop-up menus to System 6 +applications. + +In System 7 and later, you can define a control with procID 1008, but +prior to that, some hand-holding is required to achieve the expected +control behavior. + +These functions take care of the grunt work for System 6: + +- drawing the control +- opening the menu with PopUpMenuSelect() +- storing the selected item + +To use it, you only need to provide: + +- a WindowPtr for the containing window +- a Rect for the bounds of the menu control +- a MenuHandle to the menu +- styling options + +...and add hooks in three places: + +1. Initialization +2. Event loop +3. Window update + +See PopUp.h for more documentation and styling options. + +=== Example === + +// 1. Initialization + +PopUpPtr gPopup; // <--- + +void WindowInit() +{ + WindowPtr window; + Rect windRect; + Rect popupRect = { 10, 10, 29, 120 }; // <--- recommend 19px height + MenuHandle menu; + + window = GetNewWindow(kBaseResID, nil, kMoveToFront); + menu = GetMenu(kPopUpMenuResourceID); + + gPopup = CreatePopUp(window, &popupRect, menu, kPopUpStyleAll); // <--- + + SetPort(window); + ShowWindow(window); +} + +// 2. Event loop + +void DoEvent(EventRecord *eventPtr) +{ + if (HandlePopUpEvent(gPopup, eventPtr)) // <--- + { + // gPopup->item contains the newly-selected item + return; + } + + // ...rest of event handlers... +} + +// 3. Window updates + +void DoUpdate(EventRecord *eventPtr) +{ + WindowPtr window = (WindowPtr)eventPtr->message; + + BeginUpdate(window); + + DrawPopUp(gPopup); // <--- + + EndUpdate(window); +}