Background

One of the design goals for Windows 8 Modern Apps is to reduce the amount of chrome on the User Interface.  Chrome in this use doesn’t mean the browser, but the amount of non data related controls and widgets on the screen.  Such as buttons, links, tabs, etc.  The initial guidance wanted to remove essentially ALL chrome, but with Windows 8.1, that has been relaxed a bit.  Now, the goal is to remove all unnecessary chrome from the user interface, still using the AppBar, the NavBar, and the Windows 8 Charms to handle most of what developers would have traditionally placed in the main layout.

In my last blog series (starting with Setting HTML Styles with Binding in Windows 8 WinJS Apps ), I definitely broke the rules! As you can see in Figure 1, there is a LOT of chrome on this screen, especially the section highlighted in red.

image
Figure 1 – Way too much chrome!

The ToggleSwitches might get used once or twice, and while the perform an important function, they are not pertinent to the user on a daily basis.  We could move them to the AppBar (or even move them to a fly out), but over time this will just continue to grow until it resembles the Visual Studio Options Dialog!  (Note: The VS Options Dialog has become so large it has its own search!)

The RadialMenu to the Rescue

One extremely effective way to reduce the amount of chrome on the UI is to utilize the RadialMenu control.  The RadialMenu stays neatly hidden until needed, and then only shows a small gear icon called into context.  When the user wants to change settings, the gear opens up to a full options wheel, complete with nested items to maximize utilization while minimizing its own footprint. Figure 2 shows the same form with the RadialMenu minimized (as we’ll see, it’s in focus when any of the text in the body of the screen is in focus) and Figure 3 shows the menu expanded.

image

Figure 2 – RadialMenu minimized

image

Figure 3 – RadialMenu expanded

Adding a the Telerik RadControls for Windows 8 HTML

Adding a RadialMenu is easy.  Starting where we left off in my last post on settings, http://blogs.telerik.com/skimedic/posts/13-12-30/store-and-share-settings-in-windows-8-html-winjs-apps , add the correct reference into the project. Right click on the References, click Add, and add RadControls for Windows 8 HTML.   Open home.html, and add the script and style tags for the Telerik Windows 8 RadControls, as shown in Listing 1.

<!-- Telerik References -->

<link href="/Telerik.UI/css/common.css" rel="stylesheet" /> 
<link href="/Telerik.UI/css/light.css" rel="stylesheet" /> 
<script src="/Telerik.UI/js/jquery.js"></script> 
<script src="/Telerik.UI/js/ui.js"></script> 

Listing 1 – Adding the Telerik script and source markup

For full details on how to get started with the Telerik RadControls for Windows 8 HTML, see my previous post http://blogs.telerik.com/skimedic/posts/13-07-24/getting-started-with-your-first-windows-8-html-app-using-radcontrols-part-1 .

Adding a RadialMenu

Once your project is configured to use the RadControls for Windows 8 HTML, adding a RadialMenu is easy.  As with all other Windows 8 WinJS based controls, start with a <div> tag.  Add “Telerik.UI.RadialMenu” for the data-win-control. The two data-win-options to start with are Target and Position.  When the HTML element as specified by the target gets the focus, the RadialMenu will become visible.  The position property determines where the RadialMenu will appear in relation to the target element.  (For more information on the RadialMenu, please see the very detailed help documentation http://www.telerik.com/help/windows-8-html/radialmenu-overview.html ). Set the target to the <div> called “contentContainer” and the position to “bottom”.  The contentContainer is the <div> control that holds all of the text in our sample app, and “bottom” positions the RadialMenu centered underneath that div.

<div data-win-control="Telerik.UI.RadRadialMenu" data-win-options="{
target: '#contentContainer',
position:'bottom'}"> 
</div> 

Listing 2 – A rudimentary RadialMenu

Adding the Menu Items

