AppleScript GUI elements besides dialog - dialog

I was wondering if there is a way in AppleScript to create a small Applet of sorts, without having to use a bunch of dialogs, and I think it would be nicer in the end.
Here is the script I have currently, courtesy of AppleScript Wikia
set x1 to text returned of (display dialog "What is X1?" default answer "")
set y1 to text returned of (display dialog "What is Y1?" default answer "")
set x2 to text returned of (display dialog "What is X2?" default answer "")
set y2 to text returned of (display dialog "What is Y2?" default answer "")
display dialog "Distance = " & ((x2 - x1) ^ 2 + (y2 - y1) ^ 2) ^ (1 / 2)
Now, obviously, I understand this script, as it is quite simple!
But I was wondering, if a small Applet such as this were to be a little more useful and practical, it would be better to have some sort of window, without barraging the user with a bunch of dialogs.
Is there a way I can construct a window of sorts, with input fields and a "Calculate" button or something like that.
Or, at this point, would it just be better to construct a super simple Objective-C application?

Applescript offers only very basic interaction with the user natively beyond what you gave displayed there. Xcode includes support to create simple applications with a GUI front and an Applescript back. New Project>Mac OS X>Application>Applescript Application. Documentation is limited, and at this point, if you have the Cocoa chops, I would suggest just going that route for easier long-term support.

You know you can do that in one dialog instead of 4...
set theValues to text returned of (display dialog "Enter X1 Y1 X2 Y2 separated by a space." default answer "")
set {tids, text item delimiters} to {text item delimiters, space}
set {x1, y1, x2, y2} to text items of theValues
set text item delimiters to tids
display dialog "Distance = " & ((x2 - x1) ^ 2 + (y2 - y1) ^ 2) ^ (1 / 2)
So you just enter all the values at once with a space between each value. Then in code you separate it out into your variables. If your values will always be positive then you can just get the "words" of theValues to make it even more simple. But I would stick with using text item delimiters in case you want to also use negative values. Using "words" strips off the "-" symbol from the numbers.
If you wanted to get really fancy you could have the user put each value on a separate line like this...
set theValues to text returned of (display dialog "Enter X1 Y1 X2 Y2 on separate lines." default answer (return & return & return))
set {x1, y1, x2, y2} to paragraphs of theValues
display dialog "Distance = " & ((x2 - x1) ^ 2 + (y2 - y1) ^ 2) ^ (1 / 2)
TO EXPLAIN TEXT ITEM DELIMITERS:
You can convert a string into a list by getting the "text items" of the string. There is a value called "text item delimiters" (tids) which determines how that string is broken up into a list. By default tids is "" (eg. nothing). So for example look at this script...
set theString to "some text words"
set theList to text items of theString
--> {"s", "o", "m", "e", " ", "t", "e", "x", "t", " ", "w", "o", "r", "d", "s"}
The list you get is each character of the string as a separate item. That's because tids is the default value of "". Now let's look what happens if we change tids to something else. Let's make tids a space character instead and run the script again...
set theString to "some text words"
set text item delimiters to space
set theList to text items of theString
--> {"some", "text", "words"}
By making it a space the string gets broken up into the items that had a space between them. So you see we can control how the string is turned into a list by controlling tids. One thing to note: when we change tids to something other than the default value, after using it we have to change tids back. This is safe programming because some other part of the script may depend on the value of tids. So get in the habit of resetting tids after you're done. That's the basics of what the tids code does. It stores the initial value of tids (so we can change it back later), changes tids to a space, uses tids to turn the string into a list, then resets tids back to its initial value.
I hope that helps.

Related

String Operations Confusion? ELI5

