49945e
49945e
49945e
#include <tools inputmanager.h=""></tools>
49945e
c3c215
// TnzCore includes
c3c215
#include <tgl.h></tgl.h>
c3c215
49945e
49945e
//*****************************************************************************************
49945e
//    static members
49945e
//*****************************************************************************************
49945e
9f0c16
static const bool debugInputManager = false;
49945e
TInputState::TouchId TInputManager::m_lastTouchId = 0;
49945e
49945e
49945e
//*****************************************************************************************
49945e
//    TInputModifier implementation
49945e
//*****************************************************************************************
49945e
49945e
49945e
void
49945e
TInputModifier::setManager(TInputManager *manager) {
49945e
  if (m_manager != manager)
49945e
    { m_manager = manager; onSetManager(); }
49945e
}
49945e
49945e
49945e
void
7e9eb1
TInputModifier::modifyTrack(
c3c215
  const TTrack &track,
7e9eb1
  const TInputSavePoint::Holder &savePoint,
7e9eb1
  TTrackList &outTracks )
7e9eb1
{
c3c215
  if (!track.handler) {
c3c215
      track.handler = new TTrackHandler(track);
c3c215
      track.handler->tracks.push_back(
7e9eb1
        new TTrack(
c3c215
          new TTrackModifier(*track.handler) ));
7e9eb1
  }
7e9eb1
7e9eb1
  outTracks.insert(
7e9eb1
    outTracks.end(),
c3c215
    track.handler->tracks.begin(),
c3c215
    track.handler->tracks.end() );
c3c215
  if (!track.changed())
7e9eb1
    return;
7e9eb1
00337d
  int start = std::max(0, track.size() - track.pointsAdded);
c3c215
  for(TTrackList::const_iterator ti = track.handler->tracks.begin(); ti != track.handler->tracks.end(); ++ti) {
7e9eb1
    TTrack &subTrack = **ti;
00337d
    subTrack.truncate(start);
c3c215
    for(int i = start; i < track.size(); ++i)
7e9eb1
      subTrack.push_back( subTrack.modifier->calcPoint(i) );
7e9eb1
  }
00337d
  track.resetChanges();
7e9eb1
}
7e9eb1
7e9eb1
7e9eb1
void
49945e
TInputModifier::modifyTracks(
49945e
    const TTrackList &tracks,
49945e
    const TInputSavePoint::Holder &savePoint,
49945e
    TTrackList &outTracks )
49945e
{
49945e
  for(TTrackList::const_iterator i = tracks.begin(); i != tracks.end(); ++i)
c3c215
    modifyTrack(**i, savePoint, outTracks);
49945e
}
49945e
49945e
49945e
void
7e9eb1
TInputModifier::modifyHover(
7e9eb1
  const TPointD &hover,
7e9eb1
  THoverList &outHovers )
7e9eb1
{
7e9eb1
  outHovers.push_back(hover);
7e9eb1
}
7e9eb1
7e9eb1
7e9eb1
void
49945e
TInputModifier::modifyHovers(
49945e
  const THoverList &hovers,
49945e
  THoverList &outHovers )