The menu items that appear on a RadialMenu are added as data-win-options (alternatively added programmatically through JavaScript).  Each menu item takes at a minimum an id and display text and optionally an icon and an index.  The icon property takes the standard format for used for custom icons on AppBar command buttons.  Each item can optionally have sub items.  Sub Items The index (from 0 to 7) refers to the relative position to the parent item (zero is directly underneath). To have the three sub items centered on the parent item, add indexes of 7,0,1 respectively. Finally, the selectable property determines if the menu acts as a toggle button (selectable:true) or a standard button (selectable:false). Add the code to the data-win-options shown in Listing 3.

items: [
{
  id:'Style',
  text:'Style',
  icon: '\uE185',
  items: [
    {
      index:7,
      id: 'Bold',
      text: 'Bold',
      icon: '\uE19B',
      selectable: true
    },
    {
      index:0,
      id: 'Italic',
      text: 'Italic',
      icon: '\uE199',
      selectable: true
    },
    {
      index:1,
      id: 'Underline',
      text: 'Underline',
      icon: '\uE19A',
      selectable: true
    },
  ]
}]

Listing 3 – Adding the menu items

Run the project, and when the focus is on any of the controls in the target div, the RadialMenu place holders shows (a small gear icon).  Clicking that icon opens the RadialMenu, showing the one menu item that we added (see Figure 4).  When you click on the blue menu icon for the Style item, the sub items come into view (see Figure 5).
image image

Figures 4 and 5 – Main Menu (at the default start position) and Submenu items (at index 7,0,and 1)

Changing the Start Angle for the Menus

The default angle for the first menu item is –22.5 degrees.  This actually translates to 9:00 on the dial (the angle is based on polar coordinates, but for simplicity sake, I’ll use the clock positions).  If we want the first menu to start at 12:00 (the top), we need to move the start position 90 degrees to the right.  Since we start at –22.5, that is a coordinate position of 67.5 degrees.  Add the following to the data-win-options:

startAngle:67.5,

Listing 4 – Setting the Start Angle to be 12:00

Setting the Menu Values on Expanding the RadialMenu

Before we program the menu items to change the text settings, we want to make sure that the sub menu items are toggled to the correct values based on the settings configured by the user. To do this we take advantage of the expand event of the RadialMenu.  Add the following to the data-win-options (Listing 5):

onexpand:RadRadialMenuEvents.expand,

Listing 5 – Hooking up the Event Handler for the Expand event

Creating the Event Handler

