bug in FW 13.04 combobox

Re: bug in FW 13.04 combobox

Postby ADutheil » Mon May 13, 2013 2:02 pm

Lucas,

Did you try to force CBS_DROPDOWN in #xcommand REDEFINE COMBOBOX from fivewin.ch. For me it was a very quick and easy workaround.
Regards,

André Dutheil
FWH 13.04 + HB 3.2 + MSVS 10
ADutheil
 
Posts: 368
Joined: Sun May 31, 2009 6:25 pm
Location: Salvador - Bahia - Brazil

Re: bug in FW 13.04 combobox

Postby lucasdebeltran » Tue May 14, 2013 10:15 am

André,

Thanks, but I think combobox.prg should be revised and fixed, as it is a basic control too.
Muchas gracias. Many thanks.

Un saludo, Best regards,

Harbour 3.2.0dev, Borland C++ 5.82 y FWH 13.06 [producción]

Implementando MSVC 2010, FWH64 y ADO.

Abandonando uso xHarbour y SQLRDD.
User avatar
lucasdebeltran
 
Posts: 1303
Joined: Tue Jul 21, 2009 8:12 am

Re: bug in FW 13.04 combobox

Postby lucasdebeltran » Wed May 15, 2013 1:57 pm

Antonio,

Any news please?.

Thank you.
Muchas gracias. Many thanks.

Un saludo, Best regards,

Harbour 3.2.0dev, Borland C++ 5.82 y FWH 13.06 [producción]

Implementando MSVC 2010, FWH64 y ADO.

Abandonando uso xHarbour y SQLRDD.
User avatar
lucasdebeltran
 
Posts: 1303
Joined: Tue Jul 21, 2009 8:12 am

Re: bug in FW 13.04 combobox

Postby Antonio Linares » Wed May 15, 2013 3:26 pm

I have implemented several changes and with this version FWH/samples/combos.prg works fine and it keeps backwards compatibility.

Here I provide the entire class so you can test it, thanks

combobox.prg
Code: Select all  Expand view
#include "FiveWin.ch"
#include "Constant.ch"

#define GWL_STYLE          -16

#ifndef __CLIPPER__
   #define COMBO_BASE      320
#else
   #define COMBO_BASE  WM_USER
#endif

#define CB_ADDSTRING     ( COMBO_BASE + 3 )
#define CB_DELETESTRING  ( COMBO_BASE +  4 )
#define CB_GETCURSEL     ( COMBO_BASE +  7 )
#define CB_INSERTSTRING  ( COMBO_BASE + 10 )
#define CB_RESETCONTENT  ( COMBO_BASE + 11 )
#define CB_FINDSTRING    ( COMBO_BASE + 12 )
#define CB_SETCURSEL     ( COMBO_BASE + 14 )
#define CB_SHOWDROPDOWN  ( COMBO_BASE + 15 )
#define CB_GETDROPPEDSTATE  ( COMBO_BASE + 23 )
#define CB_ERR              -1

#define CB_SETMINVISIBLE     5889 // 0x1701
#define CB_GETMINVISIBLE     5890 // 0x1702

#define COLOR_WINDOW         5
#define COLOR_WINDOWTEXT     8

#define GW_CHILD             5
#define GW_HWNDNEXT          2

//----------------------------------------------------------------------------//

CLASS TComboBox FROM TControl

   DATA   aItems, aBitmaps
   DATA   lOwnerDraw, nBmpHeight, nBmpWidth
   DATA   nAt
   DATA   bDrawItem, bCloseUp
   DATA   cError AS String
   DATA   oGet
   DATA   cSearchKey   // Holds current search key for incremental search.
   DATA   lIncSearch AS LOGICAL // incremental search
   DATA   lCaseSensitive INIT .F.

   CLASSDATA aProperties ;
      INIT { "aItems", "cTitle", "cVarName", "l3D", "nClrText",;
             "nClrPane", "nAlign", "nTop", "nLeft",;
             "nWidth", "nHeight", "oFont", "Cargo" }

   METHOD New( nRow, nCol, bSetGet, aItems, nWidth, nHeight, oWnd, nHelpId,;
               bChange, bValid, nClrText, nClrBack, lPixel, oFont,;
               cMsg, lUpdate, bWhen, lDesign, acBitmaps, bDrawItem, nStyle,;
               cPict, bEChange ) CONSTRUCTOR

   METHOD ReDefine( nId, bSetGet, aItems, oWnd, nHelpId, bValid, ;
               bChange, nClrText, nClrBack, cMsg, lUpdate,;
               bWhen, acBitmaps, bDrawItem, nStyle, cPict, bEChange ) CONSTRUCTOR

   METHOD Add( cItem, nAt )
   
   METHOD GenLocals()
   
   METHOD cGenPrg()

   METHOD cToChar() INLINE  ::Super:cToChar( "COMBOBOX" )

   METHOD Change()

   METHOD Close() INLINE ::SendMsg( CB_SHOWDROPDOWN, 0 )

   METHOD CloseUp() INLINE If( ::bCloseUp != nil, Eval( ::bCloseUp, Self ),)

   METHOD CtlColor( hWndChild, hDCChild )
   METHOD Default()

   METHOD DefControl( oControl )

   METHOD Del( nAt )

   METHOD Destroy()

   METHOD DrawItem( nIdCtl, nPStruct )

   METHOD FillMeasure( nPInfo ) INLINE  LbxMeasure( nPInfo, ::nBmpHeight )

   METHOD FindString( cItem, nFrom ) INLINE ;
                              nFrom := If( nFrom == nil, 0, nFrom ),;
                              ::SendMsg( CB_FINDSTRING, nFrom, cItem ) + 1

   METHOD Find( cItem, nFrom ) INLINE ::FindString( cItem, nFrom ) != 0

   METHOD GetKeyChar( nKey )

   METHOD GetMinVisible() INLINE If( IsAppThemed(), ;
                                    ::SendMsg( CB_GETMINVISIBLE, 0, 0 ), 0 )

   METHOD HandleEvent( nMsg, nWParam, nLParam )

   METHOD Initiate( hDlg )

   METHOD Insert( cItem, nAt )

   METHOD KeyChar( nKey, nFlags )

   METHOD KeyDown( nKey, nFlags )
   
   METHOD LostFocus( hWndGetFocus )

   METHOD lValid()

   METHOD Modify( cItem, nAt )

   METHOD MouseMove( nRow, nCol, nKeyFlags )

   METHOD Open() INLINE ::SendMsg( CB_SHOWDROPDOWN, 1 )

   METHOD Refresh() INLINE  ::Set( Eval( ::bSetGet ) ), ::Super:Refresh()

   METHOD Reset( lChanged ) INLINE Eval( ::bSetGet,;
                         If( ValType( Eval( ::bSetGet ) ) == "N", 0, "" ) ),;
                         ::nAt := 0, ::SendMsg( CB_RESETCONTENT ),;
                         if( ( lChanged != NIL .and. lChanged ) .or. ( lChanged == NIL ), ::Change(), )

   METHOD Select( nItem ) INLINE ::nAt := nItem,;
                                 ::SendMsg( CB_SETCURSEL, nItem - 1, 0 )

   METHOD Set( cNewItem )

   METHOD SetBitmaps( acBitmaps )

   METHOD SetItems( aItems, lChanged ) INLINE ::Reset( lChanged ), ::aItems := aItems,;
                                    ::Default(),;
                                    if( ( lChanged != NIL .and. lChanged ) .or. ( lChanged == NIL ), ::Change(), )

   // By default, 30 is the minimum number of visible items in XP Visual Themes
   METHOD SetMinVisible( nItems ) INLINE ;
          If( IsAppThemed(), ( ::SendMsg( CB_SETMINVISIBLE, nItems, 0 ) == 1 ), .f. )

   METHOD ShowToolTip()

   METHOD VarGet()
   METHOD State() INLINE ::SendMsg( CB_GETDROPPEDSTATE, 0 )
   METHOD IsClosed() INLINE ::State() == 0
   METHOD IsOpen() INLINE ::State() == 1

   METHOD GotFocus()
   
   METHOD End() INLINE ::Hide(), If( ::oGet != nil, ::oGet:End(),), ::Super:End()
 
ENDCLASS

//----------------------------------------------------------------------------//

