interkosmos / fortran-dialog

Library to create text user interfaces in Fortran 2008
ISC License
7 stars 0 forks source link
dialog fortran fortran-2008 fortran-package-manager fpm tui xdialog

fortran-dialog

A work-in-progress wrapper module around dialog to create text user interfaces in Fortran 2008, similar to pythondialog for Python.

Packages of dialog(1) are available for most Unix-like operating systems. On FreeBSD, an older version of dialog is already part of the base system. Install the package devel/cdialog for an enhanced port:

# pkg install devel/cdialog

Add an alias to your global profile, or set the backend to cdialog before calling any dialog routines from Fortran:

call dialog_backend('cdialog')

The basic widgets are compatible to Xdialog as well. Just set the backend to Xdialog.

Coverage

Widget Supported
buildlist
calendar
checklist
dselect
editbox
form
fselect
gauge
infobox
inputbox
inputmenu
menu
mixedform
mixedgauge
msgbox
pause
passwordbox
passwordform
prgbox
programbox
progressbox
radiolist
rangebox
tailbox
tailboxbg
textbox
timebox
treeview
yesno

Build Instructions

Download the fortran-dialog repository, and execute the Makefile:

$ git clone https://github.com/interkosmos/fortran-dialog
$ cd fortran-dialog/
$ make

If you prefer the Fortran Package Manager, run:

$ fpm build --profile=release

You can add fortran-dialog as a dependency to your fpm.toml:

[dependencies]
fortran-dialog = { git = "https://github.com/interkosmos/fortran-dialog.git" }

Example

The following example just shows a message box in terminal:

! example.f90
program main
    use :: dialog

    call dialog_msgbox('This is the message box widget.', 10, 30)
end program main

Link the example against libfortran-dialog.a:

$ gfortran -o example example.f90 libfortran-dialog.a
$ ./example

To create a graphical message box with Xdialog(1), write instead:

! example.f90
program main
    use :: dialog

    call dialog_backend('Xdialog')
    call dialog_msgbox('This is the message box widget.', 10, 30)
end program main

Further Examples

More examples can be found in examples/:

Build the programs with make:

$ make examples

Widgets

This section lists code snippets in Fortran for the supported dialog(1) widgets. See the official website for screen shots.

buildlist

character(len=32) :: selected
type(dialog_type) :: dialog
type(list_type)   :: list(3)

list(1) = list_type('item1', 'List Item 1', 'on')
list(2) = list_type('item2', 'List Item 2')
list(3) = list_type('item3', 'List Item 3')

call dialog_buildlist(dialog, 'Select items:', 16, 40, 5, list, &
                      title='Build List')
call dialog_read(dialog, selected)
call dialog_close(dialog)

print '("Selected items: ", a)', trim(selected)

calendar

character(len=12) :: date
type(dialog_type) :: dialog

call dialog_calendar(dialog, 'Enter date:', 3, 42, day=1, month=1, year=2025, &
                     title='Calendar')
call dialog_read(dialog, date)
call dialog_close(dialog)

print '("Date: ", a)', date

checklist

character(len=32) :: selected
type(dialog_type) :: dialog
type(list_type)   :: list(3)

list(1) = list_type('item1', 'List Item 1', 'on')
list(2) = list_type('item2', 'List Item 2')
list(3) = list_type('item3', 'List Item 3')

call dialog_checklist(dialog, 'Select items:', 16, 40, 5, list, &
                      title='Check List')
call dialog_read(dialog, selected)
call dialog_close(dialog)

print '("Selected items: ", a)', trim(selected)

dselect

character(len=512) :: path
type(dialog_type)  :: dialog

call dialog_dselect(dialog, '/', 18, 72, title='Select Directory')
call dialog_read(dialog, path)
call dialog_close(dialog)

print '("Directory: ", a)', trim(path)

editbox

character(len=512) :: line
logical            :: eof
type(dialog_type)  :: dialog

call dialog_editbox(dialog, './examples/wumpus.f90', 18, 72, title='Edit Box')

do
    call dialog_read(dialog, line, eof)
    if (eof) exit
    print '(a)', trim(line)
end do

call dialog_close(dialog)

form

character(len=32) :: user, shell, group
type(dialog_type) :: dialog
type(form_type)   :: form(3)

form(1) = form_type('User:',  1, 1, 'user',    1, 10, 10, 0)
form(2) = form_type('Shell:', 2, 1, '/bin/sh', 2, 10, 10, 0)
form(3) = form_type('Group:', 3, 1, 'wheel',   3, 10, 10, 0)

call dialog_form(dialog, 'Set user data:', 16, 40, 5, form, &
                 ok_label='Submit', title='Form')
