Dialog helper


Forum: Programming and Scripting
Topic: Dialog helper
started by: Zucca

Posted by Zucca on Oct. 03 2007,13:35
I planned a script that helps to screate dialog based scripts.
Somehow passing variables with multiple words act differently. This script should work with whiptail too.

Read the source and post reply if you have some tips or improvements.

Code Sample
#!/bin/bash
# I don't know if the line above is for any use... But it's just my habit.
# Because this "script" should be sourced by another scripts.
# You could call this as helper-script.

# Yes. I like to add much comments.;)

# I added a licence to this script just if some one want to use this.

############################################################################
# LICENCE -=start=-                                                        #
############################################################################
#Copyright (c) 2007, Zucca
#
# All rights reserved.
#Redistribution and use in source and binary forms, with or without
#modification, are permitted provided that the following conditions are met:
#   - Redistributions of source code must retain the above copyright notice,
#     this list of conditions and the following disclaimer.
#   - Redistributions in binary form must reproduce the above copyright
#     notice, this list of conditions and the following disclaimer in the
#     documentation and/or other materials provided with the distribution.
#   - Neither the name of the Zucca's company nor the names of its
#     contributors may be used to endorse or promote products derived from
#     this software without specific prior written permission.
#
#       THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
#       CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
#       INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
#       MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
#       DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
#       CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
#       SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
#       NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
#       LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
#       HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
#       CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
#       OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
#       SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
############################################################################
# LICENCE -=end=-                                                          #
############################################################################


function chooseDialog {
   
   # This function simply choses the dialog app to use.
   # At the time of writing this only "dialog" is tested and it will be
   # chosen if found. Otherwise "whiptail" will be used.
       # There's propably many numbers of ways how to hide output.
       # I've seen much use of "> /dev/null 2>&1" but I'll stick with
       # "&> /dev/null" just because it's very neat.
       # http://tldp.org/LDP/abs/html/special-chars.html#REDIROUTERROR for
       # more. Here I use "2>" to hide error output (stderr) from
       # displaying. Normal output (stdout) will be directed to variable
       # DIALOGAPP and therefore will not be printed to screen.
   # I can't find any simplier way to assign this variable.
   # If you know better, plese inform me. ANY improvements are welcome.
   DIALOGAPP=`which dialog 2> /dev/null` \
   || DIALOGAPP=`which whiptail 2> /dev/null`
   
   # Uncomment next line to have some kind of debug information
   # echo "Dialogapp: $DIALOGAPP"
   
   # Do we need to return this variable? I haven't done research for this.
   # Just to be sure we do it.
   # return $DIALOGAPP
}

