// menu1x- // // This program demonstrates the use of labels and fonts on a form. // // This version of the program implements the button manually, without using the // wForm..endwForm macro (the HOWL declarative language). program menu1x; #linker( "comdlg32.lib" ) #linker( "comctl32.lib" ) ?@NoDisplay := true; ?@NoStackAlign := true; #includeOnce( "stdlib.hhf" ) #includeOnce( "howl.hhf" ) const applicationName := "Menu #1x"; formX := w.CW_USEDEFAULT; // Let Windows position this guy formY := w.CW_USEDEFAULT; formW := 600; formH := 600; static align( 4 ); bkgBrush_g :dword; bkgColor_g :dword; originalString :string := "This is a somewhat long string that will wrap around in the box"; // Forward declarations for the onClick widgetProcs that we're going to // call when an event occurs. proc onQuit :widgetProc; @forward; proc nullProc :widgetProc; @forward; type // Create a new class for our main application window. // All application forms must be derived from wForm_t: mainAppWindow_t: class inherits( wForm_t ); // We have to add VAR declarations for all our widgets // here. var file_1 :wMenu_p; mainAppWindow_menu :wMenu_p; dummy1 :wMenuItem_p; menu_exit :wMenuItem_p; _wMenuSeparatorWidget_ :wMenuItem_p; align(4); // We need to override these (actually, onClose is the // only one that is important): override method onClose; override method onCreate; // Every main application window must have a // constructor with the following prototype: procedure create_mainAppWindow ( caption :string; exStyle :dword; style :dword; parent :dword; x :dword; y :dword; width :dword; height :dword; bkgClr :dword; visible :boolean ); endclass; mainAppWindow_p :pointer to mainAppWindow_t; // Must have the following declarations in all (manually written) HOWL apps: static vmt( mainAppWindow_t ); mainAppWindow: mainAppWindow_t; pmainAppWindow: mainAppWindow_p := &mainAppWindow; // Here is the constructor we must supply for the mainAppWindow class: procedure mainAppWindow_t.create_mainAppWindow ( caption :string; exStyle :dword; style :dword; parent :dword; x :dword; y :dword; width :dword; height :dword; bkgClr :dword; visible :boolean ); var main :mainAppWindow_p; rs :wRadioSet_p; rsHndl :dword; begin create_mainAppWindow; push( eax ); push( ebx ); push( ecx ); push( edx ); // Standard main form initialization: // // If a class procedure call (not typical), then allocate storage // for this object: if( esi = NULL ) then mem.alloc( @size( mainAppWindow_t )); mov( eax, esi ); mov( true, cl ); else mov( this.wBase_private.onHeap, cl ); endif; // Call the wForm_t constructor to do all the default initialization: (type wForm_t [esi]).create_wForm ( "mainAppWindow", caption, exStyle, style, parent, x, y, width, height, bkgClr, visible ); // Initialize the VMT pointer: mov( &mainAppWindow_t._VMT_, this._pVMT_ ); // Retrieve the onHeap value from above and store it into // the onHeap data field: mov( cl, this.wBase_private.onHeap ); // Preserve "this" because we're about to make an object call // that will overwrite this' value: mov( esi, main ); // Code to create a wMenuItem object: mov(main,ebx); wMenuItem_t.create_wMenuItem("dummy1", ebx,w.MF_STRING, "dummy", &nullProc); mov( esi, (type mainAppWindow_t [ebx]).dummy1); mov(ebx,esi); this.insertWidget( this.dummy1); this.appendMenuItem( this.dummy1); // Code to create a wMenuSeparator object: mov(main,ebx); wMenuItem_t.create_wMenuItem ( "_wMenuSeparatorWidget_", ebx, w.MF_SEPARATOR, NULL, NULL ); mov( esi, (type mainAppWindow_t [ebx])._wMenuSeparatorWidget_); main.insertWidget((type mainAppWindow_t [ebx])._wMenuSeparatorWidget_); // Code to create a wMenuItem object: mov(main,ebx); wMenuItem_t.create_wMenuItem("menu_exit", ebx,w.MF_STRING, "Exit", &onQuit); mov( esi, (type mainAppWindow_t [ebx]).menu_exit); mov(ebx,esi); this.insertWidget( this.menu_exit); this.appendMenuItem( this.menu_exit); // Code to create a wSubMenu object: mov(main,ebx); wMenu_t.create_wMenu("file_1","file",ebx); mov( esi, (type mainAppWindow_t [ebx]).file_1); mov(ebx,esi); this.insertWidget( this.file_1); this.appendMenuItem( this.file_1); // Submenu item: dummy1 mov( this.file_1, eax ); mov( (type wMenuItem_t [eax]).handle, eax ); mov( this.dummy1,ecx ); mov( eax, (type wMenuItem_t [ecx]).wBase_private.parentHandle ); mov( this.file_1, eax ); w.AppendMenu ( (type wMenu_t [eax]).handle, (type wMenuItem_t [ecx]).wMenuItem_private.itemType, (type wMenuItem_t [ecx]).wBase_private.objectID, (type wMenuItem_t [ecx]).wMenuItem_private.itemString ); // Submenu item: _wMenuSeparatorWidget_ mov( this.file_1, eax ); mov( (type wMenuItem_t [eax]).handle, eax ); mov( this._wMenuSeparatorWidget_,ecx ); mov( eax, (type wMenuItem_t [ecx]).wBase_private.parentHandle ); mov( this.file_1, eax ); w.AppendMenu ( (type wMenu_t [eax]).handle, (type wMenuItem_t [ecx]).wMenuItem_private.itemType, (type wMenuItem_t [ecx]).wBase_private.objectID, (type wMenuItem_t [ecx]).wMenuItem_private.itemString ); // Submenu item: menu_exit mov( this.file_1, eax ); mov( (type wMenuItem_t [eax]).handle, eax ); mov( this.menu_exit,ecx ); mov( eax, (type wMenuItem_t [ecx]).wBase_private.parentHandle ); mov( this.file_1, eax ); w.AppendMenu ( (type wMenu_t [eax]).handle, (type wMenuItem_t [ecx]).wMenuItem_private.itemType, (type wMenuItem_t [ecx]).wBase_private.objectID, (type wMenuItem_t [ecx]).wMenuItem_private.itemString ); // Code to create a wMainMenu object: mov( ebx, esi ); wMenu_t.create_wMenu("mainAppWindow_menu", "main",ebx); mov( esi, (type mainAppWindow_t [ebx]).mainAppWindow_menu); mov(ebx,esi); main.insertWidget( this.mainAppWindow_menu); // Main menu item: file_1 mov( this.mainAppWindow_menu, eax ); mov( (type wMenuItem_t [eax]).handle, eax ); mov( this.file_1,ecx ); mov( eax, (type wMenuItem_t [ecx]).wBase_private.parentHandle ); mov( this.mainAppWindow_menu, eax ); w.AppendMenu ( (type wMenu_t [eax]).handle, w.MF_POPUP, (type wMenu_t [ecx]).handle, (type wMenuItem_t [ecx]).wMenuItem_private.itemString ); mov( this.mainAppWindow_menu, ecx ); w.SetMenu( this.handle, (type wMenu_t [ecx]).handle ); w.DrawMenuBar( this.handle ); this.onCreate(); // Be nice, call this guy (even if empty). pop( edx ); pop( ecx ); pop( ebx ); pop( eax ); end create_mainAppWindow; // Here's the onClick event handler for our quit button on the form. // This handler will simply quit the application: proc onQuit:widgetProc; begin onQuit; // Quit the app: w.PostQuitMessage( 0 ); end onQuit; // nullProc does nothing. proc nullProc:widgetProc; begin nullProc; stdout.put( "Pressed the dummy menu entry" nl ); end nullProc; // We'll use the main application form's onCreate method to initialize // the various buttons on the form. // // This could be done in appStart, but better to leave appStart mainly // as boilerplate code. Also, putting this code here allows us to use // "this" to access the mainAppWindow fields (a minor convenience). method mainAppWindow_t.onCreate; begin onCreate; end onCreate; /////////////////////////////////////////////////////////////////////////////// // // // The following is mostly boilerplate code for all apps (about the only thing // you would change is the size of the main app's form) // // /////////////////////////////////////////////////////////////////////////////// // // When the main application window closes, we need to terminate the // application. This overridden method handles that situation. Notice the // override declaration for onClose in the wForm declaration given earlier. // Without that, mainAppWindow_t would default to using the wVisual_t.onClose // method (which does nothing). method mainAppWindow_t.onClose; begin onClose; // Tell the winmain main program that it's time to terminate. // Note that this message will (ultimately) cause the appTerminate // procedure to be called. w.PostQuitMessage( 0 ); end onClose; // When the application begins execution, the following procedure // is called. This procedure must create the main // application window in order to kick off the execution of the // GUI application: procedure appStart; begin appStart; push( esi ); // Set up the background color (gray) for the form: // Note: use a special gray value here that will differentiate // the client area from the menu bar: mov( RGB(224,224,224), eax ); mov( eax, bkgColor_g ); w.CreateSolidBrush( eax ); mov( eax, bkgBrush_g ); // Create the main application window: mainAppWindow.create_mainAppWindow ( applicationName, // Window title w.WS_EX_CONTROLPARENT, // Need this to support TAB control selection w.WS_OVERLAPPEDWINDOW, // Style NULL, // No parent window formX, // x-coordinate for window. formY, // y-coordinate for window. formW, // Width formH, // Height bkgColor_g, // Background color true // Make visible on creation ); pop( esi ); end appStart; // appTerminate- // // Called when the application is quitting, giving the app a chance // to clean up after itself. // // Note that this is called *after* the mainAppWindow_t.onClose method // executes (indeed, mainAppWindow_t.onClose, by posting the quit message, // is what actually causes the program to begin terminating, which leads // to the execution of this procedure). procedure appTerminate; begin appTerminate; // Clean up the main application's form. // Note that this will recursively clean up all the widgets on the form. mainAppWindow.destroy(); w.DeleteObject( bkgBrush_g ); end appTerminate; // appException- // // Gives the application the opportunity to clean up before // aborting when an unhandled exception comes along: procedure appException( theException:dword in eax ); begin appException; raise( eax ); end appException; // The main program for a HOWL application must simply // call the HowlMainApp procedure. begin menu1x; HowlMainApp(); end menu1x;