StackComponent


#1

Hello! I’ve finally tidied up the code of my new favourite UI class, and it’s time to share it :slight_smile:

Introduction

This is conceptually very simple, but in practical terms it is incredibly useful. While it may not be a common trope for a proper computer-based application UI, it’s perfectly suited to mobile platforms (it’s one of the main approaches used in iOS app UI navigation, for example). I’ve taken to using it as the foundation for all my little tools lately, as it massively simplifies the job of deciding what to put where; If it makes sense for the user to consider their data in a way that reflects how the document is structured (and for small tools that’s often the case), you can just stuff things onto separate pages, and it almost designs itself.

What it is…

Basically it’s a type of container for multiple components, much like a TabbedComponent. Unlike a TabbedComponent, however, it operates using a stack. This allows you to push components on, and pop them off. You can shift the focus to any component in the stack, but typically you would want the user to interact with the one at the top; when pushing/popping, there is an ‘autoFocus’ parameter which, if true, will automatically shift the focus to the head of the stack.

It is also highly customisable. While the TabbedComponent has a built in UI for choosing which tab to show, the StackComponent leaves such duties to a separate StackComponent::Controller base class. This allows you to create all kinds of UI controls to cooperate with the stack (and even have multiple simultaneous controllers). Also, the StackComponent has been designed specifically to minimise the restrictions placed on how its contents should be arranged and animated; by subclassing it you can have the components appear in any configuration, and animate in whatever manner you like. The comments explain this is more detail.

If you’ve used an iPhone, you’ll be familiar with the way such a system can work. I’ve provided a bunch of example classes to illustrate the sort of things you can do, along with a demo app and introjucer project.

DOWNOAD
The source for these classes (and a demo project) is here: StackComponent_v1.zip
There is also a prebuilt windows binary of the demo here: StackComponent_v1DemoWin.zip

The main classes

The base StackComponent can be used as is, but it has no animations. The focused content component is stretched to fill the container’s bounds, and all others are invisible.

SlidingStackComponent is an example of a subclass with animation. This uses a ComponentAnimator to slide the old/new content components off/on screen when the focus is changed.

The StackHeaderComponent is a type of controller, designed to sit above a StackComponent. This displays a ‘Back’ button when the current focus is not at the bottom of the stack, which will pop the focused component (with autoFocus shifting focus to the new head). It also displays a title for the focused content component; the static function StackHeaderComponent::setStackContentTitle(content,title) allows you to specify what this should say when you create your content component and push it onto the stack.

There’s also a StackNavigationList. This is another example of a controller, which provides a vertical ‘breadcrumb trail’, showing your current position in (and overall contents of) the stack. Like the StackHeaderComponent, there’s a static function allowing you to attach a property to your content so it can be identified in the list.

Of course, these aren’t the only kinds of controller you could make, but they should hopefully demonstrate the sort of thing you can do. They each link to a target StackComponent, and they all update automatically to reflect the current state of their target.

The demo

I’ve made a little example program to show these things in action. It’s basically a crude ValueTree browser. It just consists of a single hypothetical content component type (ValueTreeStackPanel), which shows the contents of a ValueTree node (properties and children) in a PropertyPanel (with the child nodes presented in a listbox). If you double click a child node, it will push a new ValueTreeStackPanel onto the stack for the selected child node. It’s very basic - just about the quickest thing I could think of to illustrate it without having to design anything that required multiple pages! Also, as I couldn’t be bothered making any data, i’ve just embedded the demo project’s jucer file for it to use. Not very glamorous content, but it does the job!

There are a few other classes in the project that are largely unrelated - either used by the example controllers or just helpers for the demo. The MarginedContainerComponent is kinda handy - that’s what the StackHeaderComponent uses. It also supports easily sticking other controls on the right hand side, though I haven’t got round to exposing any of that on the actual header component yet. The HeaderLabel is used to ensure the title is centred properly whilst still being constrained to the correct bounds (I.e. Not going behind the Back button); if it just used a normal Label the centring would be off when the button is showing. I’m sure you don’t need to care much about these, anyway. The only absolutely fundamental code file pair in the demo project is StackComponent.h/cpp (though SlidingStackComponent is a little more glitzy).

Hope you find this useful!


#2

Sounds excellent! Looking forward to trying it out…


#3

Wow ! I just tried the demo and it’s pretty impressive ! Very good job.

I think even the desktop computer world is slowly moving towards more mobile-like UIs (cf Mac OSX Lion), so it might be relevant even in those cases !

I didn’t see a licence file. What licence do you want to use for publishing this code ? GPL ? MIT ? In other words, is it ok to reuse it in commercial apps ?


#4

I never really add any kind of license info here, because the stuff I tend to post is usually something anyone could have come up with should they have decided to bother; feel free to use it as you like*!

The core class here is essentially incredibly basic - it doesn’t become cool or interesting until you start putting it to use and extending it! [I guess some of the example subclasses might qualify for that]. It wouldn’t be fair for me to claim any kind of ownership of it!

*If it kills you or your family though, it’s most likely your own fault.


#5

DISCLAIMER: I am not a lawyer.
This is the minimum of what I put at the top of my open source files. Adjust as needed

// Copyright (C) 2008-2011 by {YOUR_NAME}, All rights reserved worldwide.
// This file is released under the MIT License:
// http://www.opensource.org/licenses/mit-license.php

#6

Well done mate!

I had to tweak the code a little bit in order to compile it in Xcode:

-MainWindow.cpp:

instead of:

-StackComponent.h:

instead of:

Keep up the good work! :wink:


#7

sounds fine, but I can’t access and download them.


#8

I can.


#9

I've just discovered this component, and looking forward to trying it out. However I'm getting the following errors trying to get it to compile on Xcode: 

<path-to-project>/StackDemo/Source/UI/ValueTreeStackPanel.cpp:38:19: Field type 'ValueTreeListBox' is an abstract class​

<path-to-project>/StackDemo/Source/UI/ValueTreeStackPanel.cpp:111:8: No matching member function for call to 'add'

I'm not sure if this is due to changes in JUCE since the code was put up. My C++ chops not up to recognising the problem off hand. 

EDIT: Thought I'd been bitten by missing new virtual function declarations for ValueTree, but that seems not to be it... 


#10

If you are building in Xcode the error messages can usually be expanded and the expansion has all the (very useful) notes from clang. 

 

In this case: 

 

Anyway - fix the first problem and the second one goes away. 


#11

Thank you! 

EDIT:

Also want to add that the sample app is a great example of binding ValueTree to ListBox and is helping me to restructure the UI in my app.

Thanks haydxn. Have you thought of making this into a juce module?


#12

I'm trying to get it working with the latest JUCE... and I'm not having success.  Have you got updated code?


#13

I made it into a JUCE module  - I also started tweaking it to alow different animations per component but ran into some bugs I didnt get round to resolving. I ended up going with native UI in the end. However I kept the original StackComponent code seperate, updating it for JUCE 3.2

https://github.com/adamski/AnimatedStackComponent


#14

Hi- 

Yes, I saw that code and am trying to incorporate it in 8th (http://8th-dev.com)

My current problem is that I push two items on construction, and set the index to the first one; but the second one shows until I manually resize the outer container component.  Then it works as expected...