function setDialogDimensions {
   
   # This function needs just any text for it's arguments.
   # Before calling, variable IFS should be set to "\n".
   # http://www.google.com/linux?q=Bash+IFS for more.;)
   
   # It genrates dialog dimension variables ($DIALOG_H and $DIALOG_W) with
   # proper width and height for the text depending on the terminal screen
   # size.
   # Normally if dialog is big enough it looks dirty. This function will
   # fix that.
   
   # First, get screen dimensions.
   # Ok this was quite hard for me. As I thought when script is called
   # there's no actual screen size (for example when script is called from
   # GUI). I ran some test and found no answer. Until I googled:
   # http://www.google.com/linux?q=stty+size+bash+script and found the
   # answer from the first hit. My problem was that I ran this script with
   # sh when I should ran it with sh. sh is a symbolic link to /bin/bash.
   # Either bash regonizes how it is called or it's my Linux system that
   # replaces sh with bash (I belive symbolic link is the default).
   # Anyway I added #!/bin/bash to the beginning of this script. Just to be
   # sure.
   # So next lines didn't worked at all.
   # SCREEN_H=`stty size | sed -e "s/ /\n/g" | head -n 1`
   # SCREEN_W=`stty size | sed -e "s/ /\n/g" | tail -n 1`
   
   # Next section is taken from:
   # http://www.linuxfromscratch.org/hints/downloads/files/easyrc.txt with
   # some modifications.
   
               
               # If COLUMNS hasn't been set yet (bash sets it but not
               # when called as sh), do it ourself
               
               # Get the console device if we don't have it already
               # This is ok by the FHS as there is a fallback if
               # /usr/bin/tty isn't available, for example at bootup.
               test -x /usr/bin/tty && CONSOLE=`/usr/bin/tty`
               test -z "$CONSOLE" && CONSOLE=/dev/console
               
               # Get the console size (rows columns)
               SIZE=$(stty size < $CONSOLE)
               
               # Strip off the rows leaving the columns
               SCREEN_W=${SIZE#*\ }
               
               # And get the rows too
               SCREEN_H=${SIZE%%\ *}
               
   
   echo "Screen Dimensions: $SCREEN_H $SCREEN_W"
   
   # I think decreasing eight from width and height of the max screen
   # size is enough.
   let "MAX_W = $SCREEN_W - 8"
   let "MAX_H = $SCREEN_H - 8"
   
   # Uncomment next line to have some kind of debug information
   #echo "Max dialog dimensions: $MAX_H $MAX_W"
   
   # Measure text dimensions
   TEXT_W=`echo "$@" | wc -L`
   TEXT_H=`echo "$@" | fold -sw $MAX_W | wc -l`
   
   # Uncomment next line to have some kind of debug information
   #echo "Text dimensions: $TEXT_H $TEXT_W"
   
   # Dialog needs to be a bit bigger than text dimensions.
   let "DIALOG_W = $TEXT_W + 4"
   let "DIALOG_H = $TEXT_H + 4"
   
   # Uncomment next line to have some kind of debug information
   #echo "Dialog size before check: $DIALOG_H $DIALOG_W"
   
   # If dimensions required by text are more than current screen can show
   # then set dialog dimension(s) to max.
   if [ "$DIALOG_W" -gt "$MAX_W" ]
   then
       let "DIALOG_W = $MAX_W"
   fi
   
   if [ "$DIALOG_H" -gt "$MAX_H" ]
   then
       let "DIALOG_H = $MAX_H"
   fi
   
   # Uncomment next line to have some kind of debug information
   #echo "Dialog size: $DIALOG_H $DIALOG_W"
   
   # Next line is to make a pause to read debug information
   #read
   
   # Finally, return dialog dimensions.
   # Again, I don't know if this is required.
   # return "$DIALOG_H"
   # return "$DIALOG_W"
}

########################################################
# Next functions will execute/open simple dialog tasks.#
########################################################

function msgboxDialog {
   
   chooseDialog
   OIFS="$IFS"
   IFS="\n"
   setDialogDimensions "$@"
   # Change IFS back to default
   IFS="$OIFS"
   "$DIALOGAPP" \
   --backtitle "$DIALOGBACKTITLE" \
   --title "$DIALOGTITLE" \
   --msgbox "$@" "$DIALOG_H" "$DIALOG_W"
}

# Now we can (for example) show motd in dialog by:
# msgboxDialog `cat /etc/motd`

# More functions will be added after bugs have been killed.


Thanks for advance. =)

Posted by WDef on Oct. 06 2007,15:07
This might help.  I've added my comments to you in BLOCK but only so these are discernible - I don't mean to shout at you.


Code Sample
#!/bin/bash
# I don't know if the line above is for any use.
# IT IS.

# Yes. I like to add much comments.;)

# I added a licence to this script just if some one want to use this.

############################################################################
# LICENCE -=start=- #
############################################################################
#Copyright (c) 2007, Zucca
#
# All rights reserved.
#Redistribution and use in source and binary forms, with or without
#modification, are permitted provided that the following conditions are met:
# - Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# - Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# - Neither the name of the Zucca's company nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
############################################################################
# LICENCE -=end=- #
############################################################################