call dialog_read(dialog, user)
call dialog_read(dialog, shell)
call dialog_read(dialog, group)
call dialog_close(dialog)

print '("User:  ", a)', trim(user)
print '("Shell: ", a)', trim(shell)
print '("Group: ", a)', trim(group)

fselect

character(len=512) :: path
type(dialog_type)  :: dialog

call dialog_fselect(dialog, '/', 18, 72, title='Select File')
call dialog_read(dialog, path)
call dialog_close(dialog)

print '("File: ", a)', trim(path)

gauge

character, parameter :: NL = new_line('a')

character(len=3)  :: a
integer           :: i
type(dialog_type) :: dialog

call dialog_gauge(dialog, 'Progress:', 12, 32, 0, title='Gauge')

do i = 1, 100
    select case (i)
        case (:20)
            call dialog_write(dialog, 'Validating ...' // NL)
        case (21:40)
            call dialog_write(dialog, 'Updating ...' // NL)
        case (41:60)
            call dialog_write(dialog, 'Doing more work ...' // NL)
        case (61:80)
            call dialog_write(dialog, 'Just a few seconds ...' // NL)
        case (81:)
            call dialog_write(dialog, 'Almost done ...' // NL)
    end select

    write (a, '(i0)') i
    call dialog_write(dialog, 'XXX' // NL // a // NL)
end do

call dialog_close(dialog)

infobox

call dialog_infobox(new_line('a') // 'This is the info box widget.', &
                    8, 36, title='Information', sleep=2)

inputbox

character(len=32) :: input
type(dialog_type) :: dialog

call dialog_inputbox(dialog, 'Enter your name:', 7, 32, 'Alice', title='Name')
call dialog_read(dialog, input)
call dialog_close(dialog)

print '("Input: ", a)', trim(input)

inputmenu

character(len=32) :: renamed
logical           :: eof
type(dialog_type) :: dialog
type(menu_type)   :: menu(3)

menu(1) = menu_type('item1', 'Item 1')
menu(2) = menu_type('item2', 'Item 2')
menu(3) = menu_type('item3', 'Item 3')

call dialog_inputmenu(dialog, 'Input:', 16, 40, size(menu), menu, &
                      no_tags=.true., title='Input Menu')

do
    call dialog_read(dialog, renamed, eof)
    if (eof) exit
    print '(a)', trim(renamed)
end do

call dialog_close(dialog)

menu

character(len=32) :: selected
type(dialog_type) :: dialog
type(menu_type)   :: menu(3)

menu(1) = menu_type('item1', 'Item 1')
menu(2) = menu_type('item2', 'Item 2')
menu(3) = menu_type('item3', 'Item 3')

call dialog_menu(dialog, 'Select an item:', 16, 40, size(menu), menu, &
                 no_tags=.true., title='Menu Demo')
call dialog_read(dialog, selected)
call dialog_close(dialog)

print '("Selected item: ", a)', trim(selected)

mixedform

character(len=32) :: user, shell, group
type(dialog_type) :: dialog
type(form_type)   :: form(3)

form(1) = form_type('User:',  1, 1, 'user',    1, 10, 10, 0, 2)
form(2) = form_type('Shell:', 2, 1, '/bin/sh', 2, 10, 10, 0, 0)
form(3) = form_type('Group:', 3, 1, 'wheel',   3, 10, 10, 0, 0)

call dialog_mixedform(dialog, 'Set user data:', 16, 40, 5, form, &
                      ok_label='Submit', title='Mixed Form')
call dialog_read(dialog, user)
call dialog_read(dialog, shell)
call dialog_read(dialog, group)
call dialog_close(dialog)

print '("User:  ", a)', trim(user)
print '("Shell: ", a)', trim(shell)
print '("Group: ", a)', trim(group)

mixedgauge

character(len=4) :: a
integer          :: i
type(gauge_type) :: gauge(10)

gauge(1) = gauge_type('Process one',   '0')
gauge(2) = gauge_type('Process two',   '1')
gauge(3) = gauge_type('Process three', '2')
gauge(4) = gauge_type('Process four',  '3')
gauge(5) = gauge_type('',              '8')
gauge(6) = gauge_type('Process five',  '5')
gauge(7) = gauge_type('Process six',   '6')
gauge(8) = gauge_type('Process seven', '7')
gauge(9) = gauge_type('Process eight', '4')

do i = 0, 100, 20
    write (a, '("-", i0)') i
    gauge(10) = gauge_type('Process nine', a)
    call dialog_mixedgauge('Progress:', 20, 64, 33, gauge, title='Mixed Gauge')
    call sleep(1)
end do

msgbox

call dialog_msgbox('This is the message box widget.', 8, 36, &
                   backtitle='msgbox', title='Message')

passwordbox

character(len=32) :: password
type(dialog_type) :: dialog

call dialog_passwordbox(dialog, 'Enter password:', 7, 32, &
                        insecure=.true., title='Password')
call dialog_read(dialog, password)
call dialog_close(dialog)

print '("Password: ", a)', trim(password)

passwordform

character(len=32) :: uuid, password
type(dialog_type) :: dialog
type(form_type)   :: form(2)

form(1) = form_type('UUID:',     1, 1, '12345',  1, 10, 10, 0)
form(2) = form_type('Password:', 2, 1, 'secret', 2, 10, 10, 0)

call dialog_passwordform(dialog, 'Set values:', 12, 40, 3, form, insecure=.true., &
                         ok_label='Submit', title='Password Form')
call dialog_read(dialog, uuid)
call dialog_read(dialog, password)
call dialog_close(dialog)

print '("UUID:     ", a)', trim(uuid)
print '("Password: ", a)', trim(password)

pause

integer :: stat

call dialog_pause('System reboots in 30 seconds.', 8, 36, 30, &
                  title='Pause', exit_stat=stat)

select case (stat)
    case (DIALOG_YES)
        print '("You pressed OK.")'
    case (DIALOG_NO)
        print '("You pressed Cancel.")'
    case default
        print '("You pressed Escape.")'
end select

prgbox

call dialog_prgbox('Uptime:', 'uptime', 8, 64, title='Prg Box')

programbox

character, parameter :: NL = new_line('a')

call dialog_programbox(dialog, 'Output:', 12, 32, title='Program Box')
call dialog_write(dialog, 'zzz ...' // NL)
call dialog_write(dialog, 'zzz ...' // NL)
call dialog_write(dialog, 'zzz ...' // NL)
call dialog_close(dialog)

progressbox

character, parameter :: NL = new_line('a')

call dialog_progressbox(dialog, 'Output:', 12, 32, title='Progress Box')
call dialog_write(dialog, 'zzz ...' // NL)
call dialog_write(dialog, 'zzz ...' // NL)
call dialog_write(dialog, 'zzz ...' // NL)
call dialog_close(dialog)

radiolist

character(len=32) :: selected
type(dialog_type) :: dialog
type(list_type)   :: list(3)

list(1) = list_type('item1', 'List Item 1', 'on')
list(2) = list_type('item2', 'List Item 2')
list(3) = list_type('item3', 'List Item 3')

call dialog_radiolist(dialog, 'Select items:', 16, 40, 5, list, &
                      title='Radio List')
call dialog_read(dialog, selected)
call dialog_close(dialog)

print '("Selected item: ", a)', trim(selected)

rangebox

character(len=3)  :: range
type(dialog_type) :: dialog

call dialog_rangebox(dialog, 'Select range with PGUP/PGDOWN:', 7, 32, min_value=0, &
                     max_value=42, default_value=21, title='Range Box')
call dialog_read(dialog, range)
call dialog_close(dialog)

print '("Selected range: ", a)', range

tailbox

call dialog_tailbox('/var/log/messages', 18, 72, title='Tail Box')

textbox

call dialog_textbox('./examples/wumpus.f90', 18, 72, title='Text Box')

timebox

character(len=8)  :: time
type(dialog_type) :: dialog

call dialog_inputbox(dialog, 'Enter time:', 7, 32, hour=12, minute=0, second=0, &
                     title='Time')
call dialog_read(dialog, time)
call dialog_close(dialog)

print '("Time: ", a)', time

treeview

character(len=32) :: selected
type(dialog_type) :: dialog
type(tree_type)   :: tree(4)

tree(1) = tree_type('tag1', 'one',   'off', 0)
tree(2) = tree_type('tag2', 'two',   'off', 1)
tree(3) = tree_type('tag3', 'three', 'on',  2)
tree(4) = tree_type('tag4', 'four',  'off', 1)

call dialog_treeview(dialog, 'Select item:', 0, 0, 0, tree, title='Tree View')
call dialog_read(dialog, selected)
call dialog_close(dialog)

print '("Selected: ", a)', trim(selected)

yesno

integer :: answer

answer = dialog_yesno('Please press Yes or No!', 6, 30, title='Example')

select case (answer)
    case (DIALOG_YES)
        print '("You pressed Yes.")'
    case (DIALOG_NO)
        print '("You pressed No.")'
    case default
        print '("You pressed Escape.")'
end select

Themes

You can create a new dialog(1) theme via:

$ dialog --create-rc ~/.dialogrc

Alter the settings to your liking. In /usr/local/share/examples/dialog/, you find several pre-defined themes:

Copy one of the widget styles to ~/.dialogrc.

Compatiblity

Licence

ISC