Keyboard shortcuts in an AppleScript list dialog - dialog

I am looking for a way to assign keyboard shortcuts to the items in a list dialog in AppleScript.
I am using the following to display a long list of folder names and am looking for an easy way to select an item from the list.
set selectedFolderName to {choose from list folderList}
Currently the list displays like :
Office
Personal
Projects
...
Vendors
and I have to navigate down the list with the cursor keys or mouse to select an item. I would like to be able to show either :
a) Office
b) Personal
c) Projects
...
m) Vendors
or :
Office
Personal
pRojects
...
Vendors
Then I could press the C key (first example) or R key (second example) to select 'Projects'.
I studied the AppleScript documentation, such as it is, and searched far and wide, but have not been able to spot a way to accomplish this.

I'm not totally sure if this is what you want, but I use the construct below, so that I can press "a", to select the first item, "b" to select the second item, and so on.
set litems to {"apples", "pears", "banana", "oranges", "plums", "grapes"}
set deli to "." & space & space
repeat with i from 1 to (count litems)
set item i of litems to character id (i + 96) & deli & item i of litems
end repeat
log litems
set theRes to choose from list litems
(*a. apples, b. pears, c. banana, d. oranges, e. plums, f. grapes*)
set origItem to text 5 thru -1 of item 1 of theRes
log origItem
—> plums

The second version of what you're asking is not possible. But, the first is. There is nothing built in for this kind of functionality, but you can build your own sub-routine for it. You can prepend your list items with letters or numbers (I'll use numbers since it's simpler).
on choose_from_list_with_shortcut(ls)
-- prepend the choices with "1) "
repeat with i from 1 to (count ls)
set item i of ls to (i as string) & ") " & item i of ls
end repeat
set chosenItems to choose from list ls
-- strip the prefixes from the chosen items
repeat with i from 1 to (count chosenItems)
set item i of chosenItems to text 4 thru -1 of item i of chosenItems
end repeat
return chosenItems
end choose_from_list_with_shortcut
Another option is to just start typing. Just like in the Finder, if you type the letters "pro," the list will highlight "Projects."

Related

Show Items and related SubItems on the spreadsheet

I have a vba Array of items in column 1 and items they feed in column 2.
I want to have a clean visual way to illustrate a "branching" effect on the spreadsheet but I'm at a loss on what the best method would be.
So this question is more of "What is the best method to use" kinda thing.
Just to visualize though, let's say my array looks like this:
(Col1 and Col2 separated by a space)
Array1:
PowerStrip1 TV
PowerStrip1 DVDPlayer
PowerStrip2 Soundbar
I want to have them look something like this on the excel spreadsheet:
PowerStrip1
|---> TV
|---> DVDPlayer
PowerStrip2
|---> Soundbar
Perhaps not the neatest way of showing it but you get the just. What would be the best method of achieving this look in a clean way?
Pivot Table is your friend in this. Select your data range then insert Pivot Table and arrange like below screenshot.
Unable to comment on #Harun24HR, so adding this as new answer
After creating a pivot table as mentioned by #Harun24HR, Try the following
In pivot table fields, click on the drop down available in Items field and select field setting. This will open a pop up
On subtotals & filters, select radio button besides "None"
Now go to layout & print
Have the radio button beside "show items label in outline form checked
Now and untick the check box below them
I believe this will give the desired result
Thanks guys, Harun24HR provided a perfectly good solution but I also wanted to share a different solution I came up with that displayed the information in more of a Tree-View format just in case it helps anyone else.
Lets say the Sheet name is "Summary", and the range of information to be used is A2:B200.
Assume the "Parent" information is in column "A" and the "Child" information is in column "B".
Also, you need to go to the Developer Tab -> Insert -> Active X Controls -> More Controls -> Microsoft TreeView Control, version 6.0. This is the TreeView control which will show our information.
I changed the name of the TreeView control to "tv" for simplicity.
See code below:
Sub TreeViewStuff()
'Using TreeView Nodes to populate the power sources summary
'Clear pre-existing nodes
Dim arr as variant
Dim str as string
Dim i as integer
On Error Resume Next
Sheets("Summary").tv.Nodes.Clear
'Copy range into an array
arr = Sheets("Drop Downs").Range("A2:B200")
'The first column of the array contains the parents, lets add them as keys
For i = 1 To UBound(arr)
str = ""
'Add the parent
Sheets("Summary").tv.Nodes.Add Key:=arr(i, 1), Text:=arr(i, 1)
'Expand the node
Sheets("Summary").tv.Nodes(Sheets("Summary").tv.Nodes.Count).Expanded = True
Err.Clear
Next i
'The second column will contain the kids, lets add them
For i = 1 To UBound(arr)
str = ""
'Add the kids
Sheets("Summary").tv.Nodes.Add arr(i, 1), tvwChild, arr(i, 2), arr(i, 2)
'Expand the node
Sheets("Summary").tv.Nodes(Sheets("Summary").tv.Nodes.Count).Expanded = True
Err.Clear
Next i
End Sub
The TreeView approach can give a "Dotted Line" illustration between the parent and child nodes which was something I wanted to show. Again thanks for the help!

