views:

150

answers:

2

Hello,

I'm just starting to use MetroWerks CodeWarrior 1.1 For Mac 68k in a Mac System 7.5.5, but I need to know: How can I create a simple Form with a TextBox on it? Thanks.

+1  A: 

I don't know if CodeWarrior 1.1 contains a GUI designer, but you can create a window using the native C-API (CreateNewWindow).

Problem is, there is no online documentation for 7.5 anymore, so I cannot help you in detail.

Axel Gneiting
Can you post a example of the use of CreateNewWindow? Thanks.
Nathan Campos
+1 for your tip!
Nathan Campos
+1  A: 

There are a couple ways to do it. If your version of CodeWarrior has it, you would be best off using the PowerPlant framework. This is an application framework that makes it relatively easy to build applications that follow the Mac UI standards. It's been more than 10 years, so I have fully purged the PowerPlant class hierarchy from my memory. Sorry.

Another way to do this is to create a DLOG resource in ResEdit which includes a TextEdit field that more or less fits the window. Then you write your main app, which is going to include the typical toolbox initializations (I'm doing this TOTALLY from memory):

DialogPtr myDlog;
short itemHit;
InitGraf( &qd.thePort );
InitFonts();
InitWindows();
InitMenus();
TEInit();
InitDialogs( 0L );
InitCursor();

myDlog = GetNewDialog(myDlogResID, 0L, -1L);
ShowWindow(myDlog);
while (true) {
    ModalDialog(myDlog, &itemHit);
}

Which will probably work and is the most wrong way to do UI on the Mac, but if all you want is a box with a simple, simple UI, you'll be OK.

The problem with this code is that it doesn't handle the events well, the loop is infinite, there is no handling of cut/copy/paste, there is no honoring of menu events, and so on.

The Mac toolbox of that era requires you to do a hell of a lot more work than you might think. This is why there were libraries like MacApp, Think Class Library and PowerPlant - they provided OOP methods to handle a lot of the housekeeping crap for you. At the time that I did most of my Mac programming, I build a non-class library that was raw C code that made it easier to write layered windows (with floating palettes) and fluid UI without the overhead of OOP. Basically, I had to write a window manager, a menu manager, a dialog manager, an event manager, a command dispatcher and so on. When all was said and done, there was something like 18K of overhead to build a typical application. FYI, Acrobat Search on the Macintosh up until version 4 was built on this, as was Acrobat Catalog.

You can find canonical examples in MacTech, like this which is similar code to the above.

Before you start building your entire UI out of Dialog Boxes, all the old Macintosh tech notes said DON'T DO THIS. The DialogManager is one of the most abused chunks of Macintosh code there ever was. It was built for the purpose of making it easy to put of a box that says, "Are you sure you want to close 'Untitled'?" with an OK button and a cancel button. It's surprising how much it can be abused.

The real way to do things is to write a main that initializes the toolbox items, builds a basic menu bar then allocates an object that you design, say NathanWindow. NathanWindow might look like this:

class NathanWindow {
public:
    NathanWindow();
    virtual ~NathanWindow();
    void Initialize();
    void Click(short part, EventRecord *evt);
    void Show();
    void Hide();
    void Drag();
    void Move();
    // etc;
protected:
    virtual WindowPtr MakeWindow() = 0;
    virtual void OnInit() = 0;
private:
    WindowPtr _win;
};

then you will subclass this with code to call NewWindow() in the appropriate style.

Initialize will look something like this:

void NathanWindow::Initialize()
{
    _win = MakeWindow();
    _win->refCon = this;
    OnInit();
}

now, this last little bit is the tricky part - I've put a pointer to the NathanWindow into the Macintosh WindowPtr refCon field. Then you'll build an event loop in your main code that will look like this:

void HandleMouseDown(EventRecord *evt)
{
    WindowPtr win;
    short  thePart;

    thePart = FindWindow( eventPtr->where, &win ); 
    if (win) {
        NathanWindow *nw = (NathanWindow *)win->refCon;
        nw->Click(thePart, evt);
    }
}

void  EventLoop( void )
{
    EventRecord evt;

    while ( true ) {
        if ( WaitNextEvent( everyEvent, &evt, kSleep, nil ) ) {
           switch (evt.what) {
           case mouseDown:
               HandleMouseDown(&evt);
               break;
        }
    }
}

and then Click will look like this:

NathanWindow::Click(short thePart, EventRecord *evt)
{
    switch(thePart) {
        case inGoAway: Close(); break;
        case inDrag: Drag(); break;
        case inGrow: Grow(); break;
    }
}

and so on.

And even still, this is (potentially) wrong in that you really want to have every NathanWindow to be hooked into an application parent that manages layers and groupings of windows.

A NathanWindow should contain a list of NathanControls. A NathanControl is something that can draw, responds to events, and so on.

All of this is in case you don't have PowerPlant, which does all of this for you. There was a reason why Apple liked to tout the line "it's hard to be easy", because the API that you had at your fingertips was so damn primitive.

plinth
Thanks very much! Very good explained! +1 and accepted.
Nathan Campos