RedyTutorial

Application Basics

To get started with programming a Redy application, you need a few things in your main file.

  • Define global constants that give Redy information about the application (optional)
  • Include the GUI Redy library (and other Redy libraries as needed)
  • Define a default event-handling procedure
  • Define a start procedure that creates a main window and does other initialization stuff
  • Start the GUI

Like other GUI libraries, Redy requires you to use Event-driven programming concepts. After your program starts, it will do nothing until the GUI library sends events to the event handler procedure.

global constant  
App_Name = "Redy - Basic Window", 
App_Version = "1.0" 
 
include gui/gui.e as gui 
 
procedure gui_event(object evwidget, object evtype, object evdata) 
end procedure 
 
procedure start() 
    gui:wcreate({ 
        {"name", "winMain"}, 
        {"class", "window"}, 
        {"title", App_Name}, 
        {"size", {640, 480}} 
    }) 
    gui:wcreate({ 
        {"name", "cntMain"}, 
        {"parent", "winMain"}, 
        {"class", "container"}, 
        {"orientation", "vertical"}, 
        {"sizemode_x", "expand"}, 
        {"sizemode_y", "expand"} 
    }) 
    --create other widgets here 
end procedure 
 
gui:start(routine_id("start"), routine_id("gui_event")) 

Creating Widgets

Most GUI libraries create a widget with a function, something like this:

    atom winMain = createEx( Window, "Main", 0, 0, 0, xsize, ysize, {WS_POPUP,WS_BORDER}, 0) 

This concept is easy to grasp and only takes one line of code. However, there are some complications:

  • You have to store a "handle" to the widget in a variable or constant
  • You have to remember the order and purpose of a long list of parameters between a bunch of commas, and it is easy to accidentally mess them up. You have to use a combination of constants to set various properties or options.
  • You normally have to manually set xpos, ypos, xsize, and ysize of every widget, and then have a "resize" event recalculate positions.

The reason this method is used is mostly likely because it is wrapping C functions in dll files that use pointers, handles, structures, etc. For the sake of simplicity in wrapping C libraries, it makes sense to directly translate the API to Euphoria as much as possible.

Redy takes a different approach. Because it is written in pure Euphoria, all the way down to the widget classes themselves, there was no reason to use C concepts. Instead, Euphoria concepts are used throughout the API design.

  • You create widgets with a procedure, not a function. Rather than receiving a handle, you define the handle using a string. It is up to you to use whatever naming scheme you desire. You don't have to store anything to track existing widgets. You can see if a widget exists by calling gui:wexists("widgetname").
  • You define widget properties using a sequence of {"property_name", property_value} pairs. Although this requires more typing, it is very easy to see what your code (or someone else's code) is doing. Most properties have default values, so you don't have to define all of them. The only proprties you must define are "name", "parent" (except for windows), and "class".
  • Widgets are positioned automatically by putting them inside "container" widgets. You never have to think about widget coordinates ever again! There are cases where you will want to set the height or width of a widget manually, and this will be factored in when the container recalculates widget layout.
gui:wcreate({ 
    {"name", "cntDemoBottomRight"}, 
    {"parent", "cntDemoBottom"}, 
    {"class", "container"}, 
    {"orientation", "vertical"}, --causes child widgets to be arranged vertically 
    {"sizemode_x", "equal"},     --causes child widgets to have equal width 
    {"sizemode_y", "expand"}     --causes child widgets' heights to expand to fill the entire height of the container 
}) 
 
for b = 1 to 4 do 
    gui:wcreate({ 
        {"name", "btnCmd" & sprint(b)}, --notice how you can create sets of widgets using a "for" statement or other methods 
        {"parent", "cntDemoBottomRight"}, 
        {"class", "button"}, 
        {"label", "Command " & sprint(b)} 
    }) 
end for 

Processing Events

Redy event processing is very similar to other GUI libraries. However, because events don't originate from C callbacks, widget names and event types are strings, and event data is an object that can be structured in different ways, depending on what widget class it came from.

procedure gui_event(object evwidget, object evtype, object evdata) 
    switch evwidget do 
        case "lstImages" then 
            show_image(evdata[1][1]) 
     
        case "btnLoad" then 
            if equal(evtype, "clicked") then 
        ... 

You can define a different event handler for a widget, and any children of that widget will inherit that event handler instead of using the default one.

--help.e 
procedure help_gui_event(object evwidget, object evtype, object evdata) 
end procedure 
 
procedure show_help() 
    gui:wcreate({ 
        {"name", "winHelp"}, 
        {"class", "window"}, 
        {"handler", routine_id("help_gui_event")}, 
        {"title", "Help!"}, 
        {"topmost", 1}, 
        {"size", {300, 600}} 
    }) 
    ... 
end procedure 

It doesn't necessarily have to be a window, either. For example, you could have a window with 2 containers "cntLeft" and "cntRight" and have separate event handlers for each container. Or, you can create a container called "cntDocument" and then let a separate library "doc.e" create a "canvas" widget called "canDoc" inside that container and process only the events of "canDoc". This flexibility makes it easy to create a "modular" application.

Multitasking

The Redy GUI can be controlled by multiple tasks. A built-in procedure is provided as a quick way to start a new task. This is useful for processing data and periodically updating a process bar, or displaying a splash screen for a few seconds.

    gui:call_task(routine_id("show_progress"), {}) --this calls a procedure in a new task 

The GUI itself has multiple tasks running simultaneously for event processing, blinking cursors, waiting for a response from a question in a message box, etc. Speaking of message boxes, Redy doesn't use system message boxes, but creates it's own. It is easy to pop up a message, or ask the user a question and wait for a response.

sequence ans = msgbox:waitmsg("Are you sure you want to exit?", "Question")  
if equal(ans, "Yes") then 
... 

http://redy-project.org/images/screenshots/window_close_disabled.png

Redy would greatly benefit from true multi-threading. Unfortunately, Euphoria doesn't currently support this, so make sure you follow the guidelines of Multi-tasking. Keep in mind, that because the Redy GUI is actual euphoria code that is running as part of your program, the user interface will completely stop drawing and responding while your program uses any blocking C functions or goes into a loop that doesn't call task_yield() often.

(This is a rough draft. More tutorials and examples will be provided in the official Redy Manual.)

Search



Quick Links

User menu

Not signed in.

Misc Menu