Windows and Dialogs

The windows of ocempgui.widgets are containers, that have an own caption bar, can be moved within the main pygame window and allow the user to collapse them to their caption bar. They can be drawn on top of other widgets by adjusting their depth attribute as already explained in the section called “Common widget operations - the BaseWidget”.

Window

The base for all the different window types is the Window class. It is a Bin container with the additional ability to collapse itself to its caption bar.

To create a Window you can simply call its constructor and provide an optional title text, that will be used as caption.

window = Window ("My new window")
        

The title can be retrieved or set at any later time with the title attribute.

window.title = "A new title!"
        

As already mentioned above, the Window allows the user to minimize it (and of course restore it), which is also possible in your own code.

if not window.minimized:
    window.minimize (True)
        
By overriding the minimize() method you can prevent the user from doing so, if you do not want it for a certain window.

You can align the child of the window using the align attribute. Different alignments can be combined, although not any case makes sense and some alignment combinations conflict with each other.

# Align the child at the top.
window.align = ALIGN_TOP

# Align the child at the bottom left.
window.align = ALIGN_BOTTOM | ALIGN_LEFT

# Invalid alignment, ALIGN_BOTTOM has a higher priority, thus
# the child will be aligned at the bottom.
window.align = ALIGN_TOP | ALIGN_BOTTOM
        
Thus the Window uses an aligning priority, which is explained in detail in the Window documentation.

The Window widget by default listens to the following signals:

  • SIG_MOUSEDOWN - Invoked, when a mouse button is pressed down on the Window.

  • SIG_MOUSEUP - Invoked, when a mouse button is released on the Window.

  • SIG_MOUSEMOVE - Invoked, when the mouse moves over the Window area.

Below you will find an example of the Window widget class. You do not need to care about the DialogWindow class for now as this is explained in the next section.

You can find the following example as a python script under examples/window.py.

# Window examples.
from ocempgui.widgets import *
from ocempgui.widgets.Constants import *

def _destroy_dialog (window):
    window.child.text = "#Close"
    
def create_window_view ():
    # Create and display a simple window.
    window = Window ("Simple window")
    window.child = Button ("#Not clickable")
    window.child.connect_signal (SIG_CLICKED, window.destroy)
    window.topleft = 5, 5
    window.depth = 1
    
    # Create dialog window.
    dialog = DialogWindow ("Modal dialog window")
    dialog.child = Button ("#Close first to use other widgets")
    dialog.child.connect_signal (SIG_CLICKED, _destroy_dialog, window)
    dialog.child.connect_signal (SIG_CLICKED, dialog.destroy)
    dialog.topleft = 100, 5
    dialog.depth = 2
    
    return window, dialog

if __name__ == "__main__":
    # Initialize the drawing window.
    re = Renderer ()
    re.create_screen (400, 200)
    re.title = "Window examples"
    re.color = (234, 228, 223)
    re.show_layer_info = True
    re.add_widget (*create_window_view ())
    # Start the main rendering loop.
    re.start ()

Example 39. Window example


DialogWindow

The DialogWindow is a modal Window widget, that grabs all events that are sent through the event manager it is attached to. The user will not be able to interact with other event capable elements until the DialogWindow is destroyed. Widgets, that are attached to it of course will still be notified.

The DialogWindow does not offer any new features besides those it incorporates from its parent class(es). To create a new DialogWindow you use the same constructor syntax as for the Window.

window = DialogWindow ("A new DialogWindow")
        

You can find an example of the DialogWindow in Example 39, “Window example”.

GenericDialog

It is often needed to know about how the user interacted with a certain dialog. Creating various Buttons with different callbacks or one callback, in which the buttons are distinguished is of course possible, but finding a safe distinction mode is a more complex task. You might argue, that you could check the text of the Button, but that only will work, if you do not want to offer localized version of you program.

To circumvent this and other issues the GenericDialog widget class was created. It allows you to associate different states with the buttons you want to place on it.

To create a GenericDialog you have to pass two lists to its constructor, one containing the Button widgets you want to display and one with the result states to associate with.

list1 = [Button ("OK"), Button("Cancel")]
list2 = [DLGRESULT_OK, DLGRESULT_CANCEL]
dialog = GenericDialog ("Title", list1, list2)
        
The order of the elements in both list is of value as this will

  • influence the order of the buttons from left to right,

  • influence the results of the buttons.

This means, that the first Button in the list will be displayed at the leftmost of all other Buttons, while it will be associated with the first item of the result list.

To allow a more flexible button and result behaviour (as needed in wizard dialogs for example), you can place new buttons and results at runtime on the dialog.

newlist1 = [Button ("Close"), Button ("Help")]
newlist2 = [DLGRESULT_CLOSE, DLGRESULT_USER]
dialog.set_buttons (newlist1, newlist2)
        

Now all you have to do is to connect your GenericDialog with a callback for the SIG_DIALOGRESPONSE signal, it listens to.