49945e
{
49945e
  for(THoverList::const_iterator i = hovers.begin(); i != hovers.end(); ++i)
49945e
    modifyHover(*i, outHovers);
49945e
}
49945e
49945e
c3c215
TRectD
c3c215
TInputModifier::calcDrawBounds(const TTrackList &tracks, const THoverList &hovers) {
c3c215
  TRectD bounds;
c3c215
  for(TTrackList::const_iterator i = tracks.begin(); i != tracks.end(); ++i)
c3c215
    bounds += calcDrawBoundsTrack(**i);
c3c215
  for(std::vector<tpointd>::const_iterator i = hovers.begin(); i != hovers.end(); ++i)</tpointd>
c3c215
    bounds += calcDrawBoundsHover(*i);
c3c215
  return bounds;
c3c215
}
c3c215
c3c215
49945e
void
9cf8be
TInputModifier::drawTracks(const TTrackList &tracks) {
49945e
  for(TTrackList::const_iterator i = tracks.begin(); i != tracks.end(); ++i)
c3c215
    drawTrack(**i);
9cf8be
}
9cf8be
9cf8be
9cf8be
void
9cf8be
TInputModifier::drawHovers(const std::vector<tpointd> &hovers) {</tpointd>
9cf8be
  for(std::vector<tpointd>::const_iterator i = hovers.begin(); i != hovers.end(); ++i)</tpointd>
49945e
    drawHover(*i);
49945e
}
49945e
49945e
9cf8be
void
9cf8be
TInputModifier::draw(const TTrackList &tracks, const std::vector<tpointd> &hovers) {</tpointd>
9cf8be
  drawTracks(tracks);
9cf8be
  drawHovers(hovers);
9cf8be
}
9cf8be
9cf8be
49945e
//*****************************************************************************************
49945e
//    TInputHandler implementation
49945e
//*****************************************************************************************
49945e
49945e
49945e
bool
49945e
TInputHandler::inputKeyEvent(
49945e
  bool press,
49945e
  TInputState::Key key,
49945e
  QKeyEvent *event,
49945e
  const TInputManager &manager )
49945e
{
d8eddc
  return press && event && inputKeyDown(event);
49945e
}
49945e
49945e
49945e
void
49945e
TInputHandler::inputButtonEvent(
49945e
  bool press,
49945e
  TInputState::DeviceId device,
49945e
  TInputState::Button button,
49945e
  const TInputManager &manager )
49945e
{
49945e
  if (press && button == Qt::RightButton && !manager.getOutputHovers().empty())
49945e
    inputRightButtonDown(manager.getOutputHovers().front(), manager.state);
49945e
}
49945e
49945e
49945e
void
49945e
TInputHandler::inputHoverEvent(const TInputManager &manager) {
49945e
  if (!manager.getOutputHovers().empty())
49945e
    inputMouseMove(manager.getOutputHovers().front(), manager.state);
49945e
}
49945e
49945e
49945e
void
49945e
TInputHandler::inputPaintTrackPoint(const TTrackPoint &point, const TTrack &track, bool firstTrack) {
49945e
  if (firstTrack) {
49945e
    if (track.pointsAdded == track.size())
49945e
      inputLeftButtonDown(point, track);
49945e
    else
49945e
    if (point.final)
49945e
      inputLeftButtonUp(point, track);
49945e
    else
49945e
      inputLeftButtonDrag(point, track);
49945e
   }
49945e
}
49945e
49945e
49945e
void
49945e
TInputHandler::inputPaintTracks(const TTrackList &tracks) {
49945e
  // paint track points in chronological order
49945e
  while(true) {
49945e
    TTrackP track;
49945e
    TTimerTicks minTicks = 0;
49945e
    double minTimeOffset = 0.0;
49945e
    for(TTrackList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
49945e
      const TTrack &t = **i;
49945e
      if (t.pointsAdded > 0) {
49945e
        TTimerTicks ticks = t.ticks();
49945e
        double timeOffset = t.timeOffset() + t.current().time;
49945e
        if (!track || (ticks - minTicks)*TToolTimer::frequency + timeOffset - minTimeOffset < 0.0) {
49945e
          track = *i;
49945e
          minTicks = ticks;
49945e
          minTimeOffset = timeOffset;
49945e
        }
49945e
      }
49945e
    }
49945e
    if (!track) break;
49945e
    inputPaintTrackPoint(track->current(), *track, track == tracks.front());
49945e
    --track->pointsAdded;
49945e
  }
49945e
}
49945e
49945e
49945e
//*****************************************************************************************
49945e
//    TInputManager implementation
49945e
//*****************************************************************************************
49945e
49945e
49945e
TInputManager::TInputManager():
d8eddc
  m_lastTicks(TToolTimer::ticks()),
