General suggestions, in preparation for a text-mode array navigator
Posted: Sun Apr 25, 2021 3:00 pm
Hi,
I just started working on a project for a console Tree Navigator, but it occurred to me this morning to get suggestions from people who have done similar projects before.
The original code was written by Mathieu De Smet, in '94. It was intended to display a list of directories, similar to Dos's Tree command. There are minor modifications, since discovering this a few days ago.
I'd like to repurpose this, as a general text-mode array/tree viewer and navigator, but am open to lots of suggestions as to how to approach it.
So for example, some of the questions to consider are:
Should we throw this in a loop that restarts every time we click a refresh hot key or button?
Should we keep track of the current position as an array, or convert it to some other type? What kind of structure would you use?
Should the current position during navigation be marked with a simple GET, then change it to a SAY when an arrow key is pressed?
If we wanted to save the tree, should we save it as a simple Harbour array, or xml, or in a sqlite database or dbf table?
If we want to associate a text memo with each node, how would you approach that? CDATA in an xml file, or a memo field in a database?
I expect this to be a long term project, and am just trying to save some initial analysis time of going back & forth, trying one approach then abandoning it and trying something else.
I just started working on a project for a console Tree Navigator, but it occurred to me this morning to get suggestions from people who have done similar projects before.
The original code was written by Mathieu De Smet, in '94. It was intended to display a list of directories, similar to Dos's Tree command. There are minor modifications, since discovering this a few days ago.
I'd like to repurpose this, as a general text-mode array/tree viewer and navigator, but am open to lots of suggestions as to how to approach it.
So for example, some of the questions to consider are:
Should we throw this in a loop that restarts every time we click a refresh hot key or button?
Should we keep track of the current position as an array, or convert it to some other type? What kind of structure would you use?
Should the current position during navigation be marked with a simple GET, then change it to a SAY when an arrow key is pressed?
If we wanted to save the tree, should we save it as a simple Harbour array, or xml, or in a sqlite database or dbf table?
If we want to associate a text memo with each node, how would you approach that? CDATA in an xml file, or a memo field in a database?
I expect this to be a long term project, and am just trying to save some initial analysis time of going back & forth, trying one approach then abandoning it and trying something else.
Code: Select all
#INCLUDE "COMMON.CH"
#INCLUDE "i_pseudofunc.CH"
#INCLUDE "hbcompat.CH"
Function VTree( Par_s )
LOCAL a1
LOCAL a2
cls(23, chr(177))
SETCOLOR( "W+/B,B/W,,W+/B")
a1 := GetTree( CurDrive() + ":\" + CurDir(), { |c| Qout( c ) }, .T. )
a2 := BuildTree( a1 )
// aEVAL( a2, { |e| Qout( PADR( e[1],30 )+PADR(e[2],49) ) } )
aEVAL( a2, { |e| Qout( PADR( e[1],100 ) ) } )
RETURN
*===========================================================================*
* Original Author : Mathieu De Smet, 1994
* CIS : 100140,1375
* Date : 17 Aug 1994
* Function : GetTree
* Parameters : cDrive char drivename, will read the tree from the drive
* nil will read the tree from current drive
* bOut codeblock output block when rereading tree
* lFast logical read tree fast (only '*.' ) or slow (all '*.*')
* Output : Nested Array
* \DOS
* \WINDOWS
* \WINDOWS\SYSTEM
* \WINDOWS\GAMES
* \WINDOWS\GAMES\1
* \WINDOWS\GAMES\2
* \WINDOWS\GAMES\3
* \UTIL
* => makes array like this
* { { "DOS", { } }, ;
* { "WINDOWS", { { "SYSTEM", { } }, ;
* { "GAMES" , { { "1", { } }, ;
* { "2", { } }, ;
* { "2", { } } ;
* } ;
* }
* }
* }, ;
* { "UTIL", { } } ;
* }
* looks difficult but it isn't, use debugger to understand
*------------------------------*
FUNCTION GetTree( Dir_s, bOut, lFast )
RETURN _GetTree( Dir_s , ;
IF( VALTYPE(bOut ) == "B", bOut , { || nil } ), ;
IF( VALTYPE(lFast ) == "L", lFast , .T. ) )
*------------------------------*
STATIC FUNCTION _GetTree( Dir_s, bOut, lFast )
LOCAL aDir := DIRECTORY( Dir_s +"\*."+IF( lFast, "", "*" ), "D" )
LOCAL aTree := {}
LOCAL n
AltD()
EVAL( bOut, Dir_s )
aSORT( aDir,,, { |x,y| x[1] < y[1] } )
FOR n := 1 TO LEN( aDir )
IF "D" $ aDir[ n,5 ]
IF aDir[n,1] == "." .OR. aDir[n,1] == ".."
ELSE
aAdd( aTree, { aDir[n,1], _GetTree( Dir_s+"\"+aDir[n,1], bOut, lFast ) } )
ENDIF
ENDIF
NEXT
RETURN aTree
*===========================================================================*
*===========================================================================*
* Auther : Mathieu De Smet
* CIS : 100140,1375
* Date : 17 Aug 1994
* Function : BuildTree
* Purpose : Make a nice 'tree' from the array fro GetTree
* Parameters : aTree array the tree from GetTree
* char drivename, will read the tree from the drive
* nil will read the tree from current drive
* bOut codeblock output block when rereading tree
* lFast logical read tree fast or slow
* Output : array { { cText, cPath }, ;
* ..., ;
* { cText, cPath } }
*---------------------------------*
FUNCTION BuildTree( aTree, bOut, lFast )
LOCAL aNew := {}
IF VALTYP( aTree ) != "A"
aTree := GetTree( aTree, bOut, lFast )
ENDIF
_BuildTree( aNew, "", aTree, "" )
RETURN aNew
*--------------------------------*
STATIC PROCEDURE _BuildTree( aNew, cLead, aTree, cDir )
LOCAL c1,c2
LOCAL n
FOR n := 1 TO LEN( aTree )
IF n == LEN( aTree )
c1 := "ÀÄ "
c2 := " "
ELSE
c1 := "ÃÄ "
c2 := "³ "
ENDIF
aAdd( aNew, { cLead+c1 +aTree[n,1], cDir+"\"+aTree[n,1] } )
_BuildTree( aNew, cLead+c2, aTree[n,2], cDir+"\"+aTree[n,1] )
NEXT
RETURN
*===========================================================================*
// From Super.lib
FUNCTION cls(ncColorAtt,cFillCharacter)
local cColorString
cColorString := iif(valtype(ncColorAtt)=="N",at2char(ncColorAtt),ncColorAtt)
cFillCharacter := repl( iif(cFillCharacter#nil,cFillCharacter," "),9 )
dispbox(0,0,maxrow(),maxcol(),cFillCharacter,cColorString)
RETURN ''
Function At2char(nColor)
local aFore := {"N","B","G","BG","R","RB","GR","W",;
"N+","B+","G+","BG+","R+","RB+","GR+","W+"}
local aBack := {"N","B","G","BG","R","RB","GR","W",;
"N*","B*","G*","BG*","R*","RB*","GR*","W*"}
local nFore := nColor%16
local nBack := INT(nColor/16)
local cForeground := aFore[nFore+1]
local cBackGround := aBack[nBack+1]
return ( cForeground+'/'+cBackGround )