• Solutions
    • FERC XBRL Reporting
    • FDTA Financial Reporting
    • SEC Compliance
    • Windows Clipboard Management
    • Legato Scripting
  • Products
    • GoFiler Suite
    • XBRLworks
    • SEC Exhibit Explorer
    • SEC Extractor
    • Clipboard Scout
    • Legato
  • Education
    • Training
    • SEC and EDGAR Compliance
    • Legato Developers
  • Blog
  • Support
  • Skip to blog entries
  • Skip to archive page
  • Skip to right sidebar

Friday, October 28. 2016

Legato Developers Corner #7: Happy Halloween!

Happy Halloween, everyone! In the spirit of the holiday, this week we’ll take a look at a fun way to make your dialog box spooky by animating some Halloween-themed ASCII art.


We’ll cover some new topics this installment, including:

  1. Dialogs and dialog resources
  2. Event handlers
  3. Exploding a string
  4. Timers

Our Sample Script


    string	frames[];
    int		pos, size;

int main () {
    string	s1;
    int		rc;
    
    // Get our ASCII art
    s1 = GetScriptFolder() + "ascii art.txt";

    // Convert file to string
    s1 = FileToString(s1);
    if (s1 == "") {
      rc = GetLastError();
      MessageBox('x', "Error opening frames (%08X)",rc);
      return rc;
      }

    // Break string into array by line endings
    frames = ExplodeString(s1);

    // Get the size of the array
    size = ArrayGetAxisDepth(frames);

    // Open our dialog box
    DialogBox("Holiday", "holiday_");

    return ERROR_NONE;
    }

// Event handler: dialog box load
int holiday_load() {

    ControlChangeFont(100, "Mono");
    EditSetText(100, "\r\r\r       Press Start    ");

    }

// Event handler: dialog action
int holiday_action(int id, int action) {

    // If Start was pressed, start timer
    if (id == 101) {
      pos = 0;
      DialogSetTimer(75, 1);
      }

    // If Stop was pressed, end timer
    if (id == 102) {
      DialogKillTimer(1);
      EditSetText(100, "\r\r\r       Press Start    ");
      }
    return ERROR_NONE;
    }

// Event handler: dialog box timer 
int holiday_timer(int id) {
    string	s1;
    
    // Reset to the beginning if at end
    if (pos >= size) { pos = 0; }

    // As long as less than end and not an empty string, build our frame from ASCII strings
    while ((pos < size) && (frames[pos] != "")) {
      s1 += frames[pos] + "\r\n";
      pos++;
      }

    pos++; 

    // Set the text of static control on dialog box
    EditSetText(100, s1);
    return ERROR_NONE;
    }


#beginresource

Holiday DIALOG 0, 0, 275, 190
EXSTYLE WS_EX_DLGMODALFRAME
STYLE DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "BOOOOO!"
FONT 8, "MS Sans Serif"
{
 CONTROL "Start", 101, "BUTTON", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 70, 172, 30, 12
 CONTROL "Stop", 102, "BUTTON", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 170, 172, 30, 12
 CONTROL "", 100, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 6, 0, 274, 170, 0
}

#endresource

Script Walkthrough


Our concept this week is pretty simple. We want to open a dialog box, allow the user to interact with the dialog box via a couple controls (buttons), and animate some text within the box. The Legato SDK provides an entire library of functions to create and control dialogs, from standard message boxes to more complicated custom dialogs. See the Legato SDK for more information on dialogs and how to use them. In this case, we’re going to create a
simple custom dialog box using a dialog resource:


#beginresource

Holiday DIALOG 0, 0, 275, 190
EXSTYLE WS_EX_DLGMODALFRAME
STYLE DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "BOOOOO!"
FONT 8, "MS Sans Serif"
{
 CONTROL "Start", 101, "BUTTON", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 70, 172, 30, 12
 CONTROL "Stop", 102, "BUTTON", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 170, 172, 30, 12
 CONTROL "", 100, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 6, 0, 274, 170, 0
}

#endresource

In Legato, resource templates like this one can occur in a script file itself or in a separate file with an “.rc” extension. Resource templates are required for the script to be able to create a dialog. Here we are using a simple dialog with the attributes as listed above. Again, for complete instructions concerning dialog resource templates, see the Legato Documentation. As defined in the dialog template’s header, our custom dialog box
has “BOOOOO!” as its caption and other parameters, such as being modal and visible. It also has three controls: two buttons labeled “Start” and “Stop” and a static box control where we will be rendering our ASCII art. We place our resource template at the end of the script file nestled in between #beginresource and #endresource statements.


Now that we have a dialog template, let’s do something fun with it. We first declare a global string array to hold our ASCII text frames and a couple of global integers for position and size. Let’s look at our main function.


int main () {
    string	s1;
    int		rc;
    
    s1 = GetScriptFolder() + "ascii art.txt";
    s1 = FileToString(s1);
    if (s1 == "") {
      rc = GetLastError();
      MessageBox('x', "Error opening frames (%08X)",rc);
      return rc;
      }
    frames = ExplodeString(s1);
    size = ArrayGetAxisDepth(frames);

    DialogBox("Holiday", "holiday_");

    return ERROR_NONE;
    }

Our main function loads our text file, which contains our “frames” of ASCII text delimited by return characters (“\r” or “\r\n”), into a string. We do this with the FiletoString SDK function, which we have mentioned in previous weeks. Assuming we are able to read our file, we then use a second SDK function, ExplodeString, to separate our string into lines. These are simply separate strings that together comprise an entire “frame” of ASCII text animation, and each frame is separated by an empty string as per our source file and the blank lines that separate the frames. We store the text lines in our global string array. Note that the ExplodeString function can use any delimiter to separate a string into an array of strings, but if no delimiter is specified, it uses return characters, which is exactly what we want here. We can store the size of our array using the ArrayGetAxisDepth SDK function.