METHOD New( nRow, nCol, bSetGet, aItems, nWidth, nHeight, oWnd, nHelpId,;
            bChange, bValid, nClrFore, nClrBack, lPixel, oFont,;
            cMsg, lUpdate, bWhen, lDesign, acBitmaps, bDrawItem, nStyle,;
            cPict, bEChange, cVarName ) CLASS TComboBox

   if nClrFore == nil
      nClrBack := GetSysColor( COLOR_WINDOW )
   endif

   DEFAULT nRow     := 0, nCol := 0, bSetGet := { || nil },;
           oWnd     := GetWndDefault(),;
           oFont    := oWnd:oFont,;
           aItems   := {}, nWidth := 40, nHeight := 60,;
           nClrFore := GetSysColor( COLOR_WINDOWTEXT ),;
           lPixel   := .f., lUpdate := .f., lDesign := .f.,;
           nStyle   := CBS_DROPDOWNLIST

   ::cCaption  = ""
   ::nTop      = nRow * If( lPixel, 1, CMB_CHARPIX_H )
   ::nLeft     = nCol * If( lPixel, 1, CMB_CHARPIX_W )
   ::nBottom   = ::nTop  + nHeight - 1
   ::nRight    = ::nLeft + nWidth  - 1
   ::nAt       = 0
   ::aItems    = aItems
   ::bChange   = bChange
   ::bSetGet   = bSetGet
   ::oWnd      = oWnd
   ::oFont     = oFont
   ::cSearchKey := ""

   if acBitmaps != nil
      ::SetBitmaps( acBitmaps )
   else
      ::lOwnerDraw = .f.
   endif

   ::nStyle    = nOR( If( nStyle == CBS_DROPDOWN, 0, LBS_NOTIFY ), WS_TABSTOP,;
                      nStyle,;
                      LBS_DISABLENOSCROLL, WS_CHILD, WS_VISIBLE, WS_BORDER,;
                      WS_VSCROLL, If( lDesign, WS_CLIPSIBLINGS, 0 ),;
                      If( ::lOwnerDraw, CBS_OWNERDRAWFIXED, 0 ) )

   ::nId       = ::GetNewId()
   ::nHelpId   = nHelpId
   ::bValid    = bValid
   ::lDrag     = lDesign
   ::lCaptured = .f.
   ::cMsg      = cMsg
   ::lUpdate   = lUpdate
   ::bWhen     = bWhen
   ::bDrawItem = bDrawItem

   ::SetColor( nClrFore, nClrBack )

   if Empty( ::oFont )
      DEFINE FONT ::oFont NAME GetSysFont() SIZE 0, -12
   endif
   
   ::oGet := TGet():ReDefine( nil,    ;  // ID not used
                              ::bSetGet, ;  // bSETGET(uVar)
                              Self,      ;  // oDlg
                              ::nHelpID, ;  // Help Context ID
                              cPict,     ;  // Picture
                              nil,       ;  // Valid is handled by the CBx
                              ::nClrText,;
                              ::nClrPane,;
                              ::oFont,   ;  // <oFont>
                              nil,       ;  // <oCursor>
                              cMsg,      ;  // cMsg
                              nil,       ;  // <.update.>
                              nil,       ;  // <{uWhen}>
                              bEChange,  ;  // {|nKey,nFlags,Self| <uEChange>}
                              .F.        )  // <.readonly.> )

   if ! Empty( oWnd:hWnd )
      ::Create( "COMBOBOX" )
      ::Default()
      if oFont != nil
         ::SetFont( oFont )
      endif
      oWnd:AddControl( Self )
   else
      oWnd:DefControl( Self )
   endif

   DEFAULT cVarName := "oCbx" + ::GetCtrlIndex()
   
   ::cVarName = cVarName

   if ::oGet != nil
      ::oGet:hWnd = GetWindow( ::hWnd, GW_CHILD )
      ::oGet:Link()
      ::oGet:bLostFocus = ;
         { | hCtlFocus, nAt, cItem| cItem := GetWindowText( ::hWnd ), ;
             nAt := ::SendMsg( CB_FINDSTRING, 0, Trim( cItem )) + 1,;
             Eval( ::bSetGet, cItem ),;
             ::Select( nAt ),;
             SetWindowText( ::hWnd, cItem ),;
             If( ::bValid != nil .and. ;
             GetParent( hCtlFocus ) == GetParent( ::hWnd ),;
             If( ! Eval( ::bValid, ::oGet, Self ),;
             ::PostMsg( WM_SETFOCUS ),),) }
      ::oGet:bKeyChar = { | nKey | ::GetKeyChar( nKey ) }
   endif

   if lDesign
      ::CheckDots()
   endif

return Self

//----------------------------------------------------------------------------//

METHOD ReDefine( nId, bSetGet, aItems, oWnd, nHelpId, bValid, ;
                 bChange, nClrFore, nClrBack, cMsg, lUpdate, ;
                 bWhen, acBitmaps, bDrawItem, nStyle, cPict, ;
                 bEChange ) CLASS TComboBox

   DEFAULT oWnd := GetWndDefault()

   if nClrFore == nil
      nClrBack := GetSysColor( COLOR_WINDOW )
   endif

   DEFAULT aItems   := {},;
           nClrFore := GetSysColor( COLOR_WINDOWTEXT ),;
           lUpdate  := .f., ;
           nStyle   := CBS_DROPDOWNLIST

   ::nId       = nId
   ::hWnd      = 0
   ::aItems    = aItems
   ::bChange   = bChange
   ::bSetGet   = bSetGet
   ::oWnd      = oWnd
   ::nHelpId   = nHelpId
   ::bValid    = bValid
   ::nAt       = 0
   ::lDrag     = .f.
   ::lCaptured = .f.
   ::cMsg      = cMsg
   ::lUpdate   = lUpdate
   ::bWhen     = bWhen
   ::bDrawItem = bDrawItem
   ::nStyle    = nStyle
   ::cSearchKey = ""

   if acBitmaps != nil
      ::SetBitmaps( acBitmaps )
   else
      ::lOwnerDraw = .F.
   endif

   ::SetColor( nClrFore, nClrBack )
   
   ::oGet := TGet():ReDefine( nil,    ;  // ID not used
                              ::bSetGet, ;  // bSETGET(uVar)
                              Self,      ;  // oDlg
                              ::nHelpID, ;  // Help Context ID
                              cPict,     ;  // Picture
                              nil,       ;  // Valid is handled by the CBx
                              ::nClrText,;
                              ::nClrPane,;
                              ::oFont,   ;  // <oFont>
                              nil,       ;  // <oCursor>
                              cMsg,      ;  // cMsg
                              nil,       ;  // <.update.>
                              nil,       ;  // <{uWhen}>
                              bEChange,  ;  // {|nKey,nFlags,Self| <uEChange>}
                              .F.        )  // <.readonly.> )
   ::oGet:bKeyChar = { | nKey | ::GetKeyChar( nKey ) }

   oWnd:DefControl( Self )

return Self

//----------------------------------------------------------------------------//

METHOD Add( cItem, nAt ) CLASS TComboBox

   DEFAULT nAt := 0

   if nAt == 0
      AAdd( ::aItems, cItem )
   else
      ASize( ::aItems, Len( ::aItems ) + 1 )
      AIns( ::aItems, nAt )
      ::aItems[ nAt ] = cItem
   endif

   ::SendMsg( CB_ADDSTRING, nAt, cItem )

return nil

//----------------------------------------------------------------------------//

METHOD GenLocals() CLASS TComboBox

   local cCode := ", " + ::cVarName

   cCode += ", " + "c" + SubStr( ::cVarName, 2 )

   cCode += " := " + If( ! Empty( ::GetText() ),;
            'PadR( "' + ::GetText() + '", 20 )',;
            '""' )

return cCode

//----------------------------------------------------------------------------//

METHOD cGenPrg() CLASS TComboBox

   local cCode := ""
   local n

   cCode += CRLF + "   @ " + Str( ::nTop, 3 ) + ", " + Str( ::nLeft, 3 ) + ;
            " COMBOBOX " + ::cVarName + " VAR " + "c" + ;
            SubStr( ::cVarName, 2 ) + " ITEMS {" + ;
            If( Len( ::aItems ) > 0, " ", "" )

   for n = 1 to Len( ::aItems )
      if n > 1
         cCode += ", "
      endif
      cCode += '"' + ::aItems[ n ] + '"'
   next

   cCode += If( Len( ::aItems ) > 0, " ", "" ) + "} ;" + CRLF + ;
            "      SIZE " + Str( ::nRight - ::nLeft + 1, 3 ) + ", " + ;
            Str( ::nBottom - ::nTop + 1, 3 ) + " PIXEL OF " + ;
            ::oWnd:cVarName + CRLF