I'm extremely new to python and I have no idea why this code gives me this output. I tried searching around for an answer but couldn't find anything because I'm not sure what to search for.
An explain-like-I'm-5 explanation would be greatly appreciated
astring = "hello world"
print(astring[3:7:2])
This gives me : "l"
Also
astring = "hello world"
print(astring[3:7:3])
gives me : "lw"
I can't wrap my head around why.
This is string slicing in python.
Slicing is similar to regular string indexing, but it can return a just a section of a string.
Using two parameters in a slice, such as [a:b] will return a string of characters, starting at index a up to, but not including, index b.
For example:
"abcdefg"[2:6] would return "cdef"
Using three parameters performs a similar function, but the slice will only return the character after a chosen gap. For example [2:6:2] will return every second character beginning at index 2, up to index 5.
ie "abcdefg"[2:6:2] will return ce, as it only counts every second character.
In your case, astring[3:7:3], the slice begins at index 3 (the second l) and moves forward the specified 3 characters (the third parameter) to w. It then stops at index 7, returning lw.
In fact when using only two parameters, the third defaults to 1, so astring[2:5] is the same as astring[2:5:1].
Python Central has some more detailed explanations of cutting and slicing strings in python.
I have a feeling you are over complicating this slightly.
Since the string astring is set statically you could more easily do the following:
# Sets the characters for the letters in the consistency of the word
letter-one = "h"
letter-two = "e"
letter-three = "l"
letter-four = "l"
letter-six = "o"
letter-7 = " "
letter-8 = "w"
letter-9 = "o"
letter-10 = "r"
letter11 = "l"
lettertwelve = "d"
# Tells the python which of the character letters that you want to have on the print screen
print(letter-three + letter-7 + letter-three)
This way its much more easily readable to human users and it should mitigate your error.

Write statement for a complex format / possibility to write more than once on the same excel line

