Ivan Mahonin 2b429e
#pragma once
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
#ifndef KEYSTATE_INCLUDED
Ivan Mahonin 2b429e
#define KEYSTATE_INCLUDED
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
// TnzTools includes
Ivan Mahonin 2b429e
#include <tools/tooltimer.h>
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
// TnzCore includes
Ivan Mahonin 2b429e
#include <tcommon.h>
Ivan Mahonin 2b429e
#include <tsmartpointer.h>
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
// std includes
Ivan Mahonin 2b429e
#include <map>
Ivan Mahonin 2b429e
#include <set>
Ivan Mahonin 2b429e
#include <algorithm>
Ivan Mahonin 2b429e
#include <cmath>
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
#undef DVAPI
Ivan Mahonin 2b429e
#undef DVVAR
Ivan Mahonin 2b429e
#ifdef TNZTOOLS_EXPORTS
Ivan Mahonin 2b429e
#define DVAPI DV_EXPORT_API
Ivan Mahonin 2b429e
#define DVVAR DV_EXPORT_VAR
Ivan Mahonin 2b429e
#else
Ivan Mahonin 2b429e
#define DVAPI DV_IMPORT_API
Ivan Mahonin 2b429e
#define DVVAR DV_IMPORT_VAR
Ivan Mahonin 2b429e
#endif
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
//===================================================================
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
//*****************************************************************************************
Ivan Mahonin 2b429e
//    TKeyState definition
Ivan Mahonin 2b429e
//*****************************************************************************************
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
template<typename T>
Ivan Mahonin 49945e
class TKeyStateT : public TSmartObject {
Ivan Mahonin 2b429e
public:
Ivan Mahonin 2b429e
  typedef T Type;
Ivan Mahonin 2b429e
  typedef TSmartPointerT<TKeyStateT> Pointer;
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
  struct Holder {
Ivan Mahonin 2b429e
    Pointer state;
Ivan Mahonin 2b429e
    TTimerTicks ticks;
Ivan Mahonin 2b429e
    double timeOffset;
Ivan Mahonin 2b429e
Ivan Mahonin 49945e
    explicit Holder(const Pointer &state = Pointer(), TTimerTicks ticks = 0, double timeOffset = 0.0):
Ivan Mahonin 2b429e
      state(state), ticks(ticks), timeOffset(timeOffset) { }
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
    Pointer find(const Type &value) const
Ivan Mahonin 2b429e
      { return state ? state->find(value) : Pointer(); }
Ivan Mahonin 2b429e
    bool isEmpty() const
Ivan Mahonin 2b429e
      { return !state || state->isEmpty(); }
Ivan Mahonin 2b429e
    bool isPressed(const Type &value) const
Ivan Mahonin 2b429e
      { return find(value); }
Ivan Mahonin 2b429e
    double howLongPressed(const Type &value)
Ivan Mahonin 2b429e
      { return howLongPressed(find(value), ticks, timeOffset); }
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
    static double howLongPressed(const Pointer &state, long ticks, double timeOffset) {
Ivan Mahonin efa14d
      return state
Ivan Mahonin efa14d
           ? std::max(TToolTimer::step, (ticks - state->ticks)*TToolTimer::step + timeOffset)
Ivan Mahonin efa14d
           : 0.0;
Ivan Mahonin 2b429e
    }
Ivan Mahonin 2b429e
  };
Ivan Mahonin 2b429e
Ivan Mahonin 16421e
  static const Type& none() {
Ivan Mahonin 16421e
    static Type none;
Ivan Mahonin 16421e
    return none;
Ivan Mahonin 16421e
  }
Ivan Mahonin 16421e
Ivan Mahonin 16421e
  static const Pointer& empty() {
Ivan Mahonin 16421e
    static Pointer empty = new TKeyStateT();
Ivan Mahonin 16421e
	return empty;
Ivan Mahonin 16421e
  }
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
  const Pointer previous;
Ivan Mahonin 2b429e
  const TTimerTicks ticks;
Ivan Mahonin 2b429e
  const Type value;
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
private:
Ivan Mahonin 2b429e
  TKeyStateT(const Pointer &previous, TTimerTicks ticks, const Type &value):
Ivan Mahonin 2b429e
    previous(previous), ticks(ticks), value(value) { }
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
  Pointer makeChainWithout(const Pointer &state) {
Ivan Mahonin d8eddc
    return state == this ? previous
Ivan Mahonin d8eddc
         : previous ? Pointer(new TKeyStateT(previous->makeChainWithout(state), ticks, value))
Ivan Mahonin d8eddc
         : this;
Ivan Mahonin 2b429e
  }
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
public:
Ivan Mahonin 16421e
  TKeyStateT(): ticks(0), value(none()) { }
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
  Pointer find(const Type &value) {
Ivan Mahonin 16421e
    return value == none()      ? Pointer()
Ivan Mahonin 2b429e
         : value == this->value ? this
Ivan Mahonin 2b429e
         : previous             ? previous->find(value)
Ivan Mahonin 2b429e
         :                        Pointer();
Ivan Mahonin 2b429e
  }
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
  Pointer change(bool press, const Type &value, TTimerTicks ticks) {
Ivan Mahonin 16421e
    if (value == none())
Ivan Mahonin 2b429e
      return Pointer(this);
Ivan Mahonin d8eddc
    
Ivan Mahonin d8eddc
    Pointer p = find(value);
Ivan Mahonin d8eddc
    if (press == bool(p))
Ivan Mahonin d8eddc
      return Pointer(this);
Ivan Mahonin d8eddc
    
Ivan Mahonin 2b429e
    if (ticks <= this->ticks)
Ivan Mahonin 2b429e
      ticks = this->ticks + 1;
Ivan Mahonin 2b429e
Ivan Mahonin d8eddc
    if (press)
Ivan Mahonin 2b429e
      return Pointer(new TKeyStateT((isEmpty() ? Pointer() : Pointer(this)), ticks, value));
Ivan Mahonin 2b429e
    Pointer chain = makeChainWithout(p);
Ivan Mahonin 16421e
    return chain ? chain : Pointer(new TKeyStateT(Pointer(), ticks, none()));
Ivan Mahonin 2b429e
  }
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
  bool isEmpty()
Ivan Mahonin 16421e
    { return value == none() && (!previous || previous->isEmpty()); }
Ivan Mahonin 2b429e
  bool isPressed(const Type &value)
Ivan Mahonin 2b429e
    { return find(value); }
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
  Pointer pressed(const Type &value, long ticks)
Ivan Mahonin 2b429e
    { return change(true, value, ticks); }
Ivan Mahonin 2b429e
  Pointer released(const Type &value, long ticks)
Ivan Mahonin 2b429e
    { return change(false, value, ticks); }
Ivan Mahonin 2b429e
};
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
//*****************************************************************************************
Ivan Mahonin 2b429e
//    TKeyHistory definition
Ivan Mahonin 2b429e
//*****************************************************************************************
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
template<typename T>
Ivan Mahonin 49945e
class TKeyHistoryT : public TSmartObject {
Ivan Mahonin 2b429e
public:
Ivan Mahonin 2b429e
  typedef T Type;
Ivan Mahonin 2b429e
  typedef TSmartPointerT<TKeyHistoryT> Pointer;
Ivan Mahonin 2b429e
  typedef TKeyStateT<Type> State;
Ivan Mahonin 2b429e
  typedef typename TKeyStateT<Type>::Pointer StatePointer;
Ivan Mahonin 2b429e
  typedef typename TKeyStateT<Type>::Holder StateHolder;
Ivan Mahonin d8eddc
  typedef std::map<TTimerTicks, StatePointer> StateMap;
Ivan Mahonin d8eddc
  typedef std::multiset<TTimerTicks> LockSet;
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
  class Holder {
Ivan Mahonin 2b429e
  private:
Ivan Mahonin 49945e
    Pointer m_history;
Ivan Mahonin 49945e
    TTimerTicks m_ticks;
Ivan Mahonin 49945e
    double m_timeOffset;
Ivan Mahonin 49945e
    TTimerTicks m_heldTicks;
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
  public:
Ivan Mahonin 2b429e
    Holder():
Ivan Mahonin 49945e
      m_ticks(), m_timeOffset(), m_heldTicks() { }
Ivan Mahonin 2b429e
    Holder(const Pointer &history, TTimerTicks ticks, double timeOffset = 0.0):
Ivan Mahonin 49945e
      m_ticks(), m_timeOffset(), m_heldTicks()
Ivan Mahonin 2b429e
      { set(history, ticks, timeOffset); }
Ivan Mahonin 2b429e
    Holder(const Holder &other):
Ivan Mahonin 49945e
      m_ticks(), m_timeOffset(), m_heldTicks()
Ivan Mahonin 2b429e
      { set(other); }
Ivan Mahonin 2b429e
    ~Holder()
Ivan Mahonin 2b429e
      { reset(); }
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
    Holder& operator= (const Holder &other)
Ivan Mahonin 2b429e
      { set(other); return *this; }
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
    void set(const Pointer &history, TTimerTicks ticks, double timeOffset = 0.0) {
Ivan Mahonin d8eddc
      TTimerTicks prevHeldTicks = m_heldTicks;
Ivan Mahonin d8eddc
      Pointer prevHistory = m_history;
Ivan Mahonin 49945e
      m_history = history;
Ivan Mahonin 49945e
      m_ticks = ticks;
Ivan Mahonin 49945e
      m_timeOffset = timeOffset;
Ivan Mahonin 49945e
      m_heldTicks = (m_history ? m_history->holdTicks(m_ticks) : 0);
Ivan Mahonin d8eddc
      if (prevHistory) prevHistory->releaseTicks(prevHeldTicks);
Ivan Mahonin 2b429e
    }
Ivan Mahonin 2b429e
    void set(const Holder &other)
Ivan Mahonin 2b429e
      { set(other.history(), other.ticks(), other.timeOffset()); }
Ivan Mahonin 2b429e
    void reset()
Ivan Mahonin 2b429e
      { set(Pointer(), 0); }
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
    Pointer history() const
Ivan Mahonin 49945e
      { return m_history; }
Ivan Mahonin 2b429e
    TTimerTicks ticks() const
Ivan Mahonin 49945e
      { return m_ticks; }
Ivan Mahonin 2b429e
    double timeOffset() const
Ivan Mahonin 49945e
      { return m_timeOffset; }
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
    Holder offset(double timeOffset) const {
Ivan Mahonin 2b429e
      return fabs(timeOffset) < TToolTimer::epsilon ? *this
Ivan Mahonin 16421e
           : Holder(m_history, m_ticks, m_timeOffset + timeOffset);
Ivan Mahonin 2b429e
    }
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
    StateHolder get(double time) const {
Ivan Mahonin aedcda
      TTimerTicks dticks = (TTimerTicks)ceil(TToolTimer::frequency*(time + m_timeOffset - TConsts::epsilon));
Ivan Mahonin 49945e
      StatePointer state = m_history->get(m_ticks + dticks);
Ivan Mahonin 49945e
      return StateHolder(state, m_ticks, m_timeOffset + time);
Ivan Mahonin 2b429e
    }
Ivan Mahonin 2b429e
  };
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
private:
Ivan Mahonin d8eddc
  StateMap m_states;
Ivan Mahonin d8eddc
  LockSet m_locks;
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
  void autoRemove() {
Ivan Mahonin d8eddc
    TTimerTicks ticks = m_states.rbegin()->first;
Ivan Mahonin d8eddc
    if (!m_locks.empty())
Ivan Mahonin d8eddc
      ticks = std::min(ticks, *m_locks.begin());
Ivan Mahonin 2b429e
    while(true) {
Ivan Mahonin d8eddc
      typename StateMap::iterator i = m_states.begin();
Ivan Mahonin 2b429e
      ++i;
Ivan Mahonin 49945e
      if (i == m_states.end() || (!i->second->isEmpty() && i->first >= ticks)) break;
Ivan Mahonin 49945e
      m_states.erase(i);
Ivan Mahonin 2b429e
    }
Ivan Mahonin 2b429e
  }
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
  TTimerTicks holdTicks(TTimerTicks ticks)
Ivan Mahonin 49945e
    { return *m_locks.insert(std::max(ticks, m_states.begin()->first)); }
Ivan Mahonin d8eddc
  void releaseTicks(TTimerTicks heldTicks) {
Ivan Mahonin d8eddc
    typename LockSet::iterator i = m_locks.find(heldTicks);
Ivan Mahonin d8eddc
    if (i == m_locks.end()) return;
Ivan Mahonin d8eddc
    m_locks.erase(i);
Ivan Mahonin d8eddc
    autoRemove();
Ivan Mahonin d8eddc
  }
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
  StatePointer get(TTimerTicks ticks) {
Ivan Mahonin d8eddc
    typename StateMap::iterator i = m_states.upper_bound(ticks);
Ivan Mahonin 49945e
    return i == m_states.begin() ? i->second : (--i)->second;
Ivan Mahonin 2b429e
  }
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
public:
Ivan Mahonin 2b429e
  TKeyHistoryT()
Ivan Mahonin 49945e
    { m_states[TTimerTicks()] = StatePointer(new State()); }
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
  StatePointer current() const
Ivan Mahonin 49945e
    { return m_states.rbegin()->second; }
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
  StatePointer change(bool press, Type value, TTimerTicks ticks)  {
Ivan Mahonin 2b429e
    StatePointer state = current()->change(press, value, ticks);
Ivan Mahonin 9e42bc
    if (state != current() && ticks > m_states.rbegin()->first)
Ivan Mahonin 49945e
      m_states[state->ticks] = state;
Ivan Mahonin 2b429e
    autoRemove();
Ivan Mahonin 2b429e
    return current();
Ivan Mahonin 2b429e
  }
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
  StatePointer pressed(Type value, TTimerTicks ticks)
Ivan Mahonin 2b429e
    { return change(true, value, ticks); }
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
  StatePointer released(Type value, TTimerTicks ticks)
Ivan Mahonin 2b429e
    { return change(false, value, ticks); }
Ivan Mahonin d8eddc
  
Ivan Mahonin d8eddc
  inline const StateMap& getStates() const
Ivan Mahonin d8eddc
    { return m_states; }
Ivan Mahonin d8eddc
  inline const LockSet& getLocks() const
Ivan Mahonin d8eddc
    { return m_locks; }
Ivan Mahonin 2b429e
};
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
Ivan Mahonin 2b429e
#endif