49945e
  m_handler(),
49945e
  m_tracks(1),
49945e
  m_hovers(1),
7a5892
  m_started(),
dba7b5
  m_savePointsSent(),
dba7b5
  drawPreview()
49945e
{ }
49945e
49945e
49945e
void
49945e
TInputManager::paintRollbackTo(int saveIndex, TTrackList &subTracks) {
49945e
  if (saveIndex >= (int)m_savePoints.size())
49945e
    return;
49945e
49945e
  int level = saveIndex + 1;
49945e
  if (level <= m_savePointsSent) {
49945e
    if (m_handler) {
49945e
      if (level < m_savePointsSent)
49945e
        m_handler->inputPaintPop(m_savePointsSent - level);
49945e
      m_handler->inputPaintCancel();
49945e
    }
49945e
    m_savePointsSent = level;
49945e
  }
49945e
49945e
  for(TTrackList::const_iterator i = subTracks.begin(); i != subTracks.end(); ++i) {
49945e
    TTrack &track = **i;
49945e
    if (TrackHandler *handler = dynamic_cast<trackhandler*>(track.handler.getPointer())) {</trackhandler*>
00337d
      handler->saves.resize(level);
49945e
      int cnt = handler->saves[saveIndex];
00337d
      track.resetRemoved();
49945e
      track.pointsAdded = track.size() - cnt;
49945e
    }
49945e
  }
49945e
  for(int i = level; i < (int)m_savePoints.size(); ++i)
49945e
    m_savePoints[i].savePoint()->available = false;
00337d
  m_savePoints.resize(level);
49945e
}
49945e
49945e
49945e
void
49945e
TInputManager::paintApply(int count, TTrackList &subTracks) {
49945e
  if (count <= 0)
49945e
    return;
49945e
49945e
  int level = (int)m_savePoints.size() - count;
49945e
  bool resend = true;
49945e
49945e
  if (level < m_savePointsSent) {
49945e
    // apply
49945e
    int applied = m_handler ? m_handler->inputPaintApply(m_savePointsSent - level) : false;
49945e
    applied = std::max(0, std::min(m_savePointsSent - level, applied));
49945e
    m_savePointsSent -= applied;
49945e
    if (m_savePointsSent == level) resend = false;
49945e
  }
49945e
49945e
  if (level < m_savePointsSent) {
49945e
    // rollback
49945e
    if (m_handler) m_handler->inputPaintPop(m_savePointsSent - level);
49945e
    m_savePointsSent = level;
49945e
  }
49945e
49945e
  // remove keypoints
49945e
  for(TTrackList::const_iterator i = subTracks.begin(); i != subTracks.end(); ++i) {
49945e
    TTrack &track = **i;
49945e
    if (TrackHandler *handler = dynamic_cast<trackhandler*>(track.handler.getPointer())) {</trackhandler*>
49945e
      if (resend) {
00337d
        track.resetRemoved();
49945e
        track.pointsAdded = track.size() - handler->saves[m_savePointsSent];
49945e
      }
00337d
      handler->saves.resize(level);
49945e
    }
49945e
  }
49945e
  for(int i = level; i < (int)m_savePoints.size(); ++i)
49945e
    m_savePoints[i].savePoint()->available = false;
00337d
  m_savePoints.resize(level);
49945e
}
49945e
49945e
49945e
void
49945e
TInputManager::paintTracks() {
49945e
  bool allFinished = true;
49945e
  for(TTrackList::const_iterator i = m_tracks.front().begin(); i != m_tracks.front().end(); ++i)
49945e
    if (!(*i)->finished())
49945e
      { allFinished = false; break; }
49945e
49945e
  while(true) {
49945e
    // run modifiers
49945e
    TInputSavePoint::Holder newSavePoint = TInputSavePoint::create(true);
49945e
    for(int i = 0; i < (int)m_modifiers.size(); ++i) {
49945e
      m_tracks[i+1].clear();
49945e
      m_modifiers[i]->modifyTracks(m_tracks[i], newSavePoint, m_tracks[i+1]);
49945e
    }
49945e
    TTrackList &subTracks = m_tracks.back();
49945e
7a5892
    // is paint started?
7a5892
    if (!m_started && !subTracks.empty()) {
7a5892
      m_started = true;
7a5892
      if (m_handler) m_handler->inputSetBusy(true);
7a5892
    }
7a5892
49945e
    // create handlers
49945e
    for(TTrackList::const_iterator i = subTracks.begin(); i != subTracks.end(); ++i)
49945e
      if (!(*i)->handler)
49945e
        (*i)->handler = new TrackHandler(**i, (int)m_savePoints.size());
49945e
49945e
    if (!m_savePoints.empty()) {
49945e
      // rollback
49945e
      int rollbackIndex = (int)m_savePoints.size();
49945e
      for(TTrackList::const_iterator i = subTracks.begin(); i != subTracks.end(); ++i) {
49945e
        TTrack &track = **i;
49945e
        if (track.pointsRemoved > 0) {
49945e
          int count = track.size() - track.pointsAdded;
49945e
          if (TrackHandler *handler = dynamic_cast<trackhandler*>(track.handler.getPointer()))</trackhandler*>
49945e
            while(rollbackIndex > 0 && (rollbackIndex >= (int)m_savePoints.size() || handler->saves[rollbackIndex] > count))
49945e
              --rollbackIndex;
49945e
        }
49945e
      }
49945e
      paintRollbackTo(rollbackIndex, subTracks);
49945e
49945e
      // apply
49945e
      int applyCount = 0;
49945e
      while(applyCount < (int)m_savePoints.size() && m_savePoints[(int)m_savePoints.size() - applyCount - 1].isFree())
49945e
        ++applyCount;
49945e
      paintApply(applyCount, subTracks);
49945e
    }
49945e
49945e
    // send to handler
49945e
    if (m_savePointsSent == (int)m_savePoints.size() && !subTracks.empty() && m_handler)
49945e
      m_handler->inputPaintTracks(subTracks);
00337d
    for(TTrackList::const_iterator i = subTracks.begin(); i != subTracks.end(); ++i)
00337d
      (*i)->resetChanges();
49945e
49945e
    // is paint finished?
c3c215
    newSavePoint.unlock();
49945e
    if (newSavePoint.isFree()) {
49945e
      newSavePoint.savePoint()->available = false;
49945e
      if (allFinished) {
49945e
        paintApply((int)m_savePoints.size(), subTracks);
362052
        // send to tool final
362052
        if (!subTracks.empty()) {
9e42bc
          if (m_handler) m_handler->inputPaintTracks(subTracks);
362052
          for(TTrackList::const_iterator i = subTracks.begin(); i != subTracks.end(); ++i)
362052
            (*i)->resetChanges();
362052
        }
49945e
        for(std::vector<ttracklist>::iterator i = m_tracks.begin(); i != m_tracks.end(); ++i)</ttracklist>
49945e
          i->clear();
7a5892
        if (m_started) {
7a5892
          if (m_handler) m_handler->inputSetBusy(false);
7a5892
          m_started = false;
7a5892
        }
49945e
      }
49945e
      break;
49945e
    }
49945e
49945e
    // create save point
49945e
    if (m_handler && m_handler->inputPaintPush()) ++m_savePointsSent;
49945e
    m_savePoints.push_back(newSavePoint);
49945e
    for(TTrackList::const_iterator i = subTracks.begin(); i != subTracks.end(); ++i)
49945e
      if (TrackHandler *handler = dynamic_cast<trackhandler*>((*i)->handler.getPointer()))</trackhandler*>
49945e
        handler->saves.push_back((*i)->size());
49945e
  }
49945e
}
49945e
49945e
49945e
int
49945e
TInputManager::trackCompare(
49945e
  const TTrack &track,
49945e
  TInputState::DeviceId deviceId,
d8eddc
  TInputState::TouchId touchId ) const
