index

patterns: declare sync apply

This is my take on the usual "model, view, controller" pattern.

declare


Associate variable names with widgets, labels, and default values.
geometryUI::geometryUI() { // constructor 
  Add(3/*how many*/, xUI,"X",0., yUI,"Y",0., zUI,"Z",0.); // add to base class managed list. 
  load();  // Set defaults. 
  sync(0); // Redraw UI. 
}
The base class "plug" (or "plugin") keeps lists of components. That's about all it needs to supply save, load, restore, undo, print, and cut/paste.

sync


Match UI with model.

The UI has two jobs. It lets the user change internal state, and it shows the internal state-- which can, after all, be changed in other ways, like loading a new session.

A typical sync does three things:

1. if (widget X was touched) {make appropriate change}
2. set widget X to internal state value.
3. if (ANY widget was touched) {notify owner by running callback}

The callback is installed by the owner and calls its sync function. The owner does the same-- reacts to the component, sets its sub-components (with "sync(0)"), and reports to it's owner.

At the top of the pile is the application itself, which might respond by redrawing its window with the new settings, and saving an undo checkpoint.
void Dashboard::sync(Widget*o) { 
  if (o== heatOnUI) turn_heat_on(); 
  if (o==radioOnUI) turn_radio_on(); 
  // etc, then: 
  heatOnUI ->value(is_heat_on()); 
  radioOnUI->value(is_radio_on()); 
  if (o) do_callback(); // "o" not null means a sub-component called sync(). 
} 

//... 

void Interior::sync(Widget*o) { 
  if (o== dashboardUI) play_annoying_ding(); 
  if (o==smartphoneUI)  inform_government(); 
  // etc, then: 
  dashboardUI ->sync(0); 
  smartphoneUI->sync(0); 
  if (o) do_callback(); 
}

apply

The module performs its function.

The incoming argument is a single pointer with the appropriate context. If the pointer is zero, it means clear any internal data (for example, when loading a new session).

This is a place to calculate data, draw stuff, or modify contextual state.

Adding modules


Add modules to the program with a list of prototype.

The program need know very little about the modules: new(), sync(), apply(), and how to make a clone.

Call sync(0) on a module to check/sync internal state.

Summary

This pattern is succinct and flexible. Creating a new element is rote and touches only the code file itself, and the file that uses it. Commenting out the prototype constructor completely removes the element from the system.

It's a nesting pattern that can build up multiple levels-- just sync() and apply() internal widgets or libraries as usual, and make sure they do_callback() when they are changed.

nedwaves.com 2017 [171108]