Modes (menu system abstractions)

I’ve been working on abstracting menu systems for a while.
While I’m still not done, I’ve done enough to start checking things in, so I thought I’d write something to explain a little bit about how it works.

At the most fundamental level, a “mode” can be basically anything. When a mode is active, most or all events gets forwarded to the mode instead of getting handled by the prop. There is a linked list of modes, which works like a stack, so you can “push” a mode onto the stack, and when you pop it, it goes back to whatever mode it was on before. The prop itself is the default mode.

From there on, I’ve tried to decompose mode behaviors into class templates that can be easily changed so that different menu systems can be created without having to re-write everything from scratch. This decomposition is done with C++ templates, and in some ways it’s similar to how the style system works, but in others it’s not, so let’s take a look at how it works.

First of all, there is a class hierarcy:

* ModeInterface : base class for all modes
* SelectCancelMode -> ModeInterface: base class for modes which have Select / Cancel functionality.
* SmoothMode -> SelectCancelMode: Base class for smooth rotation, like color wheels
* SteppedMode -> SelectCancelMode: Base class for any type of menu that has discrete steps
* MenuMode -> SteppedMode: Base class for any menu that has a known number of steps

There are going to be a lot more mode classes, but these should serve as an example of how everything is split up into pieces. Normally when you write C++, you just write the class hierarchy directly. This is easy and fairly easy to extend, but it it becomes ugly if you want to make changes to one of the base classes. Let’s say for instance that you wanted to change the buttons for the “SelectCancelMode”. You can easily write your own mode that works exactly like SelectCancelMode, but since all of the other modes listed above inherit from SelectCancelMode, your class won’t do anything unless you either modify those clases to inherit from your new class, or, you make your own versions of all the classes.

To fix this, I’ve created something called a “Menu Specification Template”. This is a templated class which in a simple case can look like this:

template<class SPEC>
struct ColorChangeOnlyMenuSpec {
  typedef mode::SelectCancelMode SelectCancelMode;
  typedef mode::SteppedMode<SPEC> SteppedMode;
  typedef mode::SmoothMode<SPEC> SmoothMode;
  typedef mode::SmoothVariationMode<SPEC> SmoothVariationMode;
  typedef mode::SteppedVariationMode<SPEC> SteppedVariationMode;
  typedef mode::ColorChangeMode<SPEC> RootMenu;
};

Now, as you can see almost all the modes listed above are actually templates which takes the SPEC as an argument. And when SteppedMode wants to inherit SelectCancelMode, it doesn’t inherit it directly, instead it inherits it from SPEC::SelectCancelMode. This means that if you want to replace SelectCancelMode, all you would need to do is to create a SPEC which overrides it, like:

template<class SPEC>
struct MyColorChangeSPEC : public ColorChangeOnlyMenuSpec<SPEC> {
   typedef   MyAwesomeSelectCancelMode  SelectCancelMode;
};

Then when any class in the menu system needs a “SelectCancelMode”, it will use your new cancel mode (which is apparently awesome).

The goal here is to make it easy both to add/remove menu entries, and to change how the menu system behaves at a fundamental level.

Anyways, some of this code is already in github, and there is more coming, so stay tuned.

1 Like

PS: I’ve anybody has seen a class hierarchy controlled through a SPEC template/class like this before, let me know. I’m not sure if it’s a new invention or not…

So… am I misunderstanding this or are you “overriding” type defines??

Is mode a placeholder for an implementing mode or an actual “base” of classes? (It seems like the latter based on what you describe above… is it a namespace/class which just holds defaults?)

I guess I don’t fully understand what the SPEC class will be? A class to hold your overrides and additional menu items essentially?

Using templates like this is something I’ve certainly not encountered before (though I’m without a doubt a novice), so please excuse the perhaps lack of knowledge, but in your implementation:
If your SPEC class you’re templating for is, at some level, supposed to be the class that does any overriding you want and sets up you other menu and menu items, where does the template chaining end? What class would end up being passed into, say MyColorChangeSPEC if you wanted to now use it, having overridden SelectCancelMode?