return cCode

//----------------------------------------------------------------------------//

METHOD Change() CLASS TComboBox

   local cItem := ::GetText() // Current Value
   local nAt

   nAt = ::SendMsg( CB_GETCURSEL ) + 1

   if nAt == ::nAt .and. ! Empty( Eval( ::bSetGet ) )
      return nil
   endif

   ::nAt := nAt

   if ::nAt != 0 .and. ::nAt <= Len( ::aItems )
      if ValType( Eval( ::bSetGet ) ) == "N"
         Eval( ::bSetGet, ::nAt )
      else
         Eval( ::bSetGet, ::aItems[ ::nAt ] )
      endif
   endif

   if ::oGet != nil                        // Always not nil for dropdown
      ::oGet:VarPut( Eval( ::bSetGet ) )   // udate variable before calling bChange
      ::oGet:Refresh()
   endif

   if ::bChange != nil
      Eval( ::bChange, Self, cItem )
   endif

return nil

//----------------------------------------------------------------------------//

METHOD DefControl( oControl ) CLASS TComboBox

   if ::aControls == nil
      ::aControls = {}
   endif

   AAdd( ::AControls, oControl )

return nil

//----------------------------------------------------------------------------//

METHOD Set( cNewItem ) CLASS TComboBox

   local nAt

   if ValType( cNewItem ) == "N"
      nAt = cNewItem
      if nAt == 0
         nAt = 1
      endif
   else
      nAt = AScan( ::aItems,;
                   { | cItem | Upper( AllTrim( cItem ) ) == ;
                               Upper( AllTrim( cNewItem ) ) } )
   endif

   if ValType( cNewItem ) == "N" .or. nAt != 0 .and. ::oGet == nil
      ::Select( nAt )
   else
      cNewItem = cValToChar( cNewItem )
   endif

   Eval( ::bSetGet, cNewItem )
   SetWindowText( ::hWnd , cNewItem )
   
return nil

//----------------------------------------------------------------------------//

METHOD LostFocus( hWndGetFocus ) CLASS TComboBox

   local nAt := ::SendMsg( CB_GETCURSEL )

   ::Super:LostFocus( hWndGetFocus )

   if nAt != CB_ERR
      ::nAt = nAt + 1
      if ValType( Eval( ::bSetGet ) ) == "N"
         Eval( ::bSetGet, nAt + 1 )
      else
         Eval( ::bSetGet, If( ::oGet == nil, ::aItems[ nAt + 1 ], ::oGet:GetText() ) )        
      endif
   else
      Eval( ::bSetGet, GetWindowText( ::hWnd ) )
   endif

return nil

//----------------------------------------------------------------------------//

METHOD Modify( cItem, nAt ) CLASS TComboBox

   DEFAULT nAt := 0

   if nAt != 0
      ::aItems[ nAt ] = cItem
      ::SendMsg( CB_DELETESTRING, nAt - 1 )
      ::SendMsg( CB_INSERTSTRING, nAt - 1, cItem )
   endif

return nil

//----------------------------------------------------------------------------//

METHOD Insert( cItem, nAt ) CLASS TComboBox

   DEFAULT nAt := 0

   if nAt != 0
      ASize( ::aItems, Len( ::aItems ) + 1 )
      AIns( ::aItems, nAt )
      ::aItems[ nAt ] = cItem
      ::SendMsg( CB_INSERTSTRING, nAt - 1, cItem )
   endif

return nil

//----------------------------------------------------------------------------//

METHOD GotFocus() CLASS TComboBox

   ::cSearchKey := ""

return ::Super:GotFocus()

//----------------------------------------------------------------------------//

METHOD KeyChar( nKey, nFlags ) CLASS TComboBox

   local nNewAT := 0, nOldAT := ::nAT, uItem

   if Len( ::aItems ) == 0
      return 0
   endif

   if ::lIncSearch
      do case
         case nKey = 32   // VK_DELETE (DO NOT WORK!)
              if ::oGet == nil
                 ::cSearchKey = ""
                 nNewAt = 1
                 uItem  = ::aItems[ nNewAt ]
              else    
                 ::cSearchKey += " "
              endif  
           
         case nKey = VK_BACK
              ::cSearchKey = Left( ::cSearchKey, Len( ::cSearchKey ) - 1 )
           
         case nKey = 190
              nKey = 0
              ::cSearchKey += "."
             
         case ::oGet != nil .and. nKey = VK_TAB
              if ! GetKeyState( VK_SHIFT )
                 ::oWnd:GoNextCtrl( ::hWnd )
              else  
                 ::oWnd:GoPrevCtrl( ::hWnd )
              endif
              return 0  
           
         otherwise
              if ::lCaseSensitive
                 ::cSearchKey += Chr( nKey )
              else
                ::cSearchKey += Upper( Chr( nKey ) )
              endif
      endcase
   
      if Empty( uItem )
         if nNewAt == 0
            if ::lCaseSensitive
               nNewAt = AScan( ::aItems, { | x | SubStr( x, 1, Len( ::cSearchKey ) ) == ::cSearchKey } )
            else
               nNewAt = AScan( ::aItems, { | x | SubStr( Upper( x ), 1, Len( ::cSearchKey ) ) == ::cSearchKey } )
            endif
            if ::oGet == nil
               uItem = ::aItems[ If( nNewAt > 0, nNewAt, Max( ::nAT, 1 ) ) ]
            else  
               uItem = If( nNewAt > 0, ::aItems[ nNewAt ], ::cSearchKey )
            endif  
         else
            uItem = ::aItems[ Max( nNewAt, 1) ]
         endif  
      endif
      ::Set( If( ValType( Eval( ::bSetGet ) ) == "N", AScan( ::aItems, uItem ), uItem ) )
      if ::oGet != nil
         ::oGet:SetPos( Len( ::cSearchKey ) + 1 )
      endif  
   endif  

   if ::bChange != nil
      if ::oGet != nil .or. ( nNewAT != nOldAt .and. nNewAt != 0 )
         Eval( ::bChange, Self, ::VarGet() )
      endif  
   endif

   if nKey == VK_RETURN
      return ::oWnd:GoNextCtrl( ::hWnd )
   endif
   
return If( ::lIncSearch, 0, nil )

//----------------------------------------------------------------------------//

METHOD KeyDown( nKey, nFlags ) CLASS TComboBox

   if nKey == VK_ESCAPE .and. ::IsOpen()
      ::Close()
      return 1
   endif

return ::Super:KeyDown( nKey, nFlags )

//----------------------------------------------------------------------------//

METHOD Del( nAt ) CLASS TComboBox

   DEFAULT nAt := 0

   if nAt != 0
      ADel( ::aItems, nAt )
      ASize( ::aItems, Len( ::aItems ) - 1 )
      ::SendMsg( CB_DELETESTRING, nAt - 1 )
   endif

return nil

//----------------------------------------------------------------------------//

METHOD GetKeyChar( nKey ) CLASS TComboBox

   local nAt, cText

   if ( nKey == VK_TAB .and. ! GetKeyState( VK_SHIFT ) ) .or. nKey == VK_RETURN
      ::oWnd:GoNextCtrl( ::hWnd )
      return 0
   else  
      if nKey == VK_TAB .and. GetKeyState( VK_SHIFT )
         ::oWnd:GoPrevCtrl( ::hWnd )
         return 0
      endif
   endif
   
   if ( nKey >= Asc( "A" ) .and. nKey <= Asc( "Z" ) ) .or. ;
      ( nKey >= Asc( "a" ) .and. nKey <= Asc( "z" ) )
      cText = AllTrim( ::oGet:GetText() ) + Chr( nKey )
      if ( nAt := AScan( ::aItems, { | c | Upper( Left( c, Len( cText ) ) ) == ;
                                           Upper( cText ) } ) ) != 0
         ::oGet:SetText( ::aItems[ nAt ] )
         ::oGet:oGet:buffer = PadR( ::aItems[ nAt ], Len( ::oGet:oGet:buffer ) )
         ::oGet:SetPos( ::oGet:oGet:pos + 1 )
         return 0
      endif
   endif
   
return nKey          

