]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Auto-rebuild management
authorvsv <vsv@opencascade.com>
Thu, 18 Oct 2018 16:37:37 +0000 (19:37 +0300)
committervsv <vsv@opencascade.com>
Thu, 18 Oct 2018 16:37:58 +0000 (19:37 +0300)
21 files changed:
src/ModuleBase/ModuleBase_Dialog.cpp
src/ModuleBase/ModuleBase_ModelDialogWidget.h
src/ModuleBase/ModuleBase_Tools.cpp
src/ModuleBase/ModuleBase_Tools.h
src/ParametersPlugin/ParametersPlugin_WidgetParamsMgr.cpp
src/ParametersPlugin/ParametersPlugin_WidgetParamsMgr.h
src/PartSet/PartSet_IconFactory.cpp
src/PartSet/PartSet_TreeNodes.cpp
src/PartSet/PartSet_TreeNodes.h
src/PartSet/PartSet_icons.qrc
src/PartSet/icons/hasWarning.png [new file with mode: 0644]
src/PartSet/icons/isFailed.png [new file with mode: 0644]
src/PartSet/icons/toWork.png [new file with mode: 0644]
src/XGUI/XGUI_Workshop.cpp
src/XGUI/XGUI_Workshop.h
src/XGUI/XGUI_WorkshopListener.cpp
src/XGUI/XGUI_WorkshopListener.h
src/XGUI/XGUI_pictures.qrc
src/XGUI/pictures/autoapply.png [deleted file]
src/XGUI/pictures/autoapply_start.png [new file with mode: 0644]
src/XGUI/pictures/autoapply_stop.png [new file with mode: 0644]