Overall I guess my biggest questions are “What does this look like being implemented for prop logic” and “How are these typedefs used to actually create a menu system?”

This idea (if I understand it right) makes sense from a fundamental standpoint but I’m having trouble understanding your idea of how it would actually be implemented, and I figure (at least part of my confusion) just stems from that.

PS this does seem like a neat implementation of C++ typedefs and templating :slight_smile:

You are correct, I am overriding typedefs.

mode:: is actually a namespace where I placed everything to avoid name conflicts, so mode::SelectCancelMode refers to a class in the mode namespace, and mode::SeteppedMode<SPEC> refers to a template in the mode namespace.

At the end, there will be a define which specifies which SPEC class to use for the menu, and the SPEC template will control the full layout and functionality of the menu.

Then there is a trick. Basically there is a class that does this:

class SPEC : public SPEC_TEMPLATE<SPEC> {};

This SPEC class is a real class (not a template) and it is the one that becomes the SPEC class which is passed around everywhere. (This trick has a name btw. it’s called “curiously recursive template pattern”)

All the prop class will essentially do is:

pushMenu<SPEC::RootMenu>();

In reality it’s slightly more complicated, as I created a template to do the curiously recursive template pattern thing, this is just illustration.

To answer the question of how this will actually look when building entire menues, here is an example:

There will eventually be a class in the hierarchy called a BoolSetting. To implement a BoolSetting, you might do something like this: (Please note that this isn’t entirely finalized yet, so things might change.)

struct TwistOnSetting {
  static bool get() { return saved_gesture_control.twiston; }
  static void set(bool value) {
    saved_gesture_control.twiston = value;
    saved_gesture_control.save();
  }
  static void say(SoundLibrary* lib) { lib->SayWwistIgnition(); }
};

We can wrap a BoolSetting into a menu entry sort of like this:

   SPEC::BoolEntry<SPEC, TwistOnSetting>

And we build a menu out of menu entries like this:

   SPEC::MenuListMode<
     SPEC::BoolEntry<SPEC, TwistOnSetting>,
     SPEC::BoolEntry<SPEC, StabOnSetting>,
     SPEC::BoolEntry<SPEC, SwingOnSetting>>

This would then be added to the SPEC, under some name:

   typedef
     SPEC::MenuListMode<
     SPEC::BoolEntry<SPEC, TwistOnSetting>,
     SPEC::BoolEntry<SPEC, StabOnSetting>,
     SPEC::BoolEntry<SPEC, SwingOnSetting>>
     GestureOnSettingsMenu;

And then this menu can be used inside another menu later on.
When you build a new SPEC, you can also use menues in the spec you inherit from and add entries to those menues.

Right now, I’ve written a SPEC for color change modes, and I’m working on a menu system for the “saber” prop. It should support volume, blade length changes and and changing colors and arguments in styles, but it will still be relatively simple compared to the fett263 menues.

The idea is that other props can then extend or customize the menues as much as they like to add new settings, or alternate modes of operation.

Btw, currently I have two different implementations of BoolEntry.
One that simply flips the flag immediately when you select that entry.
One that goes into a sub-menu with an “enabled” and a “disabled” entry.
The SPEC will need to pick which implementation to use. (Or provide a different one of course.)

1 Like

Ok, so then the BoolEntry would be its whole own thing defining essentially how the menu behaves? Is it expected that all BoolSetting or others of its type would have a get(), set(), and say() (Is there a base interface for this if so?)

Besides that, this seems fairly straightforward (from an implementation standpoint at least, I trust you’ve got lots of fancy stuff going on underneath). I wish I had the time to see what this’ll look like under the hood(I might need to find some, heh), but I think it makes sense.

So as I understand it, basically after you’ve set all this up and defined all the functions and what they do and your BootEntry type stuff to (if I’m understanding correctly) set how the menus function, then once you have all the meta programming stuff behind you, it’d be as simple as calling pushMenu or popMenu (or whatever they end up being) on an event or from another menu item in order to make the magic happen?

So, if I’m understanding correctly you could just the same (assuming that this structure remains, or if not something similar) do something like:

