2.4. A complete demo program: WindowsExample.g

This tutorial demonstrates more widgets and useful features.

Output

Code

require ("Application");
require ("WindowsSupport");

class WindowsExample Application
{
	menu_actions;
	menu_items;
	win;
}

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

	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: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:UpdateFrequency = 1));
	b0.CommandHandler (BN_CLICKED, b2.GetDlgCtrlID(),
		`((@b0).IsDlgButtonChecked((@b2).GetDlgCtrlID()) == 0 ? nil :
		  $DataSim:UpdateFrequency = 10));
		  
	win.onChange (#$DataSim:UpdateFrequency,
					`(@b).SetCheck (value == 1 ? 1 : 0));
	win.onChange (#$DataSim:UpdateFrequency,
					`(@b2).SetCheck (value == 10 ? 1 : 0));

	txt = win.CreateControl (GStatic, 20, 80, 70, 25, "Transparency");
	tb = .win.CreateControl (GTrackBarCtrl, 90, 80, 280, 25, "Transparency");
	tb.SetRange (50, 255, 5);
	tb.ModifyStyle (0, TBS_AUTOTICKS, 0);
	tb.SetTicFreq (5);
	tb.SetPos (255);
	.win.MessageHandler (WM_HSCROLL, `(@self).SetTransparency((@tb).GetPos()));

	// Make a field for entering Gamma commands
	txt = win.CreateControl (GammaEntry, 20, 115, 350, 20, "command");
	txt.SetBackground (0, GetSysColor (COLOR_WINDOW), 0);
	win.AddControlResizeFlags (txt.GetDlgCtrlID(), DLSZ_SIZE_X);
	txt.SetWindowText ("Type a gamma command here, then press Enter");

	// 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);
	.AddMenus();

	win.ShowWindow (SW_SHOW);
}

method WindowsExample.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();
		}
	}
	if (!destroyed_p (.win))
		.win.DestroyWindow();
}

method WindowsExample.SetTransparency (alpha)
{
	// This bit of code makes the window translucent.
	.win.ModifyStyleEx (0, WS_EX_LAYERED);
	SetLayeredWindowAttributes (.win.GetHwnd(), 0, alpha, LWA_ALPHA);
}

/* ======= An entry field that evaluates its input as Gamma ======= */

class GammaEntry GEdit
{
}

method GammaEntry.constructor ()
{
	.MessageHandler (WM_CHAR, `(@self).SubmitEval ());
}

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

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

/* ======= Print something when the user selects a file ====== */
/* This is an example of how to use the global hook on
   a file dialog to act on any file selection. */

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

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

MenuItemID := 10000;

method WindowsExample.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 WindowsExample.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 WindowsExample.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 WindowsExample.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 Dialog1 GWindow
{
	win;
	stHeader;
	stSine;
	stRamp;
	stTriangle;
	stSquare;
}

method WindowsExample.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;
	.win.Create (parent, rect, "tab", WS_CHILDWINDOW, 0);

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

	.stRamp = .win.CreateControl (GStatic, 5, row += drow, w, h, "Ramp");
	.win.onChange (#$DataSim:Ramp, `WindowsExample_update (@.stRamp, this));
	WindowsExample_update (.stRamp, #$DataSim:Ramp);
	
	.stTriangle = .win.CreateControl (GStatic, 5, row += drow, w,
									  h, "Triangle");
	.win.onChange (#$DataSim:Triangle, `WindowsExample_update (@.stTriangle, this));
	WindowsExample_update (.stTriangle, #$DataSim:Triangle);
	
	.stSquare = .win.CreateControl (GStatic, 5, row += drow, w, h, "Square");
	.win.onChange (#$DataSim:Square, `WindowsExample_update (@.stSquare, this));
	WindowsExample_update (.stSquare, #$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: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;
}

method WindowsExample.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.Create (parent, rect, "tab", WS_CHILDWINDOW, 0);

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

	.stFrequency = .win.CreateControl (GStatic, 5, row += drow, w, h, "Frequency");
	.win.onChange (#$DataSim:Frequency, `WindowsExample_update(@.stFrequency, this));
	WindowsExample_update (.stFrequency, #$DataSim:Frequency);
	
	.stOffset = .win.CreateControl (GStatic, 5, row += drow, w, h, "Offset");
	.win.onChange (#$DataSim:Offset, `WindowsExample_update(@.stOffset, this));
	WindowsExample_update (.stOffset, #$DataSim:Offset);
	
	.stUpdateFrequency = .win.CreateControl (GStatic, 5, row += drow, w, h, "UpdateFrequency");
	.win.onChange (#$DataSim:UpdateFrequency,
				   `WindowsExample_update(@.stUpdateFrequency, this));
	WindowsExample_update (.stUpdateFrequency, #$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:UpdateFrequency,
				   `(@tb).SetPos (value));
	if (!undefined_p($DataSim:UpdateFrequency))
		tb.SetPos ($DataSim:UpdateFrequency);
	win;
}

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

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

class Dialog3 GWindow
{
	win;
	lv;
}

method WindowsExample.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");

	/* One way to modify the list after it has been created is to search for an
	   entry by its column-zero text and then modify the sub-items. */
	local finfo = new LVFINDINFO();
	finfo.flags = LVFI_STRING;
	finfo.psz = "Chirpy";
	local item = .lv.FindItem (finfo, 0);
	.lv.SetItemText (item, 1, "Nobody");
	
	.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);
}

/* ======================== Support functions ==================== */

function WindowsExample_update (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));
	}
}

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

ApplicationSingleton (WindowsExample);