index d07bebf0f05b072850f6829abbe28fe320eb17c8..6c0cacd4f6cd23700d06237423ddaec2d3ac413d 100644 (file)
@@ -75,7 +75,7 @@ ModuleBase_Dialog::ModuleBase_Dialog(ModuleBase_IWorkshop* theParent, const QStr
   aFrame->setFrameStyle(QFrame::WinPanel | QFrame::Raised);
   aLayout->addWidget(aFrame);
 
-  QVBoxLayout* aBtnLayout = new QVBoxLayout(aFrame);
+  QHBoxLayout* aBtnLayout = new QHBoxLayout(aFrame);
   ModuleBase_Tools::adjustMargins(aBtnLayout);
 
   myButtonsBox = new QDialogButtonBox(
index d167da4a6403aba43e1e4676aa4aae38724b5b2d..7ce788e86d97c07042ab6986ae4645afddda0713 100644 (file)
@@ -42,7 +42,7 @@ public:
 
   /// Set general buttons from dialog
   /// \param theButtons the dialog buttons
-  void setDialogButtons(QDialogButtonBox* theButtons) { myOkCancelBtn = theButtons; }
+  virtual void setDialogButtons(QDialogButtonBox* theButtons) { myOkCancelBtn = theButtons; }
 
 protected:
 
index 67d2b349a63673374dd92e45312bb794ffac7951..a60e3c2bb875230bac764226e769b7b16d20b6d0 100755 (executable)
@@ -182,28 +182,32 @@ QPixmap composite(const QString& theAdditionalIcon, const QString& theIcon)
 {
   QImage anIcon = ModuleBase_IconFactory::loadImage(theIcon);
   QImage anAditional(theAdditionalIcon);
+  return composite(anAditional, anIcon);
+}
 
-  if (anIcon.isNull())
+QPixmap composite(const QImage& theAdditionalIcon, QImage& theIcon)
+{
+  if (theIcon.isNull())
     return QPixmap();
 
-  int anAddWidth = anAditional.width();
-  int anAddHeight = anAditional.height();
+  int anAddWidth = theAdditionalIcon.width();
+  int anAddHeight = theAdditionalIcon.height();
 
-  int aWidth = anIcon.width();
-  int aHeight = anIcon.height();
+  int aWidth = theIcon.width();
+  int aHeight = theIcon.height();
 
-  int aStartWidthPos = aWidth - anAddWidth - 1;
-  int aStartHeightPos = aHeight - anAddHeight - 1;
+  int aStartWidthPos = aWidth - anAddWidth;
+  int aStartHeightPos = aHeight - anAddHeight;
 
   for (int i = 0; i < anAddWidth && i + aStartWidthPos < aWidth; i++)
   {
     for (int j = 0; j < anAddHeight && j + aStartHeightPos < aHeight; j++)
     {
-      if (qAlpha(anAditional.pixel(i, j)) > 0)
-        anIcon.setPixel(i + aStartWidthPos, j + aStartHeightPos, anAditional.pixel(i, j));
+      if (qAlpha(theAdditionalIcon.pixel(i, j)) > 0)
+        theIcon.setPixel(i + aStartWidthPos, j + aStartHeightPos, theAdditionalIcon.pixel(i, j));
     }
   }
-  return QPixmap::fromImage(anIcon);
+  return QPixmap::fromImage(theIcon);
 }
 
 QPixmap lighter(const QString& theIcon, const int theLighterValue)
index 6dd1e0985d96d4508da53cdcca7182d592d38eb9..b2943443158a352158fefaf964dce6e81e59cae8 100755 (executable)
@@ -96,6 +96,15 @@ MODULEBASE_EXPORT void setShadowEffect(QWidget* theWidget, const bool isSetEffec
 /// \return resulting pixmap
 MODULEBASE_EXPORT QPixmap composite(const QString& theAdditionalIcon, const QString& theIcon);
 
+/// Create composite pixmap.
+/// Pixmap \a theAdditionalIcon is drawn over pixmap \a dest with coordinates
+/// specified relatively to the upper left corner of \a theIcon.
+
+/// \param theAdditionalIcon additional pixmap
+/// \param theIcon background pixmap
+/// \return resulting pixmap
+MODULEBASE_EXPORT QPixmap composite(const QImage& theAdditionalIcon, QImage& theIcon);
+
 /// Generates the pixmap lighter than the resources pixmap.
 /// Pixmap \a theIcon is lighted according to the given value.
 /// If the lighter value is greater than 100, this functions returns a lighter pixmap.
index 96e10edb14c720706a7f03058c5e5c9059301d4f..d31439d406c56b3631f462df94793bca4593a831 100644 (file)
@@ -176,7 +176,8 @@ void ParametersPlugin_TreeWidget::closeEditor(QWidget* theEditor,
 
 ParametersPlugin_WidgetParamsMgr::ParametersPlugin_WidgetParamsMgr(QWidget* theParent,
   const Config_WidgetAPI* theData)
-  : ModuleBase_ModelDialogWidget(theParent, theData)
+  : ModuleBase_ModelDialogWidget(theParent, theData),
+  isUpplyBlocked(false)
 {
   QVBoxLayout* aLayout = new QVBoxLayout(this);
 
@@ -248,6 +249,20 @@ ParametersPlugin_WidgetParamsMgr::ParametersPlugin_WidgetParamsMgr(QWidget* theP
   onSelectionChanged();
 }
 
+void ParametersPlugin_WidgetParamsMgr::setDialogButtons(QDialogButtonBox* theButtons)
+{
+  ModuleBase_ModelDialogWidget::setDialogButtons(theButtons);
+
+  QWidget* aBtnParentWgt = myOkCancelBtn->parentWidget();
+  QHBoxLayout* aBtnParentLayout = dynamic_cast<QHBoxLayout*>(aBtnParentWgt->layout());
+
+  QPushButton* aPreviewBtn = new QPushButton(tr("See preview"), aBtnParentWgt);
+  aBtnParentLayout->insertWidget(0, aPreviewBtn);
+  aBtnParentLayout->insertStretch(1, 1);
+  connect(aPreviewBtn, SIGNAL(clicked(bool)), SLOT(onShowPreview()));
+}
+
+
 QList<QWidget*> ParametersPlugin_WidgetParamsMgr::getControls() const
 {
   QList<QWidget*> aList;
@@ -783,3 +798,26 @@ bool ParametersPlugin_WidgetParamsMgr::isValid()
   return true;
 }
 
+void ParametersPlugin_WidgetParamsMgr::showEvent(QShowEvent* theEvent)
+{
+  ModuleBase_ModelDialogWidget::showEvent(theEvent);
+  SessionPtr aMgr = ModelAPI_Session::get();
+  isUpplyBlocked = aMgr->isAutoUpdateBlocked();
+  aMgr->blockAutoUpdate(true);
+  Events_Loop* aLoop = Events_Loop::loop();
+  aLoop->flush(aLoop->eventByName(EVENT_AUTOMATIC_RECOMPUTATION_DISABLE));
+}
+
+void ParametersPlugin_WidgetParamsMgr::hideEvent(QHideEvent* theEvent)
+{
+  ModuleBase_ModelDialogWidget::hideEvent(theEvent);
+  SessionPtr aMgr = ModelAPI_Session::get();
+  aMgr->blockAutoUpdate(isUpplyBlocked);
+}
+
+void ParametersPlugin_WidgetParamsMgr::onShowPreview()
+{
+  SessionPtr aMgr = ModelAPI_Session::get();
+  aMgr->blockAutoUpdate(false);
+  aMgr->blockAutoUpdate(true);
+}
\ No newline at end of file
index 0e55044b32dfbfc5d6ea1957240dbd689943a06b..98d0aefff41bf10bb264d96a7857697c3173072a 100644 (file)
@@ -71,6 +71,10 @@ public:
   /// \return a control list
   virtual QList<QWidget*> getControls() const;
 
+  /// Set general buttons from dialog
+  /// \param theButtons the dialog buttons
+  virtual void setDialogButtons(QDialogButtonBox* theButtons);
+
 protected:
   /// Saves the internal parameters to the given feature
   /// \return True in success
@@ -82,6 +86,10 @@ protected:
   /// The method called when widget is activated
   virtual void activateCustom();
 
+  virtual void showEvent(QShowEvent* theEvent);
+
+  virtual void hideEvent(QHideEvent* theEvent);
+
 private slots:
   /// Slot for reaction on double click in the table (start editing)
   /// \param theIndex the clicked index
@@ -113,6 +121,9 @@ private slots:
   /// Slot for reaction on selection in the table
   void onSelectionChanged();
 
+  // A slot for show preview button
+  void onShowPreview();
+
 private:
   /// Creates a new parameter feature
   FeaturePtr createParameter() const;
@@ -162,6 +173,8 @@ private:
   QPushButton* myRemoveBtn;
   QToolButton* myUpBtn;
   QToolButton* myDownBtn;
+
+  bool isUpplyBlocked;
 };
 
 
index 42b3d4d62f6f65b516232f300dbc7f603d3ba098..da1c13a4a2c42a8a55c3752a8819da37708cefa3 100644 (file)
@@ -64,11 +64,12 @@ QIcon PartSet_IconFactory::getIcon(ObjectPtr theObj)
       }
       break;
       case ModelAPI_StateMustBeUpdated: {
-        anIcon = ModuleBase_Tools::lighter(anIconString);
+        anIcon = ModuleBase_Tools::composite(":icons/toWork.png", anIconString);
+        //anIcon = ModuleBase_Tools::lighter(anIconString);
       }
       break;
       case ModelAPI_StateExecFailed: {
-        anIcon = ModuleBase_Tools::composite(":icons/exec_state_failed.png", anIconString);
+        anIcon = ModuleBase_Tools::composite(":icons/isFailed.png", anIconString);
       }
       break;
       case ModelAPI_StateInvalidArgument: {
@@ -80,8 +81,8 @@ QIcon PartSet_IconFactory::getIcon(ObjectPtr theObj)
     }
   }
 
-  if (theObj->data() && theObj->data()->execState() == ModelAPI_StateMustBeUpdated)
-    return QIcon(":pictures/constr_object_modified.png");
+  //if (theObj->data() && theObj->data()->execState() == ModelAPI_StateMustBeUpdated)
+  //  return QIcon(":pictures/constr_object_modified.png");
 
   std::string aGroup = theObj->groupName();
   if (aGroup == ModelAPI_ResultPart::group())
index 92d25db69152fea370540718a10e4e6f84b308b3..08e9e3681a3fe8c1f15e5e6ddda9ed6097153687 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <ModuleBase_IconFactory.h>
 #include <ModuleBase_IWorkshop.h>
+#include <ModuleBase_Tools.h>
 
 #include <PartSetPlugin_Part.h>
 
@@ -1184,6 +1185,32 @@ void PartSet_ObjectFolderNode::getFirstAndLastIndex(int& theFirst, int& theLast)
 }
 
 
+QVariant PartSet_ObjectFolderNode::data(int theColumn, int theRole) const
+{
+  const QImage anAditional(":icons/hasWarning.png");
+
+  if ((theRole == Qt::DecorationRole) && (theColumn == 1)) {
+    ObjectPtr aObject;
+    bool aHasWarning = false;
+    foreach(ModuleBase_ITreeNode* aNode, myChildren) {
+      aObject = aNode->object();
+      if (aObject.get()) {
+        ModelAPI_ExecState aState = aObject->data()->execState();
+        if ((aState == ModelAPI_StateExecFailed) || (aState == ModelAPI_StateMustBeUpdated)) {
+          aHasWarning = true;
+          break;
+        }
+      }
+    }
+    if (aHasWarning) {
+      return QIcon(ModuleBase_Tools::composite(":icons/hasWarning.png",
+                                               ":pictures/features_folder.png"));
+    }
+  }
+  return PartSet_ObjectNode::data(theColumn, theRole);
+}
+
+
 //////////////////////////////////////////////////////////////////////////////////
 QVariant PartSet_StepNode::data(int theColumn, int theRole) const
 {
index 37e6d54db359eb9dd8f8154e5c2033dda85287f0..4e37df89cf8c9eebf0fce08f6d1b497a3070cacb 100644 (file)
@@ -327,6 +327,9 @@ public:
   /// \param theGroup a name of group where objects were deleted
   virtual QTreeNodesList objectsDeleted(const DocumentPtr& theDoc, const QString& theGroup);
 
+  /// Returns the node representation according to theRole.
+  virtual QVariant data(int theColumn, int theRole) const;
+
 private:
   FeaturePtr getFeature(const std::string& theId) const;
 
index 9b19b30a5bd8e5887483f9070d98896f11cadbae..99819d90e0a46189e1330a9a98e6ae6bb5af53a7 100644 (file)
@@ -19,5 +19,8 @@
      <file>icons/group_face.png</file>
      <file>icons/group_solid.png</file>
      <file>icons/group_vertex.png</file>
+     <file>icons/toWork.png</file>
+     <file>icons/isFailed.png</file>
+     <file>icons/hasWarning.png</file>
  </qresource>
  </RCC>
diff --git a/src/PartSet/icons/hasWarning.png b/src/PartSet/icons/hasWarning.png
new file mode 100644 (file)
index 0000000..535aef2
Binary files /dev/null and b/src/PartSet/icons/hasWarning.png differ
diff --git a/src/PartSet/icons/isFailed.png b/src/PartSet/icons/isFailed.png
new file mode 100644 (file)
index 0000000..2754e56
Binary files /dev/null and b/src/PartSet/icons/isFailed.png differ
diff --git a/src/PartSet/icons/toWork.png b/src/PartSet/icons/toWork.png
new file mode 100644 (file)
index 0000000..7d3dc11
Binary files /dev/null and b/src/PartSet/icons/toWork.png differ
index 5418b3e25c4d525a1eb09d5d93cbc211d96ffa53..4c93fca0855bd0449502de9196c96e5ce0b33b8d 100755 (executable)
@@ -187,7 +187,7 @@ XGUI_Workshop::XGUI_Workshop(XGUI_SalomeConnector* theConnector)
   myOperationMgr = new XGUI_OperationMgr(this, 0);
   ModuleBase_IWorkshop* aWorkshop = moduleConnector();
   // Has to be defined first in order to get errors and messages from other components
-  myEventsListener = new XGUI_WorkshopListener(aWorkshop);
+  myEventsListener = new XGUI_WorkshopListener(this);
   mySelectionActivate = new XGUI_SelectionActivate(aWorkshop);
 
   SUIT_ResourceMgr* aResMgr = ModuleBase_Preferences::resourceMgr();
@@ -491,12 +491,11 @@ void XGUI_Workshop::initMenu()
   aCommand->connectTo(this, SLOT(onOpen()));
 
 
-  aCommand = aGroup->addFeature("AUTOCOMPUTE_CMD", tr("Block auto-apply"),
+  aCommand = aGroup->addFeature("AUTOCOMPUTE_CMD", tr("Auto rebuild"),
                                 tr("Blocks immediate apply of modifications"),
-                                QIcon(":pictures/autoapply.png"), QString(),
-                                QKeySequence(), true, true);
-  aCommand->setChecked(ModelAPI_Session::get()->isAutoUpdateBlocked());
-  aCommand->connectTo(this, SLOT(onAutoApply(bool)));
+                                QIcon(":pictures/autoapply_start.png"), QKeySequence());
+  //aCommand->setChecked(ModelAPI_Session::get()->isAutoUpdateBlocked());
+  aCommand->connectTo(this, SLOT(onAutoApply()));
 
   aCommand = aGroup->addFeature("PREF_CMD", tr("Preferences"), tr("Edit preferences"),
                                 QIcon(":pictures/preferences.png"), QKeySequence::Preferences);
@@ -1327,7 +1326,10 @@ void XGUI_Workshop::updateCommandStatus()
           aCmd->setEnabled(myModule->canRedo());
       }
       else if (aId == "AUTOCOMPUTE_CMD") {
-        aCmd->setChecked(aMgr->isAutoUpdateBlocked());
+        //aCmd->setChecked(aMgr->isAutoUpdateBlocked());
+        aCmd->setIcon(aMgr->isAutoUpdateBlocked() ?
+          QIcon(":pictures/autoapply_stop.png") :
+          QIcon(":pictures/autoapply_start.png"));
       }
       else
         // Enable all commands
@@ -2824,8 +2826,32 @@ void XGUI_Workshop::moveOutFolder(bool isBefore)
   updateCommandStatus();
 }
 