typedef SPEC::MenuListMode<
  ... stuff
> SomeOtherMenu;

typedef SPEC::MenuListMode<
  SPEC::BoolEntry<SPEC, TwistOnSetting>,
  SPEC::BoolEntry<SPEC, StabOnSetting>,
  SPEC::SomeOtherMenu
> GestureOnSettingsMenu;

In that case, does that mean MenuListMode takes in a variadic number of ModeInterfaces and is itself derived from ModeInterface such that it can be nested like so?

BoolEntry is just one type of menu entry. There will be others for for other types of settings, actions and sub-menues.

That is the idea anyways.

MenuListMode takes a list of MenuEntry classes. Making a MenuEntry from a Mode is as simple as wrapping it in a SubMenuEntry though, so your example would look something like:

typedef SPEC::MenuListMode<
  SPEC::BoolEntry<SPEC, TwistOnSetting>,
  SPEC::BoolEntry<SPEC, StabOnSetting>,
  SPEC::SubMenuEntry<SPEC::SomeOtherMenu>,
> GestureOnSettingsMenu;

SubMenuEntry simply calls pushMode<> when you select it, so it can be used with any mode.

1 Like

Awesome, that menu layout makes sense.

Ah ok, so then what’s the hierarchy there?

If I’ve created a BoolEntry out of a TwistOnSetting for example, what is the role of BoolSetting and what’s the role of TwistOnSetting?

If TwistOnSetting has a getter and setter, then I’d assume those get called by logic that’s a part of BoolEntry? (That’s why I was questioning if there was some kind of inheritance to override those get and set methods, or how that works)

Would I be correct in that BoolEntry determines how the menu functions, but the TwistOnSetting (I’m not sure what to call what this would be, is it considered a SPEC?) determines what the menu actually does?

BoolSetting is just the interface that TwistOnSetting has to conform to.
In a “normal” class hierarchy, TwistOnSetting would inherit from BoolSetting, but when working with types and static functions, that doesn’t actually help.

It works like inheritance, but it isn’t. All the methods are static so that we can call them directly from the type information. I suppose I could instantiate objects instead, but I’m not sure if that’s actually helpful, or just a waste of space.

Yes, that is correct.

Sorry, I mistyped, I meant BoolEntry vs TwistOnSetting/BoolSetting… that’s my bad.

Right, gotcha, it’s more or less a “code of honor” (for lack of any better term…)

Understood, exciting stuff!

So then my last question would just be how do you (if there is a “proper” way outlined yet) setup a menu entry type? Would that be something where it’s more expected that you create the different types of menus or would it be something that could/would be expected to be created?

If nothing else just for perhaps minor tweaks one may want to make to menu behavior… I’m not sure what this looks like complexity-wise under the hood.

The technical term is “duck typing”. (If it walks like a duck…)
With “duck typing” you don’t need to inherit from “duck” to “be a duck”, it’s enough to implement the same methods as “duck”.

I’m not sure I understand the question.
There will be classes/templates that define common types of menu entries (like a bool setting, or a submenu) if you need something different, or if you don’t like how they work, you will have to write/create your own classes. (Which can be done in the prop file).

The whole setup is intended to make minor tweaks possible without having to re-define everything from scratch, as long as the tweak fits in the with the overall system, minor tweaks should take small amount of code to do.

1 Like

Haha, gotcha.

I think that answers my question, that it’ll be a system that does its best to have a good range of menu entries for most things.

I’ll be excited to see this as it progresses, the layout as you have it seems intuitive (well, after I realized what the code layout was even doing since it was new to me) and well thought out.

Thank you very much for answering all my questions, I shall watch this system’s career with great interest :wink:

One potential drawback of this system is that the error messages you get from the compiler are terrible. Long, inscrutable and in some cases they don’t really give you a clue as to what the real problem is… Hopefully it’s not a fatal flaw…

It’s ok, I sometimes get erros like that that freeze Ardruino and make it timeout, then it says offline in yellow at bottom and won’t compile again, and I have to restart it.

The good news is that only prop makers will really be messing with making changes to the modes, so most users will never see these errors.