// button3- program button3; #linker( "comdlg32.lib" ) #linker( "comctl32.lib" ) ?@NoDisplay := true; ?@NoStackAlign := true; #includeOnce( "stdlib.hhf" ) #includeOnce( "howl.hhf" ) const applicationName := "Button Demo #3x"; 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; 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 button1 :wPushButton_p; button2 :wPushButton_p; button3 :wPushButton_p; button4 :wPushButton_p; button5 :wPushButton_p; button6 :wPushButton_p; quitButton :wPushButton_p; showState :boolean; b1Enabled :boolean; 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; // Forward declarations for the onClick widgetProcs that we're going to // call when a button is pressed. proc onSetFocus1 :widgetProc; @forward; proc onKillFocus1 :widgetProc; @forward; proc onClickChange1 :widgetProc; @forward; proc onClickChange2 :widgetProc; @forward; proc hideShowButton :widgetProc; @forward; proc enableDisableButton :widgetProc; @forward; proc moveButton :widgetProc; @forward; proc resizeButton :widgetProc; @forward; proc onDblClick :widgetProc; @forward; proc onQuit :widgetProc; @forward; // 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; begin create_mainAppWindow; push( eax ); push( ebx ); push( ecx ); push( edx ); // Standad 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 ); // Initialize the showState and enableDisableButton data fields: mov( false, this.showState ); mov( true, this.b1Enabled ); // The primary push button on the form: wPushButton_t.create_wPushButton ( "button1", // Button name "Press to change", // Caption for push button this.handle, // Parent window handle 10, // x position 10, // y position 125, // width 25, // height &onClickChange1 // initial "on click" event handler ); // Set up the onSetFocus and onKillFocus widgetProcs. (type wPushButton_t [esi]).set_onSetFocus( &onSetFocus1 ); (type wPushButton_t [esi]).set_onKillFocus( &onKillFocus1 ); mov( esi, mainAppWindow.button1 ); // Save ptr to new button main.insertWidget( esi ); // Add button to wForm's widget list. // The show/hide button on the form: wPushButton_t.create_wPushButton ( "button2", // Button name "Hide button 1", // Caption for push button this.handle, // Parent window handle 175, // x position 10, // y position 125, // width 25, // height &hideShowButton // initial "on click" event handler ); mov( esi, mainAppWindow.button2 ); // Save ptr to new button main.insertWidget( esi ); // Add button to wForm's widget list. // The enable/disable button on the form: wPushButton_t.create_wPushButton ( "button3", // Button name "Disable button 1", // Caption for push button this.handle, // Parent window handle 175, // x position 40, // y position 125, // width 25, // height &enableDisableButton // initial "on click" event handler ); mov( esi, mainAppWindow.button3 ); // Save ptr to new button main.insertWidget( esi ); // Add button to wForm's widget list. // The move button on the form: wPushButton_t.create_wPushButton ( "button4", // Button name "Move button 1", // Caption for push button this.handle, // Parent window handle 175, // x position 70, // y position 125, // width 25, // height &moveButton // initial "on click" event handler ); mov( esi, mainAppWindow.button4 ); // Save ptr to new button main.insertWidget( esi ); // Add button to wForm's widget list. // The resize button on the form: wPushButton_t.create_wPushButton ( "button5", // Button name "Resize button 1", // Caption for push button this.handle, // Parent window handle 175, // x position 100, // y position 125, // width 25, // height &resizeButton // initial "on click" event handler ); mov( esi, mainAppWindow.button5 ); // Save ptr to new button main.insertWidget( esi ); // Add button to wForm's widget list. // The double-click button on the form: wPushButton_t.create_wPushButton ( "button6", // Button name "DblClick to Click", // Caption for push button this.handle, // Parent window handle 175, // x position 130, // y position 125, // width 25, // height NULL // initial "on click" event handler ); // Set up the onDblClick event handler: (type wPushButton_t [esi]).set_onDblClick( &onDblClick ); mov( esi, mainAppWindow.button6 ); // Save ptr to new button main.insertWidget( esi ); // Add button to wForm's widget list. // We need to create a quit button and store the pointer to the // new button object in the this.button field on the form: wPushButton_t.create_wPushButton ( "quitButton", // Button name "Quit", // Caption this.handle, // parent window handle 450, // x position 525, // y position 125, // width 25, // height &onQuit // "on click" event handler ); mov( esi, mainAppWindow.quitButton ); // Save ptr to new button main.insertWidget( esi ); // Add button to wForm's widget list. this.onCreate(); // Be nice, call this guy (even if empty). pop( edx ); pop( ecx ); pop( ebx ); pop( eax ); end create_mainAppWindow; // The onDblClick widget proc will handle a double click on button6 // and simulate a single click on button 1. proc onDblClick:widgetProc; begin onDblClick; mov( mainAppWindow.button1, esi ); (type wPushButton_t [esi]).click(); end onDblClick; // The resizeButton widget proc will resize button1 between widths 125 and 150. proc resizeButton:widgetProc; begin resizeButton; mov( mainAppWindow.button1, esi ); (type wPushButton_t [esi]).get_width(); if( eax = 125 ) then stdout.put( "Resizing button to width 150" nl ); (type wPushButton_t [esi]).set_width( 150 ); else stdout.put( "Resizing button to width 125" nl ); (type wPushButton_t [esi]).set_width( 125 ); endif; end resizeButton; // The moveButton widget proc will move button1 between y positions 10 and 40. proc moveButton:widgetProc; begin moveButton; mov( mainAppWindow.button1, esi ); (type wPushButton_t [esi]).get_y(); if( eax = 10 ) then stdout.put( "Moving button to y-position 40" nl ); (type wPushButton_t [esi]).set_y( 40 ); else stdout.put( "Moving button to y-position 10" nl ); (type wPushButton_t [esi]).set_y( 10 ); endif; end moveButton; // The hideShowButton widget proc will hide and show button1. proc enableDisableButton:widgetProc; begin enableDisableButton; mov( thisPtr, esi ); if( mainAppWindow.b1Enabled ) then (type wPushButton_t [esi]).set_text( "Enable button 1" ); mov( false, mainAppWindow.b1Enabled ); stdout.put( "Disabling button 1" nl ); mov( mainAppWindow.button1, esi ); (type wPushButton_t [esi]).disable(); else (type wPushButton_t [esi]).set_text( "Disable button 1" ); mov( true, mainAppWindow.b1Enabled ); stdout.put( "Enabling button 1" nl ); mov( mainAppWindow.button1, esi ); (type wPushButton_t [esi]).enable(); endif; end enableDisableButton; // The hideShowButton widget proc will hide and show button1. proc hideShowButton:widgetProc; begin hideShowButton; mov( thisPtr, esi ); if( mainAppWindow.showState ) then (type wPushButton_t [esi]).set_text( "Hide button 1" ); mov( false, mainAppWindow.showState ); stdout.put( "Showing button 1" nl ); mov( mainAppWindow.button1, esi ); (type wPushButton_t [esi]).show(); else (type wPushButton_t [esi]).set_text( "Show button 1" ); mov( true, mainAppWindow.showState ); stdout.put( "Hiding button 1" nl ); mov( mainAppWindow.button1, esi ); (type wPushButton_t [esi]).hide(); endif; end hideShowButton; // The onSetFocus and onKillFocus widgetProcs simply print to the console // what has happened. proc onSetFocus1:widgetProc; begin onSetFocus1; stdout.put( "Set focus to button 1" nl ); end onSetFocus1; proc onKillFocus1:widgetProc; begin onKillFocus1; stdout.put( "Shifted focus from button 1" nl ); end onKillFocus1; // Here's 1 of 2 onClick handlers for button1. This widgetProc // changes the caption to "Restore caption" and sets the // onClick pointer to point at the second onClick handler. proc onClickChange1:widgetProc; var curCaption :string; curCapBuf :char[256]; begin onClickChange1; str.init( curCapBuf, @size( curCapBuf )); mov( eax, curCaption ); mov( thisPtr, esi ); // ESI already contains this, but just in case... // Print the current caption to the console window: (type wPushButton_t [esi]).get_text( curCaption ); stdout.put( "Current caption1: ", curCaption, nl ); // Change the caption: (type wPushButton_t [esi]).set_text( "Restore Button #1" ); // Point the onClick handler at onClickChange2: (type wPushButton_t [esi]).set_onClick( &onClickChange2 ); // Print the new caption to the console window: (type wPushButton_t [esi]).a_get_text(); stdout.put( "New caption1: ", (type string eax), nl nl ); str.free( eax ); end onClickChange1; // Here's 2 of 2 onClick handlers for button1. This widgetProc // changes the caption back to "Restore caption" and sets the // onClick pointer to point at the first onClick handler. proc onClickChange2:widgetProc; var curCaption :string; curCapBuf :char[256]; begin onClickChange2; str.init( curCapBuf, @size( curCapBuf )); mov( eax, curCaption ); mov( thisPtr, esi ); // ESI already contains this, but just in case... // Print the current caption to the console window: (type wPushButton_t [esi]).get_text( curCaption ); stdout.put( "Current caption2: ", curCaption, nl ); // Change the caption: (type wPushButton_t [esi]).set_text( "Button #1" ); // Point the onClick handler at onClickChange1: (type wPushButton_t [esi]).set_onClick( &onClickChange1 ); // Print the new caption to the console window: (type wPushButton_t [esi]).a_get_text(); stdout.put( "New caption2: ", (type string eax), nl nl ); str.free( eax ); end onClickChange2; // 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; // 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: w.GetSysColor( w.COLOR_MENU ); 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, // Form x-coordinate formY, // Form y-coordinate 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 button3; HowlMainApp(); end button3;