2.4. A complete demo program: wtltest.g

This tutorial demonstrates more widgets and useful features.

Output

Code

if (!require ("WindowsSupport"))
    error ("Could not load Windows support file");

class MonitorWindow
{
    menu_actions;
    menu_items;
}

method MonitorWindow.constructor ()
{
    local    win = new GWindow();
    local    rect = CreateRect(10, 10, 400, 400);
    local    b, dt, txt;
    
    win.Create (0, rect, "Monitor", WS_OVERLAPPEDWINDOW, 0);

    // This bit of code makes the window translucent.
    // win.ModifyStyleEx (0, WS_EX_LAYERED);
    // SetLayeredWindowAttributes (win.GetHwnd(), 0, 150, LWA_ALPHA);

    win.SetBackground (0, GetSysColor (COLOR_3DFACE), 0);
    win.SetChildBackground (0, GetSysColor (COLOR_3DFACE), 0);
    win.MessageHandler (WM_DESTROY, `destroy (@self));

    txt = win.CreateControl (GStatic, 20, 5, 350, 20,
                             "Start DataSim to see live data here");
    txt.SetForeground (0, 0, 0xff0000);
    txt.SetFontEx (20, 8, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, "Times");
    win.onChange (#$DataSim:DataSim.Sine,
                  `(@txt).SetWindowText(format ("%a = %.4f", this, value)));

    b0 = win.CreateControl (GGroupBox, 20, 30, 350, 40,
                           "Radio Buttons");
    win.AddControlResizeFlags (b0.GetDlgCtrlID(), DLSZ_SIZE_X);
    b = b0.CreateControl (GRadioButton, 10, 10, 150, 25,
                           "UpdateFrequency = 1");
    b2 = b0.CreateControl (GRadioButton, 180, 10, 150, 25,
                           "UpdateFrequency = 10");
    b0.AddControlResizeFlags (b2.GetDlgCtrlID(), DLSZ_MOVE_X);
    
    b0.CommandHandler (BN_CLICKED, b.GetDlgCtrlID(),
        `((@b0).IsDlgButtonChecked((@b).GetDlgCtrlID()) == 0 ? nil :
          $DataSim:DataSim.UpdateFrequency = 1));
    b0.CommandHandler (BN_CLICKED, b2.GetDlgCtrlID(),
        `((@b0).IsDlgButtonChecked((@b2).GetDlgCtrlID()) == 0 ? nil :
          $DataSim:DataSim.UpdateFrequency = 10));
//    AddButtonToggle (b0, b, #$DataSim:DataSim.UpdateFrequency, 1, 10,
//                     "Set update rate = 10",
//                     "Set update rate = 1");

    dt = win.CreateControl (GDateTimePickerCtrl, 20, 80, 150, 25, "Picker");
    dt.SetBackground (0, GetSysColor (COLOR_WINDOW), 0);

    // Make a field for entering Gamma commands
    txt = win.CreateControl (GEdit, 20, 115, 350, 20, "command");
    txt.MessageHandler (WM_CHAR, `SubmitEval ((@txt)));
    txt.SetBackground (0, GetSysColor (COLOR_WINDOW), 0);
    win.AddControlResizeFlags (txt.GetDlgCtrlID(), DLSZ_SIZE_X);
    
    txt.SetWindowText ("Type gamma command here");

    // Make a tab control.

    tab = win.CreateControl (GTabCtrl, 20, 150, 350, 200, "tabs");
    tab.ModifyStyle (TCS_TABS | TCS_RAGGEDRIGHT, TCS_FOCUSONBUTTONDOWN | TCS_FIXEDWIDTH);
    tab.SetChildBackground (0, 0xc0ffff, 0);
    
    tab.AddWindow (0, "Waveforms", CreateDialog1 (tab.GetHwnd(), ""));
    tab.AddWindow (1, "Parameters", CreateDialog2 (tab.GetHwnd(), ""));
    tab.AddWindow (2, "List", CreateDialog3 (tab.GetHwnd(), ""));
    win.AddControlResizeFlags (tab.GetDlgCtrlID(), DLSZ_SIZE_X | DLSZ_SIZE_Y);
    win.NotifyHandler (TCN_SELCHANGE, tab.GetDlgCtrlID(),
                       `(@tab).SelChange());
    tab.SetCurSel (0);
    
//    if (get_tray_menu() == 0)
//        after (2, `(@self).AddMenus());
//    else
        .AddMenus();

    win.ShowWindow (SW_SHOW);
}

