Topic: Resizing Windows in AppGraphics

In case users were not aware, AppGraphics included with Simply Fortran 2.23 now supports resizing windows.  We have a new tutorial available on how to implement resizing:

https://approximatrix.wordpress.com/201 … pgraphics/

The tutorial should be enough to get users started on creating resizeable windows.

Jeff Armstrong
Approximatrix, LLC

Re: Resizing Windows in AppGraphics

Hi Jeff,

I would like to add a file/open menu to main window of resize (just as an example of the potential use of the open file dialog).

I've successfully added 'File/saveimage',  'File/open', and 'File/quit' sub-menus to the window.

The File/saveimage and File/quit options work just fine, but the File/open dlgopenfile() option causes the system to 'hang-up'.

Do you have any suggestions on the proper use and way to add a file open dlgopenfile() menu to a main window?

Below is the code of your resize program with my revisions labeled to add menu options.

I look forward to any suggestions you or others may have to resolve this issue.

Frank

!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
appprogram resizing
use appgraphics
implicit none

    integer::myscreen
    integer::mybutton
    logical::quit

    !--------------Added-------------------------------------\/
    integer::root_menu, file_menu, item_temp
    !--------------------------------------------------------/\

    myscreen = initwindow(320, 240, closeflag=.TRUE.)
    mybutton = createbutton(270, 210, 40, 20, "Close", handle_button)

    !--------------Added-------------------------------------\/
    root_menu = addmenu("", MENU_FOR_WINDOW)
    file_menu = addmenu("File", root_menu)

    item_temp = addmenuitem("Save Screenshot...", file_menu, savescreen)
    item_temp = addmenuitem("Open", file_menu, openfile)
    item_temp = addmenuitem("Quit", file_menu, quitwndo)
    !--------------------------------------------------------/\

    quit = .FALSE.

    call enableresize(handle_resize)

    do while(.NOT. quit)
        call draw_window()
        call loop()
    end do

    call closewindow(myscreen)

    contains

    subroutine draw_window()
    use appgraphics
    implicit none
        integer::w,h

        integer::tw
        character(100)::info

        w = getmaxx()
        h = getmaxy()

        call setbuttonposition(mybutton, w-50, h-30, 40, 20)

        write(info, '(A5,1X,I5,A1,I5)') "Size:", w, "x", h

        call setviewport(0, 0, w, 40, .FALSE.)
        call clearviewport()
        tw = textwidth(trim(info))
        call outtextxy( (w/2-tw/2), 5, trim(info))

    end subroutine draw_window

    subroutine handle_button()
    use appgraphics, only: stopidle
    implicit none

        quit = .TRUE.
        call stopidle()

    end subroutine handle_button

    subroutine handle_resize()
    use appgraphics
    implicit none

        call stopidle()

    end subroutine handle_resize

    !--------------Added-------------------------------------\/
    subroutine openfile()
        USE appgraphics, ONLY: dlgopenfile
        implicit none

        CHARACTER(255)  :: input_file_name

        !   Appgraphics function dlgopenfile (filename, maskdesc, mask, title)
        input_file_name= repeat(' ', 255)

        IF( dlgopenfile( &
            input_file_name, 'Data', '*.raw', 'Enter data file') ) THEN

            Print *, "You've selected "//trim(input_file_name)
        ELSE
            Print *, "No file was selected"
        END IF

        input_file_name = TRIM(input_file_name)

    end subroutine openfile

    subroutine savescreen()
        use appgraphics, only: writeimagefile
        implicit none

        ! This call will open a file dialog since we haven't
        ! specified a filename
        call writeimagefile()

    end subroutine savescreen

    subroutine quitwndo()
        use appgraphics, only: stopidle
        implicit none

        quit = .TRUE.
        call stopidle()

    end subroutine quitwndo
    !--------------------------------------------------------/\
end program resizing
!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Re: Resizing Windows in AppGraphics

Frank,

It could be a bug.  I'll have a look tomorrow (I've been away from my desk for most of last week).

Jeff Armstrong
Approximatrix, LLC

Re: Resizing Windows in AppGraphics

Jeff,

A somewhat related issue is how to maintain an active instance of a window containing menus when selecting a sub-menu (e.g., 'Run') callback to run a related routine in another module requiring several loops.  I only seem to succeed if I close the main window after selecting the added menu 'run' option and then I must re-load the window when the active routine ends. 
Is there a way to retain a visual instance of the main window on the screen while running other routines in the background such that the results of the background run to a subroutine can then be populated in the main window?

I've also tried making the main window 'recursive' but each time a callback subroutine is selected to run and returns to the main window, another instance of the main window appears.  As a results of multiple runs, several main windows populate the screen.  I have not found a way to remove the 'older' instances of the main window after each run.  Is there a way to close ALL windows but the active one?  Closewindow seems to close everything.  And Closegraph() doesn't appear to be recognized by Appgraphics. 

It may be that I just don't fully understand the complete functionality of Appgraphics, or perhaps there are other commands that could be added to the package to make it more functional.

I must say that I fully appreciate the work you put into developing this graphic library and look forward to future developments.

Frank

Re: Resizing Windows in AppGraphics

Frank,

Regarding your first message, there does seem to be a current bug related to the file dialogs.  There seems to be a problem creating the windows due to some thread interaction issues.   I'll have a fix soon.

Regarding callbacks, AppGraphics basically runs on two threads.  The first thread is your actual program, probably Fortran, that creates the window, etc.  The second thread is a GUI thread that handles window updates and messages from the operating system in regards to the GUI.

Any callback functions will execute in the GUI thread.  You'll notice that in most of the AppGraphics examples, a callback function usually does two things:

