General suggestions, in preparation for a text-mode array navigator

General Help regarding HMG, Compilation, Linking, Samples

Moderator: Rathinagiri

HGAutomator
Posts: 188
Joined: Thu Jul 16, 2020 5:42 pm
DBs Used: DBF

General suggestions, in preparation for a text-mode array navigator

Post by HGAutomator »

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.

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 )
HGAutomator
Posts: 188
Joined: Thu Jul 16, 2020 5:42 pm
DBs Used: DBF

Re: General suggestions, in preparation for a text-mode array navigator

Post by HGAutomator »

VTree_MiniGui_Advanced_Folder.jpg
VTree_MiniGui_Advanced_Folder.jpg (243.34 KiB) Viewed 2346 times
User avatar
serge_girard
Posts: 3167
Joined: Sun Nov 25, 2012 2:44 pm
DBs Used: 1 MySQL - MariaDB
2 DBF
Location: Belgium
Contact:

Re: General suggestions, in preparation for a text-mode array navigator

Post by serge_girard »

Hi,

and how to compile?

Serge
There's nothing you can do that can't be done...
HGAutomator
Posts: 188
Joined: Thu Jul 16, 2020 5:42 pm
DBs Used: DBF

Re: General suggestions, in preparation for a text-mode array navigator

Post by HGAutomator »

I just used one of the compile.bats in the minigui\samples folders,which calls \minigui\batch\compile.bat

Edit: Sorry Serge, I think I misunderstood your question.

This is the command line I'm using, in the folder c:\minigui\myapps\VTree

Call ..\..\batch\compile.bat VTREE /C %2 %3 %4 %5 %6 %7 %8 %9

, which is calling compile.bat in the c:\minigui\batch folder.
HGAutomator
Posts: 188
Joined: Thu Jul 16, 2020 5:42 pm
DBs Used: DBF

Re: General suggestions, in preparation for a text-mode array navigator

Post by HGAutomator »

I played with the code for a few days. It's a nice visual simulation of Dos Tree, but it's not really built to be a foundation for a general text mode Tree viewer.

Thanks to anyone who looked at the code, and considered it. I'll try another approach, right now it's just trial & error.
HGAutomator
Posts: 188
Joined: Thu Jul 16, 2020 5:42 pm
DBs Used: DBF

Re: General suggestions, in preparation for a text-mode array navigator

Post by HGAutomator »

Still playing with this, but there's no structural solution or official project yet. I haven't had the chance yet to devote as much time as it deserves.

This looks much better visually, and uses various public domain snippets to achieve the effect of a navigator. Not close to the objective yet, but definitely better.


https://github.com/HBEnthusiast/Harbour ... irTree.zip


There's a related navigation utility, that I've been devoting more time to, because it's much easier to implement the interface. It's based on Super.lib's SLOTUSMENU, with some modifications. I'll share the code for this, after we work out 5-6 bugs.

serge_girard wrote: Sun Apr 25, 2021 7:55 pm Hi,

and how to compile?

Serge
Attachments
DirTree_20210711b.jpg
DirTree_20210711b.jpg (153.35 KiB) Viewed 1632 times
LotusNavigator_03.jpg
LotusNavigator_03.jpg (328.19 KiB) Viewed 1634 times
LotusNavigator_02.jpg
LotusNavigator_02.jpg (413.61 KiB) Viewed 1634 times
LotusNavigator_01.jpg
LotusNavigator_01.jpg (371.8 KiB) Viewed 1634 times
DirTree_20210711.jpg
DirTree_20210711.jpg (127.88 KiB) Viewed 1634 times
User avatar
srvet_claudio
Posts: 2193
Joined: Thu Feb 25, 2010 8:43 pm
Location: Uruguay
Contact:

Re: General suggestions, in preparation for a text-mode array navigator

Post by srvet_claudio »

Best regards.
Dr. Claudio Soto
(from Uruguay)
http://srvet.blogspot.com
HGAutomator
Posts: 188
Joined: Thu Jul 16, 2020 5:42 pm
DBs Used: DBF