function chooseDialog {

# This function simply choses the dialog app to use.
# At the time of writing this only "dialog" is tested and it will be
# chosen if found. Otherwise "whiptail" will be used.
# There's propably many numbers of ways how to hide output.
# I've seen much use of "> /dev/null 2>&1" but I'll stick with
# "&> /dev/null" just because it's very neat.
# http://tldp.org/LDP/abs/html/special-chars.html#REDIROUTERROR for
# more. Here I use "2>" to hide error output (stderr) from
# displaying. Normal output (stdout) will be directed to variable
# DIALOGAPP and therefore will not be printed to screen.
# I can't find any simplier way to assign this variable.
# If you know better, plese inform me. ANY improvements are welcome.
DIALOGAPP=`which dialog 2> /dev/null` \
|| DIALOGAPP=`which whiptail 2> /dev/null`

# Uncomment next line to have some kind of debug information
#echo "Dialogapp: $DIALOGAPP"

# Do we need to return this variable? I haven't done research for this.
# Just to be sure we do it.
# return $DIALOGAPP
}

function setDialogDimensions {

# This function needs just any text for it's arguments.
# Before calling, variable IFS should be set to "\n".
# http://www.google.com/linux?q=Bash+IFS for more.;)

# It genrates dialog dimension variables ($DIALOG_H and $DIALOG_W) with
# proper width and height for the text depending on the terminal screen
# size.
# Normally if dialog is big enough it looks dirty. This function will
# fix that.

# First, get screen dimensions.
# Ok this was quite hard for me. As I thought when script is called
# there's no actual screen size (for example when script is called from
# GUI). I ran some test and found no answer. Until I googled:
# http://www.google.com/linux?q=stty+size+bash+script and found the
# answer from the first hit. My problem was that I ran this script with
# sh when I should ran it with sh. sh is a symbolic link to /bin/bash.
# Either bash regonizes how it is called or it's my Linux system that
# replaces sh with bash (I belive symbolic link is the default).
# Anyway I added #!/bin/bash to the beginning of this script. Just to be
# sure.
# So next lines didn't worked at all.
# SCREEN_H=`stty size | sed -e "s/ /\n/g" | head -n 1`
# SCREEN_W=`stty size | sed -e "s/ /\n/g" | tail -n 1`

# Next section is taken from:
# http://www.linuxfromscratch.org/hints/downloads/files/easyrc.txt with
# some modifications.


# If COLUMNS hasn't been set yet (bash sets it but not
# when called as sh), do it ourself

# Get the console device if we don't have it already
# This is ok by the FHS as there is a fallback if
# /usr/bin/tty isn't available, for example at bootup.
test -x /usr/bin/tty && CONSOLE=`/usr/bin/tty`
test -z "$CONSOLE" && CONSOLE=/dev/console

# Get the console size (rows columns)
SIZE=$(stty size < $CONSOLE)


# Strip off the rows leaving the columns
SCREEN_W=${SIZE#*\ }

# And get the rows too
SCREEN_H=${SIZE%%\ *}


echo "Screen Dimensions: $SCREEN_H $SCREEN_W"


# DECREASED BY 2 instead
# SET PARAMETERS LIKE THIS AS VARS SO YOU CAN PLAY WITH THEM

if [ "$SCREEN_W" -gt 0 ]; then
let "MAX_W = $SCREEN_W - 2"
fi

if [ "$SCREEN_H" -gt 0 ]; then
let "MAX_H = $SCREEN_H - 2"
fi

# Uncomment next line to have some kind of debug information
#echo "Max dialog dimensions: $MAX_H $MAX_W"

# Measure text dimensions

# NEED DOUBLE QUOTES AOUND $1 TO PRESERVE LINE FORMATTING
# ELSE JUST HAVE ONE LONG LINE

TEXT_W=`echo "$1" | wc -L`
TEXT_H=`echo "$1" | wc -l`

# DON'T NEED fmt HERE

# Uncomment next line to have some kind of debug information
echo "Text dimensions: $TEXT_W $TEXT_H "


# Dialog needs to be a bit bigger than text dimensions.
# EQUAL X & Y DIMS IN WHIPTAIL DON'T GIVE A SQUARE
# DOUBLE WIDTH TO GET APPROX SQUARE IF width < 2 x Height

let "DIALOG_H = $TEXT_H + 8"

let "THRESH = 2 * $DIALOG_H"

let "DIALOG_W = $TEXT_W + 8"

if [ $DIALOG_W -lt $THRESH ]; then
let "DIALOG_W = 2 * $DIALOG_W"
fi



# Uncomment next line to have some kind of debug information
#echo "Dialog size before check: $DIALOG_H $DIALOG_W"

# SET MIN SIZE OR CAN'T SEE ANYTHING - something like:

if [ "$DIALOG_W" -lt 20 ]
then
let "DIALOG_W = 20"
fi

if [ "$DIALOG_H" -lt 10 ]
then
let "DIALOG_H = 10"
fi


echo "MAX_W is $MAX_W MAX_H is $MAX_H"
# If dimensions required by text are more than current screen can show
# then set dialog dimension(s) to max.
if [ "$DIALOG_W" -gt "$MAX_W" ]
then
let "DIALOG_W = $MAX_W"
fi

if [ "$DIALOG_H" -gt "$MAX_H" ]
then
let "DIALOG_H = $MAX_H"
fi

# Uncomment next line to have some kind of debug information
echo "Dialog size: $DIALOG_H $DIALOG_W"

# Next line is to make a pause to read debug information
#read

# Finally, return dialog dimensions.

# THIS ISN'T DOING MUCH FOR YOU HERE

}

########################################################
# Next functions will execute/open simple dialog tasks.#
########################################################

function msgboxDialog {

chooseDialog
IN="${1}"
setDialogDimensions "${IN}"

echo "dims $DIALOG_W $DIALOG_H"
$DIALOGAPP --backtitle "DIALOGBACKTITLE" --title "DIALOGTITLE" --msgbox "${IN}"  $DIALOG_H $DIALOG_W
}

# Now we can (for example) show motd in dialog by:

msgboxDialog "$(cat /etc/motd)"

# More functions will be added after bugs have been killed.


Posted by mikshaw on Oct. 06 2007,19:57
Quote
EQUAL X & Y DIMS IN WHIPTAIL DON'T GIVE A SQUARE
As far as I know, it works the same as console measurments, width is number of characters and height is number of lines of text.

Quote
# Now we can (for example) show motd in dialog by:
msgboxDialog "$(cat /etc/motd)"
This seems like unnecessarily complicated syntax. If it were me I'd definitely make an effort to use the syntax "msgboxDialog /etc/motd" instead. An alternative, though, might be to use a pipe, which might be an easier adjustment to your script:
cat /etc/motd | msgboxDialog

Posted by WDef on Oct. 06 2007,21:12
Reading from stdin like that probably means he has to parse the file line by line.  This way just puts the whole file contents into a variable for display in whiptail.
Posted by Zucca on Oct. 15 2007,13:23
Quote (mikshaw @ Oct. 06 2007,17:57)
Quote
EQUAL X & Y DIMS IN WHIPTAIL DON'T GIVE A SQUARE
As far as I know, it works the same as console measurments, width is number of characters and height is number of lines of text.

Quote
# Now we can (for example) show motd in dialog by:
msgboxDialog "$(cat /etc/motd)"
This seems like unnecessarily complicated syntax. If it were me I'd definitely make an effort to use the syntax "msgboxDialog /etc/motd" instead. An alternative, though, might be to use a pipe, which might be an easier adjustment to your script:
cat /etc/motd | msgboxDialog

dialog already has a feature to read text from a file. That was just an example. But reading from stdin would be a really nice feature.
I haven't studied bash scripting that much to make such feature yet. ;)

Posted by Zucca on Oct. 15 2007,13:46
Thanks to WDef now my script works almoost pefectly.
I have now one problem. Sometimes I need to show ASCII graphics in dialog or any text that has multiple spaces in a row. It seems that dialog (I don't know about whiptail) removes any extra spaces. Any Idea how to left these spaces there?

EDIT: A-ha! --no-collapse switch will do the thing. ;)

< http://zelan.zapto.org:8888/dialog.png >
I'll have to test with whiptail also to make this work in DSL also. ;)

Posted by WDef on Oct. 15 2007,20:25
You can make your script read argument text by calling your msgboxDialog function so:

Code Sample
msgboxDialog "$( echo -e "${1}" )"




Then try (eg):

Code Sample
./zuccacript.sh "1 2 3 \n 4 \n 5 \n 6 \n blah blah"



EDIT: Note this preserves whitespace in the argument string without  --no-collapse option to dialog/whiptail, which isn't recognized by dsl's version anyway.

Posted by Zucca on Oct. 16 2007,20:55
Do you guys have any suggestions where should this hmmm... script library (?) to be located in system.
Somewhere in /usr/share?

Posted by curaga on Oct. 16 2007,20:57
/usr/share/doc?
Posted by Zucca on Oct. 16 2007,23:02
It's rather a shared library.
You can 'include' it in a bash script with source command.

Posted by mikshaw on Oct. 16 2007,23:54
I'd say /usr/lib, /usr/local/lib, or somewhere in /opt

I mention /opt because this is DSL, and /opt is the only systemwide directory that is both writable by default and suitable for application files.

Posted by Zucca on Oct. 17 2007,09:29
Here's an example how I use this dialoghelper in my Gentoo system.
This is a .bashrc file of my root account:
Code Sample
#!/bin/bash

# If user is not in screen session AND file $HOME/.noscreen does not exist...
if [ -z `echo "$TERM" | grep screen` ] && [ ! -f "$HOME/.noscreen" ]
then

 # Ask user if he/she wants to start/continue a screen session.
 if source /usr/local/lib/dialoghelper && D_BACKTITLE="Starting a root session..." D_TITLE="Question" yesnoDialog "Start/Continue a screen session?"
 then

   # Retach screen or start new screen session.
   # Also run 'clear' after screen exit for security.
   # Yes. It's a long line. It could be more neat, but I'm lazy.

   screen -dr && clear && exit \
   || ps -U `whoami` -u `whoami` | grep screen > /dev/null \
   && echo -e "\nProblems starting screen. Now running offscreen. :(" \
   || screen && clear && exit \
   || echo -e "\nCould not start screen. Do you have screen installed and is screen in your $PATH?"
 fi
 # No else here. Do nothing if user chose not to start or continue screen session.

else
 # Otherwise tell user that $HOME/.noscreen is present or he/she just opened a new screen window.
 # Yes. A long line again.
 test -f "$HOME/.noscreen" && test -z `echo "$TERM" | grep screen` \
 && echo -e "File $HOME/.noscreen exist, no screen startup.\n run 'screen' to start new screen session, or 'screen -dr' to continue previous session."
fi


clear

# Show user the $TERM and tell that it's a new window.
# (I myself wanted to see this in every new screen window.)
echo $TERM | grep "screen" > /dev/null \
&& echo -e "New screen window opened.\nTerminal: $TERM" && sleep 1s \
|| echo -e "Root session opened offscreen.\nTerminal: $TERM"
# I added a one sec pause there to show user that the new window
# was _just_ opened. Useless... Maybe.

# Next line is just to load aliases
# I have same aliases for my root account.;)
test -f "/home/zucca/.aliases" && source /home/zucca/.aliases

echo -e "Ready.\n"

# I hope you can read how this script works.;)


Why I made this script is that I sometimes forget to start screen session. If I happen to start a long process in X terminal it will be killed if I close it or exit X (for those who are unfamiliar with screen:all processes started inside screen session will not be terminated even if you close your X terminal). This script really makes me to remember to start screen session. ;)
It's one of the most useful scripts I have made for myself. At least I think it's really neat. ;P

Before there was no choice not to start screen when logged as root now, with help of dialoghelper, there is. Of course you could do that without dialog... ;) But this is just simple example of the use of dialoghelper.
I'll be adding new features to it and compability with DSL's whiptail too.

Powered by Ikonboard 3.1.2a
Ikonboard © 2001 Jarvis Entertainment Group, Inc.