//----------------------------------------------------------------------------//

METHOD HandleEvent( nMsg, nWParam, nLParam ) CLASS TComboBox

   if nMsg == FM_CLOSEUP
      return ::CloseUp()
   endif
   
return ::Super:HandleEvent( nMsg, nWParam, nLParam )      

//----------------------------------------------------------------------------//

METHOD Initiate( hDlg ) CLASS TComboBox

   ::Super:Initiate( hDlg )

   ::Default()

   if ::oGet != nil
      ::oGet:hWnd = GetWindow( ::hWnd, GW_CHILD )
      ::oGet:Link()

      ::oGet:bLostFocus = ;
      {| hCtlFocus, nAt, cItem| cItem := GetWindowText( ::hWnd ), ;
      nAt := ::SendMsg( CB_FINDSTRING, 0, Trim( cItem )) + 1,;
      Eval( ::bSetGet, cItem ),;
      ::Select( nAt ),;
      SetWindowText( ::hWnd, cItem ),;
      If( ::bValid != nil .and. ;
      GetParent( hCtlFocus ) == GetParent( ::hWnd ),;
      If( ! Eval( ::bValid, ::oGet, Self ),;
      ::PostMsg( WM_SETFOCUS ),),) }
      ::oGet:SetFont( ::oFont )
   endif

   ::Refresh()

return nil

//----------------------------------------------------------------------------//

METHOD CtlColor( hWndChild, hDCChild ) CLASS TComboBox

   if lAnd( GetWindowLong( ::hWnd, GWL_STYLE ), CBS_DROPDOWN )
      SetTextColor( hDCChild, ::nClrText )
      SetBkColor( hDCChild, ::nClrPane )

      DEFAULT ::oBrush := TBrush():New( , ::nClrPane )

      return ::oBrush:hBrush
   endif

return nil

//----------------------------------------------------------------------------//

METHOD Default() CLASS TComboBox

   local cStart := Eval( ::bSetGet )
   
   if ! Empty( ::hWnd ) .and. ::nStyle == CBS_DROPDOWNLIST
      ::nStyle := GetWindowLong( ::hWnd, GWL_STYLE )
   endif

   if cStart == nil
      Eval( ::bSetGet, If( Len( ::aItems ) > 0, ::aItems[ 1 ], "" ) )
      cStart = If( Len( ::aItems ) > 0, ::aItems[ 1 ], "" )
   endif

   AEval( ::aItems, { | cItem, nAt | ::SendMsg( CB_ADDSTRING, nAt, cItem ) } ) // " " required by 64 bits

   if ValType( cStart ) != "N"
      ::nAt = AScan( ::aItems, { | cItem | Upper( AllTrim( cItem ) ) == ;
                                           Upper( AllTrim( cStart ) ) } )
   else
      ::nAt = cStart
   endif

   ::nAt = If( ::nAt > 0, ::nAt, 1 )

   if cStart == nil
      ::Select( ::nAt )
   else
      ::Set( cStart )
   endif

return nil

//----------------------------------------------------------------------------//

METHOD MouseMove( nRow, nCol, nKeyFlags ) CLASS TComboBox

   local nResult := ::Super:MouseMove( nRow, nCol, nKeyFlags )

return If( ::lDrag, nResult, nil )    // We want standard behavior !!!

//----------------------------------------------------------------------------//

METHOD SetBitmaps( acBitmaps ) CLASS TComboBox

   local n

   ::lOwnerDraw = .t.

   if acBitmaps != nil
      ::aBitmaps = Array( Len( acBitmaps ) )
      for n = 1 to Len( acBitmaps )
         if File( acBitmaps[ n ] )
            ::aBitmaps[ n ] = ReadBitmap( 0, acBitmaps[ n ] )
         else
            ::aBitmaps[ n ] = LoadBitmap( GetResources(), acBitmaps[ n ] )
         endif
      next
      ::nBmpHeight = nBmpHeight( ::aBitmaps[ 1 ] )
      ::nBmpWidth  = nBmpWidth( ::aBitmaps[ 1 ] )
     
      SetOwnerDrawItemHeight( ::nBmpHeight )
   endif

return nil

//----------------------------------------------------------------------------//

METHOD Destroy() CLASS TComboBox

   local n

   if ::aBitmaps != nil
      for n = 1 to Len( ::aBitmaps )
         DeleteObject( ::aBitmaps[ n ] )
      next
   endif

   if ::oGet != nil
      ::oGet:Destroy()
   endif

return ::Super:Destroy()

//----------------------------------------------------------------------------//

METHOD DrawItem( nIdCtl, nPStruct ) CLASS TComboBox

   if ::oPopup != nil
      return ::Super:DrawItem( nIdCtl, nPStruct )
   endif  

return LbxDrawItem( nPStruct, ::aBitmaps, ::aItems, ::nBmpWidth, ::bDrawItem )

//----------------------------------------------------------------------------//

METHOD VarGet() CLASS TComboBox

   local cRet, nAt := ::SendMsg( CB_GETCURSEL )

   if nAt != CB_ERR
      ::nAt = nAt + 1
      cRet := If( ::oGet == nil, ::aItems[ nAt + 1 ], ::oGet:GetText() )
   else
      cRet := GetWindowText( ::hWnd )
   endif

return cRet

//----------------------------------------------------------------------------//

METHOD lValid() CLASS TComboBox

   local lRet := .t.

   if ValType( ::bValid ) == "B"
      lRet = Eval( ::bValid, ::oGet, Self  )
   endif

return lRet

//----------------------------------------------------------------------------//

METHOD ShowToolTip() CLASS TComboBox

   local nOldBottom

   nOldBottom = ::nBottom
   ::nBottom  = ::nTop + GetTextHeight( ::hWnd ) + 8

   ::Super:ShowToolTip()
   ::nBottom  = nOldBottom

return nil

//----------------------------------------------------------------------------//
 
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42099
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: bug in FW 13.04 combobox

Postby byte-one » Wed May 15, 2013 6:16 pm

Antonio, dont use any logical reference to ::oGet
Code: Select all  Expand view
if ::oGet != nil

or so, because the oGet is always present!
Regards,
Günther
---------------------------------
office@byte-one.com
User avatar
byte-one
 
Posts: 1048
Joined: Mon Oct 24, 2005 9:54 am
Location: Austria

Re: bug in FW 13.04 combobox

Postby Antonio Linares » Wed May 15, 2013 7:19 pm

Günther,

You are right, thanks! :-)
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42099
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: bug in FW 13.04 combobox

Postby lucasdebeltran » Fri May 17, 2013 8:50 am

Antonio,

It is broken again, it does not show the selected ítem:

Code: Select all  Expand view
function Main()

   local oDlg, oCbx, oSayItem, oSayAt
   local cItem := "Lucas"

   SET _3DLOOK ON

   DEFINE DIALOg oDlg RESOURCE "TestCombo"

   REDEFINE COMBOBOX oCbx VAR cItem ITEMS { "Testing", "this", "ComboBox", "Lucas" } ;
      ID 110 OF oDlg ;
      ON CHANGE ( oSayItem:cTitle := cItem,;   // We should use also :SetText()
                  oSayAt:cTitle   := ":nAt = " + Str( oCbx:nAt, 2 ) ) ;
      VALID ( MsgBeep(), .t. )

   REDEFINE SAY oSayItem ID 120 OF oDlg

   REDEFINE BUTTON ID 130 OF oDlg ACTION oCbx:Reset()

   REDEFINE BUTTON ID 140 OF oDlg ;
      ACTION oCbx:SetItems( { "Let's", "Set", "a new", "List" } )

   REDEFINE BUTTON ID 220 OF oDlg ACTION MsgInfo( Str( oCbx:nAt ) )

   REDEFINE SAY oSayAt ID 150 OF oDlg

   ACTIVATE DIALOG oDlg CENTERED


   msgalert(cItem, "ITEM SELECTED")


return nil
Muchas gracias. Many thanks.

Un saludo, Best regards,

Harbour 3.2.0dev, Borland C++ 5.82 y FWH 13.06 [producción]

Implementando MSVC 2010, FWH64 y ADO.

Abandonando uso xHarbour y SQLRDD.
User avatar
lucasdebeltran
 
Posts: 1303
Joined: Tue Jul 21, 2009 8:12 am

Re: bug in FW 13.04 combobox

Postby Antonio Linares » Fri May 17, 2013 7:03 pm

