LCOV - code coverage report
Current view: top level - src/Selectors - Selector.hpp (source / functions) Hit Total Coverage
Test: e224b347cd670555e44f06608ac41bd1ace9d9d8 Lines: 49 49 100.0 %
Date: 2020-09-08 17:44:46 Functions: 31 55 56.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : #pragma once
       2             : 
       3             : #include "Selectable.hpp"
       4             : #include <AH/Containers/Updatable.hpp>
       5             : #include <AH/Debug/Debug.hpp>
       6             : #include <Def/Def.hpp>
       7             : 
       8             : BEGIN_CS_NAMESPACE
       9             : 
      10             : /**
      11             :  * @brief   An enumeration to set the behavior of selectors that are incremented
      12             :  *          (decremented) beyond their maximum (minimum) setting.
      13             :  */
      14             : enum class Wrap : bool {
      15             :     Clamp = false, ///< When the maximum (minimum) setting is reached,
      16             :                    ///< clamp to the maximum (minimum) setting.
      17             :                    ///< @todo  Rename to `Clamp`?
      18             :     Wrap = true,   ///< When the maximum (minimum) setting is reached,
      19             :                    ///< wrap around to the minimum (maximum) setting.
      20             :     NoWrap = false,
      21             : };
      22             : 
      23             : /// A callback for the GenericSelector class that does nothing.
      24             : struct EmptySelectorCallback {
      25             :     /// Initialize.
      26           7 :     void begin() {}
      27             :     /// Refresh, called periodically.
      28          20 :     void update() {}
      29             :     /// Called when the setting changes.
      30          23 :     void update(setting_t oldSetting, setting_t newSetting) {
      31             :         (void)oldSetting, (void)newSetting;
      32          23 :     }
      33             : };
      34             : 
      35             : /// Base class for all Selectors exposing the `get` method, so it can be used
      36             : /// by display elements etc, without having to provide the full generic type.
      37             : ///
      38             : /// A `set` method is not provided, because that would require either more
      39             : /// virtual functions, or a rather large refactoring.
      40             : class SelectorBase {
      41             :   protected:
      42             :     /// Constructor.
      43          19 :     SelectorBase() = default;
      44             : 
      45             :   public:
      46             :     /// Get the current selection/setting.
      47          45 :     setting_t get() const { return setting; }
      48             : 
      49             :   protected:
      50             :     /// The selection of the selector. It is saved in the selector as well as
      51             :     /// the selectable, because you need it in order to implement
      52             :     /// increment/decrement methods.
      53          19 :     setting_t setting = 0;
      54             : };
      55             : 
      56             : template <setting_t N, class Callback = EmptySelectorCallback>
      57          19 : class GenericSelector : public SelectorBase, public AH::Updatable<> {
      58             :   public:
      59             :     /**
      60             :      * @brief   Constructor.
      61             :      * 
      62             :      * @param   selectable
      63             :      *          The selectable object to manage. When the value of the selector
      64             :      *          changes, it changes the selection of this selectable.
      65             :      * @param   callback
      66             :      *          The callback to call when the value changes. Used for (visual)
      67             :      *          feedback from the selector (e.g. LEDs or some different kind of
      68             :      *          display).
      69             :      */
      70          19 :     GenericSelector(Selectable<N> &selectable, const Callback &callback)
      71          57 :         : selectable(selectable), callback(callback) {}
      72             : 
      73           7 :     void begin() override {
      74           7 :         callback.begin();
      75           7 :         reset();
      76           7 :     }
      77             : 
      78          20 :     void update() override { callback.update(); }
      79             : 
      80             :     /// Reset the selection to the initial selection.
      81           8 :     void reset() {
      82           8 :         setting_t initialSelection = selectable.getInitialSelection();
      83           8 :         selectable.select(initialSelection);
      84           8 :         callback.update(initialSelection, initialSelection);
      85           8 :         this->setting = initialSelection;
      86           8 :     }
      87             : 
      88             :     /** 
      89             :      * @brief   Select the given selection
      90             :      * 
      91             :      * @param   newSetting
      92             :      *          The new setting to select [0, N-1].
      93             :      */
      94          15 :     void set(setting_t newSetting) {
      95          15 :         newSetting = selectable.validateSetting(newSetting);
      96          15 :         selectable.select(newSetting);
      97          15 :         if (get() != newSetting) {
      98          15 :             callback.update(get(), newSetting);
      99          15 :             this->setting = newSetting;
     100          15 :         }
     101          15 :     }
     102             : 
     103             :     /**
     104             :      * @brief   Add one to the setting, wrap around or clamp, depending on the
     105             :      *          parameter, if the new setting would be out of range.
     106             :      * 
     107             :      * @param   wrap 
     108             :      *          Wrap or clamp if the new setting would be out of range.
     109             :      */
     110           8 :     void increment(Wrap wrap) {
     111           8 :         setting_t setting = this->get();
     112           8 :         setting++;
     113           8 :         if (setting == N) {
     114           3 :             if (wrap == Wrap::Wrap)
     115           2 :                 setting = 0;
     116             :             else
     117           1 :                 return;
     118           2 :         }
     119           7 :         this->set(setting);
     120           8 :     }
     121             : 
     122             :     /**
     123             :      * @brief   Subtract one from the setting, wrap around or clamp, depending 
     124             :      *          on the parameter, if the new setting would be out of range.
     125             :      * 
     126             :      * @param   wrap 
     127             :      *          Wrap or clamp if the new setting would be out of range.
     128             :      */
     129           5 :     void decrement(Wrap wrap) {
     130           5 :         setting_t setting = this->get();
     131           5 :         if (setting == 0) {
     132           2 :             if (wrap == Wrap::Wrap)
     133           1 :                 setting = N;
     134             :             else
     135           1 :                 return;
     136           1 :         }
     137           4 :         setting--;
     138           4 :         this->set(setting);
     139           5 :     }
     140             : 
     141             :   private:
     142             :     Selectable<N> &selectable;
     143             : 
     144             :   public:
     145             :     Callback callback;
     146             : };
     147             : 
     148             : /** 
     149             :  * @brief   A Selector with an empty callback.
     150             :  * 
     151             :  * @tparam  N
     152             :  *          The number of possible settings.
     153             :  */
     154             : template <setting_t N>
     155             : class Selector : public GenericSelector<N> {
     156             :   public:
     157             :     /// Constructor
     158             :     Selector(Selectable<N> &selectable) : GenericSelector<N>{selectable, {}} {}
     159             : };
     160             : 
     161             : END_CS_NAMESPACE

Generated by: LCOV version 1.14-6-g40580cd