I am presently working on a file to open one by one .txt documents, extract data, to finally fill a .excel document.
Because I did not know how it is possible to write multiple times on the same line of my Excel document after one write statement (because it jumps to the next line), I have created a string of characters which is filled time after time :
Data (data_limite(x),x=1,8)/10, 9, 10, 7, 9, 8, 8, 9/
do file_descr = 1,nombre_fichier,1
taille_data1 = data_limite(file_descr)
nvari = taille_data1-7
write (new_data1,"(A30,A3,A11,A3,F5.1,A3,A7,F4.1,<nvari>(A3))") description,char(9),'T-isotherme',char(9),T_trait,char(9),'d_gamma',taille_Gam,(char(9),i=1,nvari)
ecriture_descr = ecriture_descr//new_data1
end do
Main issue was I want to adapt char(9) amount with the data_limite value so I built a write statement with a variable amount of char(9).
At the end of the do-loop, I have a very complex format of ecriture_descr which has no periodic format due to the change of the nvari value
Now I want to add this to the first line of my .excel :
Open(Unit= 20 ,File='resultats.RES',status='replace')
write(20,100) 'param',char(9),char(9),char(9),char(9),char(9),'*',char(9),'nuances',char(9),'*',char(9),ecriture_descr
100 format (a5,5(a3),a,a3,a7,a,a3,???)
but I do not know how to write this format. It would have been easier if, at each iteration of the do-loop I could fill the first line of my excel and continue to fill the first line at each new new_data1 value.
EDIT : maybe adding advance='no' in my write statement would help me, I am presently trying to add it
EDIT 2 : it did not work with advance='no' but adding a '$' at the end of my format write statement disable the return of my function. By moving it to my do-loop, I guess I can solve my problem :). I am presently trying to add it
First of all, your line
ecriture_descr = ecriture_descr//new_data1
Is almost certainly not doing what you expect it to do. I assume that both ecriture_descr and new_data are of type CHARACTER(len=<some value>) -- that is a fixed length string. If you assign anything to such a string, the string is cut to length (if the assigned is too long), or padded with spaces (if the assigned is too short:
program strings
implicit none
character(len=8) :: h
h = "Hello"
print *, "|" // h // "|" ! Prints "|Hello |"
h = "Hello World"
print *, "|" // h // "|" ! Prints "|Hello Wo|"
end program strings
And this combination will work against you: ecriture_descr will already be padded to the max with spaces, so when you append new_data1 it will be just outside the range of ecriture_descr, a bit like this:
h = "Hello" ! h is actually "Hello "
h = h // "World" ! equiv to h = "Hello " // "World"
! = "Hello World"
! ^^^^^^^^^
! Only this is assigned to h => no change
If you want a string aggregator, you need to use the trim function which removes all trailing spaces:
h = trim(h) // " World"
Secondly, if you want to write to a file, but don't want to have a newline, you can add the option advance='no' into the write statement:
do i = 1, 100
write(*, '(I4)', advance='no') i
end do
This should make your job a lot easier than to create one very long string in memory and then write it all out in one go.

matlab gui edit text to graph

I am using matlab Guide. I want to take a string that I enter in an Edit text Box, and convert it into a vector of numbers so that I can plot a graph from the vector. Here is the code I wrote for converting the String into A vector of numbers:
function value = substrings (a)
j = 1;
word = a;
for i = 1:length(word)
if word(i)~= ' '
q(1,j) = str2double(word(1,i));
j = j+1;
end
end
value = q;
end
This Code eliminates spaces so if I enter '1 2 3 4 5'
It wil become [1 2 3 4 5]
The problem i have is i dont know how to include this in my main code so that i can input the string in the edit text box and the send it to a button to plot it.
here is the section in the Guide:
function text_Callback(hObject, eventdata, handles)
% hObject handle to text (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
word = get(hObject,'String');
for i = 1:length(word)
if word(i)~= ' '
q(1,k) = str2double(word(1,i));
k = k+1;
end
end
handles.To_Plot = q;
im going to plot handles.To_Plot with the button.
Hmm, I'm not quite sure what you're asking, but I'm confident I can help you if you provide clarification. Here's what I think you want:
There is no need to "send it" to anything. You just need to use guidata(hObject, handles) to sync your handles variable, then place your plot commands in the button press callback.
function button_ClickedCallback(hObject, eventdata, handles)
% hObject handle to text (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
doSomethingWith(handles.To_Plot);
end
If this isn't what you need just post some clarification to your question, and I'll try to help. Tell me about the specific output you expect, and how what you're seeing is different.

Collapsing character vectors with sprintf instead of paste

I have mostly used paste or paste0 for my pasting tasks in the past, but I'm pretty fascinated by the speed of sprintf. Yet I feel that I'm lacking some its basics.
Just wondered if there's also a way to collapse a multi-element character vector to one of length 1 as paste would do when using its collapse argument, that is, without having to specify respective wildcards and its values manually (in paste, I simply leave the task up to the function to find out how many elements should be collapsed).
x <- c("Pasted string:", "hello", "world!")
> sprintf("%s %s %s", x[1], x[2], x[3])
[1] "Pasted string: hello world!"
> paste(x, collapse=" ")
[1] "Pasted string: hello world!"
I'm looking for something like this (pseudo code)
> sprintf("<the-correct-parameter>", x)
[1] "Pasted string: hello world"
For the interested: benchmark of sprintf vs. paste
require("microbenchmark")
t1 <- median(microbenchmark(sprintf("%s %s %s", x[1], x[2], x[3]))$time)
t2 <- median(microbenchmark(paste(x, collapse=" "))$time)
> t1/t2
[1] 0.7273114
The function sprintf recycles its format string, so for example the code
cat(sprintf("%8.4f",rnorm(5)),"\n")
prints something like
-0.5685 -0.6481 0.6296 -0.0043 -1.4763
str = sprintf("%8.4f",rnorm(5))
stores the output in a vector of strings and
str_one = paste(sprintf("%8.4f",rnorm(5)),collapse='')
stores the output in a single string. The format string does not need to specify the number of floats to be printed. This also holds for printing integers and strings with the %d and %s formats.

Vim: creating a C string literal around a block of text with vertically aligned quotes?

I would like to create a macro or a script in Vim that does the following:
wrap a block of text in double quotes
escaping any quotes that appear in the text itself
have the quotes on the right side in vertical alignment
For example:
<html>
<head></head>
<body>
<h1>High Score Server</h1>
<table>
ROWS
</table>
</body>
</html>
would become:
"<html> "
"<head></head> "
"<body> "
"<h1>High Score Server</h1>"
"<table> "
"ROWS "
"</table> "
"</body> "
"</html> ";
I am able to achieve this with a macro, but without the vertical alignment of the quotes on the right side. Can anyone help me with this one?
What I'd do :
With "surround" and "Align" plugins :
1) with cursor on first line (0,0), type <C-V>)$s"
2) then <S-V>):Align " and <Enter>.
Another solution without plugins :
1) set virtual mode
:set ve=all
2) <C-V> to go in block-wise selection, with cursor at the position 0,0
3) go down to the bottom of the text, then Shift-I, type " and Esc. This should prepend the quotes.
4) now go on the left end (since ve=all, you can go where there is no text)
5) <C-V>, go down to bottom, type r"
This is long to explain, but easy to do and reproduce. Also useful in lots of case.
function Enquote()
let [startline, endline]=sort([line("'<"), line("'>")])
let lines=getline(startline, endline)
let lengths=map(copy(lines), 'len(split(v:val, ''\zs''))')
let maxlen=max(lengths)
call map(lines, '''"''.v:val.repeat(" ", maxlen-lengths[v:key]).''"''')
return setline(startline, lines)
endfunction
Explanation:
line("'<") and line("'>") get the line numbers of start and end of last visual selection.
sort([...]) sorts this line numbers since you may have started selecting lines from the end of the selection.
let [a, b]=[c, d] is a parallel assignment: sort will produce a sorted list of two items, where first item is lesser or equal to second item. Obviously, lesser is a first selected line.
len(split(v:val, '\zs')) is an advanced strlen() which supports unicode.
max(list) finds a maximum value. Obvious.
So, map(copy(lines), 'len(split(v:val, ''\zs''))') applies this strlen to all items in list. copy() is required since we do not want our list to be modified.
map(lines, '''"''.v:val.repeat(" ", maxlen-lengths[v:key]).''"''') modifies an lines in a way you require. I switched from printf to repeat because printf does not handle multibyte characters correctly (by «correctly» I mean that «¥» is one character long, while printf considers it two bytes long).
setlines(linenumber, listoflines) actually modifies buffer.
Making use of the unix program "par" to do this may well solve your problem. There's a Vimcast showing how to integrate it into vim over at http://vimcasts.org/episodes/formatting-text-with-par/
Is it possible to make two passes over the list of lines in vim script? Then you can do something like this (pseudocode):
let N = length of longest line
for each line L:
insert a " character at the beginning
append N - len(L) spaces
append a " character
best i got is a 3-pass regex.
select block in visual mode, then use:
:'<,'>s#^#"#
:'<,'>s#$# #
:'<,'>s#\(.\{28\}\).*#\1"
with the 28 being the length of your longest line.
By all means heed the previous answers and get your vim-fu in shape. Or install/modify/poke-the-author of this plugin:
http://www.vim.org/scripts/script.php?script_id=4727
From the plugin's page:
This script converts multi-line text in a C++ file to a multi-line
string literal, escaping the quote and tab characters. It also does
the reverse conversion, un-escaping some characters. It's not too
complete for now, but it will be someday if needs come.
If you need to make changes use the source-code repository:
https://bitbucket.org/dsign/stringliteral.vim
In two passes:
let l = max(map(getline("'<", "'>"), 'strwidth(v:val)'))
'<,'>s/.*/\=('"'.submatch(0).repeat(' ', l-strwidth(submatch(0)) )).'"'

Resources