Objective-C question
  • IKE
  • Acolyte of the Butterfly
    Acolyte of the Butterfly
    IKE
    Posts: 146 from 2009/11/7
    From: Southern CA
    I am trying to add menu items in this cut down version from the two source code examples in the SDK. It compiles without error and creates the menu items, but no action occurs when menu items are selected. The file is named window.m and the makefile that I am using is pasted below. I am trying to understand what I am doing wrong...any advice appreciated!

    Code:
    //window example
    #import <mui/MUIFramework.h>
    #import <proto/dos.h>
    #import <proto/graphics.h>
    #import <proto/muimaster.h>
    #import <proto/layers.h>

    @interface MyArea : MUIArea {

    MUIObject *_aboutbox;
    }
    @end

    @implementation MyArea

    + (MyArea *) myArea {

    return [[self new] autorelease];
    }

    - (id) init {

    if ((self = [super init])) {

    [self setFillArea:YES];
    [self setFrame:MUIV_Frame_Text];
    }
    return self;
    }

    - (void) dealloc {
    [super dealloc];
    }

    - (void)askMinMax:(struct MUI_MinMax *)minmax {

    minmax->MinWidth += 300;
    minmax->MinHeight += 300;
    minmax->DefWidth += 300;
    minmax->DefHeight += 300;
    minmax->MaxWidth+=600;
    minmax->MaxHeight+=600;
    }

    - (void) about {

    if (nil == _aboutbox) {

    _aboutbox = [[MCCAboutbox new] autorelease];
    [[MUIApplication currentApplication] addObject:_aboutbox];
    }

    [_aboutbox setValue:TRUE forAttribute:MUIA_Window_Open];
    }

    - (void) setMenuAction:(ULONG) menuaction {

    switch (menuaction) {

    case 666:
    [[OBApplication currentApplication] quit];
    break;

    case 668:
    [self about];
    break;
    }
    }
    @end

    int muiMain(int argc, char *argv[]) {

    MUIApplication *mapp = [[MUIApplication alloc] init];

    [mapp setTitle:@"My First Objc Window"];
    [mapp setDescription:@"wow!"];

    MUIGroup *g = [MUIGroup groupWithObjects:[MyArea myArea], nil];

    MUIWindow *w = [[MUIWindow new] autorelease];

    w.title = @"My First Objc Window";
    w.rootObject = g;

    // added here...I know it's not the right place...
    w.menustrip = [MUIMenustrip menustripWithObjects:
    [MUIMenu menuWithTitle:OBL(@"Project", @"Main menu title") objects:
    [MUIMenuitem itemWithTitle:OBL(@"About ...", @"Menu About") shortcut:OBL(@"?", @"Menu about shortcut") userData:668],
    [MUIMenuitem barItem],
    [MUIMenuitem itemWithTitle:OBL(@"Quit", @"Menu quit") shortcut:OBL(@"Q", @"Menu quit option") userData:666],
    nil],
    nil];
    //
    [mapp instantiateWithWindows:w, NULL];
    [w notify:@selector(closeRequest) performSelector:@selector(quit) withTarget:[OBApplication currentApplication]];

    [w setOpen: YES];
    [mapp run];

    [w setOpen: NO];
    [mapp release];

    return 0;
    }


    Here is the makefile:

    CC = ppc-morphos-gcc-5 -Wall -DDEBUG=0
    CFLAGS = -noixemul -I/SDK/Frameworks/include -fconstant-string-class=OBConstantString -fobjc-exceptions -g -std=gnu99 -Wl,--traditional-format
    # NOTE: make sure NOT to use _debug libraries for builds you intend to redistribute as they will not work without the SDK installed
    # !!! API/ABI not yet stable. Expect your binaries not to work with MorphOS 3.12 - they will need to be recompiled.
    LIBS = -lob.framework -lmui.framework -lobjc -ldebug -noixemul -lm -lmath

    all: Window

    %.mo : %.m
    $(CC) $(CFLAGS) -c $< -o $@

    Window:
    $(CC) $(CFLAGS) window.m $(LIBS) -o Window
    IKE

    MacMini G4 1.5Ghz/PowerBook G4 1.67Ghz/PowerMac G5 2.0Ghz DP 7,2 Radeon 9650/256MB

    Join the conversation @ r/morphos
  • »20.12.20 - 07:03
    Profile Visit Website
  • MorphOS Developer
    jacadcaps
    Posts: 2972 from 2003/3/5
    From: Canada
    Your example doesn't work because you've added -(void)setMenuAction: into the Area subclass, while it gets triggered on the Window. Note that the cvsviewer example overloads MUIWindow and that's where it gets the menu action. One way out of this is to do something like:

    Code:


    MyArea *ma;
    ...
    MUIGroup *g = [MUIGroup groupWithObjects:ma = [MyArea myArea], nil];
    ...
    [w notify:@selector(menuAction) performSelector:@selector(setMenuAction:) withRawTriggerValueTarget:ma];


    Adding this notify after the closeRequest notify will bridge the two objects and make it work. The 'rawtriggervalue' sends the vanilla value that was triggered in a mui notification (not to be used for objects!) as the 1st argument of the target selector.
  • »20.12.20 - 15:34
    Profile Visit Website
  • IKE
  • Acolyte of the Butterfly
    Acolyte of the Butterfly
    IKE
    Posts: 146 from 2009/11/7
    From: Southern CA
    Thanks for the insight! This simple window example with menu items works now.

    Code:
    //simple window example
    #import <mui/MUIFramework.h>
    #import <proto/dos.h>
    #import <proto/graphics.h>
    #import <proto/muimaster.h>
    #import <proto/layers.h>

    @interface MyArea : MUIArea {

    MUIObject *_aboutbox;
    }
    @end

    @implementation MyArea

    + (MyArea *) myArea {

    return [[self new] autorelease];
    }

    - (id) init {

    if ((self = [super init])) {

    [self setFillArea:YES];
    [self setFrame:MUIV_Frame_Text];
    }
    return self;
    }

    - (void) dealloc {
    [super dealloc];
    }

    - (void) askMinMax:(struct MUI_MinMax *) minmax {

    minmax->MinWidth += 300;
    minmax->MinHeight += 300;
    minmax->DefWidth += 300;
    minmax->DefHeight += 300;
    minmax->MaxWidth+=600;
    minmax->MaxHeight+=600;
    }

    - (void) about {

    if (nil == _aboutbox) {

    _aboutbox = [[MCCAboutbox new] autorelease];
    [[MUIApplication currentApplication] addObject:_aboutbox];
    }

    [_aboutbox setValue:TRUE forAttribute:MUIA_Window_Open];
    }

    - (void) setMenuAction:(ULONG) menuaction {

    switch (menuaction) {

    case 666:
    [[OBApplication currentApplication] quit];
    break;

    case 668:
    [self about];
    break;
    }
    }
    @end

    int muiMain(int argc, char *argv[]) {

    MUIApplication *mapp = [[MUIApplication alloc] init];

    [mapp setTitle:@"Simple Obj-c Window Example"];
    [mapp setDescription:@"Wow!"];
    [mapp setApplicationVersion:@"$VER:Window 0.1 (12.20.2020) © IKE"];
    [mapp setAuthor:@"IKE"];
    [mapp setBase:@"Simple Obj-c Window Example"];
    [mapp setCopyright:@"2020 IKE"];

    MyArea *ma;

    MUIGroup *g = [MUIGroup groupWithObjects:ma = [MyArea myArea], nil];

    MUIWindow *w = [[MUIWindow new] autorelease];

    w.title = @"Simple Obj-c Window Example";
    w.rootObject = g;

    w.menustrip = [MUIMenustrip menustripWithObjects:
    [MUIMenu menuWithTitle:OBL(@"Project", @"Main menu title") objects:
    [MUIMenuitem itemWithTitle:OBL(@"About ...", @"Menu About") shortcut:OBL(@"?", @"Menu about shortcut") userData:668],
    [MUIMenuitem barItem],
    [MUIMenuitem itemWithTitle:OBL(@"Quit", @"Menu quit") shortcut:OBL(@"Q", @"Menu quit option") userData:666],
    nil],
    nil];

    [mapp instantiateWithWindows:w, NULL];

    [w notify:@selector(closeRequest) performSelector:@selector(quit) withTarget:[OBApplication currentApplication]];
    [w notify:@selector(menuAction) performSelector:@selector(setMenuAction:) withRawTriggerValueTarget:ma];

    [w setOpen: YES];
    [mapp run];

    [w setOpen: NO];
    [mapp release];

    return 0;
    }
    IKE

    MacMini G4 1.5Ghz/PowerBook G4 1.67Ghz/PowerMac G5 2.0Ghz DP 7,2 Radeon 9650/256MB

    Join the conversation @ r/morphos
  • »20.12.20 - 20:57
    Profile Visit Website
  • Acolyte of the Butterfly
    Acolyte of the Butterfly
    Georg
    Posts: 106 from 2004/4/7
    Is error checking not needed with Objective-C? If the group object "g" is successfully created, but the window object "w" is not, will "g" still be freed?

    What happens if an app subclasses a MUI class and adds some method with name XYZ and then some year later the MUI base class is extended and now also adds a method with same name?
  • »21.12.20 - 14:30
    Profile
  • MorphOS Developer
    jacadcaps
    Posts: 2972 from 2003/3/5
    From: Canada
    Quote:

    Georg wrote:
    Is error checking not needed with Objective-C? If the group object "g" is successfully created, but the window object "w" is not, will "g" still be freed?



    As with DoMethod() calling a method on an ObjC object via [] is safe on a null pointer. In the above example, group 'g' is allocated in an autoreleased state (meaning it will be freed once you exit the scope, unless you retain it - in this particular case it'd happen in [mapp run]). If window fails to allocate, w.rootObject = g; will do nothing (it's an equivalent of [w setRootObject:g]) and so the group 'g' will remain in autoreleased state. Afterwards [mapp instantiateWithWindows:w, NULL]; will fail since MUI requires at least one window to create an Application object.

    Quote:

    What happens if an app subclasses a MUI class and adds some method with name XYZ and then some year later the MUI base class is extended and now also adds a method with same name?


    That could be a problem. A good practice is to use prefixes for your own methods.
  • »21.12.20 - 15:15
    Profile Visit Website