Ivan Mahonin 249386
Ivan Mahonin 249386
// TnzTools includes
Ivan Mahonin 249386
#include <tools/tool.h>
Ivan Mahonin 249386
#include <tools/toolutils.h>
Ivan Mahonin 249386
#include <tools/toolhandle.h>
Ivan Mahonin 249386
#include <tools/cursors.h>
Ivan Mahonin 249386
#include <tools/assistant.h>
Ivan Mahonin 3bac66
#include <tools/inputmanager.h>
Ivan Mahonin 249386
Ivan Mahonin 249386
// TnzLib includes
Ivan Mahonin 249386
#include <toonz/tapplication.h>
Ivan Mahonin 249386
#include <toonz/txshlevelhandle.h>
Ivan Mahonin 8f7a4e
#include <toonz/txsheethandle.h>
Ivan Mahonin bae79a
#include <toonz/tframehandle.h>
Ivan Mahonin bae79a
#include <toonz/dpiscale.h>
Ivan Mahonin 249386
Ivan Mahonin 249386
// TnzCore includes
Ivan Mahonin 249386
#include <tgl.h>
Ivan Mahonin 249386
#include <tproperty.h>
Ivan Mahonin 249386
#include <tmetaimage.h>
Ivan Mahonin 249386
Ivan Mahonin 4dfb4a
#include <toonzqt/selection.h>
Ivan Mahonin 4dfb4a
#include <toonzqt/selectioncommandids.h>
Ivan Mahonin 1715cd
#include <toonzqt/tselectionhandle.h>
Ivan Mahonin 1715cd
Ivan Mahonin 249386
// For Qt translation support
Ivan Mahonin 249386
#include <QCoreApplication>
Ivan Mahonin 249386
Ivan Mahonin 249386
#include <map>
Ivan Mahonin 249386
Ivan Mahonin 249386
Ivan Mahonin 249386
//-------------------------------------------------------------------
Ivan Mahonin 249386
Ivan Mahonin 249386
//=============================================================================
Ivan Mahonin 249386
// Edit Assistants Undo
Ivan Mahonin 249386
//-----------------------------------------------------------------------------
Ivan Mahonin 249386
Ivan Mahonin 249386
class EditAssistantsUndo final : public ToolUtils::TToolUndo {
Ivan Mahonin 249386
private:
Ivan Mahonin d94945
  bool m_isCreated;
Ivan Mahonin d94945
  bool m_isRemoved;
Ivan Mahonin c5e805
  int m_index;
Ivan Mahonin 249386
  TMetaObjectP m_metaObject;
Ivan Mahonin 249386
  TVariant m_oldData;
Ivan Mahonin 249386
  TVariant m_newData;
Ivan Mahonin 249386
  size_t m_size;
Ivan Mahonin 249386
Ivan Mahonin 249386
public:
Ivan Mahonin 249386
  EditAssistantsUndo(
Ivan Mahonin 249386
    TXshSimpleLevel *level,
Ivan Mahonin 249386
    const TFrameId &frameId,
Ivan Mahonin 8f7a4e
    bool frameCreated,
Ivan Mahonin 8f7a4e
    bool levelCreated,
Ivan Mahonin 8f7a4e
    bool objectCreated,
Ivan Mahonin 8f7a4e
    bool objectRemoved,
Ivan Mahonin c5e805
    int index,
Ivan Mahonin 3bac66
    TMetaObjectP metaObject,
Ivan Mahonin 249386
    TVariant oldData
Ivan Mahonin 249386
  ):
Ivan Mahonin 8f7a4e
    ToolUtils::TToolUndo(level, frameId, frameCreated, levelCreated),
Ivan Mahonin 8f7a4e
    m_isCreated(objectCreated),
Ivan Mahonin 8f7a4e
    m_isRemoved(objectRemoved),
Ivan Mahonin c5e805
    m_index(index),
Ivan Mahonin 3bac66
    m_metaObject(metaObject),
Ivan Mahonin 249386
    m_oldData(oldData),
Ivan Mahonin 249386
    m_newData(m_metaObject->data()),
Ivan Mahonin 249386
    m_size(m_oldData.getMemSize() + m_newData.getMemSize())
Ivan Mahonin 249386
  { }
Ivan Mahonin 249386
Ivan Mahonin 249386
  int getSize() const override
Ivan Mahonin 249386
    { return m_size; }
Ivan Mahonin 249386
  QString getToolName() override
Ivan Mahonin 249386
    { return QString("Edit Assistants Tool"); }
Ivan Mahonin 249386
Ivan Mahonin d94945
  void process(bool remove, const TVariant &data) const {
Ivan Mahonin c5e805
    if (TMetaImage *metaImage = dynamic_cast<TMetaImage*>(m_level->getFrame(m_frameId, true).getPointer())) {
Ivan Mahonin c5e805
      TMetaImage::Writer writer(*metaImage);
Ivan Mahonin c5e805
      bool found = false;
Ivan Mahonin c5e805
      for(TMetaObjectList::iterator i = writer->begin(); i != writer->end(); ++i)
Ivan Mahonin c5e805
        if ((*i) == m_metaObject) {
Ivan Mahonin c5e805
          if (remove) writer->erase(i);
Ivan Mahonin c5e805
          found = true;
Ivan Mahonin c5e805
          break;
Ivan Mahonin d94945
        }
Ivan Mahonin c5e805
      if (!remove) {
Ivan Mahonin c5e805
        if (!found)
Ivan Mahonin c5e805
          writer->insert(
Ivan Mahonin c5e805
            writer->begin() + std::max(0, std::min((int)writer->size(), m_index)),
Ivan Mahonin c5e805
            m_metaObject );
Ivan Mahonin c5e805
        m_metaObject->data() = data;
Ivan Mahonin c5e805
        if (m_metaObject->handler())
Ivan Mahonin c5e805
          m_metaObject->handler()->fixData();
Ivan Mahonin 249386
      }
Ivan Mahonin 249386
    }
Ivan Mahonin 249386
  }
Ivan Mahonin 249386
Ivan Mahonin 8f7a4e
  void undo() const override {
Ivan Mahonin 8f7a4e
    removeLevelAndFrameIfNeeded();
Ivan Mahonin 8f7a4e
    process(m_isCreated, m_oldData);
Ivan Mahonin 8f7a4e
    TTool::getApplication()->getCurrentXsheet()->notifyXsheetChanged();
Ivan Mahonin 8f7a4e
    notifyImageChanged();
Ivan Mahonin 8f7a4e
  }
Ivan Mahonin d94945
Ivan Mahonin 8f7a4e
  void redo() const override {
Ivan Mahonin 8f7a4e
    insertLevelAndFrameIfNeeded();
Ivan Mahonin 8f7a4e
    process(m_isRemoved, m_newData);
Ivan Mahonin 8f7a4e
    TTool::getApplication()->getCurrentXsheet()->notifyXsheetChanged();
Ivan Mahonin 8f7a4e
    notifyImageChanged();
Ivan Mahonin 8f7a4e
  }
Ivan Mahonin 249386
};
Ivan Mahonin 249386
Ivan Mahonin 249386
Ivan Mahonin 249386
//=============================================================================
Ivan Mahonin 249386
// Edit Assistants Tool
Ivan Mahonin 249386
//-----------------------------------------------------------------------------
Ivan Mahonin 249386
Ivan Mahonin 249386
class EditAssistantsTool final : public TTool {
Ivan Mahonin 249386
  Q_DECLARE_TR_FUNCTIONS(EditAssistantsTool)
Ivan Mahonin 4dfb4a
public:
Ivan Mahonin 4dfb4a
  class Selection final : public TSelection {
Ivan Mahonin 4dfb4a
  private:
Ivan Mahonin 4dfb4a
    EditAssistantsTool &tool;
Ivan Mahonin 4dfb4a
  public:
Ivan Mahonin 4dfb4a
    explicit Selection(EditAssistantsTool &tool):
Ivan Mahonin 4dfb4a
      tool(tool) { }
Ivan Mahonin 4dfb4a
    void deleteSelection() 
Ivan Mahonin 4dfb4a
      { tool.removeSelected(); }
Ivan Mahonin 4dfb4a
Ivan Mahonin 4dfb4a
    void enableCommands() override
Ivan Mahonin 4dfb4a
      { if (!isEmpty()) enableCommand(this, MI_Clear, &Selection::deleteSelection); }
Ivan Mahonin 4dfb4a
    bool isEmpty() const override
Ivan Mahonin 4dfb4a
      { return !tool.isSelected(); }
Ivan Mahonin 4dfb4a
    void selectNone() override
Ivan Mahonin 4dfb4a
      { tool.deselect(); }
Ivan Mahonin 4dfb4a
  };
Ivan Mahonin 4dfb4a
  
Ivan Mahonin 4da757
protected:
Ivan Mahonin 3bac66
  enum Mode {
Ivan Mahonin 3bac66
    ModeImage,
Ivan Mahonin 3bac66
    ModeAssistant,
Ivan Mahonin 3bac66
    ModePoint
Ivan Mahonin 3bac66
  };
Ivan Mahonin 249386
Ivan Mahonin 3bac66
  TPropertyGroup m_allProperties;
Ivan Mahonin 3bac66
  TPropertyGroup m_toolProperties;
Ivan Mahonin 249386
  TEnumProperty m_assistantType;
Ivan Mahonin 249386
  TStringId m_newAssisnantType;
Ivan Mahonin 249386
Ivan Mahonin 249386
  bool           m_dragging;
Ivan Mahonin aedcda
  bool           m_dragAllPoints;
Ivan Mahonin 9bb114
  TSmartHolderT<TImage> m_currentImage;
Ivan Mahonin 3bac66
  TMetaObjectH   m_currentAssistant;
Ivan Mahonin 249386
  bool           m_currentAssistantCreated;
Ivan Mahonin 3bac66
  bool           m_currentAssistantChanged;
Ivan Mahonin 249386
  int            m_currentAssistantIndex;
Ivan Mahonin 3bac66
  TVariant       m_currentAssistantBackup;
Ivan Mahonin c5e805
  TStringId      m_currentPointName;
Ivan Mahonin 249386
  TPointD        m_currentPointOffset;
Ivan Mahonin 249386
  TPointD        m_currentPosition;
Ivan Mahonin 249386
  TGuidelineList m_currentGuidelines;
Ivan Mahonin 249386
Ivan Mahonin 3bac66
  TMetaImage::Reader *m_reader;
Ivan Mahonin 3bac66
  TMetaImage         *m_readImage;
Ivan Mahonin 3bac66
  TMetaObjectPC       m_readObject;
Ivan Mahonin 3bac66
  const TAssistant   *m_readAssistant;
Ivan Mahonin 3bac66
Ivan Mahonin 3bac66
  TMetaImage::Writer *m_writer;
Ivan Mahonin 3bac66
  TMetaImage         *m_writeImage;
Ivan Mahonin 3bac66
  TMetaObjectP        m_writeObject;
Ivan Mahonin 3bac66
  TAssistant         *m_writeAssistant;
Ivan Mahonin 3bac66
Ivan Mahonin 4dfb4a
  Selection *selection;
Ivan Mahonin 4dfb4a
Ivan Mahonin 249386
public:
Ivan Mahonin 249386
  EditAssistantsTool():
Ivan Mahonin 249386
    TTool("T_EditAssistants"),
Ivan Mahonin 249386
    m_assistantType("AssistantType"),
Ivan Mahonin 249386
    m_dragging(),
Ivan Mahonin aedcda
    m_dragAllPoints(),
Ivan Mahonin 249386
    m_currentAssistantCreated(),
Ivan Mahonin 3bac66
    m_currentAssistantChanged(),
Ivan Mahonin 249386
    m_currentAssistantIndex(-1),
Ivan Mahonin 3bac66
    m_reader(),
Ivan Mahonin 3bac66
    m_readImage(),
Ivan Mahonin 3bac66
    m_readAssistant(),
Ivan Mahonin 3bac66
    m_writer(),
Ivan Mahonin 3bac66
    m_writeImage(),
Ivan Mahonin 3bac66
    m_writeAssistant()
Ivan Mahonin 249386
  {
Ivan Mahonin 4dfb4a
    selection = new Selection(*this);
Ivan Mahonin 66ffab
    bind(MetaImage | EmptyTarget);
Ivan Mahonin 3bac66
    m_toolProperties.bind(m_assistantType);
Ivan Mahonin 249386
    updateTranslation();
Ivan Mahonin 249386
  }
Ivan Mahonin 3bac66
Ivan Mahonin 4dfb4a
  ~EditAssistantsTool() {
Ivan Mahonin 4dfb4a
    close();
Ivan Mahonin 4dfb4a
    delete selection;
Ivan Mahonin 4dfb4a
  }
Ivan Mahonin 3bac66
Ivan Mahonin 249386
  ToolType getToolType() const override
Ivan Mahonin 249386
    { return TTool::LevelWriteTool; }
Ivan Mahonin 249386
  int getCursorId() const override
Ivan Mahonin 249386
    { return ToolCursor::StrokeSelectCursor; }
Ivan Mahonin 9bb114
  void onImageChanged() override {
Ivan Mahonin 9bb114
    if (m_currentImage != getImage(false)) resetCurrentPoint();
Ivan Mahonin 9bb114
    getViewer()->GLInvalidateAll();
Ivan Mahonin 9bb114
  }
Ivan Mahonin 249386
Ivan Mahonin 4da757
  void updateAssistantTypes() {
Ivan Mahonin 4da757
    std::wstring value = m_assistantType.getValue();
Ivan Mahonin 4da757
Ivan Mahonin 4da757
    m_assistantType.deleteAllValues();
Ivan Mahonin 4da757
    m_assistantType.addValueWithUIName(L"", tr("--"));
Ivan Mahonin 4da757
Ivan Mahonin 4da757
    const TMetaObject::Registry &registry = TMetaObject::getRegistry();
Ivan Mahonin 4da757
    for(TMetaObject::Registry::const_iterator i = registry.begin(); i != registry.end(); ++i)
Ivan Mahonin 4da757
      if (const TAssistantType *assistantType = dynamic_cast<const TAssistantType*>(i->second))
Ivan Mahonin 4da757
        if (assistantType->name)
Ivan Mahonin 4da757
          m_assistantType.addValueWithUIName(
Ivan Mahonin 4da757
            to_wstring(assistantType->name.str()),
Ivan Mahonin 4da757
            assistantType->getLocalName() );
Ivan Mahonin 4da757
Ivan Mahonin 4da757
    if (m_assistantType.indexOf(value) >= 0)
Ivan Mahonin 4da757
      m_assistantType.setValue(value);
Ivan Mahonin 4da757
  }
Ivan Mahonin 4da757
Ivan Mahonin 3bac66
  TPropertyGroup* getProperties(int) override {
Ivan Mahonin 3bac66
    m_allProperties.clear();
Ivan Mahonin 3bac66
    for(int i = 0; i < m_toolProperties.getPropertyCount(); ++i)
Ivan Mahonin 3bac66
      m_allProperties.bind( *m_toolProperties.getProperty(i) );
Ivan Mahonin 3bac66
    if (Closer closer = read(ModeAssistant)) {
Ivan Mahonin 4da757
      m_readAssistant->updateTranslation();
Ivan Mahonin 3bac66
      TPropertyGroup &assistantProperties = m_readAssistant->getProperties();
Ivan Mahonin 3bac66
      for(int i = 0; i < assistantProperties.getPropertyCount(); ++i)
Ivan Mahonin 3bac66
        m_allProperties.bind( *assistantProperties.getProperty(i) );
Ivan Mahonin 3bac66
    }
Ivan Mahonin 3bac66
    return &m_allProperties;
Ivan Mahonin 3bac66
  }
Ivan Mahonin 3bac66
Ivan Mahonin 9bb114
  void onActivate() override {
Ivan Mahonin 9bb114
    updateAssistantTypes();
Ivan Mahonin 9bb114
    resetCurrentPoint();
Ivan Mahonin 9bb114
  }
Ivan Mahonin 9bb114
Ivan Mahonin 9bb114
  void onDeactivate() override
Ivan Mahonin 9bb114
    { resetCurrentPoint(); }
Ivan Mahonin 249386
Ivan Mahonin 249386
  void updateTranslation() override {
Ivan Mahonin 4da757
    m_assistantType.setQStringName( tr("Assistant Type") );
Ivan Mahonin 4da757
    updateAssistantTypes();
Ivan Mahonin 4da757
    if (Closer closer = read(ModeAssistant))
Ivan Mahonin 4da757
      m_readAssistant->updateTranslation();
Ivan Mahonin 249386
  }
Ivan Mahonin 249386
Ivan Mahonin d07d8b
  bool onPropertyChanged(std::string name, bool addToUndo) override {
Ivan Mahonin 3bac66
    if (TProperty *property = m_toolProperties.getProperty(name)) {
Ivan Mahonin 3bac66
      if (name == m_assistantType.getName())
Ivan Mahonin 3bac66
        m_newAssisnantType = TStringId::find( to_string(m_assistantType.getValue()) );
Ivan Mahonin 3bac66
    } else {
Ivan Mahonin 3bac66
      if (Closer closer = write(ModeAssistant, true))
Ivan Mahonin 3bac66
        m_writeAssistant->propertyChanged(TStringId::find(name));
Ivan Mahonin d07d8b
      if (addToUndo) apply();
Ivan Mahonin 3bac66
      getViewer()->GLInvalidateAll();
Ivan Mahonin 3bac66
    }
Ivan Mahonin 249386
    return true;
Ivan Mahonin 249386
  }
Ivan Mahonin 4dfb4a
  
Ivan Mahonin 4dfb4a
  TSelection* getSelection() override
Ivan Mahonin 4dfb4a
    { return isSelected() ? selection : 0; }
Ivan Mahonin 4dfb4a
  
Ivan Mahonin 3bac66
protected:
Ivan Mahonin 3bac66
  void close() {
Ivan Mahonin 3bac66
    m_readAssistant = 0;
Ivan Mahonin 3bac66
    m_readObject.reset();
Ivan Mahonin 3bac66
    m_readImage = 0;
Ivan Mahonin 3bac66
    if (m_reader) delete(m_reader);
Ivan Mahonin 3bac66
    m_reader = 0;
Ivan Mahonin 3bac66
Ivan Mahonin 3bac66
    m_writeAssistant = 0;
Ivan Mahonin 3bac66
    m_writeObject.reset();
Ivan Mahonin 3bac66
    m_writeImage = 0;
Ivan Mahonin 3bac66
    if (m_writer) delete(m_writer);
Ivan Mahonin 3bac66
    m_writer = 0;
Ivan Mahonin 3bac66
  }
Ivan Mahonin 3bac66
Ivan Mahonin 3bac66
  bool openRead(Mode mode) {
Ivan Mahonin 3bac66
    close();
Ivan Mahonin 3bac66
Ivan Mahonin 3bac66
    if ( (mode >= ModeAssistant && !m_currentAssistant)
Ivan Mahonin 3bac66
      || (mode >= ModeAssistant && m_currentAssistantIndex < 0)
Ivan Mahonin c5e805
      || (mode >= ModePoint && !m_currentPointName) ) return false;
Ivan Mahonin 3bac66
Ivan Mahonin 4dfb4a
    m_readImage = dynamic_cast<TMetaImage*>(getImage(false));
Ivan Mahonin 3bac66
    if (m_readImage) {
Ivan Mahonin 3bac66
      m_reader = new TMetaImage::Reader(*m_readImage);
Ivan Mahonin 3bac66
      if (mode == ModeImage) return true;
Ivan Mahonin 3bac66
Ivan Mahonin 3bac66
      if ( m_currentAssistantIndex < (int)(*m_reader)->size()
Ivan Mahonin 3bac66
        && (**m_reader)[m_currentAssistantIndex] == m_currentAssistant )
Ivan Mahonin 3bac66
      {
Ivan Mahonin 3bac66
        m_readObject = (**m_reader)[m_currentAssistantIndex];
Ivan Mahonin 3bac66
        m_readAssistant = m_readObject->getHandler<TAssistant>();
Ivan Mahonin 3bac66
        if (mode == ModeAssistant) return true;
Ivan Mahonin 3bac66
Ivan Mahonin c5e805
        if (m_readAssistant->findPoint(m_currentPointName)) {
Ivan Mahonin 3bac66
          if (mode == ModePoint) return true;
Ivan Mahonin 3bac66
        }
Ivan Mahonin 3bac66
      }
Ivan Mahonin 3bac66
    }
Ivan Mahonin 3bac66
Ivan Mahonin 3bac66
    close();
Ivan Mahonin 3bac66
    return false;
Ivan Mahonin 3bac66
  }
Ivan Mahonin 3bac66
Ivan Mahonin 3bac66
  void touch() {
Ivan Mahonin 3bac66
    if (m_writeAssistant && !m_currentAssistantChanged) {
Ivan Mahonin 3bac66
      m_currentAssistantBackup = m_writeAssistant->data();
Ivan Mahonin 3bac66
      m_currentAssistantChanged = true;
Ivan Mahonin 3bac66
    }
Ivan Mahonin 3bac66
  }
Ivan Mahonin 3bac66
Ivan Mahonin 3bac66
  bool openWrite(Mode mode, bool touch = false) {
Ivan Mahonin 3bac66
    close();
Ivan Mahonin 3bac66
Ivan Mahonin 3bac66
    if ( (mode >= ModeAssistant && !m_currentAssistant)
Ivan Mahonin 3bac66
      || (mode >= ModeAssistant && m_currentAssistantIndex < 0)
Ivan Mahonin c5e805
      || (mode >= ModePoint && !m_currentPointName) ) return false;
Ivan Mahonin 3bac66
Ivan Mahonin 3bac66
    m_writeImage = dynamic_cast<TMetaImage*>(getImage(true));
Ivan Mahonin 3bac66
    if (m_writeImage) {
Ivan Mahonin 3bac66
      m_writer = new TMetaImage::Writer(*m_writeImage);
Ivan Mahonin 3bac66
      if (mode == ModeImage) return true;
Ivan Mahonin 3bac66
Ivan Mahonin 3bac66
      if ( m_currentAssistantIndex < (int)(*m_writer)->size()
Ivan Mahonin 3bac66
        && (**m_writer)[m_currentAssistantIndex] == m_currentAssistant )
Ivan Mahonin 3bac66
      {
Ivan Mahonin 3bac66
        m_writeObject = (**m_writer)[m_currentAssistantIndex];
Ivan Mahonin 3bac66
        m_writeAssistant = m_writeObject->getHandler<TAssistant>();
Ivan Mahonin 3bac66
        if ( (mode == ModeAssistant)
Ivan Mahonin c5e805
          || (mode == ModePoint && m_writeAssistant->findPoint(m_currentPointName)) )
Ivan Mahonin 3bac66
        {
Ivan Mahonin 3bac66
          if (touch) this->touch();
Ivan Mahonin 3bac66
          return true;
Ivan Mahonin 3bac66
        }
Ivan Mahonin 3bac66
      }
Ivan Mahonin 3bac66
    }
Ivan Mahonin 3bac66
Ivan Mahonin 3bac66
    close();
Ivan Mahonin 3bac66
    return false;
Ivan Mahonin 3bac66
  }
Ivan Mahonin 3bac66
Ivan Mahonin 3bac66
Ivan Mahonin 3bac66
  //! helper functions for construction like this:
Ivan Mahonin 3bac66
  //!   if (Closer closer = read(ModeAssistant)) { do-something... }
Ivan Mahonin 3bac66
  struct Closer {
Ivan Mahonin 3bac66
    struct Args {
Ivan Mahonin 3bac66
      EditAssistantsTool *owner;
Ivan Mahonin 3bac66
      Args(EditAssistantsTool &owner): owner(&owner) { }
Ivan Mahonin 3bac66
      operator bool() const //!< declare bool-convertor here to prevent convertion path: Args->Closer->bool
Ivan Mahonin 3bac66
        { return owner && (owner->m_reader || owner->m_writer); }
Ivan Mahonin 3bac66
      void close()
Ivan Mahonin 3bac66
        { if (owner) owner->close(); }
Ivan Mahonin 3bac66
    };
Ivan Mahonin 3bac66
    Closer(const Args &args): args(args) { }
Ivan Mahonin 3bac66
    ~Closer() { args.close(); }
Ivan Mahonin 3bac66
    operator bool() const { return args; }
Ivan Mahonin 3bac66
  private:
Ivan Mahonin 3bac66
    Args args;
Ivan Mahonin 3bac66
  };
Ivan Mahonin 3bac66
Ivan Mahonin 3bac66
  Closer::Args read(Mode mode)
Ivan Mahonin 3bac66
    { openRead(mode); return Closer::Args(*this); }
Ivan Mahonin 3bac66
  Closer::Args write(Mode mode, bool touch = false)
Ivan Mahonin 3bac66
    { openWrite(mode, touch); return Closer::Args(*this); }
Ivan Mahonin 3bac66
Ivan Mahonin 3bac66
  void updateOptionsBox()
Ivan Mahonin cbbe07
    { getApplication()->getCurrentTool()->notifyToolOptionsBoxChanged(); }
Ivan Mahonin 3bac66
Ivan Mahonin 3bac66
  void resetCurrentPoint(bool updateOptionsBox = true) {
Ivan Mahonin 3bac66
    close();
Ivan Mahonin 9bb114
    m_currentImage.reset();
Ivan Mahonin 3bac66
    m_currentAssistant.reset();
Ivan Mahonin 249386
    m_currentAssistantCreated = false;
Ivan Mahonin 3bac66
    m_currentAssistantChanged = false;
Ivan Mahonin 249386
    m_currentAssistantIndex = -1;
Ivan Mahonin c5e805
    m_currentPointName.reset();
Ivan Mahonin 249386
    m_currentPointOffset = TPointD();
Ivan Mahonin 249386
    m_currentAssistantBackup.reset();
Ivan Mahonin 9bb114
Ivan Mahonin 9bb114
    // deselect points
Ivan Mahonin 9bb114
    if (Closer closer = read(ModeImage))
Ivan Mahonin 9bb114
      for(TMetaObjectListCW::iterator i = (*m_reader)->begin(); i != (*m_reader)->end(); ++i)
Ivan Mahonin 9bb114
        if (*i)
Ivan Mahonin 9bb114
          if (const TAssistant *assistant = (*i)->getHandler<TAssistant>())
Ivan Mahonin 9bb114
            assistant->deselectAll();
Ivan Mahonin 9bb114
Ivan Mahonin 3bac66
    if (updateOptionsBox) this->updateOptionsBox();
Ivan Mahonin 249386
  }
Ivan Mahonin 249386
Ivan Mahonin 3bac66
  bool findCurrentPoint(const TPointD &position, double pixelSize = 1, bool updateOptionsBox = true) {
Ivan Mahonin 3bac66
    resetCurrentPoint(false);
Ivan Mahonin 3bac66
    if (Closer closer = read(ModeImage)) {
Ivan Mahonin 9bb114
      m_currentImage.set(m_readImage);
Ivan Mahonin 3bac66
      for(TMetaObjectListCW::iterator i = (*m_reader)->begin(); i != (*m_reader)->end(); ++i) {
Ivan Mahonin 3bac66
        if (!*i) continue;
Ivan Mahonin 3bac66
Ivan Mahonin 3bac66
        const TAssistant *assistant = (*i)->getHandler<TAssistant>();
Ivan Mahonin 3bac66
        if (!assistant) continue;
Ivan Mahonin 3bac66
Ivan Mahonin 3bac66
        assistant->deselectAll();
Ivan Mahonin 7900ea
Ivan Mahonin 7900ea
        // last points is less significant and don't affecting the first points
Ivan Mahonin 7900ea
        // so iterate points in reverse order to avoid unsolvable points overlapping
Ivan Mahonin 7900ea
        const TAssistantPointOrder &points = assistant->pointsOrder();
Ivan Mahonin 7900ea
        for( TAssistantPointOrder::const_reverse_iterator j = points.rbegin();
Ivan Mahonin 7900ea
             j != points.rend() && m_currentAssistantIndex < 0;
Ivan Mahonin 7900ea
             ++j )
Ivan Mahonin 7900ea
        {
Ivan Mahonin 7900ea
          const TAssistantPoint &p = **j;
Ivan Mahonin 3bac66
          TPointD offset = p.position - position;
Ivan Mahonin c5e805
          if (p.visible && norm2(offset) <= p.radius*p.radius*pixelSize*pixelSize) {
Ivan Mahonin 3bac66
            m_currentAssistant.set(*i);
Ivan Mahonin 3bac66
            m_currentAssistantIndex = i - (*m_reader)->begin();
Ivan Mahonin 7900ea
            m_currentPointName = p.name;
Ivan Mahonin 3bac66
            m_currentPointOffset = offset;
Ivan Mahonin 3bac66
            assistant->selectAll();
Ivan Mahonin 3bac66
          }
Ivan Mahonin 249386
        }
Ivan Mahonin 249386
      }
Ivan Mahonin 249386
    }
Ivan Mahonin 3bac66
Ivan Mahonin 3bac66
    if (updateOptionsBox) this->updateOptionsBox();
Ivan Mahonin 3bac66
    return m_currentAssistantIndex >= 0;
Ivan Mahonin 249386
  }
Ivan Mahonin 249386
Ivan Mahonin 3bac66
  bool apply() {
Ivan Mahonin 3bac66
    bool success = false;
Ivan Mahonin 3bac66
    if (m_currentAssistantChanged || m_currentAssistantCreated) {
Ivan Mahonin 7900ea
      if (Closer closer = write(ModeAssistant)) {
Ivan Mahonin 3bac66
        m_writeAssistant->fixData();
Ivan Mahonin 3bac66
        TUndoManager::manager()->add(new EditAssistantsUndo(
Ivan Mahonin 3bac66
          getApplication()->getCurrentLevel()->getLevel()->getSimpleLevel(),
Ivan Mahonin 3bac66
          getCurrentFid(),
Ivan Mahonin 8f7a4e
          m_isFrameCreated,
Ivan Mahonin 8f7a4e
          m_isLevelCreated,
Ivan Mahonin 3bac66
          m_currentAssistantCreated,
Ivan Mahonin 3bac66
          false,
Ivan Mahonin c5e805
          m_currentAssistantIndex,
Ivan Mahonin 3bac66
          m_writeObject,
Ivan Mahonin 3bac66
          m_currentAssistantBackup ));
Ivan Mahonin 3bac66
        m_currentAssistantCreated = false;
Ivan Mahonin 3bac66
        m_currentAssistantChanged = false;
Ivan Mahonin 8f7a4e
        m_isFrameCreated = false;
Ivan Mahonin 8f7a4e
        m_isLevelCreated = false;
Ivan Mahonin 3bac66
        success = true;
Ivan Mahonin 3bac66
      }
Ivan Mahonin 3bac66
    }
Ivan Mahonin 3bac66
Ivan Mahonin 3bac66
    if (success) {
Ivan Mahonin 3bac66
      notifyImageChanged();
Ivan Mahonin 3bac66
      getApplication()->getCurrentTool()->notifyToolChanged();
Ivan Mahonin 4dfb4a
      TTool::getApplication()->getCurrentSelection()->setSelection( getSelection() );
Ivan Mahonin 3bac66
      getViewer()->GLInvalidateAll();
Ivan Mahonin 3bac66
    }
Ivan Mahonin 3bac66
Ivan Mahonin 3bac66
    return success;
Ivan Mahonin 249386
  }
Ivan Mahonin 4dfb4a
  
Ivan Mahonin 8f7a4e
public:
Ivan Mahonin 4dfb4a
  void deselect()
Ivan Mahonin 4dfb4a
    { resetCurrentPoint(); }
Ivan Mahonin 4dfb4a
  
Ivan Mahonin 4dfb4a
  bool isSelected()
Ivan Mahonin 4dfb4a
    { return read(ModeAssistant); }
Ivan Mahonin 4dfb4a
  
Ivan Mahonin 4dfb4a
  bool removeSelected() {
Ivan Mahonin 4dfb4a
    apply();
Ivan Mahonin 4dfb4a
    bool success = false;
Ivan Mahonin 4dfb4a
    if (Closer closer = write(ModeAssistant, true)) {
Ivan Mahonin 4dfb4a
      (*m_writer)->erase((*m_writer)->begin() + m_currentAssistantIndex);
Ivan Mahonin 4dfb4a
      TUndoManager::manager()->add(new EditAssistantsUndo(
Ivan Mahonin 4dfb4a
          getApplication()->getCurrentLevel()->getLevel()->getSimpleLevel(),
Ivan Mahonin 4dfb4a
          getCurrentFid(),
Ivan Mahonin 4dfb4a
          false,  // frameCreated
Ivan Mahonin 4dfb4a
          false,  // levelCreated
Ivan Mahonin 4dfb4a
          false,  // objectCreated
Ivan Mahonin 4dfb4a
          true,   // objectRemoved
Ivan Mahonin 4dfb4a
          m_currentAssistantIndex, m_writeObject, m_writeObject->data()));
Ivan Mahonin 4dfb4a
      success = true;
Ivan Mahonin 4dfb4a
    }
Ivan Mahonin 4dfb4a
Ivan Mahonin 4dfb4a
    if (success) notifyImageChanged();
Ivan Mahonin 4dfb4a
Ivan Mahonin 4dfb4a
    resetCurrentPoint();
Ivan Mahonin 4dfb4a
    getApplication()->getCurrentTool()->notifyToolChanged();
Ivan Mahonin 4dfb4a
    TTool::getApplication()->getCurrentSelection()->setSelection( getSelection() );
Ivan Mahonin 4dfb4a
    getViewer()->GLInvalidateAll();
Ivan Mahonin 4dfb4a
    return success;
Ivan Mahonin 4dfb4a
  }
Ivan Mahonin 4dfb4a
  
Ivan Mahonin 8f7a4e
  bool preLeftButtonDown() override {
Ivan Mahonin af0f93
    if (m_assistantType.getIndex() != 0) touchImage();
Ivan Mahonin 4dfb4a
    TTool::getApplication()->getCurrentSelection()->setSelection( getSelection() );
Ivan Mahonin 8f7a4e
    return true;
Ivan Mahonin 8f7a4e
  }
Ivan Mahonin 8f7a4e
Ivan Mahonin aedcda
  void leftButtonDown(const TPointD &position, const TMouseEvent &event) override {
Ivan Mahonin 3bac66
    apply();
Ivan Mahonin 249386
    m_dragging = true;
Ivan Mahonin aedcda
    m_dragAllPoints = false;
Ivan Mahonin 249386
    if (m_newAssisnantType) {
Ivan Mahonin 249386
      // create assistant
Ivan Mahonin 7900ea
      resetCurrentPoint(false);
Ivan Mahonin 3bac66
      if (Closer closer = write(ModeImage)) {
Ivan Mahonin 3bac66
        TMetaObjectP object(new TMetaObject(m_newAssisnantType));
Ivan Mahonin 3bac66
        if (TAssistant *assistant = object->getHandler<TAssistant>()) {
Ivan Mahonin c5e805
          assistant->setDefaults();
Ivan Mahonin 7900ea
          assistant->move(position);
Ivan Mahonin 7900ea
          assistant->selectAll();
Ivan Mahonin 4dfb4a
          m_currentImage.set(m_writeImage);
Ivan Mahonin aedcda
          m_dragAllPoints = true;
Ivan Mahonin c5e805
          m_currentAssistantCreated = true;
Ivan Mahonin c5e805
          m_currentAssistantChanged = true;
Ivan Mahonin c5e805
          m_currentAssistantIndex = (int)(*m_writer)->size();
Ivan Mahonin c5e805
          m_currentAssistant = object;
Ivan Mahonin c5e805
          m_currentPointName = assistant->getBasePoint().name;
Ivan Mahonin c5e805
          m_currentPointOffset = TPointD();
Ivan Mahonin c5e805
          m_currentAssistantBackup = assistant->data();
Ivan Mahonin 3bac66
          (*m_writer)->push_back(object);
Ivan Mahonin 249386
        }
Ivan Mahonin 249386
      }
Ivan Mahonin 7900ea
      updateOptionsBox();
Ivan Mahonin 249386
      m_newAssisnantType.reset();
Ivan Mahonin 3bac66
    } else {
Ivan Mahonin 985f38
      findCurrentPoint(position, getViewer()->getPixelSize());
Ivan Mahonin aedcda
      if (event.isShiftPressed())
Ivan Mahonin aedcda
        if (Closer closer = read(ModePoint)) {
Ivan Mahonin aedcda
          m_currentPointName = m_readAssistant->getBasePoint().name;
Ivan Mahonin aedcda
          m_currentPointOffset = m_readAssistant->getBasePoint().position - position;
Ivan Mahonin aedcda
          m_dragAllPoints = true;
Ivan Mahonin aedcda
        }
Ivan Mahonin 249386
    }
Ivan Mahonin 3bac66
Ivan Mahonin 249386
    m_currentPosition = position;
Ivan Mahonin 249386
    getViewer()->GLInvalidateAll();
Ivan Mahonin 249386
  }
Ivan Mahonin 249386
Ivan Mahonin 249386
  void leftButtonDrag(const TPointD &position, const TMouseEvent&) override {
Ivan Mahonin aedcda
    if (m_dragAllPoints) {
Ivan Mahonin b15438
      if (Closer closer = write(ModeAssistant))
Ivan Mahonin b15438
        if (m_writeAssistant->move(position + m_currentPointOffset))
Ivan Mahonin b15438
          touch();
Ivan Mahonin 7900ea
    } else {
Ivan Mahonin b15438
      if (Closer closer = write(ModePoint))
Ivan Mahonin b15438
        if (m_writeAssistant->movePoint(m_currentPointName, position + m_currentPointOffset))
Ivan Mahonin b15438
          touch();
Ivan Mahonin 7900ea
    }
Ivan Mahonin 249386
    m_currentPosition = position;
Ivan Mahonin 249386
    getViewer()->GLInvalidateAll();
Ivan Mahonin 249386
  }
Ivan Mahonin 249386
Ivan Mahonin 249386
  void leftButtonUp(const TPointD &position, const TMouseEvent&) override {
Ivan Mahonin 4dfb4a
    if (m_dragAllPoints) {
Ivan Mahonin b15438
      if (Closer closer = write(ModeAssistant))
Ivan Mahonin b15438
        if (m_writeAssistant->move(position + m_currentPointOffset))
Ivan Mahonin b15438
          touch();
Ivan Mahonin 7900ea
    } else {
Ivan Mahonin b15438
      if (Closer closer = write(ModePoint))
Ivan Mahonin b15438
        if (m_writeAssistant->movePoint(m_currentPointName, position + m_currentPointOffset))
Ivan Mahonin b15438
          touch();
Ivan Mahonin 7900ea
    }
Ivan Mahonin 3bac66
Ivan Mahonin 3bac66
    apply();
Ivan Mahonin d94945
    m_assistantType.setIndex(0);
Ivan Mahonin 249386
    getApplication()->getCurrentTool()->notifyToolChanged();
Ivan Mahonin 4dfb4a
    TTool::getApplication()->getCurrentSelection()->setSelection( getSelection() );
Ivan Mahonin 249386
    m_currentPosition = position;
Ivan Mahonin 249386
    getViewer()->GLInvalidateAll();
Ivan Mahonin aedcda
    m_dragAllPoints = false;
Ivan Mahonin 249386
    m_dragging = false;
Ivan Mahonin 249386
  }
Ivan Mahonin 249386
Ivan Mahonin bae79a
  void mouseMove(const TPointD &position, const TMouseEvent&) override {
Ivan Mahonin bae79a
    m_currentPosition = position;
Ivan Mahonin bae79a
    m_currentPointOffset = TPointD();
Ivan Mahonin bae79a
    getViewer()->GLInvalidateAll();
Ivan Mahonin bae79a
  }
Ivan Mahonin bae79a
Ivan Mahonin 249386
  void draw() override {
Ivan Mahonin 249386
    m_currentGuidelines.clear();
Ivan Mahonin bae79a
    TPointD position = m_currentPosition + m_currentPointOffset;
Ivan Mahonin bae79a
    
Ivan Mahonin 249386
    // draw assistants
Ivan Mahonin 3bac66
    if (Closer closer = read(ModeImage))
Ivan Mahonin 3bac66
    for(TMetaObjectListCW::iterator i = (*m_reader)->begin(); i != (*m_reader)->end(); ++i)
Ivan Mahonin 249386
      if (*i)
Ivan Mahonin 249386
      if (const TAssistant *assistant = (*i)->getHandler<TAssistant>())
Ivan Mahonin 249386
      {
Ivan Mahonin 249386
        assistant->drawEdit(getViewer());
Ivan Mahonin 249386
        assistant->getGuidelines(
Ivan Mahonin 249386
          m_currentPosition + m_currentPointOffset,
Ivan Mahonin 249386
          TAffine(),
Ivan Mahonin 249386
          m_currentGuidelines );
Ivan Mahonin 249386
      }
Ivan Mahonin bae79a
    
Ivan Mahonin bae79a
    // draw assistans from other layers
Ivan Mahonin bae79a
    TImage *currentImage = getImage(false);
Ivan Mahonin bae79a
    if (TToolViewer *viewer = getViewer())
Ivan Mahonin bae79a
    if (TApplication *application = getApplication())
Ivan Mahonin bae79a
    if (TXshLevelHandle *levelHandle = application->getCurrentLevel())
Ivan Mahonin bae79a
    if (TXshLevel *level = levelHandle->getLevel())
Ivan Mahonin bae79a
    if (TXshSimpleLevel *simpleLevel = level->getSimpleLevel())
Ivan Mahonin bae79a
    if (TFrameHandle *frameHandle = application->getCurrentFrame())
Ivan Mahonin bae79a
    if (TXsheetHandle *XsheetHandle = application->getCurrentXsheet())
Ivan Mahonin bae79a
    if (TXsheet *Xsheet = XsheetHandle->getXsheet())
Ivan Mahonin bae79a
    {
Ivan Mahonin bae79a
      TPointD dpiScale = getCurrentDpiScale(simpleLevel, getCurrentFid());
Ivan Mahonin bae79a
      int frame = frameHandle->getFrame();
Ivan Mahonin bae79a
      int count = Xsheet->getColumnCount();
Ivan Mahonin bae79a
      TAffine worldToTrack;
Ivan Mahonin bae79a
      worldToTrack.a11 /= dpiScale.x;
Ivan Mahonin bae79a
      worldToTrack.a22 /= dpiScale.y;
Ivan Mahonin bae79a
Ivan Mahonin bae79a
      for(int i = 0; i < count; ++i)
Ivan Mahonin bae79a
      if (TXshColumn *column = Xsheet->getColumn(i))
Ivan Mahonin bae79a
      if (column->isCamstandVisible())
Ivan Mahonin bae79a
      if (column->isPreviewVisible())
Ivan Mahonin bae79a
      if (TImageP image = Xsheet->getCell(frame, i).getImage(false))
Ivan Mahonin bae79a
      if (image->getType() == TImage::META)
Ivan Mahonin bae79a
      if (image != currentImage)
Ivan Mahonin bae79a
      if (TMetaImage *metaImage = dynamic_cast<TMetaImage*>(image.getPointer()))
Ivan Mahonin bae79a
      {
Ivan Mahonin bae79a
        TAffine imageToTrack = worldToTrack * getColumnMatrix(i);
Ivan Mahonin bae79a
        glPushMatrix(); tglMultMatrix(imageToTrack);
Ivan Mahonin bae79a
Ivan Mahonin bae79a
        TMetaImage::Reader reader(*metaImage);
Ivan Mahonin bae79a
        for(TMetaObjectListCW::iterator i = reader->begin(); i != reader->end(); ++i)
Ivan Mahonin bae79a
        if (*i)
Ivan Mahonin bae79a
        if (const TAssistant *assistant = (*i)->getHandler<TAssistant>()) {
Ivan Mahonin bae79a
          assistant->getGuidelines(position, imageToTrack, m_currentGuidelines);
Ivan Mahonin bae79a
          assistant->draw(viewer, false);
Ivan Mahonin bae79a
        }
Ivan Mahonin bae79a
          
Ivan Mahonin bae79a
        glPopMatrix();
Ivan Mahonin bae79a
      }
Ivan Mahonin bae79a
    }
Ivan Mahonin 249386
Ivan Mahonin 249386
    // draw guidelines
Ivan Mahonin 249386
    for(TGuidelineList::const_iterator i = m_currentGuidelines.begin(); i != m_currentGuidelines.end(); ++i)
Ivan Mahonin 249386
      (*i)->draw();
Ivan Mahonin 249386
  }
Ivan Mahonin 249386
};
Ivan Mahonin 249386
Ivan Mahonin 249386
//-------------------------------------------------------------------
Ivan Mahonin 249386
Ivan Mahonin 249386
EditAssistantsTool editAssistantsTool;