0% found this document useful (0 votes)
46 views

Overview of Ada GUI

This document summarizes an alternative approach to GUI programming in Ada compared to traditional frameworks. The traditional approach requires registering callbacks and giving up program control to the GUI, resulting in unintuitive programs. The Ada GUI approach allows the GUI to run concurrently with its own task, preserving the natural top-down structure of Ada programs. It provides a portable interface and includes an example all-Ada implementation using a browser as the platform.

Uploaded by

9rl0im17
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
46 views

Overview of Ada GUI

This document summarizes an alternative approach to GUI programming in Ada compared to traditional frameworks. The traditional approach requires registering callbacks and giving up program control to the GUI, resulting in unintuitive programs. The Ada GUI approach allows the GUI to run concurrently with its own task, preserving the natural top-down structure of Ada programs. It provides a portable interface and includes an example all-Ada implementation using a browser as the platform.

Uploaded by

9rl0im17
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 5

1

Overview of Ada GUI


Jeffrey R Carter
PragmAda Software Engineering, https://github.com/jrcarter/

Abstract sequential things: First it does X, then Y, and then Z.


Consider a typical program that does not use a GUI:
This is a summary of the presentation of the same title
made in the Ada devroom at FOSDEM 2022. with Ada.Text_IO;
Traditional GUIs require registering callbacks and
then giving up the program's thread of control to the procedure No_GUI is
GUI. This results in an unnatural programming style -- Empty
that runs counter to the way people typically learn to begin -- No_GUI
All_Commands : loop
read programs. Ada GUI uses an alternative
Ada.Text_IO.Put
approach suited to a concurrent language. (Item =>
Keywords: Ada, GUI. "Enter g, h, or q: ");

1 Introduction One_Command : declare


