From Oldunreal-Wiki
Jump to navigation Jump to search

Part 1: Before We BeginPart 2: Creating and Using MenusPart 3: Tabbed PagesPart 4: Scrolling Client Areas

Part 1: Before We Begin

This tutorial assumes you are already familiar with the basics of programming the UWindows system. This includes making windows and client windows, adding controls to windows, adding a spot on the modmenu, and generally understanding the terminology. When I talk about ClientWindows and FramedWindows, I am going to assume that you know the difference between them. As such, I will not walk you through the process of doing these things. Please see my introductory tutorial for that type of help.

All of my class names begin with 'sq' (for Squidi), and then an uppercase abbreviation of what that particular item is. ClientWindows are CW, Framed Windows are FW, Menu Bars are MB, Menus are M, and so on. Then is the mod type (in this case "Tutorial"). After that, if it is necessary, is a description of the object. sqFWTutorial and sqCWTutorial are sufficient enough to distinguish a difference. However, individual menus might be called sqMTutorialGame and sqMTutorialHelp.

Part 2: Creating and Using Menus

To use menus in your configuartion windows, you need a way to get to the menu. This can be accomplished through a MenuBar, or through using Right Clicks to bring up a pop up menu. MenuBars are a little easier follow, so we'll start there. To create a Menu (and MenuBar), you must subclass the appropriate object (UWindowMenuBar and UWindowPulldownMenu). Since both MenuBars and Menus are descendents from UWindowDialogControl, they can both exist inside framed windows, and are created using the CreateControl() function.

In the following examples, I haven't implemented the tooltips helpbar that the main menu bar makes. It makes things a little more complicated. If you want to add in this help functionality, checkout UMenuGameMenu and the likes. Also, I won't go into Right Click menus at this time, as I'm unsure how Mac users do the right click. I don't want to promote an activity that I'm not sure everyone can participate in.

//====================================================================// sqMBTutorial.//====================================================================class sqMBTutorial expands UWindowMenuBar;

var UWindowPulldownMenu Game, Help;var UWindowMenuBarItem GameItem, HelpItem;

function Created(){


bAlwaysOnTop = False;

GameItem = AddItem("Game");Game = GameItem.CreateMenu(class'sqPMTutorialGame');

// For this menu, we are using the built in HelpMenu HelpItem = AddItem("Help"); Help = HelpItem.CreateMenu(class'UMenuHelpMenu');

Spacing = 12;


/**** Adding in the following code will make the menuBar drawn in the** current look and feel, as opposed to a generic gray one**** function DrawMenuBar(Canvas C)** {** LookAndFeel.Menu_DrawMenuBar(Self, C);** }******/

//====================================================================// sqPMTutorialGame.//====================================================================class sqPMTutorialGame expands UWindowPulldownMenu;

var UWindowPulldownMenuItem NewGame, Load, Save, GameOptions, Quit;

function Created(){


// Add menu items. NewGame = AddMenuItem("New Game", None); Load = AddMenuItem("Load", None); Save = AddMenuItem("Save", None); AddMenuItem("-", None); Quit = AddMenuItem("Quit", None);


function ExecuteItem(UWindowPulldownMenuItem I){

switch(I) {

case NewGame: // new game menu item was selected


case Load: // Load menu item was selected


case Save: // Save Menu Item was selected


case Quit: // Quit menu item was selected





Add the MenuBar to your window with the following code (in the clientwindow's Created() function): MenuBar = sqMBTutorial(CreateWindow(class'sqMBTutorial', 0, 0, WinWidth, 16));

And that's about it. You may want to put some code in the client window's Resized() function to change the width of the menuBar when the window changes sizes. Otherwise, the user may make the window larger than the menuBar, and you'll see empty space. Another thing of note is that you don't need to add a menuBar to the top of a window. You can put it anywhere. Just remember that the pulldown menus will drop below the menuBar no matter where the location is.

Part 3: Tabbed Pages

An example of Tabbed Pages can be seen in the preferences dialog. The window has several tabs at the top of the window which will select between the different pages of configurable options. Making a TabbedPage is incredibly easy. You just need to create a control of type UWindowPageControl, and then add the different pages to it. Each page is just a client window of type UWindowPageWindow. Since UWindowPageWindow is descended from UWindowDialogClientWindow, you create them in the same fashion as you would a normal client window. In fact, if you aren't really sure whether or not your client window will ever be used in a tabbed page, you can go ahead and make it a subclass of UWindowPageWindow anyway. The change is transparent to UWindows, and saves you from having to change parent classes if you decide later on to put it under a tab.

To create a tab control, just do the following in your client window's Created() function:

Pages = UWindowPageControl( CreateWindow(class'UWindowPageControl', 0, 0, WinWidth, WinHeight));

To add a page to the tab bar, just use the following code, where XXX is the class name of the Page Window you want to add. And that's it. The most important thing to remember is to subclass UWindowPageWindow for your client window needs.

Pages.AddPage("Test", class'XXX');

Part 4: Scrolling Client Areas

Maybe you've noticed that when you resize windows, the controls and content don't change. They are obscured by the edges of the window when it gets too small. One way to change this is to resize each of the controls when the window changes in size. My client window has the following code to make sure the menu bar and tabbed controls stay with proportion to the window's size. The function Resized() is called whenever the client area changes size.

function Resized(){


MenuBar.WinLeft = 0;MenuBar.WinTop = 0;MenuBar.WinWidth = WinWidth; MenuBar.WinHeight = 16; Pages.WinTop = 20; Pages.WinLeft = 10; Pages.WinWidth = WinWidth - 20; Pages.WinHeight = WinHeight - 30;


This works great because the menu bar and tab area always have a size relative to the window. But in cases where you have controls and other client windows, you can't always change their size small enough. The solution to this is to provide a scrollable area. The class UWindowScrollingDialogClient (which is a Page Window) provides scrollbars which allows its own client area to remain the same size and be scrolled around in.

They are really easy to use. Just like a framed window, they have a client class variable which will create the specified client area. This time the client window doesn't need to be a PageWindow. Here is some sample code (lifted straight out of UMenuHUDConfigScrollingClient)

class UMenuHUDConfigScrollClient extends UWindowScrollingDialogClient;

function Created(){

ClientClass = Class<UMenuPageWindow>(DynamicLoadObject( GetPlayerOwner().MyHUD.HUDConfigWindowType, class'Class'));



The scrolling client exists as an invisible layer between the client area, and the container in which the client area exists. Most of UT's dialogs use scrolling clients for the internal client areas. Then if the area is too large, or the user sets big fonts, the user can still get to every control. You should really use scrolling clients whenever you get the chance, as they add functionality which either is invisible to the user, or makes his life a lot easier. It does, however, add one more class to your user interface for each client area which uses it.