Lucas,

Fixed, in line 452, I forgot to remove the ::oGet checking:

if ValType( cNewItem ) == "N" .or. nAt != 0 // .and. ::oGet == nil

so, the right way is:

if ValType( cNewItem ) == "N" .or. nAt != 0
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42099
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: bug in FW 13.04 combobox

Postby Antonio Linares » Fri May 17, 2013 7:09 pm

I have also changed the position of the call to SetWindowText() so the final changes look like this:

Image
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42099
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: bug in FW 13.04 combobox

Postby lucasdebeltran » Fri May 17, 2013 7:10 pm

Antonio,

Your fix shows Lucas in the combo, but at the end I don´t get cItem at:

msgalert(cItem, "ITEM SELECTED")


Thanks.
Muchas gracias. Many thanks.

Un saludo, Best regards,

Harbour 3.2.0dev, Borland C++ 5.82 y FWH 13.06 [producción]

Implementando MSVC 2010, FWH64 y ADO.

Abandonando uso xHarbour y SQLRDD.
User avatar
lucasdebeltran
 
Posts: 1303
Joined: Tue Jul 21, 2009 8:12 am

Re: bug in FW 13.04 combobox

Postby Antonio Linares » Sat May 18, 2013 10:41 am

Lucas,

Fixed. In combobox.prg line 476:

Instead of:
Eval( ::bSetGet, If( ::oGet == nil, ::aItems[ nAt + 1 ], ::oGet:GetText() ) )

use:
Eval( ::bSetGet, GetWindowText( ::hWnd ) )

testcomb.prg and combos.prg are working fine :-)
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42099
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: bug in FW 13.04 combobox

Postby lucasdebeltran » Sat May 18, 2013 11:34 am

Antonio,

Thank you. It seems working ok now.

Best regards
Muchas gracias. Many thanks.

Un saludo, Best regards,

Harbour 3.2.0dev, Borland C++ 5.82 y FWH 13.06 [producción]

Implementando MSVC 2010, FWH64 y ADO.

Abandonando uso xHarbour y SQLRDD.
User avatar
lucasdebeltran
 
Posts: 1303
Joined: Tue Jul 21, 2009 8:12 am

Re: bug in FW 13.04 combobox

Postby TimStone » Sun May 19, 2013 7:44 pm

Antonio,

Have you published the revised 13.04 yet ?

In the past, the following code has worked fine:

