+ Add two instance variables, nRow and nCol. Existing in Clipper 5.3.
Only was modified the Hilite and SetPos method, for save in
this variables, the position of cursor.
1568 lines
46 KiB
Plaintext
1568 lines
46 KiB
Plaintext
/*
|
|
* $Id$
|
|
*/
|
|
|
|
/*
|
|
* Harbour Project source code:
|
|
* TBrowse Class
|
|
*
|
|
* Copyright 1999 Antonio Linares <alinares@fivetech.com>
|
|
* www - http://www.harbour-project.org
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this software; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
|
* Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/).
|
|
*
|
|
* As a special exception, the Harbour Project gives permission for
|
|
* additional uses of the text contained in its release of Harbour.
|
|
*
|
|
* The exception is that, if you link the Harbour libraries with other
|
|
* files to produce an executable, this does not by itself cause the
|
|
* resulting executable to be covered by the GNU General Public License.
|
|
* Your use of that executable is in no way restricted on account of
|
|
* linking the Harbour library code into it.
|
|
*
|
|
* This exception does not however invalidate any other reasons why
|
|
* the executable file might be covered by the GNU General Public License.
|
|
*
|
|
* This exception applies only to the code released by the Harbour
|
|
* Project under the name Harbour. If you copy code from other
|
|
* Harbour Project or Free Software Foundation releases into a copy of
|
|
* Harbour, as the General Public License permits, the exception does
|
|
* not apply to the code that you add in this way. To avoid misleading
|
|
* anyone as to the status of such modified files, you must delete
|
|
* this exception notice from them.
|
|
*
|
|
* If you write modifications of your own for Harbour, it is your choice
|
|
* whether to permit this exception to apply to your modifications.
|
|
* If you do not wish that, delete this exception notice.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* The following parts are Copyright of the individual authors.
|
|
* www - http://www.harbour-project.org
|
|
*
|
|
* Copyright 2000, '01, '02 Maurilio Longo <maurilio.longo@libero.it>
|
|
* Cursor movement handling, stabilization loop, multi-line headers and footers support
|
|
* ::PageUp(), ::PageDown(), ::Down(), ::Up(), ::GoBottom(), ::GoTop(), ::Stabilize()
|
|
* ::GotoXY(), ::DispCell(), ::WriteMLineText(), ::RedrawHeaders(),
|
|
* ::SetFrozenCols(), ::SetColumnWidth()
|
|
*
|
|
* Copyright 2001 Manu Exposito <maex14@dipusevilla.es>
|
|
* Activate data PICTURE DispCell(nColumn, nColor)
|
|
*
|
|
*/
|
|
|
|
|
|
/* NOTE: Don't use SAY in this module, use DispOut(), DispOutAt() instead,
|
|
otherwise it will not be CA-Cl*pper compatible. [vszakats] */
|
|
|
|
/* TODO: :firstScrCol() --> nScreenCol
|
|
Determines screen column where the first table column is displayed.
|
|
Xbase++ compatible method */
|
|
|
|
/* TODO: :viewArea() --> aViewArea
|
|
Determines the coordinates for the data area of a TBrowse object.
|
|
Xbase++ compatible method */
|
|
|
|
#include "common.ch"
|
|
#include "hbclass.ch"
|
|
#include "color.ch"
|
|
#include "inkey.ch"
|
|
#include "setcurs.ch"
|
|
#include "button.ch"
|
|
CLASS TBrowse
|
|
|
|
DATA aColumns // Array to hold all browse columns
|
|
DATA autoLite // Logical value to control highlighting
|
|
DATA cargo // User-definable variable
|
|
DATA colorSpec // Color table for the TBrowse display
|
|
DATA colPos // Current cursor column position
|
|
DATA colSep // Column separator character
|
|
DATA footSep // Footing separator character
|
|
DATA goBottomBlock // Code block executed by TBrowse:goBottom()
|
|
DATA goTopBlock // Code block executed by TBrowse:goTop()
|
|
DATA headSep // Heading separator character
|
|
DATA hitBottom // Indicates the end of available data
|
|
DATA hitTop // Indicates the beginning of available data
|
|
DATA leftVisible // Indicates position of leftmost unfrozen column in display
|
|
DATA nBottom // Bottom row number for the TBrowse display
|
|
DATA nLeft // Leftmost column for the TBrowse display
|
|
DATA nRight // Rightmost column for the TBrowse display
|
|
DATA nTop // Top row number for the TBrowse display
|
|
DATA rightVisible // Indicates position of rightmost unfrozen column in display
|
|
DATA rowCount // Number of visible data rows in the TBrowse display
|
|
DATA rowPos // Current cursor row position
|
|
DATA skipBlock // Code block used to reposition data source
|
|
DATA stable // Indicates if the TBrowse object is stable
|
|
|
|
#ifdef HB_COMPAT_C53
|
|
DATA nRow // Row number for the actual cell
|
|
DATA nCol // Col number for the actual cell
|
|
DATA aKeys
|
|
DATA mColpos,mrowPos,message
|
|
#endif
|
|
|
|
ACCESS freeze INLINE ::nFrozenCols // Number of columns to freeze/frozen
|
|
ASSIGN freeze(nHowMany) INLINE ::SetFrozenCols(nHowMany)
|
|
|
|
METHOD New(nTop, nLeft, nBottom, nRight) // Constructor
|
|
METHOD Down() // Moves the cursor down one row
|
|
METHOD End() // Moves the cursor to the rightmost visible data column
|
|
METHOD GoBottom() // Repositions the data source to the bottom of file
|
|
METHOD GoTop() // Repositions the data source to the top of file
|
|
METHOD Home() // Moves the cursor to the leftmost visible data column
|
|
MESSAGE Left() METHOD _Left() // Moves the cursor left one column
|
|
METHOD PageDown() // Repositions the data source downward
|
|
METHOD PageUp() // Repositions the data source upward
|
|
METHOD PanEnd() // Moves the cursor to the rightmost data column
|
|
METHOD PanHome() // Moves the cursor to the leftmost visible data column
|
|
METHOD PanLeft() // Pans left without changing the cursor position
|
|
METHOD PanRight() // Pans right without changing the cursor position
|
|
MESSAGE Right() METHOD _Right() // Moves the cursor right one column
|
|
METHOD Up() // Moves the cursor up one row
|
|
|
|
METHOD AddColumn( oCol )
|
|
METHOD DelColumn( nPos ) // Delete a column object from a browse
|
|
METHOD InsColumn( nPos, oCol ) // Insert a column object in a browse
|
|
METHOD GetColumn( nColumn ) // Gets a specific TBColumn object
|
|
METHOD SetColumn( nColumn, oCol ) // Replaces one TBColumn object with another
|
|
METHOD ColWidth( nColumn ) // Returns the display width of a particular column
|
|
METHOD ColCount() INLINE ::nColumns
|
|
METHOD ColorRect() // Alters the color of a rectangular group of cells
|
|
METHOD Configure( nMode ) // Reconfigures the internal settings of the TBrowse object
|
|
// nMode is an undocumented parameter in CA-Cl*pper
|
|
METHOD DeHilite() // Dehighlights the current cell
|
|
METHOD ForceStable() // Performs a full stabilization
|
|
METHOD Hilite() // Highlights the current cell
|
|
METHOD Invalidate() // Forces entire redraw during next stabilization
|
|
METHOD RefreshAll() // Causes all data to be recalculated during the next stabilize
|
|
METHOD RefreshCurrent() INLINE; // Causes the current row to be refilled and repainted on next stabilize
|
|
::aRedraw[ ::RowPos ] := .T., ::stable := .F., Self
|
|
METHOD Stabilize() // Performs incremental stabilization
|
|
|
|
#ifdef HB_COMPAT_C53
|
|
METHOD SetKey(nKey, bBlock)
|
|
METHOD ApplyKey(nKey)
|
|
METHOD InitKeys(Self)
|
|
METHOD TApplyKey(nKey, o)
|
|
METHOD HitTest(nMouseRow,nMouseCol)
|
|
#endif
|
|
|
|
PROTECTED: /* P R O T E C T E D */
|
|
|
|
METHOD MGotoYX(nRow, nCol) // Given screen coordinates nRow, nCol sets TBrowse cursor on underlaying cell
|
|
// _M_GotoXY because this method will mostly be called to handle mouse requests
|
|
|
|
HIDDEN: /* H I D D E N */
|
|
|
|
METHOD PosCursor() // Positions the cursor to the beginning of the call, used only when autolite==.F.
|
|
METHOD LeftDetermine() // Determine leftmost unfrozen column in display
|
|
METHOD DispCell(nColumn, nColor) // Displays a single cell and returns cell type as a single letter like Valtype()
|
|
METHOD HowManyCol(nWidth) // Counts how many cols can be displayed
|
|
METHOD RedrawHeaders(nWidth) // Repaints TBrowse Headers
|
|
METHOD Moved() // Every time a movement key is issued I need to reset certain properties
|
|
// of TBrowse, I do these settings inside this method
|
|
|
|
METHOD WriteMLineText(cStr, nPadLen, lHeader, cColor) // Writes a multi-line text where ";" is a line break, lHeader
|
|
// is .T. if it is a header and not a footer
|
|
METHOD SetFrozenCols(nHowMany) // Handles freezing of columns
|
|
METHOD SetColumnWidth(oCol) // Calcs width of given column
|
|
|
|
DATA aRect // The rectangle specified with ColorRect()
|
|
DATA aRectColor // The color positions to use in the rectangle specified with ColorRect()
|
|
DATA aRedraw // Array of logical items indicating, is appropriate row need to be redraw
|
|
DATA aColsWidth // Array with width of TBrowse's columns
|
|
DATA lHeaders // Internal variable which indicates whether there are column footers to paint
|
|
DATA lFooters // Internal variable which indicates whether there are column footers to paint
|
|
DATA lRedrawFrame // True if I need to redraw Headers/Footers
|
|
DATA nColsWidth // Total width of visible columns plus ColSep
|
|
DATA nColsVisible // Number of columns that fit on the browse width
|
|
DATA lHitTop // Internal Top/Bottom reached flag
|
|
DATA lHitBottom
|
|
DATA nRecsToSkip // Recs to skip on next Stabilize()
|
|
DATA nNewRowPos // Next position of data source (after first phase of stabilization)
|
|
DATA nLastRetrieved // Position, relative to first row, of last retrieved row (with an Eval(::SkipBlock, n))
|
|
|
|
DATA nHeaderHeight // How many lines is highest Header/Footer and so how many lines of
|
|
DATA nFooterHeight // screen space I have to reserve
|
|
DATA nFrozenWidth // How many screen column are not available on the left side of TBrowse display
|
|
// > 0 only when there are frozen columns
|
|
DATA nFrozenCols // Number of frozen columns on left side of TBrowse
|
|
DATA nColumns // Number of columns added to TBrowse
|
|
DATA lNeverDisplayed // .T. if TBrowse has never been stabilized()
|
|
#ifdef HB_COMPAT_C53
|
|
DATA rect
|
|
DATA aVisibleCols
|
|
#endif
|
|
ENDCLASS
|
|
|
|
|
|
METHOD New(nTop, nLeft, nBottom, nRight) CLASS TBrowse
|
|
|
|
default nTop to 0
|
|
default nLeft to 0
|
|
default nBottom to MaxRow()
|
|
default nRight to MaxCol()
|
|
|
|
::aColumns := {}
|
|
::aColsWidth := {}
|
|
::AutoLite := .T.
|
|
::leftVisible := 1
|
|
::ColPos := 1
|
|
::HitBottom := .F.
|
|
::HitTop := .F.
|
|
::lHitTop := .F.
|
|
::lHitBottom := .F.
|
|
::ColorSpec := SetColor()
|
|
::ColSep := " "
|
|
::FootSep := ""
|
|
::HeadSep := ""
|
|
::RowPos := 1
|
|
::nNewRowPos := 1
|
|
::stable := .F.
|
|
::nLastRetrieved := 1
|
|
::nRecsToSkip := 0
|
|
::aRedraw := {}
|
|
::lHeaders := .F.
|
|
::lFooters := .F.
|
|
::lRedrawFrame := .T.
|
|
::aRect := {}
|
|
::aRectColor := {}
|
|
::nColsWidth := 0
|
|
::nColsVisible := 0
|
|
::nHeaderHeight := 1
|
|
::nFooterHeight := 1
|
|
::nFrozenWidth := 0
|
|
::nFrozenCols := 0
|
|
::nColumns := 0
|
|
::lNeverDisplayed := .T.
|
|
|
|
::nTop := nTop
|
|
::nLeft := nLeft
|
|
::nBottom := nBottom
|
|
::nRight := nRight
|
|
|
|
#ifdef HB_COMPAT_C53
|
|
::mColPos := 0
|
|
::mRowPos := 0
|
|
::rect :={nTop,nLeft,nBottom,nRight}
|
|
::aVisibleCols :={}
|
|
::message :=''
|
|
::nRow := 0
|
|
::nCol := 0
|
|
#endif
|
|
|
|
return Self
|
|
|
|
|
|
METHOD Invalidate() CLASS TBrowse
|
|
|
|
AFill(::aRedraw, .T.)
|
|
::stable := .F.
|
|
::lRedrawFrame := .T.
|
|
|
|
return Self
|
|
|
|
|
|
METHOD RefreshAll() CLASS TBrowse
|
|
|
|
AFill(::aRedraw, .T.)
|
|
::stable := .F.
|
|
|
|
return Self
|
|
|
|
|
|
METHOD Configure(nMode) CLASS TBrowse
|
|
|
|
local n, nHeight
|
|
local nLeft,nRight
|
|
|
|
::lHeaders := .F.
|
|
::lFooters := .F.
|
|
::lRedrawFrame := .T.
|
|
|
|
// Are there column headers to paint ?
|
|
for n := 1 to ::nColumns
|
|
if !Empty(::aColumns[n]:Heading)
|
|
::lHeaders := .T.
|
|
exit
|
|
endif
|
|
next
|
|
|
|
// Are there column footers to paint ?
|
|
for n := 1 to ::nColumns
|
|
if !Empty(::aColumns[n]:Footing)
|
|
::lFooters := .T.
|
|
exit
|
|
endif
|
|
next
|
|
|
|
::nHeaderHeight := 1
|
|
::nFooterHeight := 1
|
|
|
|
// Find out highest header and footer
|
|
for n := 1 to ::nColumns
|
|
|
|
if ::lHeaders .AND. !Empty(::aColumns[n]:Heading)
|
|
nHeight := Len(::aColumns[n]:Heading) - Len(StrTran(::aColumns[n]:Heading, ";")) + 1
|
|
|
|
if nHeight > ::nHeaderHeight
|
|
::nHeaderHeight := nHeight
|
|
endif
|
|
|
|
endif
|
|
|
|
if ::lFooters .AND. !Empty(::aColumns[n]:Footing)
|
|
nHeight := Len(::aColumns[n]:Footing) - Len(StrTran(::aColumns[n]:Footing, ";")) + 1
|
|
|
|
if nHeight > ::nFooterHeight
|
|
::nFooterHeight := nHeight
|
|
endif
|
|
|
|
endif
|
|
next
|
|
|
|
|
|
// 20/nov/2000 - maurilio.longo@libero.it
|
|
// If I add (or remove) header or footer (separator) I have to change number
|
|
// of available rows
|
|
::RowCount := ::nBottom - ::nTop + 1 - iif( ::lHeaders, ::nHeaderHeight, 0 ) - ;
|
|
iif( ::lFooters, ::nFooterHeight, 0 ) - iif( Empty( ::HeadSep ), 0, 1 ) - ;
|
|
iif( Empty( ::FootSep ), 0, 1 )
|
|
|
|
if Len(::aRedraw) <> ::RowCount
|
|
::aRedraw := Array(::RowCount)
|
|
endif
|
|
|
|
::Invalidate()
|
|
|
|
// Force re-evaluation of space occupied by frozen columns
|
|
if ::freeze > 0
|
|
::SetFrozenCols(::freeze)
|
|
endif
|
|
#ifdef HB_COMPAT_C53
|
|
nleft:=::nLeft
|
|
nRight:=::nRight
|
|
::rect:={::ntop+::nHeaderHeight,::nleft,::nbottom-::nHeaderHeight,::nright}
|
|
for n:= nleft to nright
|
|
aadd(::aVisibleCols,n)
|
|
next
|
|
#endif
|
|
return Self
|
|
|
|
|
|
// Adds a TBColumn object to the TBrowse object
|
|
METHOD AddColumn( oCol ) CLASS TBrowse
|
|
|
|
AAdd( ::aColumns, oCol )
|
|
AAdd( ::aColsWidth, ::SetColumnWidth(oCol))
|
|
::nColumns++
|
|
::Configure( 2 )
|
|
|
|
return Self
|
|
|
|
|
|
// Insert a column object in a browse
|
|
METHOD InsColumn( nPos, oCol )
|
|
|
|
ASize( ::aColumns, ++::nColumns)
|
|
AIns( ::aColumns, nPos )
|
|
ASize( ::aColsWidth, ::nColumns)
|
|
AIns( ::aColsWidth, nPos )
|
|
|
|
::aColumns[ nPos ] := oCol
|
|
::aColsWidth[ nPos ] := ::SetColumnWidth(oCol)
|
|
::Configure( 2 )
|
|
|
|
return oCol
|
|
|
|
|
|
// Gets a specific TBColumn object
|
|
METHOD GetColumn( nColumn )
|
|
|
|
return iif( 0 < nColumn .AND. nColumn <= ::nColumns, ::aColumns[ nColumn ], NIL )
|
|
|
|
|
|
// Replaces one TBColumn object with another
|
|
METHOD SetColumn( nColumn, oCol )
|
|
|
|
LOCAL oOldCol
|
|
|
|
if 0 < nColumn .AND. nColumn <= ::nColumns
|
|
oOldCol := ::aColumns[ nColumn ]
|
|
::aColumns[ nColumn ] := oCol
|
|
::aColsWidth[nColumn] := ::SetColumnWidth(oCol)
|
|
::Configure( 2 )
|
|
endif
|
|
|
|
return oOldCol
|
|
|
|
|
|
// Returns the display width of a particular column
|
|
METHOD ColWidth( nColumn )
|
|
|
|
return iif( 0 < nColumn .AND. nColumn <= ::nColumns, ::aColsWidth[ nColumn ], NIL )
|
|
|
|
|
|
METHOD DelColumn( nPos ) CLASS TBrowse
|
|
|
|
local oCol := ::aColumns[ nPos ]
|
|
local n
|
|
|
|
ADel( ::aColumns, nPos )
|
|
ADel( ::aColsWidth, nPos)
|
|
ASize( ::aColumns, --::nColumns)
|
|
ASize( ::aColsWidth, ::nColumns)
|
|
|
|
::Configure( 2 )
|
|
|
|
return oCol
|
|
|
|
|
|
METHOD SetFrozenCols(nHowMany) CLASS TBrowse
|
|
|
|
LOCAL nCol
|
|
LOCAL nWidth := ::nRight - ::nLeft + 1 // Visible width of the browse
|
|
|
|
::nFrozenCols := nHowMany
|
|
// Space inside TBrowse window reserved for frozen columns
|
|
::nFrozenWidth := 0
|
|
|
|
// If I've never displayed this TBrowse before I cannot calc occupied space since
|
|
// columns:width is not yet set, ::Stabilize() will call me later
|
|
if ! ::lNeverDisplayed
|
|
|
|
if nHowMany > 0
|
|
for nCol := 1 TO nHowMany
|
|
::nFrozenWidth += ::aColsWidth[ nCol ]
|
|
if nCol < ::nColumns
|
|
::nFrozenWidth += iif( ::aColumns[ nCol + 1 ]:ColSep != NIL,;
|
|
Len( ::aColumns[ nCol + 1 ]:ColSep ),;
|
|
Len( ::ColSep ) )
|
|
endif
|
|
next
|
|
endif
|
|
|
|
for nCol := 1 to ::nColumns
|
|
if nHowMany > 0
|
|
// If there are columns which are larger than TBrowse display width minus
|
|
// frozen columns reserved space, shrihnk them to fit
|
|
if ::nFrozenWidth + ::aColsWidth[ nCol ] > nWidth
|
|
::aColsWidth[ nCol ] := nWidth - ::nFrozenWidth
|
|
endif
|
|
|
|
else
|
|
// Reset column widths
|
|
::aColsWidth[ nCol ] := ::SetColumnWidth(::aColumns[ nCol ])
|
|
endif
|
|
next
|
|
endif
|
|
|
|
return nHowMany
|
|
|
|
|
|
METHOD SetColumnWidth( oCol ) CLASS TBrowse
|
|
|
|
LOCAL xRes, cType, nTokenPos := 0, nL, cHeading
|
|
LOCAL nWidthMax := ::nRight - ::nLeft +1 // Visible width of TBrowse
|
|
LOCAL nWidth := 0,nColWidth:=0,nLen:=0
|
|
|
|
|
|
// if oCol has :Width property set I use it
|
|
if oCol:Width <> nil //.AND. oCol:Width < (nWidthMax - 4)
|
|
nWidth := oCol:Width
|
|
|
|
else
|
|
if ISBLOCK( oCol:block )
|
|
|
|
cType := Valtype(xRes := Eval( oCol:block ) )
|
|
|
|
do case
|
|
case cType == "N"
|
|
nLen := Len( Str( xRes ) )
|
|
|
|
case cType == "L"
|
|
nLen:=1
|
|
|
|
case cType == "C"
|
|
nLen := Len( xRes )
|
|
|
|
case cType == "D"
|
|
nLen= len(DToC( xRes ) )
|
|
|
|
otherwise
|
|
nLen := 0
|
|
endcase
|
|
|
|
|
|
cHeading := oCol:Heading + ";"
|
|
while (nL := Len(__StrTkPtr(@cHeading, @nTokenPos, ";"))) > 0
|
|
nColWidth += nL
|
|
enddo
|
|
endif
|
|
|
|
if nColWidth>nWidthMax
|
|
nColWidth:=nWidthMax
|
|
endif
|
|
if nlen>nWidthMax
|
|
nLen:=nWidthMax
|
|
endif
|
|
nWidth:= if(nColwidth>nLen,nColwidth,nLen)
|
|
endif
|
|
return nWidth
|
|
|
|
|
|
METHOD Down() CLASS TBrowse
|
|
|
|
::Moved()
|
|
::nRecsToSkip := 1
|
|
|
|
return Self
|
|
|
|
|
|
METHOD Up() CLASS TBrowse
|
|
|
|
::Moved()
|
|
::nRecsToSkip := -1
|
|
|
|
return Self
|
|
|
|
|
|
METHOD End() CLASS TBrowse
|
|
|
|
::Moved()
|
|
|
|
if ::ColPos < ::rightVisible
|
|
::ColPos := ::rightVisible
|
|
::lRedrawFrame := .T.
|
|
::RefreshCurrent()
|
|
endif
|
|
|
|
return Self
|
|
|
|
|
|
METHOD GoBottom() CLASS TBrowse
|
|
|
|
local nToTop
|
|
|
|
|
|
::Moved()
|
|
|
|
Eval(::goBottomBlock)
|
|
// Skip back from last record as many records as TBrowse can hold
|
|
nToTop := Abs(Eval(::SkipBlock, -(::RowCount - 1)))
|
|
// From top of TBrowse new row position is nToTop + 1 records away
|
|
::nNewRowPos := nToTop + 1
|
|
// Last read record is first record inside TBrowse
|
|
::nLastRetrieved := 1
|
|
::RefreshAll()
|
|
|
|
return Self
|
|
|
|
|
|
METHOD GoTop() CLASS TBrowse
|
|
|
|
::Moved()
|
|
|
|
Eval(::goTopBlock)
|
|
::nLastRetrieved := 1
|
|
::nNewRowPos := 1
|
|
::RefreshAll()
|
|
|
|
return Self
|
|
|
|
|
|
METHOD Home() CLASS TBrowse
|
|
|
|
::Moved()
|
|
|
|
if ::ColPos != ::leftVisible
|
|
::ColPos := ::leftVisible
|
|
::lRedrawFrame := .T.
|
|
::RefreshCurrent()
|
|
endif
|
|
|
|
return Self
|
|
|
|
|
|
METHOD _Right() CLASS TBrowse
|
|
|
|
::Moved()
|
|
|
|
if ::ColPos < ::rightVisible
|
|
::ColPos++
|
|
else
|
|
if ::ColPos < ::nColumns
|
|
::rightVisible++
|
|
::leftVisible := ::LeftDetermine()
|
|
::ColPos++
|
|
::lRedrawFrame := .T.
|
|
::RefreshAll()
|
|
endif
|
|
endif
|
|
|
|
return Self
|
|
|
|
|
|
METHOD _Left() CLASS TBrowse
|
|
|
|
local leftVis := ::leftVisible
|
|
|
|
::Moved()
|
|
|
|
if ::ColPos > ::leftVisible
|
|
::ColPos--
|
|
else
|
|
if ::ColPos <= Max(::leftVisible, ::nFrozenCols) .AND. ::ColPos > 1
|
|
while leftVis == ::leftVisible
|
|
::rightVisible--
|
|
::leftVisible := ::LeftDetermine()
|
|
end
|
|
::ColPos--
|
|
::lRedrawFrame := .T.
|
|
::RefreshAll()
|
|
endif
|
|
endif
|
|
|
|
return Self
|
|
|
|
|
|
METHOD LeftDetermine() CLASS TBrowse
|
|
|
|
local nWidthMax := ::nRight - ::nLeft + 1 // Visible width of the browse
|
|
local nWidth := ::nFrozenWidth
|
|
local nCol
|
|
|
|
nCol := ::rightVisible
|
|
while nWidth < nWidthMax .and. nCol > ::nFrozenCols
|
|
|
|
nWidth += ::aColsWidth[ nCol ] +;
|
|
iif( ::aColumns[ nCol ]:ColSep != NIL,;
|
|
Len( ::aColumns[ nCol ]:ColSep ),;
|
|
Len( ::ColSep ) )
|
|
|
|
if nWidth < nWidthMax
|
|
nCol--
|
|
endif
|
|
enddo
|
|
|
|
return Min(nCol + 1, ::nColumns)
|
|
|
|
|
|
METHOD PageDown() CLASS TBrowse
|
|
|
|
::Moved()
|
|
|
|
::nRecsToSkip := (::RowCount - ::RowPos) + ::RowCount
|
|
|
|
return Self
|
|
|
|
|
|
METHOD PageUp() CLASS TBrowse
|
|
|
|
::Moved()
|
|
|
|
::nRecsToSkip := - ((::RowPos - 1) + ::RowCount)
|
|
|
|
return Self
|
|
|
|
|
|
METHOD PanEnd() CLASS TBrowse
|
|
|
|
::Moved()
|
|
|
|
if ::ColPos < ::nColumns
|
|
if ::rightVisible < ::nColumns
|
|
::rightVisible := ::nColumns
|
|
::leftVisible := ::LeftDetermine()
|
|
::ColPos := ::rightVisible
|
|
::lRedrawFrame := .T.
|
|
::RefreshAll()
|
|
else
|
|
::ColPos := ::rightVisible
|
|
::RefreshCurrent()
|
|
endif
|
|
endif
|
|
|
|
return Self
|
|
|
|
|
|
METHOD PanHome() CLASS TBrowse
|
|
|
|
::Moved()
|
|
|
|
if ::ColPos > 1
|
|
if ::leftVisible > ::nFrozenCols + 1
|
|
::leftVisible := ::nFrozenCols + 1
|
|
::ColPos := 1
|
|
::RefreshAll()
|
|
::lRedrawFrame := .T.
|
|
else
|
|
::ColPos := 1
|
|
::RefreshCurrent()
|
|
endif
|
|
endif
|
|
|
|
return Self
|
|
|
|
|
|
METHOD PanLeft() CLASS TBrowse
|
|
|
|
local n := ::ColPos - ::leftVisible
|
|
local leftVis := ::leftVisible
|
|
|
|
::Moved()
|
|
|
|
if ::leftVisible > ::nFrozenCols + 1
|
|
while leftVis == ::leftVisible
|
|
::rightVisible--
|
|
::leftVisible := ::LeftDetermine()
|
|
end
|
|
::ColPos := Min( ::leftVisible + n, ::rightVisible )
|
|
::lRedrawFrame := .T.
|
|
::RefreshAll()
|
|
endif
|
|
|
|
return Self
|
|
|
|
|
|
METHOD PanRight() CLASS TBrowse
|
|
|
|
local n := ::ColPos - ::leftVisible
|
|
|
|
::Moved()
|
|
|
|
if ::rightVisible < ::nColumns
|
|
::rightVisible++
|
|
::leftVisible := ::LeftDetermine()
|
|
::ColPos := Min( ::leftVisible + n, ::rightVisible )
|
|
::lRedrawFrame := .T.
|
|
::RefreshAll()
|
|
endif
|
|
|
|
return Self
|
|
|
|
|
|
METHOD DeHilite() CLASS TBrowse
|
|
|
|
local nRow := ::nTop + ::RowPos + iif(::lHeaders, ::nHeaderHeight, 0 ) + iif(Empty(::HeadSep), 0, 1) - 1
|
|
local cType
|
|
|
|
SetPos( nRow, ::aColumns[ ::ColPos ]:ColPos )
|
|
|
|
cType := ::DispCell(::ColPos, CLR_STANDARD)
|
|
|
|
SetPos(nRow, ::aColumns[ ::ColPos ]:ColPos + iif(cType == "L", ::aColsWidth[::ColPos] / 2, 0 ))
|
|
|
|
return Self
|
|
|
|
|
|
METHOD ForceStable() CLASS TBrowse
|
|
|
|
while !::Stabilize()
|
|
end
|
|
|
|
return Self
|
|
|
|
|
|
METHOD Hilite() CLASS TBrowse
|
|
|
|
local nRow, nCol
|
|
local cType
|
|
|
|
nRow := ::nTop + ::RowPos + iif(::lHeaders, ::nHeaderHeight, 0) + iif(Empty(::HeadSep), 0, 1) - 1
|
|
nCol := ::aColumns[ ::ColPos ]:ColPos
|
|
|
|
// Start of cell
|
|
SetPos( nRow, nCol)
|
|
|
|
cType := ::DispCell(::ColPos, CLR_ENHANCED)
|
|
nCol += iif(cType == "L", ::aColsWidth[::ColPos] / 2, 0 )
|
|
|
|
// Put cursor back on first char of cell value
|
|
SetPos(nRow, nCol)
|
|
|
|
#ifdef HB_COMPAT_C53
|
|
::nRow := nRow
|
|
::nCol := nCol
|
|
#endif
|
|
|
|
return Self
|
|
|
|
|
|
METHOD PosCursor() CLASS TBrowse
|
|
|
|
local nRow := ::nTop + ::RowPos + iif(::lHeaders, ::nHeaderHeight, 0) + iif(Empty(::HeadSep), 0, 1) - 1
|
|
local nCol
|
|
local cType := ValType( Eval( ::aColumns[ ::ColPos ]:block ) )
|
|
|
|
nCol := ::aColumns[ ::ColPos ]:ColPos + iif(cType == "L", ::aColsWidth[::ColPos] / 2, 0 )
|
|
|
|
// Put cursor on first char of cell value
|
|
SetPos(nRow, nCol)
|
|
|
|
#ifdef HB_COMPAT_C53
|
|
::nRow := nRow
|
|
::nCol := nCol
|
|
#endif
|
|
|
|
return Self
|
|
|
|
|
|
// Calculate how many columns fit on the browse width including ColSeps
|
|
METHOD HowManyCol(nWidth) CLASS TBrowse
|
|
|
|
local nToAdd
|
|
|
|
// They were locals, so now I need to clear them (should fix this)
|
|
::nColsWidth := 0
|
|
::nColsVisible := 0
|
|
|
|
if ::nFrozenCols > 0
|
|
if ::leftVisible <= ::nFrozenCols
|
|
::leftVisible := ::nFrozenCols + 1
|
|
endif
|
|
|
|
::nColsVisible := 0
|
|
while ::nColsVisible < ::nFrozenCols
|
|
|
|
nToAdd := ::aColsWidth[ ::nColsVisible + 1 ]
|
|
|
|
if ::nColsVisible >= 1 .and. ::nColsVisible < ::nColumns
|
|
nToAdd += iif( ::aColumns[ ::nColsVisible + 1 ]:ColSep != NIL,;
|
|
Len( ::aColumns[ ::nColsVisible + 1 ]:ColSep ),;
|
|
Len( ::ColSep ) )
|
|
endif
|
|
|
|
if ::nColsWidth + nToAdd > nWidth
|
|
exit
|
|
endif
|
|
|
|
::nColsWidth += nToAdd
|
|
::nColsVisible++
|
|
enddo
|
|
|
|
|
|
if ::nColsWidth > nWidth
|
|
/* NOTE: Why do I change frozen columns here? */
|
|
::Freeze := 0
|
|
::nColsWidth := 0
|
|
endif
|
|
endif
|
|
|
|
::nColsVisible := ::leftVisible - 1
|
|
|
|
while ::nColsVisible < ::nColumns
|
|
|
|
nToAdd := ::aColsWidth[ ::nColsVisible + 1 ]
|
|
|
|
if ::nColsVisible >= ::leftVisible .or. ::nFrozenCols > 0
|
|
nToAdd += iif( ::aColumns[ ::nColsVisible + 1 ]:ColSep != NIL,;
|
|
Len( ::aColumns[ ::nColsVisible + 1 ]:ColSep ),;
|
|
Len( ::ColSep ) )
|
|
endif
|
|
|
|
if ::nColsWidth + nToAdd > nWidth
|
|
exit
|
|
endif
|
|
|
|
::nColsWidth += nToAdd
|
|
::nColsVisible++
|
|
enddo
|
|
|
|
::rightVisible := ::nColsVisible
|
|
|
|
return Self
|
|
|
|
|
|
// Gets TBrowse width and width of displayed columns plus colsep
|
|
METHOD RedrawHeaders(nWidth) CLASS TBrowse
|
|
|
|
local n, nTPos, nBPos
|
|
local cBlankBox := Space(9)
|
|
local nScreenRowT, nScreenRowB
|
|
local nLCS // Len(ColSep)
|
|
|
|
if ::lHeaders // Drawing headers
|
|
|
|
// Clear area of screen occupied by headers
|
|
DispBox(::nTop, ::nLeft, ::nTop + ::nHeaderHeight - 1, ::nRight, cBlankBox, ::ColorSpec)
|
|
|
|
// Set cursor at first field start of description
|
|
DevPos(::nTop, ::nLeft + (( nWidth - ::nColsWidth ) / 2))
|
|
|
|
for n := iif(::nFrozenCols > 0, 1, ::leftVisible) to ::rightVisible
|
|
if ::nFrozenCols > 0 .and. n == ::nFrozenCols + 1
|
|
n := ::leftVisible
|
|
endif
|
|
|
|
::WriteMLineText(::aColumns[ n ]:Heading, ::aColsWidth[ n ], .T., ::ColorSpec)
|
|
|
|
if n < ::rightVisible
|
|
// Set cursor at start of next field description
|
|
DevPos(Row(), Col() + iif(::aColumns[n + 1]:ColSep != NIL, Len(::aColumns[n + 1]:ColSep), Len(::ColSep)))
|
|
|
|
endif
|
|
next
|
|
endif
|
|
|
|
if ! Empty( ::HeadSep ) //Draw horizontal heading separator line
|
|
DispOutAt((nScreenRowT := ::nTop + iif(::lHeaders, ::nHeaderHeight , 0 )), ::nLeft,;
|
|
Replicate( Right( ::HeadSep, 1 ), nWidth), ::ColorSpec)
|
|
endif
|
|
|
|
if ! Empty( ::FootSep ) //Draw horizontal footing separator line
|
|
DispOutAt((nScreenRowB := ::nBottom - iif(::lFooters, ::nFooterHeight, 0)), ::nLeft,;
|
|
Replicate(Right(::FootSep, 1), nWidth), ::ColorSpec)
|
|
endif
|
|
|
|
nTPos := nBPos := ::nLeft + (( nWidth - ::nColsWidth ) / 2 )
|
|
|
|
// Draw headin/footing column separator
|
|
for n := iif(::nFrozenCols > 0, 1, ::leftVisible) to ::rightVisible
|
|
if ::nFrozenCols > 0 .and. n == ::nFrozenCols + 1
|
|
n := ::leftVisible
|
|
endif
|
|
|
|
if n < ::rightVisible
|
|
nLCS := iif(::aColumns[n + 1]:ColSep != NIL, Len(::aColumns[n + 1]:ColSep), Len(::ColSep))
|
|
|
|
if ! Empty( ::HeadSep )
|
|
DispOutAT(nScreenRowT, (nTPos += ::aColsWidth[ n ]), ::HeadSep, ::ColorSpec )
|
|
nTPos += Len(::HeadSep) + (nLCS - Len(::HeadSep))
|
|
endif
|
|
|
|
if ! Empty( ::FootSep )
|
|
DispOutAT(nScreenRowB, (nBPos += ::aColsWidth[ n ]), ::FootSep, ::ColorSpec )
|
|
nBPos += Len(::FootSep) + (nLCS - Len(::FootSep))
|
|
endif
|
|
|
|
endif
|
|
next
|
|
|
|
if ::lFooters // Drawing footers
|
|
|
|
// Clear area of screen occupied by footers
|
|
DispBox(::nBottom - ::nFooterHeight + 1, ::nLeft, ::nBottom, ::nRight, cBlankBox, ::ColorSpec)
|
|
|
|
// Set cursor at first field start of description
|
|
DevPos(::nBottom, ::nLeft + (( nWidth - ::nColsWidth ) / 2))
|
|
|
|
for n := iif( ::nFrozenCols > 0, 1, ::leftVisible ) to ::rightVisible
|
|
if ::nFrozenCols > 0 .and. n == ::nFrozenCols + 1
|
|
n := ::leftVisible
|
|
endif
|
|
|
|
::WriteMLineText(::aColumns[ n ]:Footing, ::aColsWidth[ n ], .F., ::ColorSpec)
|
|
|
|
if n < ::rightVisible
|
|
// Set cursor at start of next field description
|
|
DevPos(Row(), Col() + iif(::aColumns[n + 1]:ColSep != NIL, Len(::aColumns[n + 1]:ColSep), Len(::ColSep)))
|
|
|
|
endif
|
|
next
|
|
endif
|
|
|
|
return Self
|
|
|
|
|
|
METHOD Stabilize() CLASS TBrowse
|
|
|
|
local nRow, n
|
|
local nWidth := ::nRight - ::nLeft + 1 // Visible width of the browse
|
|
local cColColor // Column color to use
|
|
local oStartCol, oEndCol
|
|
local lDisplay // Is there something to show inside current cell?
|
|
local nRecsSkipped // How many records do I really skipped?
|
|
local nFirstRow // Where is on screen first row of TBrowse?
|
|
local nOldCursor // Current shape of cursor (which I remove before stabilization)
|
|
|
|
|
|
// I need to set columns width If TBrowse was never displayed before
|
|
if ::lNeverDisplayed
|
|
//AEVal(::aColumns, {|oCol| ::SetColumnWidth(oCol)} )
|
|
|
|
// NOTE: It must be before call to ::SetFrozenCols() since this call
|
|
// tests this iVar value, and I set it to .F. since I'm going to display TBrowse
|
|
// for first time
|
|
::lNeverDisplayed := .F.
|
|
|
|
// Force re-evaluation of frozen space since I could not calc it before
|
|
// being columns width not set
|
|
if ::freeze > 0
|
|
::SetFrozenCols(::freeze)
|
|
endif
|
|
endif
|
|
|
|
nOldCursor := SetCursor(SC_NONE)
|
|
|
|
if ::lRedrawFrame
|
|
// How may columns fit on TBrowse width?
|
|
::HowManyCol(nWidth)
|
|
::RedrawHeaders(nWidth)
|
|
|
|
// Now that browser frame has been redrawn we don't need to redraw it unless
|
|
// displayed columns change
|
|
::lRedrawFrame := .F.
|
|
|
|
else
|
|
oStartCol := ::aColumns[ iif( ::rightVisible != 0, ::rightVisible, 1 ) ]
|
|
oEndCol := ::aColumns[ iif( ::nFrozenCols > 0, 1, ::leftVisible ) ]
|
|
::nColsWidth := iif( oStartCol != NIL, oStartCol:ColPos, 0 ) + ;
|
|
iif( oStartCol != NIL, ::aColsWidth[ iif( ::rightVisible != 0, ::rightVisible, 1 ) ], 0 ) - oEndCol:ColPos
|
|
|
|
endif
|
|
|
|
// From this point there is stabilization of rows which is made up of three phases
|
|
// 1st repositioning of data source
|
|
// 2nd redrawing of rows, after each row we exit stabilization loop with .F.
|
|
// 3rd if all rows have been redrawn we set ::stable state to .T.
|
|
if !::stable
|
|
|
|
// NOTE: I can enter here because of a movement key or a ::RefreshAll():ForceStable() call
|
|
|
|
// If I have a requested movement still to handle
|
|
if ::nRecsToSkip <> 0
|
|
|
|
// If I'm not under cursor (maybe I've interrupted an ongoing stabilization) I have to set data source to cursor position
|
|
if ::nLastRetrieved <> ::nNewRowPos
|
|
Eval(::SkipBlock, ::nNewRowPos - ::nLastRetrieved)
|
|
::nLastRetrieved := ::nNewRowPos
|
|
endif
|
|
|
|
nRecsSkipped := Eval(::SkipBlock, ::nRecsToSkip)
|
|
|
|
// I've tried to move past top or bottom margin
|
|
if nRecsSkipped == 0
|
|
|
|
if ::nRecsToSkip > 0
|
|
::lHitBottom := .T.
|
|
|
|
elseif ::nRecsToSkip < 0
|
|
::lHitTop := .T.
|
|
|
|
// else ::nRecsToSkip == 0
|
|
//
|
|
endif
|
|
|
|
elseif nRecsSkipped == ::nRecsToSkip
|
|
|
|
// If after movement I'm still inside present TBrowse
|
|
if (::nNewRowPos + nRecsSkipped >= 1) .AND. (::nNewRowPos + nRecsSkipped <= ::RowCount)
|
|
::nNewRowPos += nRecsSkipped
|
|
::nLastRetrieved := ::nNewRowPos
|
|
// This is needed since present TBrowse has no cache, so I need to repaint current row
|
|
// rereading it from data source and to force rereading from data source I have to mark
|
|
// row as invalid
|
|
::aRedraw[::nNewRowPos] := .T.
|
|
|
|
else
|
|
// It was K_PGDN or K_PGUP
|
|
if Abs(nRecsSkipped) >= ::RowCount
|
|
|
|
// K_PGDN
|
|
if nRecsSkipped > 0
|
|
::nLastRetrieved := ::RowCount
|
|
|
|
else // K_PGUP
|
|
::nLastRetrieved := 1
|
|
|
|
endif
|
|
::RefreshAll()
|
|
|
|
else // K_DN or K_UP
|
|
|
|
// Where does really start first TBrowse row?
|
|
nFirstRow := ::nTop + iif( ::lHeaders, ::nHeaderHeight, 0 ) + iif( Empty( ::HeadSep ), 0, 1 )
|
|
|
|
// I'm at top or bottom of TBrowse so I can scroll
|
|
if ::nNewRowPos == ::RowCount
|
|
Scroll(nFirstRow + nRecsSkipped - 1, ::nLeft, nFirstRow + ::RowCount - 1, ::nRight, nRecsSkipped)
|
|
::nLastRetrieved := ::RowCount
|
|
|
|
else
|
|
Scroll(nFirstRow, ::nLeft, nFirstRow + ::RowCount + nRecsSkipped, ::nRight, nRecsSkipped)
|
|
::nLastRetrieved := 1
|
|
|
|
endif
|
|
|
|
// I've scrolled on screen rows, now I need to scroll ::aRedraw array as well!
|
|
if nRecsSkipped > 0
|
|
/*for nRow := 2 to Len(::aRedraw)
|
|
::aRedraw[nRow - 1] := ::aRedraw[nRow]
|
|
next*/
|
|
ACopy(::aRedraw, ::aRedraw, 2,, 1)
|
|
else
|
|
// Cannot use ACopy() here
|
|
for nRow := ::RowCount - 1 to 1 step -1
|
|
::aRedraw[nRow + 1] := ::aRedraw[nRow]
|
|
next
|
|
endif
|
|
|
|
::aRedraw[::nNewRowPos] := .T.
|
|
endif
|
|
endif
|
|
|
|
else // I couldn't move as far as requested
|
|
|
|
// I need to refresh all rows if I go past current top or bottom row
|
|
if (::nNewRowPos + nRecsSkipped < 1) .OR. (::nNewRowPos + nRecsSkipped > ::RowCount)
|
|
// don't go past boundaries
|
|
::nNewRowPos := iif(nRecsSkipped > 0, ::RowCount, 1)
|
|
::RefreshAll()
|
|
|
|
else
|
|
::nNewRowPos += nRecsSkipped
|
|
::aRedraw[::nNewRowPos] := .T.
|
|
|
|
endif
|
|
|
|
::nLastRetrieved := ::nNewRowPos
|
|
|
|
endif
|
|
|
|
// Data source moved, so next time I won't enter this stage of stabilization
|
|
::nRecsToSkip := 0
|
|
|
|
// Exit first stage of stabilization
|
|
SetCursor(nOldCursor)
|
|
return .F.
|
|
|
|
endif
|
|
|
|
// Data source is alredy at correct record number, now we need
|
|
// to repaint browser accordingly.
|
|
for nRow := 1 to ::RowCount
|
|
|
|
// if there is a row to repaint
|
|
if ::aRedraw[nRow]
|
|
|
|
DispOutAt(::nTop + nRow + iif(::lHeaders, ::nHeaderHeight, 0) + iif(Empty(::HeadSep), 0, 1) - 1, ::nLeft,;
|
|
Space( ( nWidth - ::nColsWidth ) / 2 ), ::ColorSpec )
|
|
|
|
for n := iif( ::nFrozenCols > 0, 1, ::leftVisible ) to ::rightVisible
|
|
|
|
if ::nFrozenCols > 0 .and. n == ::nFrozenCols + 1
|
|
n := ::leftVisible
|
|
endif
|
|
|
|
if nRow == 1
|
|
::aColumns[ n ]:ColPos := Col()
|
|
endif
|
|
|
|
// NOTE: If my TBrowse has 20 rows but I have only 3 recs, clipper clears
|
|
// remaining 17 rows in a single operation, I will, instead, try to skip
|
|
// 17 times. Should be made more clever.
|
|
if nRow <> ::nLastRetrieved
|
|
if lDisplay := Eval(::SkipBlock, nRow - ::nLastRetrieved) == (nRow - ::nLastRetrieved)
|
|
::nLastRetrieved := nRow
|
|
endif
|
|
else
|
|
lDisplay := .T.
|
|
endif
|
|
|
|
if lDisplay
|
|
::DispCell(n, CLR_STANDARD)
|
|
|
|
else
|
|
// Clear cell
|
|
DispOut( Space( ::aColsWidth[ n ] ), ::ColorSpec )
|
|
|
|
endif
|
|
|
|
if n < ::rightVisible
|
|
if ::aColumns[ n + 1 ]:ColSep != NIL
|
|
DispOut( ::aColumns[ n + 1 ]:ColSep, ::ColorSpec )
|
|
|
|
elseif ::ColSep != NIL
|
|
DispOut( ::ColSep, ::ColorSpec )
|
|
|
|
endif
|
|
endif
|
|
next
|
|
|
|
DispOut(Space(Int(Round((nWidth - ::nColsWidth) / 2, 0))), ::ColorSpec)
|
|
|
|
// doesn't need to be redrawn
|
|
::aRedraw[nRow] := .F.
|
|
|
|
// Exit incremental row stabilization
|
|
SetCursor(nOldCursor)
|
|
return .F.
|
|
endif
|
|
|
|
next
|
|
|
|
// If I reach this point I've repainted all rows so I can set ::stable state
|
|
if nRow > ::RowCount
|
|
|
|
// If I have fewer records than available TBrowse rows, cursor cannot be lower than
|
|
// last record (note ::lHitBottom is set only during a movement)
|
|
if ::nLastRetrieved < ::nNewRowPos
|
|
::nNewRowPos := ::nLastRetrieved
|
|
endif
|
|
|
|
// If I'm not already under cursor I have to set data source to cursor position
|
|
if ::nLastRetrieved <> ::nNewRowPos
|
|
Eval(::SkipBlock, ::nNewRowPos - ::nLastRetrieved)
|
|
::nLastRetrieved := ::nNewRowPos
|
|
endif
|
|
|
|
// new cursor position
|
|
::RowPos := ::nNewRowPos
|
|
|
|
::HitTop := ::lHitTop
|
|
::HitBottom := ::lHitBottom
|
|
|
|
if ::AutoLite
|
|
::Hilite()
|
|
else
|
|
::PosCursor()
|
|
endif
|
|
SetCursor(nOldCursor)
|
|
::stable := .T.
|
|
|
|
return .T.
|
|
endif
|
|
|
|
else
|
|
/* NOTE: DBU relies upon current cell being reHilited() even if already stable */
|
|
if ::AutoLite
|
|
::Hilite()
|
|
else
|
|
::PosCursor()
|
|
endif
|
|
SetCursor(nOldCursor)
|
|
return .T.
|
|
|
|
endif
|
|
|
|
return .F.
|
|
|
|
|
|
// Movement keys cause TBrowse to become unstable.
|
|
METHOD Moved() CLASS TBrowse
|
|
|
|
// No need to Dehilite() current cell more than once
|
|
if ::stable
|
|
// Internal flags used to set ::HitTop/Bottom during next stabilization
|
|
::lHitTop := .F.
|
|
::lHitBottom := .F.
|
|
|
|
if ::AutoLite
|
|
::DeHilite()
|
|
else
|
|
::PosCursor()
|
|
endif
|
|
::stable := .F.
|
|
endif
|
|
|
|
return Self
|
|
|
|
|
|
METHOD ColorRect( aRect, aRectColor ) CLASS TBrowse
|
|
|
|
::aRect := aRect
|
|
::aRectColor := aRectColor
|
|
|
|
return Self
|
|
|
|
|
|
METHOD DispCell( nColumn, nColor ) CLASS TBrowse
|
|
|
|
LOCAL oCol := ::aColumns[nColumn]
|
|
LOCAL nWidth := ::aColsWidth[nColumn]
|
|
LOCAL ftmp := Eval(oCol:block)
|
|
LOCAL cType := ValType( ftmp )
|
|
LOCAL cPict := iif(Empty(oCol:Picture), "", oCol:Picture)
|
|
|
|
LOCAL tmp
|
|
|
|
// NOTE: When nColor is used as an array index we need to increment it by one since CLR_STANDARD is 0
|
|
LOCAL cColor := iif(oCol:ColorBlock != NIL,;
|
|
hb_ColorIndex(::ColorSpec, Eval(oCol:ColorBlock, ftmp)[nColor + 1] - 1),;
|
|
hb_ColorIndex(::ColorSpec, nColor))
|
|
|
|
do case
|
|
case cType $ "CM"
|
|
DispOut( PadL(Transform(ftmp, cPict), nWidth ), cColor )
|
|
|
|
case cType == "N"
|
|
DispOut( PadR(Transform(ftmp, cPict), nWidth ), cColor )
|
|
|
|
case cType == "D"
|
|
cPict := iif(cPict == "", "@D", cPict)
|
|
DispOut( PadR(Transform(ftmp, cPict), nWidth ), cColor )
|
|
|
|
case cType == "L"
|
|
tmp := PadC( "X", nWidth )
|
|
DispOut( Space( Len( tmp ) - Len( LTrim( tmp ) ) ) )
|
|
DispOut( iif(ftmp, "T", "F"), cColor )
|
|
DispOut( Space( Len( tmp ) - Len( RTrim( tmp ) ) ) )
|
|
|
|
otherwise
|
|
DispOut( Space(nWidth), cColor )
|
|
|
|
endcase
|
|
|
|
return cType
|
|
|
|
|
|
#ifdef HB_COMPAT_C53
|
|
|
|
METHOD ApplyKey(nKey) CLASS TBrowse
|
|
|
|
return ::TApplyKey(nKey, self)
|
|
|
|
|
|
METHOD InitKeys(o) CLASS TBROWSE
|
|
|
|
Default o:aKeys to {{K_DOWN,{|Ob,nKey| Ob:Down(),0}},;
|
|
{K_END,{|Ob,nKey| Ob:End(),0}},;
|
|
{K_CTRL_PGDN,{|Ob,nKey| Ob:GoBottom(),0}},;
|
|
{K_CTRL_PGUP,{|Ob,nKey| Ob:GoTop(),0}},;
|
|
{K_HOME,{|Ob,nKey| Ob:Home(),0}},;
|
|
{K_LEFT,{|Ob,nKey| Ob:Left(),0}},;
|
|
{K_PGDN,{|Ob,nKey| Ob:PageDown(),0}},;
|
|
{K_PGUP,{|Ob,nKey| Ob:PageUp(),0}},;
|
|
{K_CTRL_END,{|Ob,nKey| Ob:PanEnd(),0}},;
|
|
{K_CTRL_HOME,{|Ob,nKey| Ob:PanHome(),0}},;
|
|
{K_CTRL_LEFT,{|Ob,nKey| Ob:PanLeft(),0}},;
|
|
{K_CTRL_RIGHT,{|Ob,nKey| Ob:PanRight(),0}},;
|
|
{K_RIGHT,{|Ob,nKey| Ob:Right(),0}},;
|
|
{K_UP,{|Ob,nKey| Ob:Up(),0}},;
|
|
{K_ESC,{|Ob,nKey| -1 }},;
|
|
{K_LBUTTONDOWN,{|Ob,nKey| tbmouse(ob,mrow(),mcol())}}}
|
|
return o
|
|
|
|
|
|
METHOD SetKey(nKey,bBlock) CLASS TBrowse
|
|
|
|
local bReturn,nPos
|
|
|
|
::InitKeys(self)
|
|
|
|
if (nPos:=ascan(::aKeys,{|x| x[1]==nkey}))==0
|
|
if ( ISBLOCK( bBlock ) )
|
|
bReturn:= bBlock
|
|
aadd(::aKeys,{nKey,bBlock})
|
|
endif
|
|
bReturn:=bBlock
|
|
|
|
elseif (ISBLOCK(bBlock))
|
|
::aKeys[npos][2]:=bBlock
|
|
bReturn:=bBlock
|
|
|
|
elseif PCOUNT()==1
|
|
bReturn:= ::aKeys[npos][2]
|
|
|
|
elseif ( bReturn:= ::aKeys[ nPos ][ 2 ], PCount() == 2 .AND. ;
|
|
ISNIL( bBlock ) .AND. nKey != 0 )
|
|
adel(::aKeys, nPos)
|
|
asize(::akeys, Len(::aKeys) - 1)
|
|
endif
|
|
|
|
return bReturn
|
|
|
|
|
|
METHOD TApplyKey( nKey, oBrowse ) CLASS tBrowse
|
|
|
|
local bBlock := oBrowse:setkey(nKey), nReturn:=0
|
|
|
|
default bBlock to oBrowse:setkey(0)
|
|
|
|
if ( ISNIL( bBlock ) )
|
|
nReturn := 1
|
|
else
|
|
nReturn := eval(bBlock, oBrowse, nKey)
|
|
endif
|
|
|
|
return nReturn
|
|
#endif
|
|
|
|
|
|
// NOTE: Not tested, could be broken
|
|
METHOD MGotoYX(nRow, nCol) CLASS TBrowse
|
|
|
|
local nColsLen, nI, nNewRow
|
|
|
|
// Am I inside TBrowse display area ?
|
|
if nRow > ::nTop .AND. nRow < ::nBottom .AND. ;
|
|
nCol > ::nLeft .AND. nCol < ::nRight
|
|
|
|
// if not stable force repositioning of data source; maybe this is not first Stabilize() call after
|
|
// TBrowse became unstable, but we need to call Stabilize() al least one time before moving again to be sure
|
|
// data source is under cursor position
|
|
if ! ::stable
|
|
::Stabilize()
|
|
|
|
else
|
|
::Moved()
|
|
|
|
endif
|
|
|
|
// Set new row position
|
|
nNewRow := nRow - ::nTop + iif(::lHeaders, ::nHeaderHeight, 0) + iif(Empty(::HeadSep), 0, 1) - 1
|
|
::nRecsToSkip := nNewRow - ::nNewRowPos
|
|
|
|
// move data source accordingly
|
|
::Stabilize()
|
|
|
|
// Now move to column under nCol
|
|
nColsLen := 0
|
|
// NOTE: I don't think it is correct, have to look up docs
|
|
nI := iif(::nFrozenCols > 0, ::nFrozenCols, ::leftVisible)
|
|
|
|
while nColsLen < nCol .AND. nI < ::rightVisible
|
|
|
|
nColsLen += ::aColsWidth[nI]
|
|
if nI >= 1 .AND. nI < ::nColumns
|
|
nColsLen += iif(::aColumns[nI]:ColSep != NIL, Len(::aColumns[nI]:ColSep), Len(::ColSep))
|
|
endif
|
|
|
|
nI++
|
|
|
|
enddo
|
|
|
|
::ColPos := nI
|
|
|
|
// Force redraw of current row with new cell position
|
|
::RefreshCurrent()
|
|
|
|
endif
|
|
|
|
return Self
|
|
|
|
|
|
METHOD WriteMLineText(cStr, nPadLen, lHeader, cColor) CLASS TBrowse
|
|
|
|
local n, cS
|
|
local nCol := Col()
|
|
local nRow := Row()
|
|
|
|
// Do I have to write an header or a footer?
|
|
if lHeader
|
|
|
|
// Simple case, write header as usual
|
|
if ::nHeaderHeight == 1
|
|
DispOut(PadR(cStr, nPadLen), cColor)
|
|
|
|
else
|
|
// __StrToken needs that even last token be ended with token separator
|
|
cS := cStr + ";"
|
|
|
|
for n := ::nHeaderHeight to 1 step -1
|
|
DevPos(nRow + n - 1, nCol)
|
|
DispOut(PadR(__StrToken(@cS, n, ";"), nPadLen), cColor)
|
|
|
|
next
|
|
|
|
DevPos(nRow, nCol + nPadLen)
|
|
|
|
endif
|
|
|
|
// footer
|
|
else
|
|
|
|
// Simple case, write footer as usual
|
|
if ::nFooterHeight == 1
|
|
DispOut(PadR(cStr, nPadLen), cColor)
|
|
|
|
else
|
|
// __StrToken needs that even last token be ended with token separator
|
|
cS := cStr + ";"
|
|
|
|
for n := 0 to (::nFooterHeight - 1)
|
|
DevPos(nRow - n, nCol)
|
|
DispOut(PadR(__StrToken(@cS, ::nFooterHeight - n, ";"), nPadLen), cColor)
|
|
next
|
|
|
|
DevPos(nRow, nCol + nPadLen)
|
|
|
|
endif
|
|
|
|
endif
|
|
|
|
return Self
|
|
|
|
|
|
function TBrowseNew(nTop, nLeft, nBottom, nRight)
|
|
|
|
return TBrowse():New(nTop, nLeft, nBottom, nRight)
|
|
|
|
|
|
#ifdef HB_COMPAT_C53
|
|
function TBMOUSE( oBrowse, nMouseRow, nMouseCol )
|
|
|
|
local Local1
|
|
if ( oBrowse:hittest(nMouseRow, nMouseCol) == -5121 )
|
|
|
|
Local1 := oBrowse:mrowpos - oBrowse:rowpos
|
|
|
|
|
|
do while ( Local1 < 0 )
|
|
Local1++
|
|
oBrowse:up()
|
|
enddo
|
|
|
|
do while ( Local1 > 0 )
|
|
Local1--
|
|
oBrowse:down()
|
|
enddo
|
|
|
|
Local1 := oBrowse:mcolpos - oBrowse:colpos
|
|
|
|
do while ( Local1 < 0 )
|
|
Local1++
|
|
oBrowse:left()
|
|
enddo
|
|
|
|
do while ( Local1 > 0 )
|
|
Local1--
|
|
oBrowse:right()
|
|
enddo
|
|
|
|
return 0
|
|
endif
|
|
|
|
return 1
|
|
|
|
Method hitTest(mrow,mcol) CLASS TBROWSE
|
|
local i
|
|
::mRowPos := ::rowPos
|
|
::mColPos := ::colPos
|
|
|
|
|
|
if mRow< ::rect[1] .or. mRow > ::rect[3]
|
|
return HTNOWHERE
|
|
endif
|
|
|
|
if mCol < ::rect[2] .or. mCol > ::rect[4]
|
|
return HTNOWHERE
|
|
endif
|
|
|
|
::mRowPos := mRow - ::rect[1]+1
|
|
for i = 1 to len(::aVisibleCols)
|
|
if ::aVisibleCols[i] > mcol
|
|
exit
|
|
endif
|
|
next
|
|
|
|
::mColpos := ::aVisibleCols[i]
|
|
|
|
return HTCELL
|
|
#endif
|