-void XGUI_Workshop::onAutoApply(bool isToggle)
+void XGUI_Workshop::onAutoApply()
 {
   SessionPtr aMgr = ModelAPI_Session::get();
-  aMgr->blockAutoUpdate(isToggle);
-}
\ No newline at end of file
+  bool isBlocked = aMgr->isAutoUpdateBlocked();
+  aMgr->blockAutoUpdate(!isBlocked);
+}
+
+void XGUI_Workshop::updateAutoComputeState()
+{
+  SessionPtr aMgr = ModelAPI_Session::get();
+  bool isComputeBlocked = aMgr->isAutoUpdateBlocked();
+#ifdef HAVE_SALOME
+  QAction* aUpdateCmd;
+  QList<QAction*> aCommands = workshop()->salomeConnector()->commandList();
+  foreach(QAction* aCmd, aCommands) {
+    if (aCmd->data().toString() == "AUTOCOMPUTE_CMD") {
+      aUpdateCmd = aCmd;
+      break;
+    }
+  }
+  aUpdateCmd->setIcon(isComputeBlocked? QIcon(":pictures/autoapply_stop.png") :
+    QIcon(":pictures/autoapply_start.png"));
+#else
+  AppElements_MainMenu* aMenuBar = myMainWindow->menuObject();
+  AppElements_Command* aUpdateCmd = aMenuBar->feature("AUTOCOMPUTE_CMD");
+  aUpdateCmd->button()->setIcon(isComputeBlocked? QIcon(":pictures/autoapply_stop.png") :
+    QIcon(":pictures/autoapply_start.png"));
+#endif
+}
index b25938005a21f9ef06f57dd2fdaf6f83407eab23..f9504dfeedefbeb88c713a3f3ccc275ba144a009 100755 (executable)
@@ -320,6 +320,8 @@ Q_OBJECT
   /// \param theDirectory a path to directory
   void openDirectory(const QString& theDirectory);
 
