diff --git a/harbour/source/rtl/ttopbar.prg b/harbour/source/rtl/ttopbar.prg index cf54747da1..73ec7bb475 100644 --- a/harbour/source/rtl/ttopbar.prg +++ b/harbour/source/rtl/ttopbar.prg @@ -55,7 +55,10 @@ #include "color.ch" #include "common.ch" #include "inkey.ch" +#include "setcurs.ch" +#include "getexit.ch" #include "hbsetup.ch" +#include "hbclass.ch" #ifdef HB_COMPAT_C53 @@ -71,54 +74,124 @@ an exit statement and two assigments which is good for speed critical and small functions. [jlalin] */ + +/* +* +* (according to MenuSys of Clipper 5.3b) +* Code in C-style comment blocks may be uncommented to test non-CUA +* menuing behavior which permits returning to the selected menu item. +* +*/ + +/*** +* +* MenuModal( , , , , ; +* , cMsgColor, GetList ) --> nReturn +* +* Standard Menu System Modal handling for Menu Items +* +***/ + +FUNCTION MenuModal( oTopMenu, nSelection, nMsgRow, nMsgLeft, nMsgRight, ; + cMsgColor, GetList ) + +RETURN oTopMenu:Modal( nSelection, nMsgRow, nMsgLeft, nMsgRight, ; + cMsgColor, GetList ) + //--------------------------------------------------------------------------// function TopBar( nRow, nLeft, nRight ) - LOCAL oClass + local oTopBar := nil - if ISNUMBER( 1 ) .and. ISNUMBER( 2 ) .and. ISNUMBER( 3 ) - - oClass := HBClass():New( "TOPBARMENU" ) - oClass:AddData( "cargo" ) - oClass:AddData( "colorSpec" , "N/W,W/N,W+/W,W+/N,N+/W,W/N" ) - oClass:AddData( "current" , 0 ) - oClass:AddData( "itemCount" , 0 ) - oClass:AddData( "left" , nLeft ) - oClass:AddData( "right" , nRight ) - oClass:AddData( "row" , nRow ) - oClass:AddData( "aItems" , {} ) - - oClass:AddMethod( "AddItem" , @AddItem() ) - oClass:AddMethod( "DelItem" , @DelItem() ) - oClass:AddMethod( "Display" , @Display() ) - oClass:AddMethod( "GetAccel" , @GetAccel() ) - oClass:AddMethod( "GetFirst" , @GetFirst() ) - oClass:AddMethod( "GetItem" , @GetItem() ) - oClass:AddMethod( "GetLast" , @GetLast() ) - oClass:AddMethod( "GetNext" , @GetNext() ) - oClass:AddMethod( "GetPrev" , @GetPrev() ) - - /* NOTE: This method exists but it is not - documented in the manuals nor the NG's [jlalin] - */ - oClass:AddMethod( "GetShortct", @GetShortct() ) - - oClass:AddMethod( "HitTest" , @HitTest() ) - oClass:AddMethod( "InsItem" , @InsItem() ) - oClass:AddMethod( "Select" , @_Select() ) - oClass:AddMethod( "SetItem" , @SetItem() ) - - oClass:Create() - else - return nil + if ISNUMBER( nRow ) .and. ISNUMBER( nLeft ) .and. ISNUMBER( nRight ) + oTopBar := TopBarMenu():New( nRow, nLeft, nRight ) endif -return oClass:Instance() +return oTopBar //--------------------------------------------------------------------------// -static function AddItem( oItem ) +CLASS TopBarMenu + + DATA ClassName init "TOPBARMENU" + DATA aItems init {} + DATA cargo + DATA colorSpec init "N/W,W/N,W+/W,W+/N,N+/W,W/N" + DATA current init 0 + DATA itemCount init 0 + DATA left + DATA right + DATA row + + // Additional Data to simulate MenuSys.prg of C53 + + DATA oMenu + DATA aMenuList + DATA nMenuLevel + DATA nOldRow PROTECTED + DATA nOldCol PROTECTED + DATA nOldCursor PROTECTED + DATA lOldMsgFlag + DATA cOldMessage + + /* Hold the value of the last TopBarItem position: + DATA nTopBar INIT 1 + Array of PopUp MenuItem positions. + DATA aPopUp INIT {} */ + + METHOD New( nRow, nLeft, nRight ) + METHOD AddItem( oItem ) + METHOD DelItem( nPos ) + METHOD Display() + METHOD GetAccel( nKey ) + METHOD GetFirst() + METHOD GetItem( nPos ) + METHOD GetLast() + METHOD GetNext() + METHOD GetPrev() + + /* NOTE: This method exists but it is not + documented in the manuals nor the NG's [jlalin] + */ + METHOD GetShortct( nKey ) + + METHOD HitTest( nRow, nCol ) + METHOD InsItem( nPos, oItem ) + MESSAGE Select( nPos ) METHOD _Select( nPos ) + METHOD SetItem( nPos, oItem ) + METHOD __AltToKey( nKey ) PROTECTED + + // Additional Data to simulate MenuSys.prg of C53 + + METHOD ModalGet( nSelect, oMenuMsg ) + METHOD Modal( nSelection, nMsgRow, nMsgLeft, nMsgRight, ; + cMsgColor, GetList ) + METHOD IsShortCut( nKey, nID ) + METHOD IsQuick( nKey, nID ) + METHOD PushMenu( lSelect ) + METHOD PopMenu() + METHOD PopChild( nNewLevel ) + METHOD PopAll() + METHOD Execute() + METHOD MHitTest( oNewMenu, nNewLevel, nNewItem ) + +ENDCLASS + +//--------------------------------------------------------------------------// +METHOD New( nRow, nLeft, nRight ) CLASS TopBarMenu + + ::aItems := {} + ::colorSpec := "N/W,W/N,W+/W,W+/N,N+/W,W/N" + ::current := 0 + ::itemCount := 0 + ::left := nLeft + ::right := nRight + ::row := nRow + +return Self + +//--------------------------------------------------------------------------// +METHOD AddItem( oItem ) CLASS TopBarMenu - LOCAL Self := QSelf() LOCAL oLast ::itemCount++ @@ -133,35 +206,31 @@ static function AddItem( oItem ) return Self //--------------------------------------------------------------------------// -static function DelItem( nPos ) - - LOCAL Self := QSelf() +METHOD DelItem( nPos ) CLASS TopBarMenu if nPos > 0 .and. nPos <= Len( ::aItems ) - aDel( ::aItems, nPos ) - aSize( ::aItems, Len( ::aItems ) - 1 ) + aDel( ::aItems, nPos, .T. ) + ::itemCount-- endif return Self //--------------------------------------------------------------------------// -static function GetFirst() +METHOD GetFirst() CLASS TopBarMenu - LOCAL Self := QSelf() - LOCAL n + LOCAL aItems - for n := 1 to ::itemCount - if ::aItems[ n ]:enabled - return n + FOR EACH aItems IN ::aItems + if aItems:enabled + return HB_EnumIndex() endif next return 0 //--------------------------------------------------------------------------// -static function GetItem( nPos ) +METHOD GetItem( nPos ) CLASS TopBarMenu - LOCAL Self := QSelf() LOCAL oItem if nPos > 0 .and. nPos <= ::itemCount @@ -171,9 +240,8 @@ static function GetItem( nPos ) return oItem //--------------------------------------------------------------------------// -static function GetLast() +METHOD GetLast() CLASS TopBarMenu - LOCAL Self := QSelf() LOCAL n for n := ::itemCount to 1 step -1 @@ -185,9 +253,8 @@ static function GetLast() return 0 //--------------------------------------------------------------------------// -static function GetNext() +METHOD GetNext() CLASS TopBarMenu - LOCAL Self := QSelf() LOCAL n if ::current < ::itemCount @@ -201,9 +268,8 @@ static function GetNext() return 0 //--------------------------------------------------------------------------// -static function GetPrev() +METHOD GetPrev() CLASS TopBarMenu - LOCAL Self := QSelf() LOCAL n if ::current > 1 @@ -222,18 +288,17 @@ return 0 first item is disabled 2) when a menuitem is disabled it will ignore the key [jlalin] */ -static function GetAccel( nKey ) +METHOD GetAccel( nKey ) CLASS TopBarMenu - LOCAL Self := QSelf() LOCAL nAt := 0 - LOCAL cKey := Upper( __AltToKey( nKey ) ) /* By now */ - LOCAL n + LOCAL cKey := Upper( ::__AltToKey( nKey ) ) /* By now */ + LOCAL aItems - for n := 1 to ::itemCount - nAt := At( "&", ::aItems[ n ]:caption ) - if nAt > 0 .and. ::aItems[ n ]:enabled .and. ; - Upper( SubStr( ::aItems[ n ]:caption, nAt + 1, 1 ) ) == cKey - return n + FOR EACH aItems IN ::aItems + nAt := At( "&", aItems:caption ) + if nAt > 0 .and. aItems:enabled .and. ; + Upper( SubStr( aItems:caption, nAt + 1, 1 ) ) == cKey + return HB_EnumIndex() endif next @@ -247,17 +312,16 @@ return 0 This method correct a bug in Cl*pper: when click on a disabled menuitem it will ignore it [jlalin] */ -static function HitTest( nRow, nCol ) +METHOD HitTest( nRow, nCol ) CLASS TopBarMenu - LOCAL Self := QSelf() - LOCAL n + LOCAL aItems if ::row == nRow - for n := 1 to ::itemCount - if nCol >= ::aItems[ n ]:column .and. ; - nCol <= ::aItems[ n ]:column + Len( ::aItems[ n ]:caption ) .and. ; - ::aItems[ n ]:enabled - return n + FOR EACH aItems IN ::aItems + if nCol >= aItems:column .and. ; + nCol <= aItems:column + Len( aItems:caption ) .and. ; + aItems:enabled + return HB_EnumIndex() endif next endif @@ -265,30 +329,17 @@ static function HitTest( nRow, nCol ) return HTNOWHERE //--------------------------------------------------------------------------// -static function InsItem( nPos, oItem ) - - LOCAL Self := QSelf() - LOCAL n +METHOD InsItem( nPos, oItem ) CLASS TopBarMenu if nPos > 0 .and. nPos <= ::itemCount - - aSize( ::aItems, ::itemCount + 1 ) - - for n := ::itemCount to nPos - ::aItems[ n ] := ::aItems[ n - 1 ] - next - - ::aItems[ nPos ] := oItem - ::itemCount := Len( ::aItems ) - + aIns( ::aItems, nPos, oItem, .T. ) + ::itemCount++ endif return Self //--------------------------------------------------------------------------// -static function _Select( nPos ) - - LOCAL Self := QSelf() +METHOD _Select( nPos ) CLASS TopBarMenu if ( nPos > 0 .and. nPos <= ::itemCount ) .and. ; nPos != ::current .and. ::aItems[ nPos ]:enabled @@ -307,9 +358,7 @@ static function _Select( nPos ) return Self //--------------------------------------------------------------------------// -static function SetItem( nPos, oItem ) - - LOCAL Self := QSelf() +METHOD SetItem( nPos, oItem ) CLASS TopBarMenu if nPos > 0 .and. nPos <= ::itemCount ::aItems[ nPos ] := oItem @@ -318,26 +367,24 @@ static function SetItem( nPos, oItem ) return Self //--------------------------------------------------------------------------// -static function GetShortct( nKey ) +METHOD GetShortct( nKey ) CLASS TopBarMenu - LOCAL Self := QSelf() - LOCAL n + LOCAL aItems - for n := 1 to ::itemCount - if ::aItems[ n ]:shortcut == nKey - return n + FOR EACH aItems IN ::aItems + if aItems:shortcut == nKey + return HB_EnumIndex() endif next return 0 //--------------------------------------------------------------------------// -static function Display() +METHOD Display() CLASS TopBarMenu - LOCAL Self := QSelf() LOCAL oPopup LOCAL nAt - LOCAL n + LOCAL aItems LOCAL cPrompt LOCAL nOldRow := Row() @@ -349,28 +396,28 @@ static function Display() DispOutAt( ::row, ::left, ; Space( ::right - ::left + 1 ), hb_ColorIndex( ::colorSpec, CLR_STANDARD ) ) - for n := 1 to ::itemCount + FOR EACH aItems IN ::aItems - nAt := At( "&", ::aItems[ n ]:caption ) - cPrompt := " " + StrTran( ::aItems[ n ]:caption, "&", "" ) + " " + nAt := At( "&", aItems:caption ) + cPrompt := " " + StrTran( aItems:caption, "&", "" ) + " " DispOutAt( ; - ::row, ::aItems[ n ]:column, ; + ::row, aItems:column, ; cPrompt, ; hb_ColorIndex( ::colorSpec, ; - iif( ::aItems[ n ]:enabled, ; - iif( n == ::current, CLR_ENHANCED, CLR_STANDARD ), ; + iif( aItems:enabled, ; + iif( HB_EnumIndex() == ::current, CLR_ENHANCED, CLR_STANDARD ), ; CLR_UNSELECTED ) ) ) if nAt > 0 - DispOutAt( ::row, ::aItems[ n ]:column + nAt, ; - SubStr( ::aItems[ n ]:caption, nAt + 1, 1 ), ; + DispOutAt( ::row, aItems:column + nAt, ; + SubStr( aItems:caption, nAt + 1, 1 ), ; hb_ColorIndex( ::colorSpec, ; - iif( n == ::current, CLR_BACKGROUND, CLR_BORDER ) ) ) + iif( HB_EnumIndex() == ::current, CLR_BACKGROUND, CLR_BORDER ) ) ) endif - if ::aItems[ n ]:isPopup() - ::aItems[ n ]:data:SetCoors( n, ::row + 1, ::aItems[ n ]:column ) + if aItems:isPopup() + aItems:data:SetCoors( ::row + 1, aItems:column, .t. ) endif next @@ -390,7 +437,7 @@ static function Display() return Self //--------------------------------------------------------------------------// -static function __AltToKey( nKey ) +METHOD __AltToKey( nKey ) CLASS TopBarMenu local nIndex := AScan( { K_ALT_A, K_ALT_B, K_ALT_C, K_ALT_D, K_ALT_E, K_ALT_F,; K_ALT_G, K_ALT_H, K_ALT_I, K_ALT_J, K_ALT_K, K_ALT_L,; @@ -400,4 +447,678 @@ static function __AltToKey( nKey ) return iif( nIndex > 0, SubStr( "ABCDEFGHIJKLMNOPQRSTUVWXYZ", nIndex, 1 ), "" ) +//--------------------------------------------------------------------------// + +/* The routines below were added by Larry Sevilla */ +/* based on the MenuSys.prg of Clipper 5.3b */ + +/*** +* +* IsShortCut( , , ) -> .T. | .F. +* +* ShortCut processing for initial Get or Menu Item. +* +***/ +METHOD IsShortCut( nKey, nID ) CLASS TopBarMenu + + RETURN ( ::IsQuick( nKey, @nID ) ) + + +/*** +* +* IsQuick( , , ) --> .T. | .F. +* +* IsShortCut() for secondary ShortCut processing. +* Navigates to the next Get or Menu Item from the +* Current if more than one uses the same ShortCut. +* +***/ +METHOD IsQuick( nKey, nID ) CLASS TopBarMenu + + LOCAL nItem, nTotal, nShortCut, oItem // , i + + IF ( ( nShortCut := ::GetShortCt( nKey ) ) == 0 ) + nTotal := ::ItemCount + + FOR nItem := 1 TO nTotal + IF ( !( oItem := ::GetItem( nItem ) ):Enabled ) + ELSEIF ( !( oItem:IsPopUp() ) ) + ELSEIF ( oItem:Data:IsQuick( nKey, @nID ) ) + RETURN ( .T. ) + ENDIF + NEXT + + ELSEIF ( !( oItem := ::GetItem( nShortCut ) ):IsPopUp() ) + IF oItem:Enabled + ::Select( nShortCut ) + EVAL( oItem:Data, oItem ) + nID := oItem:ID + RETURN ( .T. ) + ENDIF + + ENDIF + + RETURN ( .F. ) + +/*** +* ModalGet +***/ +METHOD ModalGet( nSelect, oMsg ) CLASS TopBarMenu + +RETURN ::Modal( nSelect, oMsg:Row, oMsg:Left, oMsg:Right, oMsg:Color ) + +/*** +* +* MenuModal( , , , , ; +* , cMsgColor, GetList ) --> nReturn +* +* Standard Menu System Modal handling for Menu Items +* +***/ +METHOD Modal( nSelection, nMsgRow, nMsgLeft, nMsgRight, ; + cMsgColor, GetList ) CLASS TopBarMenu + + LOCAL nKey, nNewItem, lLeftDown, oNewMenu, nNewLevel, ; + nEvent, oMenuItem, nMenuItem, nReturn, oMenuMsg, ; + nTemp, bKeyBlock, lSubMenu, cColor, lWhile + + nReturn := 0 + + ::nOldRow := ROW() + ::nOldCol := COL() + ::nOldCursor := SetCursor( SC_NONE ) + + oMenuMsg := MenuMssgLine():new( nMsgRow, nMsgLeft, nMsgRight, cMsgColor ) + + IF oMenuMsg:Flag + cColor := setColor( oMenuMsg:Color ) + @ oMenuMsg:Row, oMenuMsg:Left CLEAR TO oMenuMsg:Row, oMenuMsg:Right + setColor(cColor) + oMenuMsg:SaveScreen() + ENDIF + + ::Select( nSelection ) + + ::Display() + + IF nSelection <= 0 + WHILE ( nSelection <= 0 ) + + nEvent := SET( _SET_EVENTMASK, INKEY_KEYBOARD + INKEY_LDOWN ) + nKey := Inkey( 0 ) + SET( _SET_EVENTMASK, nEvent ) + + IF ( nKey == K_LBUTTONDOWN .OR. nKey == K_LDBLCLK ) + nSelection := ::HitTest( MRow(), MCol() ) + + ELSEIF ( ( nSelection := ::GetAccel( nKey ) ) != 0 ) + + ELSEIF ( ::IsShortCut( nKey, @nReturn ) ) + // Restore system entry state settings from file-wide array: + // saStatics := ACLONE( aSavMenuSys ) + RETURN ( nReturn ) + + ELSE + nSelection := 1 + + ENDIF + + ENDDO + + ::Select( nSelection ) + ::Display() + + ENDIF + + IF ( !::GetItem( nSelection ):Enabled ) + // Restore system entry state settings from file-wide array: + // saStatics := ACLONE( aSavMenuSys ) + RETURN ( 0 ) + ENDIF + + ::oMenu := Self + ::aMenuList := array( 16 ) + ::nMenuLevel := 1 + ::aMenuList[1] := ::oMenu + + lLeftDown := mLeftDown() + + /* Continue pushing MenuItems until there are no more to push: + DO WHILE ( ::PushMenu( .T. ) ) + ENDDO */ + + oMenuMsg:Show( Self, .T. ) + + lWhile := .T. + WHILE lWhile + /* Save Current TopBar MenuItem: + nTopBar := ::Current + // Save Current PopUp MenuItem: + ::aPopUp[::nMenuLevel] := ::oMenu:Current */ + nKey := INKEY( 0 ) + // Check for SET KEY first + IF !( ( bKeyBlock := SETKEY( nKey ) ) == NIL ) + EVAL( bKeyBlock, PROCNAME(1), PROCLINE(1), "" ) + LOOP + ENDIF + + Switch nKey + case K_MOUSEMOVE + //====== mouse movement. + + IF ( lLeftDown ) + // Changed '!HitTest' to '!MHitTest': + IF ( ! ::MHitTest( @oNewMenu, @nNewLevel, @nNewItem ) ) + //------------ hit nowhere. + + ELSEIF ( nNewLevel != ::nMenuLevel ) + //------------ menu level change. + + IF ( nNewItem == oNewMenu:Current ) + ELSEIF ( oNewMenu:GetItem( nNewItem ):Enabled ) + ::oMenu := oNewMenu + ::PopChild( nNewLevel ) + ::oMenu:Select( nNewItem ) + ::oMenu:Display() + ::PushMenu( .T. ) + oMenuMsg:Show( Self, .T. ) + ENDIF + + ELSEIF ( nNewItem != oNewMenu:Current() ) + //------------ menu item change. + + ::PopChild( ::nMenuLevel ) + + IF ( ::oMenu:GetItem( nNewItem ):Enabled ) + ::oMenu:Select( nNewItem ) + ::oMenu:Display() + ::PushMenu( .T. ) + oMenuMsg:Show( Self, .T. ) + ENDIF + + ENDIF + + ENDIF + EXIT + + case K_DOWN + //====== down arrow key. + + IF ::oMenu:ClassName() == "TOPBARMENU" + IF ( ::PushMenu( .T. ) ) + oMenuMsg:Show( Self, .T. ) + ENDIF + ELSE // IF ( saStatics[ SNMENULEVEL ] > 1 ) + nTemp := ::oMenu:GetNext() + IF ( nTemp == 0 ) + nTemp := ::oMenu:GetFirst() + ENDIF + ::oMenu:Select( nTemp ) + ::oMenu:Display() + oMenuMsg:Show( Self, .T. ) + + ENDIF + EXIT + + case K_UP + //====== up arrow key. + + IF ::oMenu:ClassName() != "TOPBARMENU" + nTemp := ::oMenu:GetPrev() + IF ( nTemp == 0 ) + nTemp := ::oMenu:GetLast() + ENDIF + ::oMenu:Select( nTemp ) + ::oMenu:Display() + oMenuMsg:Show( Self, .T. ) + + ENDIF + EXIT + + case K_LEFT + //====== left arrow key. + /** Reset PopUp MenuItem to 1: + ::aPopUp[::nMenuLevel] := 1 **/ + IF ( lSubMenu := ::nMenuLevel > 1 ) + ::PopMenu() + ENDIF + IF ::oMenu:ClassName() == "TOPBARMENU" + nTemp := ::oMenu:GetPrev() + IF ( nTemp == 0 ) + nTemp := ::oMenu:GetLast() + ENDIF + ::oMenu:Select( nTemp ) + ::oMenu:Display() + IF lSubMenu + ::PushMenu( .T. ) + ENDIF + ENDIF + oMenuMsg:Show( Self, .T. ) + EXIT + + case K_RIGHT + //====== right arrow key. + /* Reset PopUp MenuItem to 1: + ::aPopUp[ ::nMenuLevel ] := 1 */ + IF ( lSubMenu := ::nMenuLevel > 1 ) + /* Test !PopMenu() to determine calling PopAll(): + IF !( ::PopMenu() ) + ::PopAll() + ENDIF */ + ::PopMenu() + ENDIF + + IF ::oMenu:ClassName() == "TOPBARMENU" + nTemp := ::oMenu:GetNext() + IF ( nTemp == 0 ) + nTemp := ::oMenu:GetFirst() + ENDIF + ::oMenu:Select( nTemp ) + ::oMenu:Display() + IF lSubMenu + ::PushMenu( .T. ) + ENDIF + ENDIF + oMenuMsg:Show( Self, .T. ) + EXIT + + case K_ENTER + //====== enter key . + + IF ( ::PushMenu( .T. ) ) + oMenuMsg:Show( Self, .T. ) + + ELSE + oMenuMsg:Show( Self, .F. ) + nReturn := ::Execute() + IF ( nReturn != 0 ) + lWhile := .F. + EXIT + ENDIF + + ENDIF + EXIT + + case K_ESC + //====== escape key - go to previous menu + + IF ::PopMenu() + ::oMenu:Display() + oMenuMsg:Show( Self, .T. ) + ELSE + + IF ::oMenu:ClassName() == "POPUPMENU" + ::oMenu:Close() + ENDIF + // Bail out if at the top menu item: + nReturn := -1 + lWhile := .F. + EXIT + + ENDIF + EXIT + + case K_LBUTTONDOWN + //====== mouse left button press. + + // Changed '!HitTest' to '!MHitTest': + IF ( ! ::MHitTest( @oNewMenu, @nNewLevel, @nNewItem ) ) + // Added the following to test Get System HitTest(): + IF ( !( GetList == NIL ) .AND. ; + HitTest( GetList, MROW(), MCOL(), oMenuMsg:aMsg ) != 0 ) + GETACTIVE():ExitState := GE_MOUSEHIT + // Reset Get System values: + // ReadStats( SNLASTEXIT, GE_MOUSEHIT ) + __GetListActive():nLastExitState := GE_MOUSEHIT + // IF ReadStats( SOMENU ):ClassName() == "POPUPMENU" + IF ::oMenu:ClassName() == "POPUPMENU" + ::PopMenu() + ENDIF + // ENDIF + nReturn := -1 + lWhile := .F. + EXIT + ENDIF + + //// Warning: New test for hitting NOWHERE on the Canvas area!!! + IF ::oMenu:ClassName() == "POPUPMENU" + ::PopMenu() + ENDIF + + ELSEIF ( nNewLevel == ::nMenuLevel ) + ::oMenu:Select( nNewItem ) + ::oMenu:Display() + ::PushMenu(.T.) + oMenuMsg:Show( Self, .T. ) + + ELSE + ::nMenuLevel := nNewLevel + ::oMenu := ::aMenuList[ ::nMenuLevel ] + + nMenuItem := ::oMenu:Current + oMenuItem := ::oMenu:GetItem( nMenuItem ) + IF ( ( oMenuItem := ::oMenu:GetItem( ::oMenu:Current ) ):IsPopUp() ) + oMenuItem:Data:Close() + ENDIF + + IF !( nMenuItem == nNewItem ) + nMenuItem := nNewItem + ::oMenu:Select( nNewItem ) + ::oMenu:Display() + ::PushMenu( .T. ) + ENDIF + + oMenuMsg:Show( Self, .T. ) + ENDIF + + lLeftDown := .T. + EXIT + + case K_LBUTTONUP + //====== mouse left button release. + + lLeftDown := .F. + + // Changed '!HitTest' to '!MHitTest': + IF ( ! ::MHitTest( @oNewMenu, @nNewLevel, @nNewItem ) ) + ELSEIF ( nNewLevel == ::nMenuLevel ) + IF ( nNewItem == ::oMenu:Current ) + oMenuMsg:Show( Self, .F. ) + nReturn := ::Execute() + IF ( nReturn != 0 ) + lWhile := .F. + EXIT + ENDIF + ENDIF + + ELSE + + /* This may not be necessary: + nNewItem := ::oMenu:GetFirst() + IF ( nNewItem == 0 ) + ELSE + ::oMenu:Select( nNewItem ) + ::oMenu:Display() + oMenuMsg:Show( Self, .T. ) + ENDIF */ + + ENDIF + EXIT + + Default + + if ( ( nNewItem := ::oMenu:GetAccel( nKey ) ) != 0 ) + //=== check for menu item accelerator key. + + IF ::oMenu:GetItem( nNewItem ):Enabled + ::oMenu:Select( nNewItem ) + ::oMenu:Display() + + /* Code insert to Debug selected menu item in graphics mode: + @ 20, 70 SAY STR( nNewItem, 3 ) + INKEY(0) + @ 20, 70 SAY SPACE( 3 ) */ + + IF ( ! ::PushMenu( .T. ) ) + oMenuMsg:Show( Self, .F. ) + nReturn := ::Execute() + IF ( nReturn != 0 ) + lWhile := .F. + EXIT + ENDIF + ENDIF + oMenuMsg:Show( Self, .T. ) + + ENDIF + + elseif ::IsShortCut( nKey, @nReturn ) + + IF ( nReturn != 0 ) + lWhile := .F. + EXIT + ENDIF + + // Added the following to test Get System HitTest(): + elseif !( GetList == NIL ) .AND. ; + ( ( nNewItem := Accelerator( GetList, nKey, oMenuMsg:aMsg ) ) != 0 ) + GETACTIVE():ExitState := GE_SHORTCUT + + // Reset Get System values: + // ReadStats( SNNEXTGET, nNewItem ) + __GetListActive():nNextGet := nNewItem + // IF ReadStats( SOMENU ):ClassName() == "POPUPMENU" + IF ::oMenu:ClassName() == "POPUPMENU" + ::PopMenu() + ENDIF + // ENDIF + nReturn := -1 + lWhile := .F. + EXIT + + elseif ( nNewItem := ::GetAccel( nKey ) ) != 0 + //=== check for the top menu item accelerator key + + IF ::GetItem( nNewItem ):Enabled + ::PopAll() + ::oMenu:Select( nNewItem ) + ::Display() + IF ( ::GetItem( nNewItem ):IsPopUp() ) + ::PushMenu( .T. ) + ELSE + oMenuMsg:Show( Self, .F. ) + nReturn := ::Execute() + IF ( nReturn != 0 ) + lWhile := .F. + EXIT + ENDIF + ENDIF + oMenuMsg:Show( Self, .T. ) + ENDIF + ENDIF + + END + + ENDDO + + IF oMenuMsg:Flag + oMenuMsg:RestScreen() + ENDIF + + ::PopAll() + SetPos( ::nOldRow, ::nOldCol ) + SetCursor( ::nOldCursor ) + // Restore system entry state settings from file-wide array: + // saStatics := ACLONE( aSavMenuSys ) + + RETURN ( nReturn ) + +/*** +* +* PushMenu( , ) --> .T. | .F. +* +* Increment saStatics[ SNMENULEVEL ] and optionally select first item. +* If selected MenuItem IsPopUp, assign saStatics[ SOMENU ]. +* +***/ +METHOD PushMenu( lSelect ) CLASS TopBarMenu + LOCAL oNewMenu + + oNewMenu := ::oMenu:GetItem( ::oMenu:Current ) + + IF ( !( ValType( oNewMenu ) == "O" ) ) + ELSEIF ( oNewMenu:IsPopUp ) + + IF ( !( ValType( lSelect ) == "L" ) ) + lSelect := .F. + ENDIF + + ::oMenu := oNewMenu:Data + ::aMenuList[ ++::nMenuLevel ] := ::oMenu + + /* If entering a new level: + IF LEN( ::aPopUp ) < ::nMenuLevel + // Resize the array: + ASIZE( ::aPopUp, ::nMenuLevel ) + // Reset MenuItem to 1: + ::aPopUp[ ::nMenuLevel ] := 1 + ENDIF */ + + IF ( lSelect ) + ::oMenu:Select( ::oMenu:GetFirst() ) + /* Select previous item: + ::oMenu:Select( ::aPopUp[ ::nMenuLevel ) */ + ELSE + ::oMenu:Select( 0 ) + + ENDIF + + IF !( ::oMenu:IsOpen ) + ::oMenu:Open() + ENDIF + + RETURN ( .T. ) + + ENDIF + + RETURN ( .F. ) + + +/*** +* +* PopMenu( ) --> .T. | .F. +* +* Close SubMenuItem and Return to the upper MenuItem level. +* +***/ +METHOD PopMenu() CLASS TopBarMenu + IF ( ::nMenuLevel > 1 ) + ::oMenu:Select(0) + ::oMenu:Close(.T.) + // Decrement MenuItem level and assign: + ::oMenu := ::aMenuList[ --::nMenuLevel ] + RETURN ( .T. ) + + ENDIF + + RETURN ( .F. ) + + +/*** +* +* PopChild( , ) --> .T. | .F. +* +* Close PopUp Child MenuItem and Return to the upper MenuItem level. +* +***/ +METHOD PopChild( nNewLevel ) CLASS TopBarMenu + LOCAL oOldMenuItem, nCurrent + + IF ( ( nCurrent := ::oMenu:Current ) != 0 ) + oOldMenuItem := ::oMenu:GetItem( nCurrent ) + IF ( oOldMenuItem:IsPopUp ) + oOldMenuItem:Data:Close() + ::nMenuLevel := nNewLevel + RETURN ( .T. ) + ENDIF + + ENDIF + + RETURN ( .F. ) + + +/*** +* +* PopAll( ) --> .T. +* +* Close all Menus below Top Menu and Return to upper MenuItem level. +* +***/ +METHOD PopAll( ) CLASS TopBarMenu + IF ::aMenuList[2] != NIL + ::aMenuList[2]:Close() + ENDIF + // Set the menu level and position relative to the top menu item: + ::nMenuLevel := 1 + ::oMenu := ::aMenuList[ 1 ] + + RETURN ( .T. ) + +/*** +* +* Execute( ) --> oNewMenu:Id | 0 +* +* EVAL()uate the Data block if selected MenuItem is !IsPopUp. +* +***/ +METHOD Execute() CLASS TopBarMenu + + LOCAL oNewMenu, nCurrent := 0, lPas := .T. + + oNewMenu := ::oMenu:GetItem( ::oMenu:Current ) + + IF ( !( ValType( oNewMenu ) == "O" ) ) + // Execute the Data block if selected MenuItem is !IsPopUp: + ELSEIF ( !oNewMenu:IsPopUp ) + IF ( ::oMenu:ClassName() $ "TOPBARMENU_POPUPMENU" ) + SETPOS( ::nOldRow, ::nOldCol ) + SETCURSOR( ::nOldCursor ) + EVAL( oNewMenu:Data, oNewMenu ) + SETCURSOR( SC_NONE ) + lPas := .F. + ENDIF + + // Pop the Menu: + IF ::PopMenu() + nCurrent := ::oMenu:Current + ENDIF + + ::oMenu:Select( nCurrent ) + // Display newly selected current menu item: + IF ( ::oMenu:ClassName() == "POPUPMENU" .AND. ; + ::nMenuLevel == 1 .AND. ! ::oMenu:IsOpen ) + ::oMenu:Open() + ENDIF + + IF lPas + ::oMenu:Close() + SETPOS( ::nOldRow, ::nOldCol ) + SETCURSOR( ::nOldCursor ) + EVAL( oNewMenu:Data, oNewMenu ) + SETCURSOR( SC_NONE ) + + ENDIF + + RETURN ( oNewMenu:Id ) + + ENDIF + + RETURN ( 0 ) + +/*** +* +* MHitTest( , , , ) --> .T. | .F. +* +* Test to find the Mouse location. +* Note: Formal parameters received here were passed by reference. +* +***/ +METHOD MHitTest( oNewMenu, nNewLevel, nNewItem ) CLASS TopBarMenu + + FOR nNewLevel := ::nMenuLevel TO 1 STEP -1 + oNewMenu := ::aMenuList[ nNewLevel ] + nNewItem := oNewMenu:HitTest( mRow(), mCol() ) + if ( nNewItem < 0 ) + // Test for the mouse on Menu separator or border + RETURN ( .F. ) + + elseif ( nNewItem > 0 ) .AND. oNewMenu:GetItem( nNewItem ):Enabled + // Test for the mouse on an enabled item in the menu + RETURN ( .T. ) + + endif + + NEXT + + RETURN ( .F. ) + #endif