49945e
{
49945e
  if (track.deviceId < deviceId) return -1;
49945e
  if (deviceId < track.deviceId) return  1;
49945e
  if (track.touchId < touchId) return -1;
49945e
  if (touchId < track.touchId) return 1;
49945e
  return 0;
49945e
}
49945e
49945e
49945e
const TTrackP&
49945e
TInputManager::createTrack(
49945e
  int index,
49945e
  TInputState::DeviceId deviceId,
49945e
  TInputState::TouchId touchId,
49945e
  TTimerTicks ticks,
49945e
  bool hasPressure,
49945e
  bool hasTilt )
49945e
{
49945e
  TTrackP track = new TTrack(
49945e
    deviceId,
49945e
    touchId,
49945e
    state.keyHistoryHolder(ticks),
49945e
    state.buttonHistoryHolder(deviceId, ticks),
49945e
    hasPressure,
49945e
    hasTilt );
49945e
  return *m_tracks.front().insert(m_tracks[0].begin() + index, track);
49945e
}
49945e
49945e
49945e
const TTrackP&
49945e
TInputManager::getTrack(
49945e
  TInputState::DeviceId deviceId,
49945e
  TInputState::TouchId touchId,
49945e
  TTimerTicks ticks,
49945e
  bool hasPressure,
49945e
  bool hasTilt )