Now we load our dialog box. We do this with the DialogBox SDK function. We need to pass two parameters to this function: the name of the resource template (“Holiday”), and the prefix of the functions that will handle this dialog’s events (“holiday_”). Legato controls the message loop for dialog boxes and provides default functions to handle events pertaining to the dialog (such as exiting the dialog). As with other scripting languages like Javascript, you as the programmer write event handlers that override the default behavior the dialog box has. This isn’t necessary, but we want to control how this dialog behaves so we’ll point the script toward our own set of event handlers.


That’s all our main function does. At this point, our “Holiday” dialog loads. Let’s take a look at our event handlers. Our _load function will execute first:


int holiday_load() {

    ControlChangeFont(100, "Mono");
    EditSetText(100, "\r\r\r       Press Start    ");

    }


It’s pretty simple. We change our dialog font using the ControlChangeFont SDK function (note that the ControlChangeFont function is only available in version 4.15b of GoFiler Complete and later). We also set some text using the EditSetText SDK function, targeting our static control via its ID. We instruct our users to press the Start button to get our animation going.


int holiday_action(int id, int action) {

    if (id == 101) {
      pos = 0;
      DialogSetTimer(75, 1);
      }
    if (id == 102) {
      DialogKillTimer(1);
      EditSetText(100, "\r\r\r       Press Start    ");
      }
    return ERROR_NONE;
    }

Our main event handler is the _action function, which is executed when the user interacts with the dialog box through either of its two button controls. This function receives two parameters: the id, which is the ID of the control that fired the event, and the action, which is the submessage. In this case, we want to know which button the user pressed and execute accordingly. The id will match the ID of the control as specified in our dialog template, so we can check to see if the Start or Stop button was pressed. If it’s the Start button, we set our position to zero with the pos variable and begin our timer using the DialogSetTimer SDK function. This function sets a timer within the dialog, which we create here with a 75 ms interval. Every tick of the timer fires an event that can be handled by our _timer function.


int holiday_timer(int id) {
    string	s1;
    
    if (pos >= size) { pos = 0; }

    while ((pos < size) && (frames[pos] != "")) {
      s1 += frames[pos] + "\r\n";
      pos++;
      }

    pos++; 
    EditSetText(100, s1);
    return ERROR_NONE;
    }

The _timer function is what actually performs our “animation”. First, we check to see if our current position within the array (pos) is greater than the array size. Again, these are global variables, so they maintain their value outside our event handler functions. If we’ve finished our animation by moving in the array to the last line of text, we reset to the beginning. Then, using a while loop, we concatenate our lines together to make a frame. We go through the array, line by line, until we encounter the end of a frame, which is denoted by an empty string. Then we again use the SDK function EditSetText to set our static frame, with the control ID of 100, to contain the value of our string.


Our timer runs indefinitely until the user presses the Stop button. Back in our _action event handler, we execute the code in the if block matching our Stop button’s ID.


    if (id == 102) {
      DialogKillTimer(1);
      EditSetText(100, "\r\r\r       Press Start    ");
      }

Once the user presses Stop, we end our timer with the DialogKillTimer SDK function and reset our static frame to the instructions with which we began.


So there you have it, a way to animate ASCII text in a custom dialog within Legato using timers, strings, and event handlers. I hope this introduction to dialogs and events is helpful, and have a frightful Halloween!


A screenshot of the dialog created by the Legato Script.

Download the ascii art.txt!



 




Maggie Gardner joined Novaworks in the summer of 2016 but has been working with Legato since its release in 2015. She has over ten years experience programming in SAS, PHP and C++.


Additional Resources

Novaworks’ Legato Resources

Legato Script Developers LinkedIn Group

Primer: An Introduction to Legato 


Posted by
Margaret Gardner
in Development at 12:52
Trackbacks
Trackback specific URI for this entry

No Trackbacks

Comments
Display comments as (Linear | Threaded)
No comments
The author does not allow comments to this entry

Quicksearch

Categories

  • XML Accounting
  • XML AICPA News
  • XML FASB News
  • XML GASB News
  • XML IASB News
  • XML Development
  • XML Events
  • XML FERC
  • XML eForms News
  • XML FERC Filing Help
  • XML Filing Technology
  • XML Information Technology
  • XML Investor Education
  • XML MSRB
  • XML EMMA News
  • XML FDTA
  • XML MSRB Filing Help
  • XML Novaworks News
  • XML GoFiler Online Updates
  • XML GoFiler Updates
  • XML XBRLworks Updates
  • XML SEC
  • XML Corporation Finance
  • XML DERA
  • XML EDGAR News
  • XML Investment Management
  • XML SEC Filing Help
  • XML XBRL
  • XML Data Quality Committee
  • XML GRIP Taxonomy
  • XML IFRS Taxonomy
  • XML US GAAP Taxonomy

Calendar

Back May '25 Forward
Mo Tu We Th Fr Sa Su
Saturday, May 17. 2025
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  

Feeds

  • XML
Sign Up Now
Get SEC news articles and blog posts delivered monthly to your inbox!
Based on the s9y Bulletproof template framework

Compliance

  • FERC
  • EDGAR
  • EMMA

Software

  • GoFiler Suite
  • SEC Exhibit Explorer
  • SEC Extractor
  • XBRLworks
  • Legato Scripting

Company

  • About Novaworks
  • News
  • Site Map
  • Support

Follow Us:

  • LinkedIn
  • YouTube
  • RSS
  • Newsletter
  • © 2024 Novaworks, LLC
  • Privacy
  • Terms of Use
  • Trademarks and Patents
  • Contact Us