Automatic numbering in Excel with hierarchy

I would like to do an automatic summary numbering. The only thing we could do is to number the A's (the titles) but the subtitles should be numbered automatically. If the title = 1, subtitle 1.1, below 1.1.1 and so on.
Let's say the titles are A, B and C are subtibles.
The pattern should be like this
1.A
1.1 B
1.2 B
2.A
2.1 B
2.1.1 C
So I tried this : https://stackoverflow.com/a/32321112/7968011
What I get
What we want
What we want
If you have your Level Marker as "A" / "B" / "C" in Column A, and the heading in Column B, then you can use the following (convoluted) code:
=REPT(CHAR(9), CODE(A1)-65) & SUMPRODUCT(--(A:A="A")*--(ROW(A:A)<=ROW(A1))) & "." & IF(CODE(A1)>65,SUMPRODUCT(--(A:A="B")*--(ROW(A:A)<=ROW(A1))*--(ROW(A:A)>=MAX(--ROW(A:A)*--(A:A="A")*--(ROW(A:A)<=ROW(A1))))) & ".","") & IF(CODE(A1)>66,SUMPRODUCT(--(A:A="C")*--(ROW(A:A)<=ROW(A1))*--(ROW(A:A)>=MAX(--ROW(A:A)*--(A:A="B")*--(ROW(A:A)<=ROW(A1))))) & ".","") & CHAR(9) & B1
Let's break it down into steps:
Start with Tabs to indent the heading (0 for "A", 1 for "B", 2 for "C"): REPT(CHAR(9), CODE(A1)-65) where Char(9) is a Tab.
Next, we want to count how many "A"s have we had. We can use SUMPRODUCT to run this as an Array Formula, looking for cells where the value is "A" and the Row is <= current row: SUMPRODUCT(--(A:A="A")*--(ROW(A:A)<=ROW(A1))). Shove a dot after that, and you have your heading number.
Next, IF Column A is "B" or later in the alphabet (IF(CODE(A1)>65, since CODE("A")=65, CODE("B")=66, etc) then we want to count how many "B"s since the last "A". This is very similar to our last query, but we need a ROW(A:A)>=LAST_A. But, what is LAST_A? Well, we want the MAX Row where Column A = "A" and Row <= current row. So, MAX(--ROW(A:A)*--(A:A="A")*--(ROW(A:A)<=ROW(A1))).
This gives SUMPRODUCT(--(A:A="B")*--(ROW(A:A)<=ROW(A1))*--(ROW(A:A)>=MAX(--ROW(A:A)*--(A:A="A")*--(ROW(A:A)<=ROW(A1)))))
Now, we need to add the IF and the full-stop, to get
If(Code(A1)>65,SUMPRODUCT(--(A:A="B")*--(ROW(A:A)<=ROW(A1))*--(Row(A:A)>=MAX(--ROW(A:A)*--(A:A="A")*--(ROW(A:A)<=ROW(A1))))) & ".","")
Repeat the same for all "C"s since the last "B", and then finally add a Tab (CHAR(9)) and the value in Column B.
(If you want, for example, 4 spaces or 6 hyphens or 7 dots instead of Tabs at the start of the row or between the number and the tile, just replace the first or last CHAR(9))
{EDIT} Example:
Fast and dirty.
Just enter the first section manualy.
Then insert it below:
=IF(A3="down",B2&"1.",IF(A3="up",LEFT(B2,LEN(B2)-4)&MID(B2,LEN(B2)-3,1)+1&".",LEFT(B2,LEN(B2)-2)&MID(B2,LEN(B2)-1,1)+1&"."))
When you write "down" it will add "1." in the end of the string above.
When you write "up" it will remove the last 2 chars and add 1 to the last char of the string above.
if you dont write nothing it will add 1 to the last char.
bug: "up" will not work if section is > 9.

Power Query: Adding characters to a set limit across several columns/rows

Very new to PQ, and I'm pretty sure it can do what I need in this situation, but I need help figuring out how to get there.
I have a timesheet report with 20 columns covering 50 rows that will need to be formatted to a word doc for uploading into a separate system. The original data in the cells range from 0 to any negative 2 digit number (ex: "-20"), but they need to be formatted to a seven-character set ending in ".00".
Examples:
0 will need to become "0000.00"
-4 will need to become "-004.00"
-25 will need to become "-025.00"
I think I should be able to use the text.insert function, but I'm not familiar enough with M Language to get it to do what I want it to do.
Any solutions/suggestions?
Here's my previous answer revisited...set up to use a function. You can just invoke the function once for each column you want to reformat. You'll just pass the name of the column you want to reformat to the function as you invoke the function each time.
Create a new blank query:
Open the new query in Advanced Editor and highlight everything in it:
Paste this over the highlighted text in the Advanced Editor:
let
FormatIt = (SourceColumn) =>
let
Base = Number.Round(SourceColumn,2)*.01,
Source = try Text.Start(Text.Range(
if Base < 7 then Text.From(Base) & "001" else
Text.From(Base),0,7),2) & Text.Range(Text.Range(
if Base < 7 then Text.From(Base) & "001" else
Text.From(Base),0,7),3,2) & "." & Text.End(Text.Range(
if Base < 7 then Text.From(Base) & "001" else
Text.From(Base),0,7),2)
otherwise "0000.00"
in
Source
in
FormatIt
...and click Done.
You'll see a new function has been created and listed in the Queries list on the left side of the screen.
Then go to your query with the columns you want to reformat (click on the name of your query that has the numbers you want to change in it, on the left side of the screen) and...
Click Invoke Custom Function
And fill out the pop-up like this:
- You can make up a different New column name than Custom.1.
- Function Query is the name of your query you are calling (the one you just created when you pasted the code)...for me, it's called Query1.
- Source Column is the column with the numbers you want to format.
...and click OK.
You can invoke this function once for each column. It will create a new formatted column for each.
You can use this formula = Text.PadStart(Text.From([Column1]),4,"0")&".00") in PQ to add new column that looks similar to your needs.
Here's an admittedly "busy" formula to do it:
= Table.AddColumn(#"Changed Type", "Custom", each Text.Start(Text.Range(if Number.Round([Column1],2)*.01 < 7 then Text.From(Number.Round([Column1],2)*.01) & "001" else Text.From(Number.Round([Column1],2)*.01),0,7),2) & Text.Range(Text.Range(if Number.Round([Column1],2)*.01 < 7 then Text.From(Number.Round([Column1],2)*.01) & "001" else Text.From(Number.Round([Column1],2)*.01),0,7),3,2) & "." & Text.End(Text.Range(if Number.Round([Column1],2)*.01 < 7 then Text.From(Number.Round([Column1],2)*.01) & "001" else Text.From(Number.Round([Column1],2)*.01),0,7),2))
It assumes your numbers that you want formatted are in Column1 to start. It creates a new column...Custom...with the formatted result.
To try it out, start with Column1 already populated and loaded into Power Query; then click the Add Column tab and then the Custom Column button, and populate the pop-up window like this:
...and click OK.
With more time, the repetitive parts could be made with variables to shorten this up a bit. This could also be turned into a function, given some time. But I don't have the time right now, so I figured I'd give you at least "something."

How can I separate all the characters of a word into separate fields?

I have a random word generation script that works perfectly. I also have a few single character-width fields, exactly the same amount of them as the longest possible word that can be generated. Below each field I have a line that would resemble an underscore. Each field has a unique id, numbered from one like so: "letter1", "letter2".... and so on. Likewise, each line has the id of "line1", "line2", and so on.
Now that I've set the stage, here is what I want to happen. On the opening of the card, I want all of the letter fields to hide as I will have them show individually outside this subroutine. I then want all of the lines to hide, and then only the amount of lines that are required for the random word should show again. (The same number as length(randomword) from left to right.) Now, the random word should be looped through and the first character should be put into the field "letter1", and the second into "letter2", and so on. The word will change each time the card is opened, so it is important that this is not bruteforced (which unfortunately, myself having two weeks experience with LiveCode, is the only thing I know concretely how to do).
Could someone with more experience do me a solid and provide the code I would need to do this, and the location I should put the code in? (the card? the letter fields? I really don't know at this point).
I am happy to provide further description if I have not been articulate about my problem.
Try this (my LiveCode is a bit rusty):
on openCard
//Put your word generation script here
put 0 into amtOfLines
put 0 into amtOfLetters
repeat until amtOfLines is 6 //Replace 6 with the amount of lines
add 1 to amtOfLines
put "line" & amtOfLines into x
set the visible of graphic x to false
end repeat
repeat until amtOfLetters is 6 //Replace 6 with the amount of fields
add 1 to amtOfLetters
put "letter" & amtOfLetters into x
set the visible of field x to false
end repeat
put 0 into amtOfLines
put 0 into amtOfLetters
repeat until amtOfLines is length(randomword)
add 1 to amtOfLines
put "line" & amtOfLines into x
set the visible of graphic x to true
end repeat
repeat until amtOfLetters is length(randomword)
add 1 to amtOfLetters
put "letter" & amtOfLetters into x
set the visible of field x to true
end repeat
put 0 into amtOfChars
repeat until amtOfChars is length(randomword)
add 1 to amtOfChars
put "letter" & amtOfChars into x
set the text of field x to char amtOfChars of randomword
end repeat
end openCard
This would go in the card script.
EDIT: Fixed some errors.
This would go into the card script:
on setup pRandomWord
put 6 into tNumObjs -- or however many fields there are
put length(pRandomWord) into tLen
repeat with x = 1 to tNumObjs
hide fld ("letter"&x)
if x <= tLen then
put char x of pRandomWord into fld ("letter"&x)
show grc ("line"&x)
else
hide grc ("line" & x)
end if
end repeat
end setup
When you want to use it, put the random word into a variable and call the setup handler like this:
setup randomWord
This does everything in a single repeat loop. The random word is passed to the setup handler in the parameter "pRandomWord".

Creating a limited drop-down List

So say I have a table x by y entries.
X is far too great, or changes often enough, that making X additional tables/lists/named ranges is absurd.
However, I need to make a drop-down list of some of y.
Specifically:
Name | A | B | C | ..
Yannis| 20 |Yellow| Green| ..
Mirrah| 400 |Purple|Yellow| ..
.
.
.
I need a drop-down select of Name to change the options in a different drop-down list, which is based off of B & C.
Normally you can do this with either a Filter or INDIRECT(). However, it is beyond unreasonable to create a unique table, or name define, for each entry in X.
It is possible to create a table with all the possible entries for B & C, if there was a way to filter a named define for a list based off of the first table (using vlookup(), most likely)
In layman's terms: I need list 1 to filter list 2 where list 1 is either enormous or subject to constant change.
Gah, so this:
=INDIRECT("'InfoDump'!" & ADDRESS(MATCH(C5,PkmList,0)+25,10))
put into the data validation list works, however it's only one entry, and I need 3.
simply adding commas and copies causes error messages.
The one entry that this supplies is correctly referenced (dynamically) from the table without any need for more tables/namedRanges.
C5 is where the first list is
PkmList is the NamedRange for the first column of the Table
+25 'cause the table starts at A25 (column title)
10 referencing the first of 3 columns I need in the second list.
Okay!
After some experimentation, this accomplishes what I was looking for:
=INDIRECT("'InfoDump'!" & (ADDRESS(MATCH(C5,PkmList,0)+25,10)) & ":" & ((ADDRESS(MATCH(C5,PkmList,0)+25,12))))
or, in some different terms:
=INDIRECT("'sheetName'!" & (ADDRESS(MATCH(DropDownOne,DropDownOneCriteria,0)+(AdjustRow),(AdjustColumn))) & ":" & ((ADDRESS(MATCH(DropDownOne,DropDownOneCriteria,0)+(AdjustRow),(AdjustColumn)))))
Data validation hates logic.
-
In the most basic sense:
Match(a,b,c) gets the location of 'a' in 'b' (c is the same as vlookup's exact match option)
Address(row,column) gets the "j26" address, you can (as I did) adjust from where you found the match. (in my case, 25 down 'casue the table actually started at A25, but the list started at '1'; then 10 - 12 across for the 3 options I needed to list)
indirect(txt) turns this into a list. more or less. use "'sheetName'!" for referencing a different sheet.
-
So in the end this gives you a "=A2:A4" in the Data validation bar, based on another list. Same as using the popular work around that is the fruit vegetable cabbage example, but this doesn't require you to make multiple named ranges. (Which means it works for a single large changing table).

Resources