49945e
{
49945e
  TTrackList &origTracks = m_tracks.front();
49945e
  if (origTracks.empty())
49945e
    return createTrack(0, deviceId, touchId, ticks, hasPressure, hasTilt);
49945e
  int cmp;
49945e
49945e
  int a = 0;
49945e
  cmp = trackCompare(*origTracks[a], deviceId, touchId);
49945e
  if (cmp == 0) return origTracks[a];
49945e
  if (cmp < 0) return createTrack(a, deviceId, touchId, ticks, hasPressure, hasTilt);
49945e
49945e
  int b = (int)origTracks.size() - 1;
49945e
  cmp = trackCompare(*origTracks[b], deviceId, touchId);
49945e
  if (cmp == 0) return origTracks[b];
49945e
  if (cmp > 0) return createTrack(b+1, deviceId, touchId, ticks, hasPressure, hasTilt);
49945e
49945e
  // binary search: tracks[a] < tracks[c] < tracks[b]
49945e
  while(true) {
49945e
    int c = (a + b)/2;
49945e
    if (a == c) break;
49945e
    cmp = trackCompare(*origTracks[c], deviceId, touchId);
49945e
    if (cmp < 0) b = c; else
49945e
      if (cmp > 0) a = c; else
49945e
        return origTracks[c];
49945e
  }
49945e
  return createTrack(b, deviceId, touchId, ticks, hasPressure, hasTilt);
49945e
}
49945e
49945e
49945e
void
49945e
TInputManager::addTrackPoint(
49945e
  const TTrackP& track,
49945e
  const TPointD &position,
49945e
  double pressure,
49945e
  const TPointD &tilt,
49945e
  double time,
49945e
  bool final )