Re: General suggestions, in preparation for a text-mode array navigator

Post by HGAutomator »

srvet,

Thanks, but there are lots of Windows examples floating around. I mean, Windows itself has a treeview. I want to build something in 32 or 64-bit text mode.

The Turbo C example you pointed to might be of some value, thanks for that. Unfortunately, the link that was provided in that post

https://computerspy.weebly.com/turbo-c-plus-plus.html

, is not longer available. I'll search around for it.

There are also some delphi/pascal applications around with examples of text-mode treeviews. But they are all missing important parts of the source code, and impossible to compile without these missing modules.

So the Harbour version has to be built from scratch. I'll do it eventually, but it just helps to have a tree example to step through in real-time.

At any rate, I can start building the Nodes and Tree classes, even without having the visual interface yet. There are sufficient examples for cloning.
HGAutomator
Posts: 188
Joined: Thu Jul 16, 2020 5:42 pm
DBs Used: DBF

Re: General suggestions, in preparation for a text-mode array navigator

Post by HGAutomator »

I'm no longer certain that a Tree-based navigation system is worth writing in Harbour, since there are full-featured applications already available, as other posters have indicated. Building a simple tree is certainly feasible, but adding all the frills would take years.

Here is the source code for the Lotus-style navigator. This will be updated.


LotusMenu.prg:

Code: Select all

/* Rewrite of SLOTUSMENU from Super.lib */

#include "inkey.ch"
#ifndef K_LBUTTONDOWN
#define K_LBUTTONDOWN   1002   //   mouse left key press
#define K_RBUTTONDOWN   1004   //   mouse right key press
#endif
#define K_FORWARD_SLASH 47
#define K_MOUSELEFT K_LBUTTONDOWN
#define K_MOUSERIGHT K_RBUTTONDOWN
static Current_a
static Element_n := 1
static Stack_a   := {}


/*
ÕìÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
³ FUNCTION Lotus_Menu()
* Modification of SuperLib's SLOTUSMENU()
ÆÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
³
³  Short:
³  ------
³  Lotus_Menu() 1-2-3 style menu
³
³  Returns:
³  --------
³  <expReturn> => depends on several factors
³
³  Syntax:
³  -------
³  Lotus_Menu(nTop,nLeft,nBottom,nRight,Options_a,[lBox],;
³        [lSaveRest],[lReset])
³
³  Description:
³  ------------
³  Draws a 1-2-3 style menu from <nTop>,<nLeft> to
³  <nTop+1>,<nRight>.
³
³  <nTop> is the menu option line. <nTop+1> is the
³  message line.
³
³  <Options_a> is an array of arrays in the format:
³
³  {  {cOption,Message_s,expAction},
³  {cOption,Message_s,expAction},... }
³
³  where <cOption> is the option prompt, <Message_s> is
³  the option message, and <expAction> is the option action.
³
³  <expAction> may be of three types:
³
³      1.    a codeblock, in which case it is executed on
³            ENTER
³
³      2.    a submenu array of the form:
³
³         {  {cOption,Message_s,expAction},  ;
³             {cOption,Message_s,expAction},... }
³            which is displayed on ENTER. Pressing ESCAPE
³            from the submenu returns to the prior menu.
³
³            The submenu <expaction> may be a codeblock,
³            another subarray, or any other value, etc.
³            Thus nesting can go as deep as you like.
³
³      3.    any other value, which is returned to the
³            calling program on ENTER.
³
³  Pressing ESCAPE from the main menu returns 0
³
³  [lBox]  If True, the menu is drawn inside of a popup
³  box. Actual dimensions of the menu area then become
³  <nTop>+1,<nLeft>+1 to <nTop>+2,<nRight>-1. Default is False - no box.
³
³  [lSaveRest] If True, the underlying screen is saved
³  and restored on entrance/exit. Default is False - no restore.
³
³  [lReset] If True, the menu is reset to first option
³  on exit. Default is False - menu remembers where it was.
³
³  Lotus_Clear() resets the menu.
³
³  Examples:
³  ---------
³
³   proc test
³   local nReturn := 0
³   local aMain := {}
³   local aSub1 := {{"Pizza",     "Eat Pizza", {||pizza()}},;
³                   {"Spaghetti", "Eat Spaghetti", {||spagett()}},;
³                   {"Tortellini","Eat Tortellini", {||tortellini()}} }
³
³   local aSub2 := {{"Steak",     "Eat Steak", {||steak()}},;
³                   {"Hamburger", "Eat Hamburger",  {||burgers()}},;
³                   {"Chili Dog", "Eat Chili Dog",  {||burntwice()}}  }
³
³   aadd(aMain,{"Italian","Eat Italian food",aSub1})
³   aadd(aMain,{"American","Eat American food",aSub2})
³   aadd(aMain,{"Quit","Just not hungry - Quit",0})
³   aadd(aMain,{"Relief","Already ate - need Alka Seltzer",{||alka()} })
³
³   Lotus_Menu(0,0,0,79,aMain,.t.,.t.,.t.)
³
³   Lotus_Clear()  // !! always use this to clear the menu
³
³  Notes:
³  -------
³
³  Always use Lotus_Clear() after calling SLOTUSMENU()
³
³  Source:
³  -------
³  S_LOTMEN.PRG
³
ÔíÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
*/
FUNCTION Lotus_Menu(nTop,nLeft,nbottom,nRight,Options_a,lBox,lSaveRest,lReset)
LOCAL oTb,cBox,nColumn
LOCAL nTbTop,nTbLeft,nTbBottom,nTbRight,nWidth
LOCAL expReturn := 0
LOCAL nLastkey,cLastkey,nFirstLetter
LOCAL nMouseR, nMouseC
Local Col_n := 0