REDEFINE COMBOBOX oCB2 VAR oAptr:AptClr ID 4065 OF oCalDlg ;
ITEMS { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" } ;
BITMAPS { "CJ00", "CJ01","CJ02", "CJ03", "CJ04", "CJ05", "CJ06", "CJ07", "CJ08","CJ09", "CJ10" }

AptClr is a character field of length 2.

The .rc entry is :

CONTROL "", 4065, "ComboBox", CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | WS_TABSTOP, 240, 80, 50, 100

With 13.04, when I do a save on the data fields, AptClr saves a blank to the record even if one of the items has been selected.

Is this part of the problem you are studying with the combobox control ?

As I said, the code used to work. Now it doesn't.

Thanks.

Tim
Tim Stone
http://www.MasterLinkSoftware.com
http://www.autoshopwriter.com
timstone@masterlinksoftware.com
Using: FWH 23.10 with Harbour 3.2.0 / Microsoft Visual Studio Community 2022-24 32/64 bit
User avatar
TimStone
 
Posts: 2944
Joined: Fri Oct 07, 2005 1:45 pm
Location: Trabuco Canyon, CA USA

Re: bug in FW 13.04 combobox

Postby Antonio Linares » Mon May 20, 2013 6:30 am

Tim,

We have not published the revised FWH 13.04 yet.

Here you have the most recent combobox.prg with all the changes:

combobox.prg
Code: Select all  Expand view
#include "FiveWin.ch"
#include "Constant.ch"

#define GWL_STYLE          -16

#ifndef __CLIPPER__
   #define COMBO_BASE      320
#else
   #define COMBO_BASE  WM_USER
#endif

#define CB_ADDSTRING     ( COMBO_BASE + 3 )
#define CB_DELETESTRING  ( COMBO_BASE +  4 )
#define CB_GETCURSEL     ( COMBO_BASE +  7 )
#define CB_INSERTSTRING  ( COMBO_BASE + 10 )
#define CB_RESETCONTENT  ( COMBO_BASE + 11 )
#define CB_FINDSTRING    ( COMBO_BASE + 12 )
#define CB_SETCURSEL     ( COMBO_BASE + 14 )
#define CB_SHOWDROPDOWN  ( COMBO_BASE + 15 )
#define CB_GETDROPPEDSTATE  ( COMBO_BASE + 23 )
#define CB_ERR              -1

#define CB_SETMINVISIBLE     5889 // 0x1701
#define CB_GETMINVISIBLE     5890 // 0x1702

#define COLOR_WINDOW         5
#define COLOR_WINDOWTEXT     8

#define GW_CHILD             5
#define GW_HWNDNEXT          2

//----------------------------------------------------------------------------//

CLASS TComboBox FROM TControl

   DATA   aItems, aBitmaps
   DATA   lOwnerDraw, nBmpHeight, nBmpWidth
   DATA   nAt
   DATA   bDrawItem, bCloseUp
   DATA   cError AS String
   DATA   oGet
   DATA   cSearchKey   // Holds current search key for incremental search.
   DATA   lIncSearch AS LOGICAL // incremental search
   DATA   lCaseSensitive INIT .F.

   CLASSDATA aProperties ;
      INIT { "aItems", "cTitle", "cVarName", "l3D", "nClrText",;
             "nClrPane", "nAlign", "nTop", "nLeft",;
             "nWidth", "nHeight", "oFont", "Cargo" }

   METHOD New( nRow, nCol, bSetGet, aItems, nWidth, nHeight, oWnd, nHelpId,;
               bChange, bValid, nClrText, nClrBack, lPixel, oFont,;
               cMsg, lUpdate, bWhen, lDesign, acBitmaps, bDrawItem, nStyle,;
               cPict, bEChange ) CONSTRUCTOR

   METHOD ReDefine( nId, bSetGet, aItems, oWnd, nHelpId, bValid, ;
               bChange, nClrText, nClrBack, cMsg, lUpdate,;
               bWhen, acBitmaps, bDrawItem, nStyle, cPict, bEChange ) CONSTRUCTOR

   METHOD Add( cItem, nAt )
   
   METHOD GenLocals()
   
   METHOD cGenPrg()

   METHOD cToChar() INLINE  ::Super:cToChar( "COMBOBOX" )

   METHOD Change()

   METHOD Close() INLINE ::SendMsg( CB_SHOWDROPDOWN, 0 )

   METHOD CloseUp() INLINE If( ::bCloseUp != nil, Eval( ::bCloseUp, Self ),)

   METHOD CtlColor( hWndChild, hDCChild )
   METHOD Default()

   METHOD DefControl( oControl )

   METHOD Del( nAt )

   METHOD Destroy()

   METHOD DrawItem( nIdCtl, nPStruct )

   METHOD FillMeasure( nPInfo ) INLINE  LbxMeasure( nPInfo, ::nBmpHeight )

   METHOD FindString( cItem, nFrom ) INLINE ;
                              nFrom := If( nFrom == nil, 0, nFrom ),;
                              ::SendMsg( CB_FINDSTRING, nFrom, cItem ) + 1

   METHOD Find( cItem, nFrom ) INLINE ::FindString( cItem, nFrom ) != 0

   METHOD GetKeyChar( nKey )

   METHOD GetMinVisible() INLINE If( IsAppThemed(), ;
                                    ::SendMsg( CB_GETMINVISIBLE, 0, 0 ), 0 )

   METHOD HandleEvent( nMsg, nWParam, nLParam )

   METHOD Initiate( hDlg )

   METHOD Insert( cItem, nAt )

   METHOD KeyChar( nKey, nFlags )

   METHOD KeyDown( nKey, nFlags )
   
   METHOD LostFocus( hWndGetFocus )

   METHOD lValid()

   METHOD Modify( cItem, nAt )

   METHOD MouseMove( nRow, nCol, nKeyFlags )

   METHOD Open() INLINE ::SendMsg( CB_SHOWDROPDOWN, 1 )

   METHOD Refresh() INLINE  ::Set( Eval( ::bSetGet ) ), ::Super:Refresh()

   METHOD Reset( lChanged ) INLINE Eval( ::bSetGet,;
                         If( ValType( Eval( ::bSetGet ) ) == "N", 0, "" ) ),;
                         ::nAt := 0, ::SendMsg( CB_RESETCONTENT ),;
                         if( ( lChanged != NIL .and. lChanged ) .or. ( lChanged == NIL ), ::Change(), )

   METHOD Select( nItem ) INLINE ::nAt := nItem,;
                                 ::SendMsg( CB_SETCURSEL, nItem - 1, 0 )

   METHOD Set( cNewItem )

   METHOD SetBitmaps( acBitmaps )

   METHOD SetItems( aItems, lChanged ) INLINE ::Reset( lChanged ), ::aItems := aItems,;
                                    ::Default(),;
                                    if( ( lChanged != NIL .and. lChanged ) .or. ( lChanged == NIL ), ::Change(), )

   // By default, 30 is the minimum number of visible items in XP Visual Themes
   METHOD SetMinVisible( nItems ) INLINE ;
          If( IsAppThemed(), ( ::SendMsg( CB_SETMINVISIBLE, nItems, 0 ) == 1 ), .f. )

   METHOD ShowToolTip()

   METHOD VarGet()
   METHOD State() INLINE ::SendMsg( CB_GETDROPPEDSTATE, 0 )
   METHOD IsClosed() INLINE ::State() == 0
   METHOD IsOpen() INLINE ::State() == 1

   METHOD GotFocus()
   
   METHOD End() INLINE ::Hide(), If( ::oGet != nil, ::oGet:End(),), ::Super:End()
 
ENDCLASS

//----------------------------------------------------------------------------//

METHOD New( nRow, nCol, bSetGet, aItems, nWidth, nHeight, oWnd, nHelpId,;
            bChange, bValid, nClrFore, nClrBack, lPixel, oFont,;
            cMsg, lUpdate, bWhen, lDesign, acBitmaps, bDrawItem, nStyle,;
            cPict, bEChange, cVarName ) CLASS TComboBox

   if nClrFore == nil
      nClrBack := GetSysColor( COLOR_WINDOW )
   endif

   DEFAULT nRow     := 0, nCol := 0, bSetGet := { || nil },;
           oWnd     := GetWndDefault(),;
           oFont    := oWnd:oFont,;
           aItems   := {}, nWidth := 40, nHeight := 60,;
           nClrFore := GetSysColor( COLOR_WINDOWTEXT ),;
           lPixel   := .f., lUpdate := .f., lDesign := .f.,;
           nStyle   := CBS_DROPDOWNLIST

   ::cCaption  = ""
   ::nTop      = nRow * If( lPixel, 1, CMB_CHARPIX_H )
   ::nLeft     = nCol * If( lPixel, 1, CMB_CHARPIX_W )
   ::nBottom   = ::nTop  + nHeight - 1
   ::nRight    = ::nLeft + nWidth  - 1
   ::nAt       = 0
   ::aItems    = aItems
   ::bChange   = bChange
   ::bSetGet   = bSetGet
   ::oWnd      = oWnd
   ::oFont     = oFont
   ::cSearchKey := ""

   if acBitmaps != nil
      ::SetBitmaps( acBitmaps )
   else
      ::lOwnerDraw = .f.
   endif

   ::nStyle    = nOR( If( nStyle == CBS_DROPDOWN, 0, LBS_NOTIFY ), WS_TABSTOP,;
                      nStyle,;
                      LBS_DISABLENOSCROLL, WS_CHILD, WS_VISIBLE, WS_BORDER,;
                      WS_VSCROLL, If( lDesign, WS_CLIPSIBLINGS, 0 ),;
                      If( ::lOwnerDraw, CBS_OWNERDRAWFIXED, 0 ) )

   ::nId       = ::GetNewId()
   ::nHelpId   = nHelpId
   ::bValid    = bValid
   ::lDrag     = lDesign
   ::lCaptured = .f.
   ::cMsg      = cMsg
   ::lUpdate   = lUpdate
   ::bWhen     = bWhen
   ::bDrawItem = bDrawItem

   ::SetColor( nClrFore, nClrBack )

   if Empty( ::oFont )
      DEFINE FONT ::oFont NAME GetSysFont() SIZE 0, -12
   endif
   
   ::oGet := TGet():ReDefine( nil,    ;  // ID not used
                              ::bSetGet, ;  // bSETGET(uVar)
                              Self,      ;  // oDlg
                              ::nHelpID, ;  // Help Context ID
                              cPict,     ;  // Picture
                              nil,       ;  // Valid is handled by the CBx
                              ::nClrText,;
                              ::nClrPane,;
                              ::oFont,   ;  // <oFont>
                              nil,       ;  // <oCursor>
                              cMsg,      ;  // cMsg
                              nil,       ;  // <.update.>
                              nil,       ;  // <{uWhen}>
                              bEChange,  ;  // {|nKey,nFlags,Self| <uEChange>}
                              .F.        )  // <.readonly.> )

   if ! Empty( oWnd:hWnd )
      ::Create( "COMBOBOX" )
      ::Default()
      if oFont != nil
         ::SetFont( oFont )
      endif
      oWnd:AddControl( Self )
   else
      oWnd:DefControl( Self )
   endif

   DEFAULT cVarName := "oCbx" + ::GetCtrlIndex()
   
   ::cVarName = cVarName

   if ::oGet != nil
      ::oGet:hWnd = GetWindow( ::hWnd, GW_CHILD )
      ::oGet:Link()
      ::oGet:bLostFocus = ;
         { | hCtlFocus, nAt, cItem| cItem := GetWindowText( ::hWnd ), ;
             nAt := ::SendMsg( CB_FINDSTRING, 0, Trim( cItem )) + 1,;
             Eval( ::bSetGet, cItem ),;
             ::Select( nAt ),;
             SetWindowText( ::hWnd, cItem ),;
             If( ::bValid != nil .and. ;
             GetParent( hCtlFocus ) == GetParent( ::hWnd ),;
             If( ! Eval( ::bValid, ::oGet, Self ),;
             ::PostMsg( WM_SETFOCUS ),),) }
      ::oGet:bKeyChar = { | nKey | ::GetKeyChar( nKey ) }
   endif

   if lDesign
      ::CheckDots()
   endif

return Self

//----------------------------------------------------------------------------//

METHOD ReDefine( nId, bSetGet, aItems, oWnd, nHelpId, bValid, ;
                 bChange, nClrFore, nClrBack, cMsg, lUpdate, ;
                 bWhen, acBitmaps, bDrawItem, nStyle, cPict, ;
                 bEChange ) CLASS TComboBox

   DEFAULT oWnd := GetWndDefault()

   if nClrFore == nil
      nClrBack := GetSysColor( COLOR_WINDOW )
   endif

   DEFAULT aItems   := {},;
           nClrFore := GetSysColor( COLOR_WINDOWTEXT ),;
           lUpdate  := .f., ;
           nStyle   := CBS_DROPDOWNLIST

   ::nId       = nId
   ::hWnd      = 0
   ::aItems    = aItems
   ::bChange   = bChange
   ::bSetGet   = bSetGet
   ::oWnd      = oWnd
   ::nHelpId   = nHelpId
   ::bValid    = bValid
   ::nAt       = 0
   ::lDrag     = .f.
   ::lCaptured = .f.
   ::cMsg      = cMsg
   ::lUpdate   = lUpdate
   ::bWhen     = bWhen
   ::bDrawItem = bDrawItem
   ::nStyle    = nStyle
   ::cSearchKey = ""

   if acBitmaps != nil
      ::SetBitmaps( acBitmaps )
   else
      ::lOwnerDraw = .F.
   endif

   ::SetColor( nClrFore, nClrBack )
   
   ::oGet := TGet():ReDefine( nil,    ;  // ID not used
                              ::bSetGet, ;  // bSETGET(uVar)
                              Self,      ;  // oDlg
                              ::nHelpID, ;  // Help Context ID
                              cPict,     ;  // Picture
                              nil,       ;  // Valid is handled by the CBx
                              ::nClrText,;
                              ::nClrPane,;
                              ::oFont,   ;  // <oFont>
                              nil,       ;  // <oCursor>
                              cMsg,      ;  // cMsg
                              nil,       ;  // <.update.>
                              nil,       ;  // <{uWhen}>
                              bEChange,  ;  // {|nKey,nFlags,Self| <uEChange>}
                              .F.        )  // <.readonly.> )
   ::oGet:bKeyChar = { | nKey | ::GetKeyChar( nKey ) }

   oWnd:DefControl( Self )

return Self

//----------------------------------------------------------------------------//

METHOD Add( cItem, nAt ) CLASS TComboBox

   DEFAULT nAt := 0

   if nAt == 0
      AAdd( ::aItems, cItem )
   else
      ASize( ::aItems, Len( ::aItems ) + 1 )
      AIns( ::aItems, nAt )
      ::aItems[ nAt ] = cItem
   endif

   ::SendMsg( CB_ADDSTRING, nAt, cItem )

return nil

//----------------------------------------------------------------------------//

METHOD GenLocals() CLASS TComboBox

   local cCode := ", " + ::cVarName

   cCode += ", " + "c" + SubStr( ::cVarName, 2 )

   cCode += " := " + If( ! Empty( ::GetText() ),;
            'PadR( "' + ::GetText() + '", 20 )',;
            '""' )

return cCode

//----------------------------------------------------------------------------//

METHOD cGenPrg() CLASS TComboBox

   local cCode := ""
   local n

   cCode += CRLF + "   @ " + Str( ::nTop, 3 ) + ", " + Str( ::nLeft, 3 ) + ;
            " COMBOBOX " + ::cVarName + " VAR " + "c" + ;
            SubStr( ::cVarName, 2 ) + " ITEMS {" + ;
            If( Len( ::aItems ) > 0, " ", "" )

   for n = 1 to Len( ::aItems )
      if n > 1
         cCode += ", "
      endif
      cCode += '"' + ::aItems[ n ] + '"'
   next

   cCode += If( Len( ::aItems ) > 0, " ", "" ) + "} ;" + CRLF + ;
            "      SIZE " + Str( ::nRight - ::nLeft + 1, 3 ) + ", " + ;
            Str( ::nBottom - ::nTop + 1, 3 ) + " PIXEL OF " + ;
            ::oWnd:cVarName + CRLF

return cCode

//----------------------------------------------------------------------------//

METHOD Change() CLASS TComboBox

   local cItem := ::GetText() // Current Value
   local nAt

   nAt = ::SendMsg( CB_GETCURSEL ) + 1

   if nAt == ::nAt .and. ! Empty( Eval( ::bSetGet ) )
      return nil
   endif

   ::nAt := nAt

   if ::nAt != 0 .and. ::nAt <= Len( ::aItems )
      if ValType( Eval( ::bSetGet ) ) == "N"
         Eval( ::bSetGet, ::nAt )
      else
         Eval( ::bSetGet, ::aItems[ ::nAt ] )
      endif
   endif

   if ::oGet != nil                        // Always not nil for dropdown
      ::oGet:VarPut( Eval( ::bSetGet ) )   // udate variable before calling bChange
      ::oGet:Refresh()
   endif

   if ::bChange != nil
      Eval( ::bChange, Self, cItem )
   endif

return nil

//----------------------------------------------------------------------------//

METHOD DefControl( oControl ) CLASS TComboBox

   if ::aControls == nil
      ::aControls = {}
   endif

   AAdd( ::AControls, oControl )

return nil

//----------------------------------------------------------------------------//

METHOD Set( cNewItem ) CLASS TComboBox

   local nAt

   if ValType( cNewItem ) == "N"
      nAt = cNewItem
      if nAt == 0
         nAt = 1
      endif
   else
      nAt = AScan( ::aItems,;
                   { | cItem | Upper( AllTrim( cItem ) ) == ;
                               Upper( AllTrim( cNewItem ) ) } )
   endif

   if ValType( cNewItem ) == "N" .or. nAt != 0
      ::Select( nAt )
   else
      cNewItem = cValToChar( cNewItem )
      SetWindowText( ::hWnd , cNewItem )
   endif

   Eval( ::bSetGet, cNewItem )
   
return nil

//----------------------------------------------------------------------------//

METHOD LostFocus( hWndGetFocus ) CLASS TComboBox

   local nAt := ::SendMsg( CB_GETCURSEL )

   ::Super:LostFocus( hWndGetFocus )

   if nAt != CB_ERR
      ::nAt = nAt + 1
      if ValType( Eval( ::bSetGet ) ) == "N"
         Eval( ::bSetGet, nAt + 1 )
      else
         Eval( ::bSetGet, GetWindowText( ::hWnd ) )        
      endif
   else
      Eval( ::bSetGet, GetWindowText( ::hWnd ) )
   endif

return nil

//----------------------------------------------------------------------------//

METHOD Modify( cItem, nAt ) CLASS TComboBox

   DEFAULT nAt := 0

   if nAt != 0
      ::aItems[ nAt ] = cItem
      ::SendMsg( CB_DELETESTRING, nAt - 1 )
      ::SendMsg( CB_INSERTSTRING, nAt - 1, cItem )
   endif

return nil

//----------------------------------------------------------------------------//

METHOD Insert( cItem, nAt ) CLASS TComboBox

   DEFAULT nAt := 0

   if nAt != 0
      ASize( ::aItems, Len( ::aItems ) + 1 )
      AIns( ::aItems, nAt )
      ::aItems[ nAt ] = cItem
      ::SendMsg( CB_INSERTSTRING, nAt - 1, cItem )
   endif

return nil

//----------------------------------------------------------------------------//

METHOD GotFocus() CLASS TComboBox

   ::cSearchKey := ""

return ::Super:GotFocus()

//----------------------------------------------------------------------------//

METHOD KeyChar( nKey, nFlags ) CLASS TComboBox

   local nNewAT := 0, nOldAT := ::nAT, uItem

   if Len( ::aItems ) == 0
      return 0
   endif

   if ::lIncSearch
      do case
         case nKey = 32   // VK_DELETE (DO NOT WORK!)
              if ::oGet == nil
                 ::cSearchKey = ""
                 nNewAt = 1
                 uItem  = ::aItems[ nNewAt ]
              else    
                 ::cSearchKey += " "
              endif  
           
         case nKey = VK_BACK
              ::cSearchKey = Left( ::cSearchKey, Len( ::cSearchKey ) - 1 )
           
         case nKey = 190
              nKey = 0
              ::cSearchKey += "."
             
         case ::oGet != nil .and. nKey = VK_TAB
              if ! GetKeyState( VK_SHIFT )
                 ::oWnd:GoNextCtrl( ::hWnd )
              else  
                 ::oWnd:GoPrevCtrl( ::hWnd )
              endif
              return 0  
           
         otherwise
              if ::lCaseSensitive
                 ::cSearchKey += Chr( nKey )
              else
                ::cSearchKey += Upper( Chr( nKey ) )
              endif
      endcase
   
      if Empty( uItem )
         if nNewAt == 0
            if ::lCaseSensitive
               nNewAt = AScan( ::aItems, { | x | SubStr( x, 1, Len( ::cSearchKey ) ) == ::cSearchKey } )
            else
               nNewAt = AScan( ::aItems, { | x | SubStr( Upper( x ), 1, Len( ::cSearchKey ) ) == ::cSearchKey } )
            endif
            if ::oGet == nil
               uItem = ::aItems[ If( nNewAt > 0, nNewAt, Max( ::nAT, 1 ) ) ]
            else  
               uItem = If( nNewAt > 0, ::aItems[ nNewAt ], ::cSearchKey )
            endif  
         else
            uItem = ::aItems[ Max( nNewAt, 1) ]
         endif  
      endif
      ::Set( If( ValType( Eval( ::bSetGet ) ) == "N", AScan( ::aItems, uItem ), uItem ) )
      if ::oGet != nil
         ::oGet:SetPos( Len( ::cSearchKey ) + 1 )
      endif  
   endif  

   if ::bChange != nil
      if ::oGet != nil .or. ( nNewAT != nOldAt .and. nNewAt != 0 )
         Eval( ::bChange, Self, ::VarGet() )
      endif  
   endif

   if nKey == VK_RETURN
      return ::oWnd:GoNextCtrl( ::hWnd )
   endif
   
return If( ::lIncSearch, 0, nil )

//----------------------------------------------------------------------------//

METHOD KeyDown( nKey, nFlags ) CLASS TComboBox

   if nKey == VK_ESCAPE .and. ::IsOpen()
      ::Close()
      return 1
   endif

return ::Super:KeyDown( nKey, nFlags )

//----------------------------------------------------------------------------//

METHOD Del( nAt ) CLASS TComboBox

   DEFAULT nAt := 0

   if nAt != 0
      ADel( ::aItems, nAt )
      ASize( ::aItems, Len( ::aItems ) - 1 )
      ::SendMsg( CB_DELETESTRING, nAt - 1 )
   endif

return nil

//----------------------------------------------------------------------------//

METHOD GetKeyChar( nKey ) CLASS TComboBox

   local nAt, cText

   if ( nKey == VK_TAB .and. ! GetKeyState( VK_SHIFT ) ) .or. nKey == VK_RETURN
      ::oWnd:GoNextCtrl( ::hWnd )
      return 0
   else  
      if nKey == VK_TAB .and. GetKeyState( VK_SHIFT )
         ::oWnd:GoPrevCtrl( ::hWnd )
         return 0
      endif
   endif
   
   if ( nKey >= Asc( "A" ) .and. nKey <= Asc( "Z" ) ) .or. ;
      ( nKey >= Asc( "a" ) .and. nKey <= Asc( "z" ) )
      cText = AllTrim( ::oGet:GetText() ) + Chr( nKey )
      if ( nAt := AScan( ::aItems, { | c | Upper( Left( c, Len( cText ) ) ) == ;
                                           Upper( cText ) } ) ) != 0
         ::oGet:SetText( ::aItems[ nAt ] )
         ::oGet:oGet:buffer = PadR( ::aItems[ nAt ], Len( ::oGet:oGet:buffer ) )
         ::oGet:SetPos( ::oGet:oGet:pos + 1 )
         return 0
      endif
   endif
   
return nKey          

//----------------------------------------------------------------------------//

METHOD HandleEvent( nMsg, nWParam, nLParam ) CLASS TComboBox

   if nMsg == FM_CLOSEUP
      return ::CloseUp()
   endif
   
return ::Super:HandleEvent( nMsg, nWParam, nLParam )      

//----------------------------------------------------------------------------//

METHOD Initiate( hDlg ) CLASS TComboBox

   ::Super:Initiate( hDlg )

   ::Default()

   if ::oGet != nil
      ::oGet:hWnd = GetWindow( ::hWnd, GW_CHILD )
      ::oGet:Link()
      ::oGet:bLostFocus = ;
      {| hCtlFocus, nAt, cItem| cItem := GetWindowText( ::hWnd ), ;
      nAt := ::SendMsg( CB_FINDSTRING, 0, Trim( cItem )) + 1,;
      Eval( ::bSetGet, cItem ),;
      ::Select( nAt ),;
      SetWindowText( ::hWnd, cItem ),;
      If( ::bValid != nil .and. ;
      GetParent( hCtlFocus ) == GetParent( ::hWnd ),;
      If( ! Eval( ::bValid, ::oGet, Self ),;
      ::PostMsg( WM_SETFOCUS ),),) }
      ::oGet:SetFont( ::oFont )
   endif

   ::Refresh()

return nil

//----------------------------------------------------------------------------//

METHOD CtlColor( hWndChild, hDCChild ) CLASS TComboBox

   if lAnd( GetWindowLong( ::hWnd, GWL_STYLE ), CBS_DROPDOWN )
      SetTextColor( hDCChild, ::nClrText )
      SetBkColor( hDCChild, ::nClrPane )

      DEFAULT ::oBrush := TBrush():New( , ::nClrPane )

      return ::oBrush:hBrush
   endif

return nil

//----------------------------------------------------------------------------//

METHOD Default() CLASS TComboBox

   local cStart := Eval( ::bSetGet )
   
   if ! Empty( ::hWnd ) .and. ::nStyle == CBS_DROPDOWNLIST
      ::nStyle := GetWindowLong( ::hWnd, GWL_STYLE )
   endif

   if cStart == nil
      Eval( ::bSetGet, If( Len( ::aItems ) > 0, ::aItems[ 1 ], "" ) )
      cStart = If( Len( ::aItems ) > 0, ::aItems[ 1 ], "" )
   endif

   AEval( ::aItems, { | cItem, nAt | ::SendMsg( CB_ADDSTRING, nAt, cItem ) } ) // " " required by 64 bits

   if ValType( cStart ) != "N"
      ::nAt = AScan( ::aItems, { | cItem | Upper( AllTrim( cItem ) ) == ;
                                           Upper( AllTrim( cStart ) ) } )
   else
      ::nAt = cStart
   endif

   ::nAt = If( ::nAt > 0, ::nAt, 1 )

   if cStart == nil
      ::Select( ::nAt )
   else
      ::Set( cStart )
   endif

return nil

//----------------------------------------------------------------------------//

METHOD MouseMove( nRow, nCol, nKeyFlags ) CLASS TComboBox

   local nResult := ::Super:MouseMove( nRow, nCol, nKeyFlags )

return If( ::lDrag, nResult, nil )    // We want standard behavior !!!

//----------------------------------------------------------------------------//

METHOD SetBitmaps( acBitmaps ) CLASS TComboBox

   local n

   ::lOwnerDraw = .t.

   if acBitmaps != nil
      ::aBitmaps = Array( Len( acBitmaps ) )
      for n = 1 to Len( acBitmaps )
         if File( acBitmaps[ n ] )
            ::aBitmaps[ n ] = ReadBitmap( 0, acBitmaps[ n ] )
         else
            ::aBitmaps[ n ] = LoadBitmap( GetResources(), acBitmaps[ n ] )
         endif
      next
      ::nBmpHeight = nBmpHeight( ::aBitmaps[ 1 ] )
      ::nBmpWidth  = nBmpWidth( ::aBitmaps[ 1 ] )
     
      SetOwnerDrawItemHeight( ::nBmpHeight )
   endif

return nil

//----------------------------------------------------------------------------//

METHOD Destroy() CLASS TComboBox

   local n

   if ::aBitmaps != nil
      for n = 1 to Len( ::aBitmaps )
         DeleteObject( ::aBitmaps[ n ] )
      next
   endif

   if ::oGet != nil
      ::oGet:Destroy()
   endif

return ::Super:Destroy()

//----------------------------------------------------------------------------//

METHOD DrawItem( nIdCtl, nPStruct ) CLASS TComboBox

   if ::oPopup != nil
      return ::Super:DrawItem( nIdCtl, nPStruct )
   endif  

return LbxDrawItem( nPStruct, ::aBitmaps, ::aItems, ::nBmpWidth, ::bDrawItem )

//----------------------------------------------------------------------------//

METHOD VarGet() CLASS TComboBox

   local cRet, nAt := ::SendMsg( CB_GETCURSEL )

   if nAt != CB_ERR
      ::nAt = nAt + 1
      cRet := If( ::oGet == nil, ::aItems[ nAt + 1 ], ::oGet:GetText() )
   else
      cRet := GetWindowText( ::hWnd )
   endif

return cRet

//----------------------------------------------------------------------------//

METHOD lValid() CLASS TComboBox

   local lRet := .t.

   if ValType( ::bValid ) == "B"
      lRet = Eval( ::bValid, ::oGet, Self  )
   endif

return lRet

//----------------------------------------------------------------------------//

METHOD ShowToolTip() CLASS TComboBox

   local nOldBottom

   nOldBottom = ::nBottom
   ::nBottom  = ::nTop + GetTextHeight( ::hWnd ) + 8

   ::Super:ShowToolTip()
   ::nBottom  = nOldBottom

return nil

//----------------------------------------------------------------------------//
 
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42099
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: bug in FW 13.04 combobox

Postby byte-one » Mon May 20, 2013 8:14 am

Antonio, here are still a logical call to ::oGet and should removed!

    METHOD VarGet() CLASS TComboBox

    local cRet, nAt := ::SendMsg( CB_GETCURSEL )

    if nAt != CB_ERR
    ::nAt = nAt + 1
    cRet := If( ::oGet == nil, ::aItems[ nAt + 1 ], ::oGet:GetText() ) //::OGET!!!
    else
    cRet := GetWindowText( ::hWnd )
    endif

    return cRet
Regards,
Günther
---------------------------------
office@byte-one.com
User avatar
byte-one
 
Posts: 1048
Joined: Mon Oct 24, 2005 9:54 am
Location: Austria

PreviousNext

Return to FiveWin for Harbour/xHarbour

Who is online

Users browsing this forum: No registered users and 32 guests