+  void updateAutoComputeState();
+
 signals:
   /// Emitted when selection happens in Salome viewer
   void salomeViewerSelection();
@@ -396,7 +398,7 @@ signals:
 #endif
 
   /// A slot calleon toggle of auto-compute button
-  void onAutoApply(bool isToggle);
+  void onAutoApply();
 
   /// Activates/deactivates the trihedron in the viewer AIS context
   void onTrihedronVisibilityChanged(bool theState);
index f7720512d9fc73e38d1df1ff9d9458ab63063735..7701c221b70b1375a1764282380bbd044b4063f3 100755 (executable)
@@ -82,7 +82,7 @@
 const std::string DebugFeatureKind = "";//"Extrusion";
 #endif
 
-XGUI_WorkshopListener::XGUI_WorkshopListener(ModuleBase_IWorkshop* theWorkshop)
+XGUI_WorkshopListener::XGUI_WorkshopListener(XGUI_Workshop* theWorkshop)
   : myWorkshop(theWorkshop),
     myUpdatePrefs(false)
 {
@@ -113,6 +113,8 @@ void XGUI_WorkshopListener::initializeEventListening()
 
   aLoop->registerListener(this, Events_Loop::eventByName("FinishOperation"));
   aLoop->registerListener(this, Events_Loop::eventByName("AbortOperation"));
+  aLoop->registerListener(this, Events_Loop::eventByName(EVENT_AUTOMATIC_RECOMPUTATION_ENABLE));
+  aLoop->registerListener(this, Events_Loop::eventByName(EVENT_AUTOMATIC_RECOMPUTATION_DISABLE));
 }
 
 //******************************************************