1. Set a flag
2. Release the idle state

All of the computation code in the examples is written in the Fortran thread.   Basically, the design would be to initialize the window in the main Fortran thread and enter an idle state to wait for a command.   When a user, for example, clicks a "Run" menu item, the callback associated with that menu item would set a flag, possibly something similar to "start_run = .TRUE.", followed by a command to exit the idle state, call stopidle().  The main program would then take action after leaving the idle state based on flags that have been set.

When you actually start executing long-running code in your callback, it basically disallows the GUI thread from performing any Window updates.   You would need to somehow get the main thread to perform the task you're requesting.

I've rewritten your attached program with a few changes.  Basically, menu items will now trigger a task variable to be set and release the idle state.  Based on the value of task, the main program will take some action:

!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
program resizing
use appgraphics
implicit none

    integer::myscreen
    integer::mybutton
    integer, volatile::task
    
    integer, parameter::task_quit=0
    integer, parameter::task_open=1
    integer, parameter::task_run=2
    
    integer::run_item

    !--------------Added-------------------------------------\/
    integer::root_menu, file_menu, item_temp
    !--------------------------------------------------------/\

    myscreen = initwindow(320, 240, closeflag=.TRUE.)
    mybutton = createbutton(270, 210, 40, 20, "Close", handle_button)

    !--------------Added-------------------------------------\/
    root_menu = addmenu("", MENU_FOR_WINDOW)
    file_menu = addmenu("File", root_menu)

    item_temp = addmenuitem("Save Screenshot...", file_menu, savescreen)
    item_temp = addmenuitem("Open", file_menu, handle_open)
    run_item = addmenuitem("Run", file_menu, handle_run)
    item_temp = addmenuitem("Quit", file_menu, quitwndo)
    !--------------------------------------------------------/\

    call enableresize(handle_resize)

    task = -1

    do while(task .NE. task_quit)
        call draw_window()
        call loop()
        select case(task)
            case (task_open)
                call openfile()
            case (task_run)
                call longrun()
        end select
    end do

    call closewindow(myscreen)

    contains

    subroutine draw_window()
    use appgraphics
    implicit none
        integer::w,h

        integer::tw
        character(100)::info

        w = getmaxx()
        h = getmaxy()

        call setbuttonposition(mybutton, w-50, h-30, 40, 20)

        write(info, '(A5,1X,I5,A1,I5)') "Size:", w, "x", h

        call setviewport(0, 0, w, 40, .FALSE.)
        call clearviewport()
        tw = textwidth(trim(info))
        call outtextxy( (w/2-tw/2), 5, trim(info))

    end subroutine draw_window

    subroutine handle_button()
    use appgraphics, only: stopidle
    implicit none
    
        task = task_quit
        call stopidle()

    end subroutine handle_button

    subroutine handle_resize()
    use appgraphics
    implicit none

        call stopidle()

    end subroutine handle_resize
    
    subroutine handle_open()
    use appgraphics
    implicit none

        task = task_open
        call stopidle()

    end subroutine handle_open

    !--------------Added-------------------------------------\/
    subroutine openfile()
        USE appgraphics, ONLY: dlgopenfile
        implicit none

        CHARACTER(255)  :: input_file_name

        !   Appgraphics function dlgopenfile (filename, maskdesc, mask, title)
        input_file_name= repeat(' ', 255)

        IF( dlgopenfile( &
            input_file_name, 'Data', '*.raw', 'Enter data file') ) THEN

            Print *, "You've selected "//trim(input_file_name)
        ELSE
            Print *, "No file was selected"
        END IF

        input_file_name = TRIM(input_file_name)

    end subroutine openfile

    subroutine savescreen()
        use appgraphics, only: writeimagefile
        implicit none

        ! This call will open a file dialog since we haven't
        ! specified a filename
        call writeimagefile()

    end subroutine savescreen

    subroutine handle_run()
        use appgraphics, only: stopidle
        implicit none
    
        task = task_run
        call stopidle()
        
    end subroutine handle_run
    
    subroutine longrun()
        implicit none
        
        real::starttime, nowtime
        
            call enablemenuitem(run_item, .FALSE.)
        
            call cpu_time(starttime)
            nowtime = starttime
            do while(nowtime - starttime .LT. 5.0)
                call cpu_time(nowtime)
                Print  *, "no"
            end do
            
            call enablemenuitem(run_item, .TRUE.)
            
    end subroutine longrun

    subroutine quitwndo()
        use appgraphics, only: stopidle
        implicit none

        task = task_quit
        call stopidle()

    end subroutine quitwndo
    !--------------------------------------------------------/\
end program resizing

Incidentally, calling dlgopenfile in this manner actually works, although it is a bug that it doesn't work in the manner you had been using it.   You'll also note that I added a long-running process as an example that is executed in the longrun subroutine.  This subroutine should disable all menu items, but right now it will only disable the "Run" item.  In reality, though, there is yet another bug that is causing the identifiers returned by addmenuitem to be meaningless.  I'll be looking into that problem too.

Jeff Armstrong
Approximatrix, LLC

Re: Resizing Windows in AppGraphics

As a quick update, the addmenuitem function works properly. There was an issue with enablemenuitem in the library that has since been fixed.

Jeff Armstrong
Approximatrix, LLC

Re: Resizing Windows in AppGraphics

Jeff,

Thank you for your quick response and suggestions.
I have not tried them as of yet, but will shortly.

Since you mentioned the issue with enablemenuitem, I should also mention that I found disablemenuitem to be unreliable.

Thanks again, I'll try your example.

Frank