49945e
{
49945e
  track->push_back( TTrackPoint(
49945e
    position,
49945e
    pressure,
49945e
    tilt,
49945e
    (double)track->size(),
49945e
    time,
49945e
    0.0, // length will calculated inside of TTrack::push_back
49945e
    final ));
49945e
}
49945e
49945e
49945e
void
49945e
TInputManager::touchTracks(bool finish) {
49945e
  for(TTrackList::const_iterator i = m_tracks.front().begin(); i != m_tracks.front().end(); ++i) {
49945e
    if (!(*i)->finished() && (*i)->size() > 0) {
49945e
      const TTrackPoint &p = (*i)->back();
d8eddc
      addTrackPoint(*i, p.position, p.pressure, p.tilt, fixTicks(m_lastTicks)*TToolTimer::step, finish);
49945e
    }
49945e
  }
49945e
}
49945e
49945e
49945e
void
49945e
TInputManager::modifierActivate(const TInputModifierP &modifier) {
49945e
  modifier->setManager(this);
49945e
  modifier->activate();
49945e
}
49945e
49945e
49945e
void
49945e
TInputManager::modifierDeactivate(const TInputModifierP &modifier) {
49945e
  modifier->deactivate();
49945e
  modifier->setManager(NULL);
49945e
}
49945e
49945e
49945e
void
c3c215
TInputManager::processTracks() {
c3c215
  paintTracks();
9e42bc
  if (m_handler) {
9e42bc
    TRectD bounds = calcDrawBounds();
9e42bc
    if (!bounds.isEmpty()) {
9e42bc
      m_handler->inputInvalidateRect(m_prevBounds + bounds);
9e42bc
      m_nextBounds += bounds;
9e42bc
    }
7a5892
  }
c3c215
}
49945e
49945e
49945e
void
49945e
TInputManager::finishTracks() {
49945e
  touchTracks(true);
49945e
  processTracks();
49945e
}
49945e
49945e
49945e
void
49945e
TInputManager::reset() {
49945e
  // forget about handler paint stack
49945e
  // assuime it was already reset by outside
7a5892
  m_started = false;
49945e
  m_savePointsSent = 0;
49945e
49945e
  // reset save point
49945e
  for(int i = 0; i < (int)m_savePoints.size(); ++i)
49945e
    m_savePoints[i].savePoint()->available = false;
49945e
  m_savePoints.clear();
49945e
49945e
  // reset tracks
49945e
  for(int i = 0; i < (int)m_tracks.size(); ++i)
49945e
    m_tracks[i].clear();
49945e
}
49945e
49945e
49945e
void
49945e
TInputManager::setHandler(TInputHandler *handler) {
d8eddc
  if (m_handler == handler) return;
d8eddc
  finishTracks();
49945e
  m_handler = handler;
49945e
}
49945e
49945e
49945e
int
49945e
TInputManager::findModifier(const TInputModifierP &modifier) const {
49945e
  for(int i = 0; i < getModifiersCount(); ++i)
49945e
    if (getModifier(i) == modifier)
49945e
      return i;
49945e
  return -1;
49945e
}
49945e
49945e
49945e
void
49945e
TInputManager::insertModifier(int index, const TInputModifierP &modifier) {
49945e
  if (findModifier(modifier) >= 0) return;
49945e
  finishTracks();
49945e
  m_modifiers.insert(m_modifiers.begin() + index, modifier);
49945e
  m_tracks.insert(m_tracks.begin() + index + 1, TTrackList());
49945e
  m_hovers.insert(m_hovers.begin() + index + 1, THoverList());
49945e
  modifierActivate(modifier);
49945e
}
49945e
49945e
49945e
void
49945e
TInputManager::removeModifier(int index) {
49945e
  if (index >= 0 && index < getModifiersCount()) {
49945e
    finishTracks();
49945e
    modifierDeactivate(m_modifiers[index]);
49945e
    m_modifiers.erase(m_modifiers.begin() + index);
49945e
    m_tracks.erase(m_tracks.begin() + index + 1);
49945e
    m_hovers.erase(m_hovers.begin() + index + 1);
49945e
  }
49945e
}
49945e
49945e
49945e
void
49945e
TInputManager::clearModifiers() {
49945e
  while(getModifiersCount() > 0)
49945e
    removeModifier(getModifiersCount() - 1);
49945e
}
49945e
49945e
49945e
void
49945e
TInputManager::trackEvent(
49945e
  TInputState::DeviceId deviceId,
49945e
  TInputState::TouchId touchId,
49945e
  const TPointD &position,
49945e
  const double *pressure,
49945e
  const TPointD *tilt,
49945e
  bool final,
49945e
  TTimerTicks ticks )