Add a new JavaScript file into the home folder in your project named radialMenuEvents.js.  Add a self executing function and a WinJS Namespace named “RadRadialMenuEvents”.  Add a property function called “expand” and mark if supported for processing (so it can be used in markup as we specified in Listing 5.  The framework code for the new file is shown in Listing 6.

/// <reference path="//Microsoft.WinJS.1.0/js/ui.js" /> 
/// <reference path="//Microsoft.WinJS.1.0/js/base.js" /> 
(function () {
  "use strict";
  WinJS.Namespace.define("RadRadialMenuEvents", {
    expand: WinJS.Utilities.markSupportedForProcessing(function (e) {
    }),
  });
})();

Listing 6 – Core code for RadialMenu Event Handlers

The event argument contains a menu property that represents the RadialMenu that was just expanded.  On the menu object, we need to get each of the menu items (by calling the getItem(id) method), and set the selected value to the settings properties textIsBold, textIsItalic, and textIsUnderlined.  These are the same properties we created in my previous post to bind the ToggleSwitches to the Model settings. The code for the event handler is shown in Listing 7.

expand: WinJS.Utilities.markSupportedForProcessing(function (e) {
//var myMenu = menuControl.winControl;
var myMenu = e.menu;
  myMenu.getItem("Bold").selected = Model.textSettings.textIsBold;
  myMenu.getItem("Italic").selected = Model.textSettings.textIsItalic;
  myMenu.getItem("Underline").selected = Model.textSettings.textIsUnderlined;
}),

Listing 7 – RadialMenu expand event handler

Run the program and change set the Bold and Underline to true and the Italic to false (or any combination thereof).  Expand the RadialMenu and you will see that the highlighted sub menu items match the ToggleSwitch values (as in Figure 6).

image

Figure 6 – Setting the menu item values based on the application settings

Updating the Settings with the RadialMenu

The next step is to update the settings when the user toggles one of the submenu items.  When a menu item is clicked, the action event is raised by the RadialMenu.  Add the following to the data-win-options (Listing 8):

onaction:RadRadialMenuEvents.action,

Listing 8 – Wiring up the action event

Adding the Action Event Handler

The action event argument has a property “item” that represents the menu item that was clicked.  By examining the id of the item, we can tell what menu item was clicked.  Then we need to call the appropriate function to change the value of the particular setting. Add the following code to the RadRadialMenuEvents Namespace (Listing 9):

action: WinJS.Utilities.markSupportedForProcessing(function (e) {
var action = e.item.id;
switch(action) {
  case "Bold":
    UISettings.setTextIsBold(null,e.menu.getItem("Bold").selected);
    break;
  case "Italic":
    UISettings.setTextIsItalic(null,e.menu.getItem("Italic").selected);
    break;
  case "Underline":
    UISettings.setTextIsUnderlined(null,e.menu.getItem("Underline").selected);
    break;

  default:
    break;
  }
}),

Listing 9 – The action Event Handler

If we weren’t keeping the ToggleSwitches (and in a real application we would remove them since that’s why we added the RadialMenu in the first place), we wouldn’t add the second parameter to the call to setTextIs<style>. 

The final change is in the setTextIs<style> functions in uiSettings.js (Listing 10):

setTextIsBold: WinJS.Utilities.markSupportedForProcessing( function (e,val) {
  var isTrue = (e ? e.currentTarget.winControl.checked : false) || val || false;
  if (isTrue) {
    settings.values["textWeight"] = Model.textSettings.textWeight = bold;
  } else {
    settings.values["textWeight"] = Model.textSettings.textWeight = normal;
  }
  WinJS.Application.queueEvent({ type: "TextSettingsChanged" });
}),

setTextIsUnderlined: WinJS.Utilities.markSupportedForProcessing( function(e,val) { 
    var isTrue = (e ? e.currentTarget.winControl.checked : false ) || val || false;
    if (isTrue) {
      settings.values["textDecoration"] = Model.textSettings.textDecoration = underline;
    } else {
      settings.values["textDecoration"] = Model.textSettings.textDecoration = normal;
    }
    WinJS.Application.queueEvent({ type: "TextSettingsChanged" });
}),

setTextIsItalic: WinJS.Utilities.markSupportedForProcessing( function(e,val) { 
    var isTrue = (e ? e.currentTarget.winControl.checked : false ) || val || false;
    if (isTrue) {
      settings.values["textFontStyle"] = Model.textSettings.textFontStyle = italic;
    } else {
      settings.values["textFontStyle"] = Model.textSettings.textFontStyle = none;
    }
    WinJS.Application.queueEvent({ type: "TextSettingsChanged" });
}),

Listing 10 – Update setTextIs<style> functions

Run the application again, and when you expand the RadialMenu and toggle the menus, not only does the text change accordingly, but the ToggleSwitches stay in sync.

Summary

The RadialMenu is a great mechanism for cleaning up the user interface, especially for items that don’t really belong in the AppBar or on the UI.  With an expandable structure capable of supporting multiple nested menu items, it can handle a great number of menu options in a very company control.


Japikse
About the Author

Phil Japikse

is an international speaker, a Microsoft MVP, ASPInsider, INETA Community Champion, MCSD, CSM/ CSP, and a passionate member of the developer community. Phil has been working with .Net since the first betas, developing software for over 20 years, and heavily involved in the agile community since 2005. Phil also hosts the Hallway Conversations podcast (www.hallwayconversations.com) and serves as the Lead Director for the Cincinnati .Net User’s Group (http://www.cinnug.org). You can follow Phil on twitter via www.twitter.com/skimedic, or read his personal blog at www.skimedic.com/blog.

 

Comments

Comments are disabled in preview mode.