method MonitorWindow.destructor ()
{
    local        id, count, traymenu, i, item;

    try
    {
        with x in .menu_actions do
            remove_menu_action (car(x), cdr(x));
    }
    catch
    {
        princ ("Error: ", _last_error_, "\n");
        print_stack();
    }
    
    with x in .menu_items do
    {
        try
        {
            id = car(x);
            traymenu = get_tray_menu();
            count = GetMenuItemCount (traymenu);
            item = new MENUITEMINFO;
            item.cbSize = 48;
            item.fMask = MIIM_ID | MIIM_SUBMENU;
        
            if (cdr(x)) // id is a submenu hmenu
            {
                for (i=0; i<count; i++)
                {
                    if (GetMenuItemInfo (traymenu, i, 1, item) != 0
                        && item.hSubMenu == id)
                        DeleteMenu (traymenu, i, MF_BYPOSITION);
                }
            }
            else // id is a menu item command id
            {
                for (i=0; i<count; i++)
                {
                    if (GetMenuItemInfo (traymenu, i, 1, item) != 0
                        && item.wID == id)
                        DeleteMenu (traymenu, i, MF_BYPOSITION);
                }
            }
        }
        catch
        {
            princ ("Error: ", _last_error_, "\n");
            print_stack();
        }
    }
}

function Typing (txt)
{
    local str = txt.GetWindowText();
    princ (str, "\n");
}

function SubmitEval (txt)
{
    if (wParam == VK_RETURN)
    {
        local str = txt.GetWindowText();
        princ (str, "\n");
        local x = eval_string (string(str,";"), t);
        princ ("    ");
        pretty_print (x);
        terpri();
        //        show_log();
    }
    nil;
}

/* =============== Add menu items to the tray menu =========== */

MenuItemID := 10000;

method GFileDialog.OnSelChange ()
{
    local    buf = make_buffer(256);
    .GetFilePath (buf, 256);
    princ ("Selection changed: ", buffer_to_string(buf), "\n");
}

method MonitorWindow.SelectTrayMenuItem (id)
{
    local        win = new GColorDialog();
    princ ("HWND: ", win.m_hWnd, " = ", win.GetHwnd(), "\n");
    local        result = win.DoModal(0);
    if (result == 1)
    {
        princ ("You chose the color: ", hex(win.GetColor()), "\n");
    }
}

method MonitorWindow.AddSubMenu (parent, pos, label)
{
    local    submenu = CreatePopupMenu();
    InsertMenu (traymenu, pos, MF_BYPOSITION | MF_POPUP,
                submenu, label);
    .menu_items = cons (cons (submenu, t), .menu_items);
    submenu;
}

method MonitorWindow.AddMenuItem (parent, pos, label, code)
{
    local    info = new MENUITEMINFO();
        
    info.cbSize = 48;
    info.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID;
    info.fType = MFT_STRING;
    info.wID = ++MenuItemID;
    info.dwTypeData = label;
    InsertMenuItem (parent, pos, 1, info);
    local action = add_menu_action (MenuItemID, code);
    .menu_actions = cons (action, .menu_actions);
}