49945e
{
d8eddc
  ticks = fixTicks(ticks);
49945e
  TTrackP track = getTrack(deviceId, touchId, ticks, (bool)pressure, (bool)tilt);
49945e
  if (!track->finished()) {
d8eddc
    ticks = fixTicks(ticks);
49945e
    double time = (double)(ticks - track->ticks())*TToolTimer::step - track->timeOffset();
49945e
    addTrackPoint(
49945e
      track,
49945e
      position,
49945e
      pressure ? *pressure : 0.5,
49945e
      tilt ? *tilt : TPointD(),
49945e
      time,
49945e
      final );
49945e
  }
49945e
}
49945e
49945e
49945e
bool
49945e
TInputManager::keyEvent(
49945e
  bool press,
49945e
  TInputState::Key key,
49945e
  TTimerTicks ticks,
49945e
  QKeyEvent *event )
49945e
{
9f0c16
  bool wasPressed = state.isKeyPressed(key);
d8eddc
  ticks = fixTicks(ticks);
49945e
  state.keyEvent(press, key, ticks);
49945e
  processTracks();
49945e
  bool result = m_handler && m_handler->inputKeyEvent(press, key, event, *this);
9f0c16
  if (wasPressed != press) {
9f0c16
    touchTracks();
9f0c16
    processTracks();
9f0c16
    //hoverEvent(getInputHovers());
9f0c16
  }
49945e
  return result;
49945e
}
49945e
49945e
49945e
void
49945e
TInputManager::buttonEvent(
49945e
  bool press,
49945e
  TInputState::DeviceId deviceId,
49945e
  TInputState::Button button,
49945e
  TTimerTicks ticks )
