Hi Below is the ACHoice as class code which I wrote years back. Right now I cannot collect why I did so as memory has faded. May be this code comes handy if someone one wants to give it a look. Just let me know if some function is missing. It is simply a copy and paste operation.
======================================== //----------------------------------------------------------------------// //----------------------------------------------------------------------// //----------------------------------------------------------------------// // // AChoice() Class Code // //----------------------------------------------------------------------// //----------------------------------------------------------------------// //----------------------------------------------------------------------// #ifdef __HARBOUR__ #include 'HBClass.ch' #else #include 'classv.ch' #endif //----------------------------------------------------------------------// CREATE CLASS AChoiceNew #ifndef __HARBOUR__ EXPORT: #endif VAR nTop, nLeft, nBottom, nRight VAR acItems VAR xSelect VAR cUserFunc VAR nPos VAR nHiLiteRow VAR oWin VAR cargo_ VAR nNumCols VAR nNumRows VAR acCopy VAR alSelect VAR nNewPos VAR lFinished VAR nKey VAR nMode VAR nAtTop VAR nAtBtm VAR nItems VAR bScan VAR lUserFunc VAR nUserFunc VAR bUserFunc VAR cLoClr VAR cHiClr VAR cUnClr VAR nFrstItem VAR nLastItem VAR bAction VAR mrc_ METHOD Init METHOD Destroy METHOD DispPageNew METHOD DispLineNew METHOD Up METHOD Down METHOD PageUp METHOD PageDown METHOD GoTop METHOD GoBottom METHOD Top METHOD Bottom METHOD GoTo METHOD Exe METHOD DeHilite METHOD HiLite METHOD DispAtNew ENDCLASS //----------------------------------------------------------------------// #ifdef __XPP__ METHOD AChoiceNew:Destroy() #else METHOD Destroy() #endif #ifndef __HARBOUR__ ::nTop := NIL ::nLeft := NIL ::nBottom := NIL ::nRight := NIL ::acItems := NIL ::xSelect := NIL ::cUserFunc := NIL ::nPos := NIL ::nHiLiteRow:= NIL ::oWin := NIL ::cargo_ := NIL ::nNumCols := NIL ::nNumRows := NIL ::acCopy := NIL ::alSelect := NIL ::nNewPos := NIL ::lFinished := NIL ::nKey := NIL ::nMode := NIL ::nAtTop := NIL ::nAtBtm := NIL ::nItems := NIL ::bScan := NIL ::lUserFunc := NIL ::nUserFunc := NIL ::bUserFunc := NIL ::cLoClr := NIL ::cHiClr := NIL ::cUnClr := NIL ::nFrstItem := NIL ::nLastItem := NIL ::bAction := NIL ::mrc_ := NIL #endif Return Nil //----------------------------------------------------------------------// #ifdef __XPP__ METHOD AChoiceNew:Init( nTop, nLft, nBtm, nRgt, acItems, xSelect, ; cUserFunc, nPos, nHiLiteRow, oWin, nLastKey, cargo_ ) #else METHOD Init( nTop, nLft, nBtm, nRgt, acItems, xSelect, ; cUserFunc, nPos, nHiLiteRow, oWin, nLastKey, cargo_ ) #endif Local nCntr UN_USED( nLastKey ) DEFAULT nTop TO 0 // The topmost row of the window DEFAULT nLft TO 0 // The leftmost column of the window DEFAULT nBtm TO maxrow() + 1 // The bottommost row of the windows DEFAULT nRgt TO maxcol() + 1 // The rightmost column of the window DEFAULT acItems TO {} // The items from which TO choose DEFAULT xSelect TO .T. // Array or logical, what is selectable DEFAULT cUserFunc TO NIL // Optional function for key exceptions DEFAULT nPos TO 1 // The number of the selected item DEFAULT nHiLiteRow TO 0 // The row to be highlighted ::nTop := nTop ::nLeft := nLft ::nBottom := nBtm ::nRight := nRgt ::acItems := acItems ::xSelect := xSelect ::cUserFunc := cUserFunc ::nPos := nPos ::nHiLiteRow := nHiLiteRow ::oWin := oWin ::cargo_ := cargo_ ::nNumCols := 0 // Number of columns in the window ::nNumRows := 0 // Number of rows in the window ::acCopy := {} // A padded copy of the items ::alSelect := {} // Select permission ::nNewPos := 0 // The next item to be selected ::lFinished := .F. // Is processing finished? ::nKey := 0 // The keystroke to be processed ::nMode := AC_IDLE // The current operating mode ::nAtTop := 1 // The number of the item at the top ::nAtBtm := 1 // The number of the item at the bottom ::nItems := 0 // The number of items ::bScan := { | cX | if( left( cX, 1 ) == upper( chr( ::nKey ) ), .T., .F. ) } ::lUserFunc := ( !empty( ::cUserFunc ) ) ::nUserFunc := 0 // Return value from user function ::bUserFunc := { || AC_ABORT } // Block form of user function ::cLoClr := Before( ",", setcolor() ) ::cHiClr := Before( ",", After( ",", setcolor() ) ) ::cUnClr := After( ",", After( ",", After( ",", After( ",", setcolor() ) ) ) ) ::nFrstItem := 0 ::nLastItem := 0 ::bAction := nil ::mrc_ := {} IF ::lUserFunc ::bUserFunc := &( "{|nM,nP,nH,nK,aC|" + ::cUserFunc + "(nM,nP,nH,nK,aC)}" ) endif IF empty( ::cHiClr ) ::cHiClr := After( "/", ::cLoClr ) + "/" + Before( "/", ::cLoClr ) endif IF empty( ::cUnClr ) ::cUnClr := ::cLoClr endif ::nNumCols := ::nRight - ::nLeft + 1 ::nNumRows := ::nBottom - ::nTop + 1 aeval( ::acItems, { | x | if( valtype( x ) == "C", aadd( ::acCopy, padr( x, ::nNumCols ) ), .F. ) } ) ::nItems := len( ::acCopy ) ::alSelect := array( ::nItems ) IF valtype( ::xSelect ) == "A" afill( ::alSelect, .T. ) for nCntr := 1 to len( ::xSelect ) IF nCntr <= ::nItems IF valtype( ::xSelect[ nCntr ] ) == "C" IF empty( ::xSelect[ nCntr ] ) ::lFinished := .T. ::nPos := 0 else ::alSelect[ nCntr ] := &( ::xSelect[ nCntr ] ) endif else ::alSelect[ nCntr ] := ::xSelect[ nCntr ] endif else nCntr := len( ::xSelect ) + 1 endif next else afill( ::alSelect, ::xSelect ) endif Return Self //----------------------------------------------------------------------// #ifdef __XPP__ METHOD AChoiceNew:Exe() #else METHOD Exe() #endif Local nOption, nLastPos IF !( ::lFinished ) ::nFrstItem := ascan( ::alSelect, .T. ) // First valid item IF ::nFrstItem == 0 ::nLastItem := 0 ::nPos := 0 ::nMode := AC_NOITEM else ::nMode := AC_IDLE ::nLastItem := ::nItems do while ( !( ::alSelect[ ::nLastItem ] ) ) ::nLastItem-- enddo endif // Ensure hilighted item can be selected ::nPos := BETWEEN( ::nFrstItem, ::nPos, ::nLastItem ) ::nNewPos := ::nPos if !( ::alSelect[ ::nNewPos ] ) if ::nNewPos == ::nLastItem ::nNewPos := ::nFrstItem endif do while ( !( ::alSelect[ ::nNewPos ] ) ) ::nNewPos++ enddo endif ::nPos := ::nNewPos // Force hilighted row to be valid // ::nHiLiteRow := BETWEEN( 0, ::nHiLiteRow, ::nNumRows - 1 ) // Force the topmost item to be a valid index of the array // ::nAtTop := BETWEEN( 1, max( 1, ::nPos - ::nHiLiteRow ), ::nItems ) // Ensure as much of the selection area as possible is covered // if ( ::nAtTop + ::nNumRows - 1 ) > ::nItems ::nAtTop := max( 1, ::nItems - ::nNumrows + 1 ) endif ::DispPageNew() endif #ifdef __XPP__ ::oWin:SetDisplayFocus( {|| ::DispPageNew() } ) #endif do while ( !::lFinished ) IF ::nMode != AC_GOTO .and. ::nMode != AC_NOITEM ::nKey := b_inkey() ::nMode := AC_IDLE ::mrc_ := mState() endif #ifdef __WVT__ if nLastPos <> ::nPos Wvt_DrawFocusRect( ::nTop + ( ::nPos - ::nAtTop ), ::nLeft, ; ::nTop + ( ::nPos - ::nAtTop ), ::nRight ) nLastPos := ::nPos endif #endif #ifdef __XPP__ do case case ::nKey == xbeK_ESC ::nKey := K_ESC case ::nKey == xbeK_CTRL_ENTER ::lFinished := .T. keyboard( chr( K_CTRL_ENTER ) ) exit ::nKey := 12121212 endcase #endif do case case ( ::bAction := SetKey( ::nKey ) ) != nil eval( ::bAction, ProcName( 1 ), ProcLine( 1 ), '' ) case ::nKey == K_MOVING ::nPos := ::DispAtNew() #ifdef __WVT__ case ::nKey == K_MWFORWARD ::Up() case ::nKey == K_MWBACKWARD ::Down() case ::nKey == K_LDBLCLK ::nPos := ::DispAtNew() ::nMode := AC_SELECT case ::nKey == K_RIGHT_DOWN nOption := WvtPopup( 1002 ) do case case nOption == K_PGUP ::PageUp() case nOption == K_PGDN ::PageDown() case nOption == K_CTRL_PGUP ::GoTop() case nOption == K_CTRL_PGDN ::GoBottom() case nOption == K_MWFORWARD ::Up() case nOption == K_MWBACKWARD ::Down() case nOption == K_HOME ::Top() case nOption == K_END ::Bottom() case nOption == K_CTRL_END ::nKey := K_CTRL_END ::lFinished := .t. Loop endcase do while inkey()<> 0 enddo #endif case ::nKey == K_LEFT_DOWN if ::mrc_[ 3 ] >= ::nTop .and. ::mrc_[ 3 ] <= ::nBottom .and. ; ::mrc_[ 4 ] >= ::nLeft .and. ::mrc_[ 4 ] <= ::nRight keyboard( chr( K_ENTER ) ) endif case ( ( ::nKey == K_ESC ) .or. ( ::nMode == AC_NOITEM ) ) .and. ( !::lUserFunc ) ::nMode := AC_ABORT ::nPos := 0 ::lFinished := .T. case ::nKey == K_UP ::Up() case ::nKey == K_DOWN ::Down() case ::nKey == K_PGUP ::PageUp() case ::nKey == K_PGDN ::PageDown() case ::nKey == K_HOME ::Top() case ::nKey == K_END ::Bottom() case ( ::nKey == K_CTRL_HOME .or. ::nKey == K_CTRL_PGUP ) ::GoTop() case ( ::nKey == K_CTRL_END .or. ::nKey == K_CTRL_PGDN ) ::GoBottom() case ( ::nKey == K_ENTER ) .and. ( !::lUserFunc ) ::nMode := AC_SELECT ::lFinished := .T. case ( ::nKey == K_RIGHT ) .and. ( !::lUserFunc ) ::nPos := 0 ::lFinished := .T. case ( ::nKey == K_LEFT ) .and. ( !::lUserFunc ) ::nPos := 0 ::lFinished := .T. case INRANGE( 32, ::nKey, 255 ) .and. ( ( !::lUserFunc ) .or. ( ::nMode == AC_GOTO ) ) ::GoTo() ::nMode := AC_IDLE case ::nMode == AC_GOTO ::nMode := AC_IDLE otherwise if ::nKey == 0 ::nMode := AC_IDLE else ::nMode := AC_EXCEPT endif endcase IF ::lUserFunc ::nUserFunc := eval( ::bUserFunc, ::nMode, ::nPos, ; ::nPos - ::nAtTop, ::nKey, ::cargo_ ) do case case ::nUserFunc == AC_ABORT ::lFinished := .T. ::nPos := 0 case ::nUserFunc == AC_SELECT ::lFinished := .T. case ::nUserFunc == AC_CONT case ::nUserFunc == AC_GOTO ::nMode := AC_GOTO endcase endif enddo Return Self //----------------------------------------------------------------------// #ifdef __XPP__ METHOD AChoiceNew:DispPageNew() #else METHOD DispPageNew() #endif local nCntr local nRow := row() local nCol := col() local nRowPos, nPos DispBegin() for nCntr := 1 to ::nNumRows nRowPos := ::nTop + nCntr - 1 nPos := ::nAtTop + nCntr - 1 if INRANGE( 1, nPos, ::nItems ) ::DispLineNew( nPos, nRowPos, nPos == ::nPos ) else DispOutAt( nRowPos, ::nLeft, space( len( ::acCopy[ 1 ] ) ), ::cLoClr, ::oWin ) endif next DispEnd() SetPos( nRow,nCol ) Return Self //----------------------------------------------------------------------// #ifdef __XPP__ METHOD AChoiceNew:DispLineNew( nPos, nRow, lHiLite ) #else METHOD DispLineNew( nPos, nRow, lHiLite ) #endif DispOutAt( nRow, ::nLeft, ::acCopy[ nPos ],; if( ::alSelect[ nPos ], ; if( lHiLite, ::cHiClr, ::cLoClr ), ::cUnClr ), ::oWin ) Return Self //----------------------------------------------------------------------// #ifdef __XPP__ METHOD AChoiceNew:DeHilite() #else METHOD DeHilite() #endif ::DispLineNew( ::nPos, ::nTop + ( ::nPos - ::nAtTop ), .F. ) Return Self //----------------------------------------------------------------------// #ifdef __XPP__ METHOD AChoiceNew:HiLite() #else METHOD HiLite() #endif ::DispLineNew( ::nPos, ::nTop + ( ::nPos - ::nAtTop ), .T. ) Return Self //----------------------------------------------------------------------// #ifdef __XPP__ METHOD AChoiceNew:Up() #else METHOD Up() #endif local nScroll if ::nPos == ::nFrstItem ::nMode := AC_HITTOP if ::nAtTop > max( 1, ::nPos - ::nNumRows + 1 ) ::nAtTop := max( 1, ::nPos - ::nNumRows + 1 ) ::DispPageNew() endif else ::nNewPos := ::nPos - 1 do while !( ::alSelect[ ::nNewPos ] ) ::nNewPos-- enddo IF INRANGE( ::nAtTop, ::nNewPos, ::nAtTop + ::nNumRows - 1 ) ::DeHilite() ::nPos := ::nNewPos ::HiLite() else DispBegin() ::DeHilite() nScroll := max( -::nNumRows, ( ::nNewPos - ( ::nAtTop + ::nNumRows - 1 ) ) ) Scroll( ::nTop, ::nLeft, ::nBottom, ::nRight, nScroll ) ::nAtTop := ::nNewPos ::nPos := max( ::nPos, ::nAtTop + ::nNumRows - 1 ) do while ( ::nPos > ::nNewPos ) ::DispLineNew( ::nPos, ::nTop + ( ::nPos - ::nAtTop ), .F. ) ::nPos-- enddo ::HiLite() Dispend() endif endif Return Self //----------------------------------------------------------------------// #ifdef __XPP__ METHOD AChoiceNew:Down() #else METHOD Down() #endif local nScroll IF ::nPos == ::nLastItem ::nMode := AC_HITBOTTOM IF ::nAtTop < min( ::nPos, ::nItems - ::nNumRows + 1 ) ::nAtTop := min( ::nPos, ::nItems - ::nNumRows + 1 ) ::DispPageNew() endif else ::nNewPos := ::nPos + 1 do while !( ::alSelect[ ::nNewPos ] ) ::nNewPos++ enddo IF INRANGE( ::nAtTop, ::nNewPos, ::nAtTop + ::nNumRows - 1 ) ::DeHilite() ::nPos := ::nNewPos ::HiLite() else Dispbegin() ::DeHilite() nScroll := min( ::nNumRows, ( ::nNewPos - ( ::nAtTop + ::nNumRows - 1 ) ) ) scroll( ::nTop, ::nLeft, ::nBottom, ::nRight, nScroll ) ::nAtTop := ::nNewPos - ::nNumRows + 1 ::nPos := max( ::nPos, ::nAtTop ) do while ( ::nPos < ::nNewPos ) ::DispLineNew( ::nPos, ::nTop + ( ::nPos - ::nAtTop ), .F. ) ::nPos ++ enddo ::Hilite() Dispend() endif endif Return Self //----------------------------------------------------------------------// #ifdef __XPP__ METHOD AChoiceNew:PageUp() #else METHOD PageUp() #endif IF ::nPos == ::nFrstItem ::nMode := AC_HITTOP IF ::nAtTop > max( 1, ::nPos - ::nNumRows + 1 ) ::nAtTop := max( 1, ::nPos - ::nNumRows + 1 ) ::DispPageNew() endif else IF INRANGE( ::nAtTop, ::nFrstItem, ::nAtTop + ::nNumRows - 1 ) ::nPos := ::nFrstItem ::nAtTop := max( ::nPos - ::nNumRows + 1, 1 ) ::DispPageNew() else if ( ::nPos - ::nNumRows + 1 ) < ::nFrstItem ::nPos := ::nFrstItem ::nAtTop := ::nFrstItem else ::nPos := max( ::nFrstItem, ::nPos - ::nNumRows + 1 ) ::nAtTop := max( 1, ::nAtTop - ::nNumRows + 1 ) do while ( ::nPos > ::nFrstItem ) .and. ( !( ::alSelect[ ::nPos ] ) ) ::nPos-- ::nAtTop-- enddo ::nAtTop := max( 1, ::nAtTop ) endif ::DispPageNew() endif endif Return Self //----------------------------------------------------------------------// #ifdef __XPP__ METHOD AChoiceNew:PageDown() #else METHOD PageDown() #endif local nGap IF ::nPos == ::nLastItem ::nMode := AC_HITBOTTOM if ::nAtTop < min( ::nPos, max( 1, ::nItems - ::nNumRows + 1 ) ) ::nAtTop := min( ::nPos, max( 1, ::nItems - ::nNumRows + 1 ) ) ::DispPageNew() endif else IF INRANGE( ::nAtTop, ::nLastItem, ::nAtTop + ::nNumRows - 1 ) ::DeHilite() ::nPos := ::nLastItem ::Hilite() else nGap := ::nPos - ::nAtTop ::nPos := min( ::nLastItem, ::nPos + ::nNumRows - 1 ) if ( ::nPos + ::nNumRows - 1 ) > ::nLastItem ::nAtTop := ::nLastItem - ::nNumRows + 1 ::nPos := min( ::nLastItem, ::nAtTop + nGap ) else ::nAtTop := ::nPos - nGap endif do while ( ::nPos < ::nLastItem ) .and. !( ::alSelect[ ::nPos ] ) ::nPos++ ::nAtTop++ enddo do while ( ::nAtTop + ::nNumRows - 1 ) > ::nItems ::nAtTop-- enddo ::DispPageNew() endif endif Return Self //----------------------------------------------------------------------// #ifdef __XPP__ METHOD AChoiceNew:Top() #else METHOD Top() #endif IF ::nPos == ::nFrstItem IF ::nAtTop == max( 1, ::nPos - ::nNumRows + 1 ) ::nMode := AC_HITTOP else ::nAtTop := max( 1, ::nPos - ::nNumRows + 1 ) ::DispPageNew() endif else ::nNewPos := ::nAtTop do while !( ::alSelect[ ::nNewPos ] ) ::nNewPos++ enddo IF ::nNewPos != ::nPos ::DeHilite() ::nPos := ::nNewPos ::HiLite() endif endif Return Self //----------------------------------------------------------------------// #ifdef __XPP__ METHOD AChoiceNew:Bottom() #else METHOD Bottom() #endif IF ::nPos == ::nLastItem IF ::nAtTop == min( ::nPos, ::nItems - ::nNumRows + 1 ) ::nMode := AC_HITBOTTOM else ::nAtTop := min( ::nPos, ::nItems - ::nNumRows + 1 ) ::DispPageNew() endif else ::nNewPos := ::nAtTop + ::nNumRows - 1 do while !( ::alSelect[ ::nNewPos ] ) ::nNewPos-- enddo IF ::nNewPos != ::nPos ::DeHilite() ::nPos := ::nNewPos ::HiLite() endif endif Return Self //----------------------------------------------------------------------// #ifdef __XPP__ METHOD AChoiceNew:GoTop() #else METHOD GoTop() #endif IF ::nPos == ::nFrstItem IF ::nAtTop == max( 1, ::nPos - ::nNumRows + 1 ) ::nMode := AC_HITTOP else ::nAtTop := max( 1, ::nPos - ::nNumRows + 1 ) ::DispPageNew() endif else ::nPos := ::nFrstItem ::nAtTop := ::nPos ::DispPageNew() endif Return Self //----------------------------------------------------------------------// #ifdef __XPP__ METHOD AChoiceNew:GoBottom() #else METHOD GoBottom() #endif IF ::nPos == ::nLastItem IF ::nAtTop == min( ::nLastItem, ::nItems - ::nNumRows + 1 ) ::nMode := AC_HITBOTTOM else ::nAtTop := min( ::nLastItem, ::nItems - ::nNumRows + 1 ) ::DispPageNew() endif else IF INRANGE( ::nAtTop, ::nLastItem, ::nAtTop + ::nNumRows - 1 ) ::DeHilite() ::nPos := ::nLastItem ::HiLite() else ::nPos := ::nLastItem ::nAtTop := max( 1, ::nPos - ::nNumRows + 1 ) ::DispPageNew() endif endif Return Self //----------------------------------------------------------------------// #ifdef __XPP__ METHOD AChoiceNew:GoTo() #else METHOD GoTo() #endif ::nNewPos := ascan( ::acCopy, ::bScan, ::nPos + 1 ) do while INRANGE( ::nPos, ::nNewPos, ::nLastItem ) .and. !( ::alSelect[ ::nNewPos ] ) ::nNewPos := ascan( ::acCopy, ::bScan, ::nNewPos + 1 ) enddo IF ::nNewPos == 0 ::nNewPos := ascan( ::acCopy, ::bScan ) do while INRANGE( 1, ::nNewPos, ::nLastItem ) .and. !( ::alSelect[ ::nNewPos ] ) ::nNewPos := ascan( ::acCopy, ::bScan, ::nNewPos + 1 ) enddo endif IF INRANGE( ::nFrstItem, ::nNewPos, ::nLastItem ) .and. ::alSelect[ ::nNewPos ] IF INRANGE( ::nAtTop, ::nNewPos, ::nAtTop + ::nNumRows - 1 ) ::DeHilite() ::nPos := ::nNewPos ::HiLite() else ::nPos := ::nNewPos ::nAtTop := BETWEEN( 1, ::nPos - ::nNumRows + 1, ::nItems ) ::DispPageNew() endif endif Return Self //----------------------------------------------------------------------// #ifdef __XPP__ METHOD AChoiceNew:DispAtNew() #else METHOD DispAtNew() #endif local nNewPos if ::mrc_[ 3 ] >= ::nTop .and. ::mrc_[ 3 ] <= ::nTop + ::nNumRows - 1 ; .and. ; ::mrc_[ 4 ] >= ::nLeft .and. ::mrc_[ 4 ] <= ::nRight if ( nNewPos := ::nAtTop + ( ::mrc_[ 3 ] - ::nTop ) ) <> ::nPos if ::alSelect[ nNewPos ] ::DeHilite() ::nPos := nNewPos ::nNewPos := ::nPos ::HiLite() /* #ifdef __WVT__ Wvt_DrawFocusRect( ::nTop + ( ::nPos - ::nAtTop ), ::nLeft, ; ::nTop + ( ::nPos - ::nAtTop ), ::nRight ) #endif */ endif endif endif Return ::nPos //----------------------------------------------------------------------// ========================================================= ----- enjoy hbIDEing... Pritpal Bedi _a_student_of_software_analysis_&_design_ -- View this message in context: http://n2.nabble.com/bug-ACHOICE-tp4524977p4526126.html Sent from the harbour-devel mailing list archive at Nabble.com. _______________________________________________ Harbour mailing list (attachment size limit: 40KB) Harbour@harbour-project.org http://lists.harbour-project.org/mailman/listinfo/harbour