@@ -184,6 +186,11 @@ void XGUI_WorkshopListener::processEvent(const std::shared_ptr<Events_Message>&
     // the viewer's update context is unblocked, the viewer's update works
     XGUI_Displayer* aDisplayer = workshop()->displayer();
     aDisplayer->enableUpdateViewer(true);
+  } else if ((theMessage->eventID() ==
+    Events_Loop::eventByName(EVENT_AUTOMATIC_RECOMPUTATION_ENABLE)) ||
+    (theMessage->eventID() ==
+      Events_Loop::eventByName(EVENT_AUTOMATIC_RECOMPUTATION_DISABLE))) {
+    myWorkshop->updateAutoComputeState();
   } else {
     //Show error dialog if error message received.
     std::shared_ptr<Events_InfoMessage> anIngfoMsg =
@@ -524,6 +531,5 @@ bool XGUI_WorkshopListener::customizeCurrentObject(const std::set<ObjectPtr>& th
 
 XGUI_Workshop* XGUI_WorkshopListener::workshop() const
 {
-  XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myWorkshop);
-  return aConnector->workshop();
+  return myWorkshop;
 }
index c338535bdefd2205599700d8bd56ced599f6142e..cece7d965200507740914a4479768c1daf9f395a 100755 (executable)
@@ -50,7 +50,7 @@ class XGUI_EXPORT XGUI_WorkshopListener : public QObject, public Events_Listener
 public:
   /// Constructor. Used only if the workshop is launched in Salome environment
   /// \param theWorkshop a reference to workshop.
-   XGUI_WorkshopListener(ModuleBase_IWorkshop* theWorkshop);
+   XGUI_WorkshopListener(XGUI_Workshop* theWorkshop);
   virtual ~XGUI_WorkshopListener();
 
   /// Register this class in the events loop for several types of events
@@ -104,7 +104,7 @@ protected:
   XGUI_Workshop* workshop() const;
 
 private:
-  ModuleBase_IWorkshop* myWorkshop; // the current workshop
+  XGUI_Workshop* myWorkshop; // the current workshop
 
   bool myUpdatePrefs;
 };