Command : constant String :=
Traditional GUI frameworks require the program to create Ada.Text_IO.Get_Line;
widgetrs, register callbacks, and then give up the thread of begin -- One_Command
control. This is a response to the inherent parallelism of a if Command'Length > 0 then
GUI by sequential languages. Programs are unintuitive to case Command (Command'First)
design, write, and understand. In a concurrent language is
such as Ada, the GUI can have its own task. This allows the when 'g' =>
GUI to preserve the intuitive way of writing and Ada.Text_IO.Put_Line
understanding programs. Ada GUI provides an interface for (Item => "Greetings");
such a GUI. There could be multiple implementations of when 'h' =>
this interface. There is an all-Ada example implementation Ada.Text_IO.Put_Line
(Item => "Hello");
that uses a browser as a platform supplied with the interface
when 'q' =>
on Github [1]. This makes the implementation very
Ada.Text_IO.Put_Line
portable. (Item => "Quitting");

2 Traditional GUI Framework exit All_Commands;


In a traditional GUI framework, the program creates when others =>
null;
widgets, registers callbacks, and gives up its thread of
end case;
control. This is due to the fact that a GUI is inherently
end if;
parallel: the user and the program run on completely end One_Command;
separate processors. The GUI needs a thread of control in end loop All_Commands;
order to be able to respond to user actions. In a sequential end No_GUI;
language, that thread must come from the program. But
there must be a mechanism for the program's code to This program is designed, written, and read top-to-bottom,
execute in response to the user's actions. This is provided with X, Y, and Z corresponding to outputting a prompt,
by the GUI calling subprograms that the program has getting a line, and processing the line.
registered with the GUI.
Compare No_GUI to a similar program that uses a GUI:
This approach has a number of consequences. What of
program code that needs to run independently of the GUI? with TGF;
There is the question of what happens if there is a GUI
event while a callback is executing. Nor is this purely an procedure With_GUI is
G : TGF.Button;
academic consideration: the Gnoga version of Mine
H : TGF.Button;
Detector [2] has to take action to deal with the possibility
Q : TGF.Button;
of a GUI event occuring during a callback. Output : TGF.Text_Box;
There is also an effect on program design, implementation,
and understanding. People learn to think of programs as procedure G_Click is
-- Empty

Ad a Use r Jou rn a l Vo lu me 22 , Nu mb e r 1, Ma rch 2 00 1


2 O ve rvie w o f A da G UI

begin -- G_Click checks of handling them all from the same set of callbacks.
Output.Set_Text There is no need to worry about when or how frequently
(Text => "Greetings"); events occur.
end G_Click;
Widgets are created by functions that return the ID of the
procedure H_Click is new widget. Operations take the ID of the widget to act on,
-- Empty with heavy use of preconditions to make sure that
begin -- H_Click operations are not applied to inappropriate widgets. Events
Output.Set_Text (Text => "Hello"); from the event queue contain the ID of the widget that
end H_Click; generated the event.

procedure Q_Click is 4 Example


-- Empty
begin -- Q_Click A simple example of the use of Ada GUI is provided by a
Output.Set_Text Luhn-checksum generator. Luhn checksums are used for
(Text => "Quitting"); the last digit of credit and debit card numbers and the like.
TGF.End_GUI;
end Q_Click; The program is given in Listing 1. The reader will note that
begin -- With_GUI the intuitive way of reading a program is preserved. First
TGF.Set_Up the program sets up the GUI, then obtains GUI events and
(Title => "Silly Example"); responds to them.
G.Create For a more complex example, the reader may want to see
(Text => "g", the Ada-GUI version of MP, a music player [3]. It
Click_Action => G_Click'Access);
demonstrates using separate parts of the program to deal
H.Create
with different operating modes. There is also an Ada-GUI
(Text => "h",
Click_Action => H_Click'Access); version of Mine Detector [2] which does not have to worry
Q.Create about event arrival timing.
(Text => "q",
Click_Action => Q_Click'Access); 5 Implementation
Output.Create; Ada GUI comes with an example implementation derived
TGF.Main_Loop;
from Gnoga, with many simplifications and modifications.
end With_GUI;
It uses a browser as its platform, making programs that use
it very portable. The implementation is also all Ada,
(TGF stands for Traditional GUI Framework; it is
making it easier for an Ada software engineer to
imaginary.) This can be read top-to-bottom, but even
understand. Other implementations are possible.
understanding how package TGF works, that doesn't give
much information. Instead, one must think in terms of
"when the user does this, the GUI calls that". The callbacks
6 Summary
normally have to modify the internal state of the program, The traditional GUI framework results in an unintuitive
and in many cases modify the GUI as well. Even for fairly approach to program implementation that can be difficult to
modest programs, the number of combinations can easily understand. The main reason for Ada GUI is to provide a
exceed the ability of the programmer or reader to keep GUI that preserves the intuitive way of writing and
them in mind. The checks within a callback to deal with the understanding programs. Ada GUI is conceptually quite
need for different actions for different cases can also simple and straightforward, and the example
become quite complex. implementation is all Ada. Ada-GUI programs should be
very portable, even to versions with alternative
3 Ada-Gui philosophy implementations.
The main idea behind Ada GUI is to use the features of
Ada to preserve the intuitive way of writing and
References
understanding programs. Ada is a concurrent language, so [1] J R Carter, Ada-GUI repository,
the GUI can have its own task to respond to events, https://github.com/jrcarter/Ada_GUI.
eliminating the need to register callbacks and give up the
thread of control. The GUI can put events on a protected [2] J R Carter, Mine-Detector respository,
queue; the program takes events from the queue when https://github.com/jrcarter/Mine_Detector.
appropriate for the program's logic. Significantly different [3] J R Carter, MP respository,
cases can be handled by separate parts of the program, https://github.com/jrcarter/MP
eliminating the combinatorial explosion and complex

Vo lu me 22 , Nu mb e r 1, Ma rch 2 00 1 A da Use r Jo u rna l


3

-- A program for generating Luhn checksums with an Ada_GUI UI


-- An Ada_GUI demo program
--
-- Copyright (C) 2022 by PragmAda Software Ebgineering
-- Released under the terms of the BSD 3-Clause license; see
-- https://opensource.org/licenses
--
with Ada.Exceptions;
with Ada.Text_IO;

with Ada_GUI;

procedure Luhn_Gen is
Input : Ada_GUI.Widget_ID;
Err : Ada_GUI.Widget_ID;
Checksum : Ada_GUI.Widget_ID;
Gen : Ada_GUI.Widget_ID;
Quit : Ada_GUI.Widget_ID;

procedure Generate;
-- Obtain input from the GUI and
-- calculate the checksum

Err_Msg : constant String := "Enter some digits";

procedure Generate is
subtype Digit is Character range '0' .. '9';

function Reversed (Value : String) return String;


-- Reverses Value.

function Squeezed (Value : String) return String;


-- Keeps the Digits of Value and discards any other characters.

function D2N (D : Digit) return Natural is


(Character'Pos (D) - Character'Pos ('0') );

function Reversed (Value : String) return String is


Result : String (Value'Range);
Last : Natural := Value'Last;
begin -- Reversed
if Value = "" then
return "";
end if;

Swap : for First in Value'First .. Value'First + (Value'Length - 1) / 2


loop
Result (First) := Value (Last);
Result (Last) := Value (First);
Last := Last - 1;
end loop Swap;

return Result;
end Reversed;

function Squeezed (Value : String) return String is


Result : String (1 .. Value'Length);
Last : Natural := 0;
begin -- Squeezed
All_Chars : for I in Value'Range loop
if Value (I) in Digit then
Last := Last + 1;
Result (Last) := Value (I);

Ad a Use r Jou rn a l Vo lu me 22 , Nu mb e r 1, Ma rch 2 00 1


4 O ve rvie w o f A da G UI

end if;
end loop All_Chars;

return Result (1 .. Last);


end Squeezed;

Forward : constant String := Input.Text;


Value : constant String := Squeezed (Reversed (Forward) );

Sum : Natural := 0;
D : Natural;
begin -- Generate
Err.Set_Text (Text => "");
Err.Set_Visibility (Visible => False);
Checksum.Set_Text (Text => "");

if Value'Length = 0 then
Err.Set_Visibility (Visible => True);
Err.Set_Text (Text => Err_Msg);

return;
end if;

All_Digits : for I in Value'Range loop


D := D2N (Value (I) );

if I rem 2 = 1 then
D := 2 * D;

if D > 9 then
D := D - 9;
end if;
end if;

Sum := Sum + D;
end loop All_Digits;

Checksum.Set_Text (Text => Integer'Image ( (9 * Sum) rem 10) );


exception -- Generate
when E : others =>
Ada.Text_IO.Put_Line (Item => "Generate: " &
Ada.Exceptions.Exception_Information (E) );
end Generate;

Event : Ada_GUI.Next_Result_Info;

use type Ada_GUI.Event_Kind_ID;


use type Ada_GUI.Widget_ID;
begin -- Luhn_Gen
Ada_GUI.Set_Up (Title => "Luhn Checksum Generator");

Input := Ada_GUI.New_Text_Box (Label => "Input :", Placeholder => Err_Msg);


Err := Ada_GUI.New_Background_Text (Break_Before => True);
Err.Set_Foreground_Color (Color => Ada_GUI.To_Color (Ada_GUI.Red) );
Err.Set_Visibility (Visible => False);
Checksum := Ada_GUI.New_Text_Box (Label => "Checksum :", Break_Before => True);
Gen := Ada_GUI.New_Button (Text => "Generate", Break_Before => True);
Quit := Ada_GUI.New_Button (Text => "Quit", Break_Before => True);

All_Events : loop
Event := Ada_GUI.Next_Event;

if not Event.Timed_Out then

Vo lu me 22 , Nu mb e r 1, Ma rch 2 00 1 A da Use r Jo u rna l


5

exit All_Events when Event.Event.Kind = Ada_GUI.Window_Closed;

if Event.Event.Kind = Ada_GUI.Left_Click then


if Event.Event.ID = Gen then
Generate;
end if;

exit All_Events when Event.Event.ID = Quit;


end if;
end if;
end loop All_Events;

Ada_GUI.End_GUI;
exception -- Luhn_Gen
when E : others =>
Ada.Text_IO.Put_Line (Item => Ada.Exceptions.Exception_Information (E) );
end Luhn_Gen;

Listing 1. A Luhn-Checksum Generator

Ad a Use r Jou rn a l Vo lu me 22 , Nu mb e r 1, Ma rch 2 00 1

You might also like