Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

Lately I come across what I think not uninteresting problem which is a good exercise for the usage of Dynamic. Assume you have files in a directory structure (a tree) like the one you find in the AddOns/Packages subdirectory. Here a snip of it

Packages/BarCharts
|-- Charts.m
|-- Charts3D.m
|-- Kernel
|   `-- init.m
|-- PacletInfo.m
`-- Usage.m
Packages/Benchmarking
|-- Benchmarking.m
|-- Kernel
|   `-- init.m
`-- PacletInfo.m
Packages/BlackBodyRadiation
|-- BlackBodyRadiation.m
|-- Kernel
|   `-- init.m
`-- PacletInfo.m

What I would like to have is a dynamically updating row of PopupMenu's which let's me select a file or directory like this

enter image description here

There should be a possibility to select directories (like the Benchmarking/Kernel) directory as well. Note that not all PopupMenu's are always visible. Their number depend on the depth of the selected file/directory. For instance consider this case

enter image description here

What I tried so far is to extract all files with FileNames and use Gather and replacement rules to convert them into a tree-structure. In this tree structure you can access then different levels and update the PopupMenu's in dependence of each other.

I'm really keen to see nice* ideas of others.

*short, interesting, intuitive, mind-boggling

share|improve this question
1  
This sort of widget is commonly called "breadcrumb bar", if you need a way to refer to it. –  Oleksandr R. May 2 '13 at 16:22
add comment

2 Answers

up vote 1 down vote accepted

My solution is only prototype but I'll update it later. It differs from Yours approach becouse my function is blind. A priori it does not know the structure of file's tree.

And there is also ActionMenu not PopupMenu. :(

This version is not very elegant but I'm going to improve this.

Lets start and set main directory and create function for each menu:

dir = {SetDirectory[$InstallationDirectory]}; 

current = 1;
MENU[j_] := Module[{k},

SetDirectory[StringJoin@Riffle[dir[[ ;; j]], "\\"]];
ActionMenu[
Dynamic@dir[[ j]],
Table[
 With[{f = FileNames[][[ i]]},
  f :> (
   current = j + 1;
   k = f;
   If[StringCount[f, "."] == 0, 
    dir = PadRight[dir[[ ;; j]], j + 1, ""]; dir[[ j + 1]] = k]
   )],
{i, Length@FileNames[]}]
 ]
 ]

now we can try:

Dynamic@Row@Table[MENU[j], {j, current}]

Basic description - we are extending path by clicking at last MENU. If You set one of previous then "current" value is changing and cutting path to the point You set. It works only for directories now by looking for "." in name. I'm going to deal with generalization later.

Ask if there are any questions.

share|improve this answer
1  
+1 You should replace "\\" by $PathnameSeparator. Remember, on good operating systems, you have the real and only / as separator. Beside that fact, that it cannot handle files, I like this one. –  halirutan May 1 '13 at 19:02
add comment

A rough straightforward implementation is to find all of the subpaths in your path, and generate a button that allows setting a new path at that level for each such subpath. Here's an implementation that generates the list of files/folders when you press the menu to ensure it's up to date.

pathParts[path_] := FileNameJoin/@Rest@FoldList[Append,{},FileNameSplit[path]]

pathPartsAlternatives[path_]:= FileNames[FileNameJoin[Append[Most@FileNameSplit[path], "*"]]]

pathPartButton[Dynamic[var_],path_] :=
DynamicModule[{subpaths={}},
    EventHandler[
        Dynamic@ActionMenu[Last@FileNameSplit[path],subpaths]
    ,"MouseDown":>
    (subpaths=(RuleDelayed[Last@FileNameSplit@#,(var=FileNameJoin[{#, If[DirectoryQ[#], ".", ""]}])]&/@pathPartsAlternatives[path])),
    PassEventsDown->True]
]

pathPartsRow[Dynamic[var_]] := 
  pathPartButton[Dynamic[var], #] & /@ pathParts[var] // Row // Dynamic
share|improve this answer
    
On OSX and Linux you don't have \ as separator for directories. Otherwise this version is nice too. –  halirutan May 1 '13 at 19:11
    
@halirutan Thanks for correction, it should be system independent now. –  jVincent May 2 '13 at 7:33
    
Btw, I finally accepted one of your answers and I chose Kubas not because his approach is better/faster/cleverer, but only because he has 1/10 of your reputation and can need some more. I liked both of your implementations! That may sound weird but otherwise I wouldn't have known which to accept, so I hope it is sensible choice. –  halirutan Jun 10 '13 at 23:55
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.