lBox      := iif(lBox#nil,lBox,.f.)
lSaveRest := iif(lSaveRest#nil,lSaveRest,.f.)
lReset    := iif(lReset#nil,lReset,.f.)
if lBox
  nBottom  := nTop+3
  nTbTop   := nTop+1
  nTbLeft  := nLeft+1
  nTbRight := nRight-1
else
  nBottom  := nTop+1
  nTbTop   := nTop
  nTbLeft  := nLeft
  nTbRight := nRight
endif
if lSaveRest
  if lBox
    cBox := Makebox(nTop,nLeft,nBottom,nRight)
  else
    cBox := Savescreen(nTop,nLeft,nBottom,nRight)
  endif
ELSEIF lBox
    Makebox(nTop,nLeft,nBottom,nRight)
endif
nWidth    := nTbRight-nTbLeft+1
if len(Stack_a)=0
  Current_a  := Options_a
endif
oTb := BuildTb(nTbTop,nTbLeft,nTbTop,nTbRight,nWidth)
oTb:colpos := Element_n

while .t.
  dispbegin()
  while !oTb:stabilize()
  end
  if Current_a[oTb:colpos,2]#nil
    @nTbTop+1,nTbLeft say padr(Current_a[oTb:colpos,2],nWidth)
  else
    scroll(nTbTop+1,nTbLeft,ntbTop+1,nTbRight,0)
  endif
  dispend()

  nMouseR := 0; nMouseC := 0
  nLastKey := rat_event(0,.f.,.f.,@nMouseR,@nMouseC)

  do case

	// ENTER on a folder, will enter that folder.
	// ENTER on a filename, will exit.
  case nLastKey == K_ENTER
    if valtype(Current_a[oTb:colpos,3])=="A"
      aadd(Stack_a,{Current_a,oTb:colpos})
      Current_a := Current_a[oTb:colpos,3]
      oTb := BuildTb(nTbTop,nTbLeft,nTbTop,nTbRight,nWidth)
      oTb:colpos := 1
    elseif valtype(Current_a[oTb:colpos,3])=="B"

    	Col_n := oTb:colpos
    	expReturn := eval(Current_a[oTb:colpos,3], Col_n )
		Return expReturn

    else
      expReturn := Current_a[oTb:colpos,3]
      exit
    endif

  case nLastKey == K_FORWARD_SLASH      // Popup menu
  	Load_Program_Menu( oTb )
		expReturn := Current_a[oTb:colpos,3]
		Return expReturn



  case nLastKey == K_ESC 	// Back
    if len(Stack_a)>0
      Current_a := atail(Stack_a)[1]
      oTb := BuildTb(nTbTop,nTbLeft,nTbTop,nTbRight,nWidth)
      oTb:colpos :=  atail(Stack_a)[2]
      aSize(Stack_a,len(Stack_a)-1)
    else
      exit
    endif


  case nLastKey == K_LEFT     // allow movement (left)
     IF oTb:colpos > 1
       oTb:left()
     ELSE
       oTb:colpos  := len(Current_a)
       oTb:refreshall()
     ENDIF
  case nLastKey == K_RIGHT    // allow movement (right)
     IF oTb:colpos < len(Current_a)
       oTb:right()
     ELSE
       oTb:colpos  := 1
       oTb:refreshall()
     ENDIF
  CASE (cLastkey := upper(chr(nLastkey)))$"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
     if cLastkey == upper(left(Current_a[oTb:colpos,1],1))
       keyboard chr(13)
     elseif (nFirstLetter := ascan(Current_a,{|e|e[1]#nil.and.upper(left(e[1],1))==cLastKey },oTb:colpos+1)) > 0 ;
        .or. (nFirstLetter := ascan(Current_a,{|e|e[1]#nil.and.upper(left(e[1],1))==cLastKey },1,oTb:colpos)) > 0
       oTb:colpos  := nFirstLetter
       oTb:refreshall()
     endif
  case MBRZMOVE(oTb,nMouseR,nMouseC)
     keyboard chr(K_ENTER)
  case MBRZCLICK(oTb,nMouseR,nMouseC)
     keyboard chr(K_ENTER)
  endcase
end
Element_n := oTb:colpos
if lSaveRest
  if lBox
    unbox(cBox)
  else
    restscreen(nTop,nLeft,nBottom,nRight,cBox)
  endif
endif
if lReset
  Lotus_Clear()
endif
return expReturn

//----------------------------------------------------------------------
FUNCTION Lotus_Clear
Stack_a := {}
Element_n := 1
return nil
//-----------------------------------------------------------------
static function BuildTb(ntop,nLeft,nbottom,nRight,nWidth)
local oTb,nColumn
local ntotWidth := ttlwidth()
scroll(nTop,nLeft,nBottom,nRight,0)
if ntotWidth >= nWidth
  oTb := tbrowsenew(nTop,nLeft,nbottom,nRight)
else
  oTb := tbrowsenew(nTop,nLeft,nbottom,nLeft+nTotWidth-1)
endif
for nColumn = 1 to len(Current_a)
  oTb:addcolumn(tbColumnNew(nil,lmblock(nColumn)))
next
otb:skipblock := {|n|0}
return oTb

//-----------------------------------------------------------------
static function lmblock(i)
return {||Current_a[i,1]}


//-----------------------------------------------------------------
static function ttlwidth
local nWidth := 0
aeval(Current_a,{|e|nWidth+=len(e[1])+1})
return nWidth



// TODO
Function Load_Program_Menu( oTb )
Local Program_Menu_a := {}


Program_Menu_a := { { "File", "New Open Exit", { || Alert( "File menu" ) } }, ;
										{ "Preview", "As Text  As Binary  As OutLine", { || Alert( "Preview menu" ) } } ;
										 }

SLOTUSMENU(23,0,24,MaxCol(),Program_Menu_a,.t.,.t.,.t.)


Return Nil


DirectoryMenu.prg:

Code: Select all

#include "FILEIO.CH"
#INCLUDE "COMMON.CH"
#INCLUDE "i_pseudofunc.CH"
#INCLUDE "hbcompat.CH"

#define ISARRAY(x)    (valtype(x)=='A')
#define ISLOGIC(x)    (valtype(x)=='L')
#define ISNUMERIC(x)  (valtype(x)=='N')
#define ISCHAR(x)     (valtype(x)=='C')
#define ISDATE(x)     (valtype(x)=='D')
#define ISOBJECT(x)   (valtype(x)=='O')
#define ISNIL(x)      x=NIL
#define NTrim( n ) LTRIM( STR( n,20, IF( n == INT( n ), 0, set(_SET_DECIMALS) ) ))

 Function Directory_Menu( Current_Directory_s )

Local Directory_a := {}
Local Names_a := {}
Local Name_s := ""											// Directory names with brackets e.g. "[ProgramData]"
Local Name_without_Brackets_s := ""
Local Attr_a := {}
Local Attr_s := ""

Local Main_Menu_a := {}

Local DirectoryEntries_n := 0
Local Nth_Directory_Entry_n := 0
Local Nth_Directory_Entry_s := ""

Local Message_s												// String list of subfolders & files in the parent directory.  

Local SubDirectory_s := ""
Local SubDirectory_Path_s := ""
Local SubDirectory_Files_a := {}
Local SubDirectory_Files_n := 0
Local Nth_SubDirectory_File_n := 0
Local Nth_SubDirectory_FileNames_a := 0
Local Nth_SubDirectory_File_s := ""
Local Nth_SubDirectory_FileNames_s := ""

If Current_Directory_s == Nil
	Current_Directory_s := CurDir()
End If


Directory_a         := DIRECTORY( "*.*", "HSD" )
Names_a       := A2TOSING(Directory_a,1)
Attr_a	 := A2TOSING(Directory_a,5)

AEVAL(Names_a,;
{|cValue,nIndex| IF(  Attr_a[nIndex] == "D",;
                     Names_a[nIndex] := "[" + Names_a[nIndex] + "]",)})

DirectoryEntries_n := Len( Names_a )

For Nth_Directory_Entry_n := 1 To DirectoryEntries_n
	Nth_Directory_Entry_s := Names_a[ Nth_Directory_Entry_n ]

	Name_s := ""
	Attr_s := Attr_a[ Nth_Directory_Entry_n ]
	Message_s := Nth_Directory_Entry_s

	// If pointing to a directory, then obtain list of subdirectories and files within that directory
	If Attr_s == "D"
	
		Name_without_Brackets_s := StrTran( Nth_Directory_Entry_s, "[", "" )
		Name_without_Brackets_s := StrTran( Name_without_Brackets_s, "]", "" )
		
		SubDirectory_Path_s := CurDrive() + ":\" + Current_Directory_s + "\" + Name_without_Brackets_s + "\*.*"
		SubDirectory_Files_a := DIRECTORY( SubDirectory_Path_s, "HSD" )

		Nth_SubDirectory_FileNames_a  := A2TOSING(SubDirectory_Files_a,1)
		Nth_SubDirectory_FileNames_s := Array_to_List( Nth_SubDirectory_FileNames_a, " " )
		// Message line will contain list of filenames and subdirectories, within the directory currently selected.
		Message_s := Nth_SubDirectory_FileNames_s

	EndIf
	AAdd( Main_Menu_a, { Nth_Directory_Entry_s, Message_s, ;
		{ | Col_n | DoSomething( Current_Directory_s,  Names_a[ Col_n ], Attr_a[ Col_n ] ) } } )

Next

cls(23, chr(177))
SETCOLOR( "W+/B,B/W,,W+/B")


Lotus_Menu(0,0,0,MaxCol(),Main_Menu_a,.t.,.t.,.t.)
Lotus_Clear()

Return Nil


// Execute this, when the user presses <ENTER>
Function DoSomething( Current_Directory_s,  Name_s, Attr_s )
Local ErrorCode_n

If "D" $ Attr_s
	Name_s = StrTran( Name_s, "[", "" )
	Name_s = StrTran( Name_s, "]", "" )

	ErrorCode_n := DirChange( Name_s )
	If ErrorCode_n <> 0
		? "Error Code from changing directory: "
		? ErrorCode_n
		Wait
	Else
		Current_Directory_s := DirName()
		Directory_Menu( Current_Directory_s )
	End If

End If


Return Nil



FUNC Array_to_List( aArray, Delimiter_s )

   LOCA cRVal := ''
   
   DEFAULT aArray TO {}
   DEFAULT Delimiter_s TO ','
           
   AEVAL( aArray, { | x1, i1 | cRVal += Any2Strg( x1 ) + IF( i1 < LEN( aArray ), Delimiter_s, "" ) } ) 
   
RETU cRVal // Array_to_List()


// Forgot where we found this routine
*-----------------------------------------------------------------------------*
FUNCTION Any2Strg( xAny )
*-----------------------------------------------------------------------------*
Local  cRVal  := '???', nType ;
       ,aCases := { { "A", { |  | "{...}" } },;
                    { "B", { |  | "{||}" } },;
                    { "C", { | x | x }},;
                    { "M", { | x | x   } },;
                    { "D", { | x | DTOC( x ) } },;
                    { "L", { | x | IF( x,"On","Off") } },;
                    { "N", { | x | NTrim( x )  } },;
                    { "O", { |  | ":Object:" } },;
                    { "U", { |  | "<NIL>" } } }

   IF (nType := ASCAN( aCases, { | a1 | VALTYPE( xAny ) == a1[ 1 ] } ) ) > 0
      cRVal := EVAL( aCases[ nType, 2 ], xAny )
   Endif

Return cRVal



Function print( row, col, str, attr )

prnt( row, col, str, attr )

Return nil

// From SuperLib
Function prnt(nRow,nColumn,cString,nAttribute)
local  cColor
if valtype(nAttribute)=="C"
   cColor := nAttribute
elseif valtype(nAttribute)=="N"
   cColor := at2char(nAttribute)
else
   cColor := setcolor()
endif
@nRow,nColumn say cString color cColor
return nil

Attachments
LotusMenu.zip
(713.04 KiB) Downloaded 67 times
User avatar
andyglezl
Posts: 1461
Joined: Fri Oct 26, 2012 7:58 pm
Location: Guadalajara Jalisco, MX
Contact:

Re: General suggestions, in preparation for a text-mode array navigator

Post by andyglezl »

Porqué Harbour ?
Porqué tienes que mostrar TODO el TreeWiew ?

Puedes seleccionar solo la carpeta que quieres ver con:

GetFolder ( [<cTitle>] , [<cInitPath>], [<cInvalidDataMsg>], [<lNewFolderButton>] , [<lIncludeFiles>] , [<nCSIDL_FolderType>] , [<nBIF_Flags>] )--> cSelectedFolderName

y de ahí hacer lo que quieres con el contenido...

*---------------------------------------------------------------------------------------------------------------------------
Why Harbour?
Why do you have to show the ENTIRE TreeWiew?

You can select only the folder you want to see with:

GetFolder ([<cTitle>], [<cInitPath>], [<cInvalidDataMsg>], [<lNewFolderButton>], [<lIncludeFiles>], [<nCSIDL_FolderType>], [<nBIF_Flags>]) -> cSelectedName

and from there do what you want with the content ...



Quizá esto pueda servirte...
*------------------------------------
Maybe this can help you ...
.
.
https://www.hmgforum.com/viewtopic.php?p=42551#p42551

https://www.hmgforum.com/viewtopic.php?p=40750#p40750
.
.
imagen_2021-10-31_134624.png
imagen_2021-10-31_134624.png (181.74 KiB) Viewed 1285 times
imagen_2021-10-31_140502.png
imagen_2021-10-31_140502.png (513.11 KiB) Viewed 1284 times
Andrés González López
Desde Guadalajara, Jalisco. México.
Post Reply