def my_callback (result, dlg):
    if result == DLGRESULT_CLOSE:
        dlg.destroy ()
    elif result == DLGRESULT_USER:
        ...

dialog,connect_signal (SIG_DIALOGRESPONSE, my_callback, dialog)
        
As you can see in the above example, this kind of dialog will not destroy itself, but instead has to be destroyed programmatically.

To place your own widgets and contents in the dialog, you can use the content attribute, which is a VFrame.

label1 = Label ("Label 1")
entry = Entry ("Hello world")
dialog.content.add_child (label1, entry)
...
        
All said about the Frame widget type applies to this one, too.

Below you will find an example of the GenericDialog widget class.

You can find the following example as a python script under examples/genericdialog.py.

# GenericDialog examples.
from ocempgui.widgets import *
from ocempgui.widgets.Constants import *

def _close (result, dialog, label):
    if result == DLGRESULT_OK:
        label.text = "You pressed OK!"
    elif result == DLGRESULT_CANCEL:
        label.text = "You pressed Cancel!"
    elif result == DLGRESULT_CLOSE:
        dialog.destroy ()

def create_dialog_view ():
    buttons = [Button ("#OK"), Button ("#Cancel"), Button ("Clo#se")]
    results = [DLGRESULT_OK, DLGRESULT_CANCEL, DLGRESULT_CLOSE]
    dialog = GenericDialog ("Generic dialog", buttons, results)
    lbl = Label ("Press the buttons to see the action.")
    dialog.content.add_child (lbl)
    dialog.connect_signal (SIG_DIALOGRESPONSE, _close, dialog, lbl)
    dialog.topleft = 30, 30
    dialog.depth = 1
    return dialog

if __name__ == "__main__":
    # Initialize the drawing window.
    re = Renderer ()
    re.create_screen (300, 300)
    re.title = "GenericDialog examples"
    re.color = (234, 228, 223)
    re.add_widget (create_dialog_view ())
    # Start the main rendering loop.
    re.start ()

Example 40. GenericDialog example


FileDialog

The FileDialog widget allows the user to choose files and directories from a FileList and can return those easily by a corresponding method. It also includes an Entry widget at the top, which keeps track of the current location and lets the user change the directory path quickly.

To create a FileDialog you have would type something like

dialog = FileDialog ("Select a file...", [Button ("OK")], [DLGRESULT_OK])
        
The first argument provides the title of the dialog, while the next two ones take the buttons and results for the dialog as already explained in the section called “GenericDialog”. There is also an optional last argument, which can set the initial directory to list as explained in the section called “FileList”.

The selected file and directory entries can be received easily using the get_filenames() method.

selection = dialog.get_filenames()
        
The selection entries will contain the absolute path to those filenames.

Below you will find an example of the FileDialog widget class.

You can find the following example as a python script under examples/filedialog.py.

# FileDialog examples.
import os
from ocempgui.widgets import *
from ocempgui.widgets.Constants import *

def _set_files (result, dialog, entry):
    string = ""
    if result == DLGRESULT_OK:
        string = "".join(["\"%s\" " % f for f in dialog.get_filenames ()])
    else:
        string = "Nothing selected"
    dialog.destroy ()
    entry.text = string
    
def _open_filedialog (renderer, entry):
    buttons = [Button ("#OK"), Button ("#Cancel")]
    buttons[0].minsize = 80, buttons[0].minsize[1]
    buttons[1].minsize = 80, buttons[1].minsize[1]
    results = [DLGRESULT_OK, DLGRESULT_CANCEL]

    dialog = FileDialog ("Select your file(s)", buttons, results)
    dialog.depth = 1 # Make it the top window.
    dialog.topleft = 100, 20
    dialog.filelist.selectionmode = SELECTION_MULTIPLE
    dialog.connect_signal (SIG_DIALOGRESPONSE, _set_files, dialog, entry)
    renderer.add_widget (dialog)

def create_file_view (renderer):
    table = Table (1, 2)
    
    hframe = HFrame (Label ("FileList"))
    hframe.add_child (FileList (200, 200))
    table.add_child (0, 0, hframe)
    
    hframe2 = HFrame (Label ("FileDialog"))
    label = Label ("Selection:")
    entry = Entry ()
    entry.minsize = 200, entry.minsize[1]
    button = Button ("#Browse")
    button.connect_signal (SIG_CLICKED, _open_filedialog, renderer, entry)
    hframe2.add_child (label, entry, button)
    table.add_child (0, 1, hframe2)
    
    table.set_row_align (0, ALIGN_TOP)
    return table

if __name__ == "__main__":
    # Initialize the drawing window.
    re = Renderer ()
    re.create_screen (550, 300)
    re.title = "FileDialog examples"
    re.color = (234, 228, 223)
    re.add_widget (create_file_view (re))
    # Start the main rendering loop.
    re.start ()

Example 41. FileDialog example