49945e
{
9f0c16
  bool wasPressed = state.isButtonPressed(deviceId, button);
d8eddc
  ticks = fixTicks(ticks);
49945e
  state.buttonEvent(press, deviceId, button, ticks);
49945e
  processTracks();
49945e
  if (m_handler) m_handler->inputButtonEvent(press, deviceId, button, *this);
9f0c16
  if (wasPressed != press) {
9f0c16
    touchTracks();
9f0c16
    processTracks();
9f0c16
    //hoverEvent(getInputHovers());
9f0c16
  }
49945e
}
49945e
49945e
49945e
void
49945e
TInputManager::hoverEvent(const THoverList &hovers) {
49945e
  if (&m_hovers[0] != &hovers)
49945e
    m_hovers[0] = hovers;
49945e
  for(int i = 0; i < (int)m_modifiers.size(); ++i) {
49945e
    m_hovers[i+1].clear();
49945e
    m_modifiers[i]->modifyHovers(m_hovers[i], m_hovers[i+1]);
49945e
  }
362052
  if (m_handler) {
362052
    TRectD bounds = calcDrawBounds();
7a5892
    if (!bounds.isEmpty()) {
7a5892
      m_handler->inputInvalidateRect(m_prevBounds + bounds);
7a5892
      m_nextBounds += bounds;
7a5892
    }
362052
    m_handler->inputHoverEvent(*this);
362052
  }
49945e
}
49945e
49945e
c3c215
TRectD
c3c215
TInputManager::calcDrawBounds() {
9f0c16
  if (debugInputManager)
9f0c16
    return TConsts::infiniteRectD;
9f0c16
c3c215
  TRectD bounds;
c3c215
  for(int i = 0; i < (int)m_modifiers.size(); ++i)
c3c215
    bounds += m_modifiers[i]->calcDrawBounds(m_tracks[i], m_hovers[i]);
c3c215
c3c215
  if (m_savePointsSent < (int)m_savePoints.size()) {
c3c215
    for(TTrackList::const_iterator ti = getOutputTracks().begin(); ti != getOutputTracks().end(); ++ti) {
c3c215
      TTrack &track = **ti;
c3c215
      if (TrackHandler *handler = dynamic_cast<trackhandler*>(track.handler.getPointer())) {</trackhandler*>
c3c215
        int start = handler->saves[m_savePointsSent] - 1;
c3c215
        if (start < 0) start = 0;
c3c215
        if (start + 1 < track.size())
c3c215
          for(int i = start + 1; i < track.size(); ++i)
c3c215
            bounds += boundingBox(track[i-1].position, track[i].position);
c3c215
      }
c3c215
    }
c3c215
  }
c3c215
c3c215
  if (!bounds.isEmpty())
362052
    bounds.enlarge(4.0);
c3c215
  
c3c215
  return bounds;
c3c215
}
c3c215
c3c215
49945e
void
49945e
TInputManager::draw() {
7a5892
  m_prevBounds = m_nextBounds;
7a5892
  m_nextBounds = TRectD();
7a5892
  
49945e
  // paint not sent sub-tracks
dba7b5
  if ( debugInputManager || (drawPreview && m_savePointsSent < (int)m_savePoints.size()) ) {
c3c215
    glPushAttrib(GL_ALL_ATTRIB_BITS);
c3c215
    tglEnableBlending();
dba7b5
    tglEnableLineSmooth(true, 1.0);
37c008
    double pixelSize = sqrt(tglGetPixelSize2());
37c008
    double colorBlack[4] = { 0.0, 0.0, 0.0, 1.0 };
37c008
    double colorWhite[4] = { 1.0, 1.0, 1.0, 1.0 };
c3c215
    for(TTrackList::const_iterator ti = getOutputTracks().begin(); ti != getOutputTracks().end(); ++ti) {
c3c215
      TTrack &track = **ti;
49945e
      if (TrackHandler *handler = dynamic_cast<trackhandler*>(track.handler.getPointer())) {</trackhandler*>
9f0c16
        int start = debugInputManager ? 0 : handler->saves[m_savePointsSent] - 1;
49945e
        if (start < 0) start = 0;
c3c215
        if (start + 1 < track.size()) {
dba7b5
          //int level = m_savePointsSent;
dba7b5
          //colorBlack[3] = (colorWhite[3] = 0.8);
9f0c16
          double radius = 2.0;
49945e
          for(int i = start + 1; i < track.size(); ++i) {
dba7b5
            //while(level < (int)handler->saves.size() && handler->saves[level] <= i)
dba7b5
            //  colorBlack[3] = (colorWhite[3] *= 0.8), ++level;
37c008
37c008
            const TPointD &a = track[i-1].position;
37c008
            const TPointD &b = track[i].position;
37c008
            TPointD d = b - a;
37c008
37c008
            double k = norm2(d);
37c008
            if (k > TConsts::epsilon*TConsts::epsilon) {
9f0c16
              k = 0.5*pixelSize/sqrt(k);
37c008
              d = TPointD(-k*d.y, k*d.x);
37c008
              glColor4dv(colorWhite);
37c008
              tglDrawSegment(a - d, b - d);
37c008
              glColor4dv(colorBlack);
37c008
              tglDrawSegment(a + d, b + d);
9f0c16
              radius = 2.0;
9f0c16
            } else {
9f0c16
              radius += 2.0;
9f0c16
            }
9f0c16
9f0c16
            if (debugInputManager) {
9f0c16
              glColor4d(0.0, 0.0, 0.0, 0.25);
9f0c16
              tglDrawCircle(b, radius*pixelSize);
49945e
            }
49945e
          }
49945e
        }
49945e
      }
49945e
    }
c3c215
    glPopAttrib();
49945e
  }
49945e
49945e
  // paint modifiers
49945e
  for(int i = 0; i < (int)m_modifiers.size(); ++i)
49945e
    m_modifiers[i]->draw(m_tracks[i], m_hovers[i]);
49945e
}
49945e
49945e
TInputState::TouchId
49945e
TInputManager::genTouchId()
49945e
  { return ++m_lastTouchId; }