method MonitorWindow.AddMenus ()
{
    local        traymenu = get_tray_menu ();

    if (traymenu != 0)
    {
        local    submenu = .AddSubMenu (traymenu, 5, "Monitor Functions");

        .AddMenuItem (submenu, -1, "Select Color", 
                      `(@self).SelectTrayMenuItem (@MenuItemID+1));
        .AddMenuItem (submenu, -1, "Select File",
                      `new GFileDialog (1).DoModal(0));
        .AddMenuItem (submenu, -1, "Select Folder",
                      `new GFolderDialog ().DoModal(0));
    }
    else
    {
    }
}

/* ==== A dialog within the first tab in the tab control ==== */

class Font
{
    m_hFont;
}

method Font.Create(nHeight,               // height of font
                   nWidth,                // average character width
                   nEscapement,           // angle of escapement
                   nOrientation,          // base-line orientation angle
                   fnWeight,              // font weight
                   fdwItalic,           // italic attribute option
                   fdwUnderline,        // underline attribute option
                   fdwStrikeOut,        // strikeout attribute option
                   fdwCharSet,          // character set identifier
                   fdwOutputPrecision,  // output precision
                   fdwClipPrecision,    // clipping precision
                   fdwQuality,          // output quality
                   fdwPitchAndFamily,   // pitch and family
                   lpszFace)           // typeface name
{
    m_hFont = CreateFontA (nHeight,
                           nWidth,
                           nEscapement,
                           nOrientation,
                           fnWeight,
                           fdwItalic,
                           fdwUnderline,
                           fdwStrikeOut,
                           fdwCharSet,
                           fdwOutputPrecision,
                           fdwClipPrecision,
                           fdwQuality,
                           fdwPitchAndFamily,
                           lpszFace);
}

method Font.destructor()
{
//     if (m_hFont)
//         DeleteObject (m_hFont);
}

class Dialog1 GWindow
{
    win;
    stHeader;
    stSine;
    stRamp;
    stTriangle;
    stSquare;
}

function CreateDialog1 (parent, str)
{
    local    win = new Dialog1();
    win.Init (parent, str);
    win;
}

method Dialog1.Init (parent, str)
{
    local        rect = CreateRect(10, 10, 10, 10);
    local        row = 5, drow = 30, w = 290, h = 20;

    .win = self;

    //    .SetBackground(0, 0x00ff00, 0);
    //    .SetChildBackground(0, 0x00ff00, 0);
    .win.Create (parent, rect, "tab", WS_CHILDWINDOW, 0);

    .stSine = .win.CreateControl (GStatic, 5, row, w, h, "Sine");
    .win.onChange (#$DataSim:DataSim.Sine, `update (@.stSine, this));
    update (.stSine, #$DataSim:DataSim.Sine);

    .stRamp = .win.CreateControl (GStatic, 5, row += drow, w, h, "Ramp");
    .win.onChange (#$DataSim:DataSim.Ramp, `update (@.stRamp, this));
    update (.stRamp, #$DataSim:DataSim.Ramp);
    
    .stTriangle = .win.CreateControl (GStatic, 5, row += drow, w,
                                      h, "Triangle");
    .win.onChange (#$DataSim:DataSim.Triangle, `update (@.stTriangle, this));
    update (.stTriangle, #$DataSim:DataSim.Triangle);
    
    .stSquare = .win.CreateControl (GStatic, 5, row += drow, w, h, "Square");
    .win.onChange (#$DataSim:DataSim.Square, `update (@.stSquare, this));
    update (.stSquare, #$DataSim:DataSim.Square);

    link = .win.CreateControl (GHyperLink, 5, row += drow, w, h,
                               "http://www.cogent.ca");
    link.SetHyperLink ("http://www.cogent.ca");
    link.SetLabel ("Visit Cogent's web page");
    link.SetLinkFont (GetStockObject (DEFAULT_GUI_FONT));
    link.ShowWindow (SW_SHOW);
    
    .win.onChange (#$DataSim:DataSim.Square,
                   `progn {
        if (value < 0)
        {
            (@win).SetBackground (0, 0xc0ffff, 0);
            (@win).SetChildBackground (0, 0xc0ffff, 0);
        }
        else
        {
            (@win).SetBackground (0, 0xffffff, 0);
            (@win).SetChildBackground (0, 0xffffff, 0);
        }
        (@win).Invalidate();
    });
    
    win;
}

/* ==== A dialog within the second tab in the tab control ==== */

class Dialog2 GWindow
{
    win;
    stHeader;
    stAmplitude;
    stFrequency;
    stOffset;
    stUpdateFrequency;
}

function CreateDialog2 (parent, str)
{
    local    win = new Dialog2();
    win.Init (parent, str);
    win;
}

method Dialog2.Init (parent, str)
{
    local        rect = CreateRect(10, 10, 10, 10);
    local        row = 5, drow = 30, w = 290, h = 20;

    .win = self;

    //    .win.SetBackground (0, GetSysColor (COLOR_3DFACE), 0);
    //.win.SetChildBackground (0, GetSysColor (COLOR_3DFACE), 0);
    .win.Create (parent, rect, "tab", WS_CHILDWINDOW, 0);

    .stAmplitude = .win.CreateControl (GStatic, 5, row,
                                       w, h, "Amplitude");
    .win.onChange (#$DataSim:DataSim.Amplitude, `update(@.stAmplitude, this));
    update (.stAmplitude, #$DataSim:DataSim.Amplitude);

    .stFrequency = .win.CreateControl (GStatic, 5, row += drow,
                                       w, h, "Frequency");
    .win.onChange (#$DataSim:DataSim.Frequency, `update(@.stFrequency, this));
    update (.stFrequency, #$DataSim:DataSim.Frequency);
    
    .stOffset = .win.CreateControl (GStatic, 5, row += drow, w,
                                    h, "Offset");
    .win.onChange (#$DataSim:DataSim.Offset, `update(@.stOffset, this));
    update (.stOffset, #$DataSim:DataSim.Offset);
    
    .stUpdateFrequency = .win.CreateControl (GStatic, 5, row += drow,
                                             w, h, "UpdateFrequency");
    .win.onChange (#$DataSim:DataSim.UpdateFrequency,
                   `update(@.stUpdateFrequency, this));
    update (.stUpdateFrequency, #$DataSim:DataSim.UpdateFrequency);

    local    tb = .win.CreateControl (GTrackBarCtrl, 5, row += drow,
                                     w, h, "FreqBar");
    
    tb.SetRange (0, 20, 1);
    tb.ModifyStyle (0, TBS_AUTOTICKS, 0);
    tb.SetTicFreq (2);
    .win.MessageHandler (WM_HSCROLL, `(@self).Scrolled(@tb));
    .win.onChange (#$DataSim:DataSim.UpdateFrequency,
                   `(@tb).SetPos (value));
    if (!undefined_p($DataSim:DataSim.UpdateFrequency))
        tb.SetPos ($DataSim:DataSim.UpdateFrequency);

    //    b = win.CreateControl (GButton, 20, 50, 150, 25, "Button 1");
    //    dt = win.CreateControl (GDateTimePickerCtrl, 20, 80, 150, 25, "Picker");
    //    txt = win.CreateControl (GStatic, 20, 20, 160, 20, "Text");
    win;
}

method Dialog2.Scrolled (tb)
{
    $DataSim:DataSim.UpdateFrequency = tb.GetPos();
}

/* ==== A dialog containing a List box ==== */

class Dialog3 GWindow
{
    win;
    lv;
}

function CreateDialog3 (parent, str)
{
    local    win = new Dialog3();
    win.Init (parent, str);
    win;
}

method Dialog3.AddPet (name, owner, species)
{
    local        n = .lv.GetItemCount();
    .lv.InsertItem (n, name);
    .lv.SetItemText (n, 1, owner);
    .lv.SetItemText (n, 2, species);
}

method Dialog3.Init (parent, str)
{
    local        rect = CreateRect(10, 10, 10, 10);
    local        w = 10, h = 10;

    .win = self;

    .win.SetBackground (0, GetSysColor (COLOR_3DFACE), 0);
    .win.Create (parent, rect, "tab", WS_CHILDWINDOW, 0);

    .lv = .CreateControl (GListViewCtrl, 0, 0, w, h, "lv");
    
    .lv.SetViewType (1);
    .lv.SetExtendedListViewStyle (LVS_EX_FULLROWSELECT | LVS_EX_ONECLICKACTIVATE, 
                                  LVS_EX_FULLROWSELECT /*| LVS_EX_ONECLICKACTIVATE*/);
    
    .lv.InsertColumn (0, "Pet", 0, 100, 0);
    .lv.InsertColumn (1, "Owner", 0, 100, 0);
    .lv.InsertColumn (2, "Species", 0, 100, 0);
    .lv.SetBackground (0, 0xffffff, 0);
    .AddPet ("Fluffy","Harold","cat");
    .AddPet ("Claws","Gwen","cat");
    .AddPet ("Buffy", "Harold", "dog");
    .AddPet ("Fang", "Benny", "dog");
    .AddPet ("Bowser", "Diane", "dog");
    .AddPet ("Chirpy", "Gwen", "bird");
    .AddPet ("Whistler", "Gwen", "bird");
    .AddPet ("Slim", "Benny", "snake");
    .AddPet ("Blob", "Benny", "slug");

    .win.AddControlResizeFlags (.lv.GetDlgCtrlID(), DLSZ_SIZE_X | DLSZ_SIZE_Y);

    .win.NotifyHandler (LVN_ITEMACTIVATE, .lv.GetDlgCtrlID(),
                        `(@self).SelectedItems(@(.lv)));
    .win;
}

method Dialog3.SelectedItems (lv)
{
    local        i, n = lv.GetItemCount(), state, items;
    for (i=0; i<n; i++)
    {
        if ((state = lv.GetItemState (i, LVIS_SELECTED)) != 0)
            items = cons (i, items);
    }
    princ (reverse(items), "\n");
    reverse (items);
}

/* ===================== More support functions ================ */

function show_value (win, point)
{
    local        val, i;
    if (!undefined_p (val = eval(point)))
    {
        point = string (point);
        if ((i = strchr (point, ':')) != -1)
            point = substr (point, i+1, -1);
        win.SetWindowText (format ("%s = %.4f", point, val));
    }
}

function update (win, point)
{
    show_value (win, point);
}

function AddButtonToggle (win, control, point, val1, val2, txt1, txt2)
{
    win.CommandHandler (BN_CLICKED, control.GetDlgCtrlID(),
                        `toggle (#@point, @control, @val1, @val2,
                                 @txt1, @txt2));
    win.onChange (point, `toggle_update (@control, #@point,
                                         @val1, @val2, @txt1, @txt2));
    toggle_update (control, point, val1, val2, txt1, txt2);
}

function toggle_update (control, point, val1, val2, txt1, txt2)
{
    /* This could run before the data points are created, which
       would give us an undefined symbol. */
    local        curval;

    /* the undefined_p function squelches an error that would
       otherwise be thrown on an undefined symbol error. */
    undefined_p(curval = eval(point));

    if (undefined_p(curval) || curval == val1)
        control.SetWindowText (txt1);
    else
        control.SetWindowText (txt2);
}

function toggle (point, control, val1, val2, txt1, txt2)
{
    /* This could run before the data points are created, which
       would give us an undefined symbol. */
    local        curval;
    undefined_p(curval = eval(point));
    
    if (undefined_p(curval) || curval == val1)
    {
        set (point, val2);
        control.SetWindowText (txt2);
    }
    else
    {
        set (point, val1);
        control.SetWindowText (txt1);
    }
}

/* ============================= Run It ========================== */

new MonitorWindow();