index 5de669be428945951540e08c67d073d0c6130c3f..ea9614f94e2b2d4bee5d4c0483a7c3b01981548b 100644 (file)
@@ -74,7 +74,8 @@
      <file>pictures/move_out_after.png</file>
      <file>pictures/move_out_before.png</file>
      <file>pictures/selection.png</file>
-     <file>pictures/autoapply.png</file>
+     <file>pictures/autoapply_start.png</file>
+     <file>pictures/autoapply_stop.png</file>
      <file>pictures/whatis.png</file>
  </qresource>
  </RCC>
diff --git a/src/XGUI/pictures/autoapply.png b/src/XGUI/pictures/autoapply.png
deleted file mode 100644 (file)
index 6298c41..0000000
Binary files a/src/XGUI/pictures/autoapply.png and /dev/null differ
diff --git a/src/XGUI/pictures/autoapply_start.png b/src/XGUI/pictures/autoapply_start.png
new file mode 100644 (file)
index 0000000..86453bb
Binary files /dev/null and b/src/XGUI/pictures/autoapply_start.png differ
diff --git a/src/XGUI/pictures/autoapply_stop.png b/src/XGUI/pictures/autoapply_stop.png
new file mode 100644 (file)
index 0000000..5bde65b
Binary files /dev/null and b/src/XGUI/pictures/autoapply_stop.png differ