浏览代码

Preventing session tabs flicker with large number of sessions

Source commit: 03cfa5b1411b866567a4b71c69ff7c15ce61556e
Martin Prikryl 7 年之前
父节点
当前提交
2645892878

+ 41 - 45
source/forms/CustomScpExplorer.cpp

@@ -584,7 +584,7 @@ void __fastcall TCustomScpExplorerForm::TerminalChanged()
     InitStatusBar();
   }
 
-  DoTerminalListChanged(false);
+  DoTerminalListChanged();
 
   if (ManagedTerminal != NULL)
   {
@@ -6235,68 +6235,64 @@ void __fastcall TCustomScpExplorerForm::NeedSession(bool ReloadSessions)
   }
 }
 //---------------------------------------------------------------------------
-void __fastcall TCustomScpExplorerForm::DoTerminalListChanged(bool Force)
+void __fastcall TCustomScpExplorerForm::DoTerminalListChanged()
 {
   TStrings * TerminalList = TTerminalManager::Instance()->TerminalList;
   int ActiveTerminalIndex = TTerminalManager::Instance()->ActiveTerminalIndex;
 
   Configuration->Usage->SetMax(L"MaxOpenedSessions", TerminalList->Count);
 
-  bool ListChanged = Force || (TerminalList->Count + 1 != SessionsPageControl->PageCount);
-  if (!ListChanged)
+  SendMessage(SessionsPageControl->Handle, WM_SETREDRAW, 0, 0);
+  try
   {
-    int Index = 0;
-    while (!ListChanged && (Index < TerminalList->Count))
+    while ((SessionsPageControl->PageCount > TerminalList->Count + 1) ||
+           // Clear the design time unthemed tab
+           ((SessionsPageControl->PageCount > 0) &&
+            (dynamic_cast<TThemeTabSheet *>(SessionsPageControl->Pages[SessionsPageControl->PageCount - 1]) == NULL)))
     {
-      ListChanged =
-        (GetSessionTabTerminal(SessionsPageControl->Pages[Index]) != TerminalList->Objects[Index]) ||
-        (SessionsPageControl->Pages[Index]->Caption != TerminalList->Strings[Index]);
-      Index++;
+      delete SessionsPageControl->Pages[SessionsPageControl->PageCount - 1];
     }
-  }
 
-  if (ListChanged)
-  {
-    SendMessage(SessionsPageControl->Handle, WM_SETREDRAW, 0, 0);
-    try
+    for (int Index = 0; Index <= TerminalList->Count; Index++)
     {
-      FSessionColors->Clear();
-
-      AddFixedSessionImages();
-
-      while (SessionsPageControl->PageCount > 0)
+      TTabSheet * TabSheet;
+      if (Index >= SessionsPageControl->PageCount)
       {
-        delete SessionsPageControl->Pages[0];
+        TabSheet = new TThemeTabSheet(SessionsPageControl);
+        TabSheet->PageControl = SessionsPageControl;
+      }
+      else
+      {
+        TabSheet = SessionsPageControl->Pages[Index];
       }
 
-      for (int Index = 0; Index < TerminalList->Count; Index++)
+      if (Index < TerminalList->Count)
       {
-        TThemeTabSheet * TabSheet = new TThemeTabSheet(SessionsPageControl);
-        TabSheet->Caption = TerminalList->Strings[Index];
         TTerminal * Terminal = dynamic_cast<TTerminal *>(TerminalList->Objects[Index]);
         TabSheet->Tag = reinterpret_cast<int>(Terminal);
-        TabSheet->PageControl = SessionsPageControl;
 
         UpdateSessionTab(TabSheet);
       }
-
-      TTabSheet * TabSheet = new TTabSheet(SessionsPageControl);
-      TabSheet->PageControl = SessionsPageControl;
-      TabSheet->ImageIndex = FNewSessionTabImageIndex;
-      UpdateNewSessionTab();
-    }
-    __finally
-    {
-      SendMessage(SessionsPageControl->Handle, WM_SETREDRAW, 1, 0);
+      else
+      {
+        TabSheet->ImageIndex = FNewSessionTabImageIndex;
+        TabSheet->Tag = 0; // not really needed
+        // We know that we are at the last page, sotherwise we could not call this (it assumes that new session tab is the last one)
+        UpdateNewSessionTab();
+      }
     }
   }
+  __finally
+  {
+    SendMessage(SessionsPageControl->Handle, WM_SETREDRAW, 1, 0);
+  }
 
   SessionsPageControl->ActivePageIndex = ActiveTerminalIndex;
 }
 //---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::TerminalListChanged(TObject * /*Sender*/)
 {
-  DoTerminalListChanged(false);
+  DoTerminalListChanged();
 }
 //---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::UpdateNewSessionTab()
@@ -6324,11 +6320,11 @@ void __fastcall TCustomScpExplorerForm::UpdateSessionTab(TTabSheet * TabSheet)
       dynamic_cast<TManagedTerminal *>(GetSessionTabTerminal(TabSheet));
     if (DebugAlwaysTrue(ManagedTerminal != NULL))
     {
-      TColor Color =
-        (ManagedTerminal == FTerminal) ? FSessionColor : ManagedTerminal->StateData->Color;
-
+      TColor Color = (ManagedTerminal == FTerminal) ? FSessionColor : ManagedTerminal->StateData->Color;
       TabSheet->ImageIndex = AddSessionColor(Color);
-      TabSheet->Caption = TTerminalManager::Instance()->GetTerminalTitle(ManagedTerminal, true);
+
+      UnicodeString TabCaption = TTerminalManager::Instance()->GetTerminalTitle(ManagedTerminal, true);
+      TabSheet->Caption = TabCaption;
 
       TThemeTabSheet * ThemeTabSheet = dynamic_cast<TThemeTabSheet *>(TabSheet);
       if (DebugAlwaysTrue(ThemeTabSheet != NULL))
@@ -6356,7 +6352,7 @@ bool __fastcall TCustomScpExplorerForm::SessionTabSwitched()
     }
     __finally
     {
-      DoTerminalListChanged(false);
+      DoTerminalListChanged();
     }
 
     FSessionsPageControlNewSessionTime = Now();
@@ -6599,7 +6595,7 @@ void __fastcall TCustomScpExplorerForm::UpdatePixelsPerInchMainWindowCounter()
 //---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::StartingDisconnected()
 {
-  DoTerminalListChanged(true);
+  DoTerminalListChanged();
 }
 //---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::PopupTrayBalloon(TTerminal * Terminal,
@@ -8592,8 +8588,9 @@ void __fastcall TCustomScpExplorerForm::UpdateImages()
 void __fastcall TCustomScpExplorerForm::CMDpiChanged(TMessage & Message)
 {
   TForm::Dispatch(&Message);
-  // regenerate session images
-  DoTerminalListChanged(true);
+  FSessionColors->Clear();
+  AddFixedSessionImages();
+  RegenerateSessionColorsImageList(FSessionColors, FSessionColorMaskImageIndex);
   UpdateImages();
 }
 //---------------------------------------------------------------------------
@@ -9414,8 +9411,7 @@ int __fastcall TCustomScpExplorerForm::AddSessionColor(TColor Color)
 {
   if (Color != 0)
   {
-    AddSessionColorImage(FSessionColors, Color, FSessionColorMaskImageIndex);
-    return FSessionColors->Count - 1;
+    return GetSessionColorImage(FSessionColors, Color, FSessionColorMaskImageIndex);
   }
   else
   {

+ 1 - 1
source/forms/CustomScpExplorer.h

@@ -596,7 +596,7 @@ protected:
     void * Arg);
   void __fastcall AnyInternalEditorModified(TObject * Sender, bool & Modified);
   virtual void __fastcall StartingDisconnected();
-  void __fastcall DoTerminalListChanged(bool Force);
+  void __fastcall DoTerminalListChanged();
   void __fastcall NeedSession(bool ReloadSessions);
   bool __fastcall DraggingAllFilesFromDirView(TOperationSide Side, TStrings * FileList);
   bool __fastcall SelectedAllFilesInDirView(TCustomDirView * DView);

+ 1 - 2
source/forms/Login.cpp

@@ -358,8 +358,7 @@ int __fastcall TLoginDialog::GetSessionImageIndex(TSessionData * Data)
   int Result;
   if (Data->Color != 0)
   {
-    AddSessionColorImage(SessionTree->Images, static_cast<TColor>(Data->Color), SiteColorMaskImageIndex);
-    Result = SessionTree->Images->Count - 1;
+    Result = GetSessionColorImage(SessionTree->Images, static_cast<TColor>(Data->Color), SiteColorMaskImageIndex);
   }
   else
   {

+ 4 - 19
source/forms/SiteAdvanced.cpp

@@ -107,7 +107,7 @@ void __fastcall TSiteAdvancedDialog::InitControls()
   UpdateNavigationTree();
 
   SelectScaledImageList(ColorImageList);
-  SetSessionColor((TColor)0);
+  FColor = TColor();
 
   MenuButton(PrivateKeyToolsButton);
 }
@@ -404,7 +404,7 @@ void __fastcall TSiteAdvancedDialog::LoadSession()
     GetEncryptKeyEdit()->Text = FSessionData->EncryptKey;
 
     // color
-    SetSessionColor((TColor)FSessionData->Color);
+    FColor = (TColor)FSessionData->Color;
   }
 
   UpdateControls();
@@ -1017,7 +1017,7 @@ void __fastcall TSiteAdvancedDialog::UpdateControls()
     else
     {
       ColorButton->Images = ColorImageList;
-      ColorButton->ImageIndex = 1;
+      ColorButton->ImageIndex = GetSessionColorImage(ColorImageList, FColor, 0);
       ColorButton->ImageAlignment = iaRight;
     }
   }
@@ -1423,24 +1423,9 @@ void __fastcall TSiteAdvancedDialog::ColorButtonClick(TObject * /*Sender*/)
 }
 //---------------------------------------------------------------------------
 void __fastcall TSiteAdvancedDialog::SessionColorChange(TColor Color)
-{
-  SetSessionColor(Color);
-  UpdateControls();
-}
-//---------------------------------------------------------------------------
-void __fastcall TSiteAdvancedDialog::SetSessionColor(TColor Color)
 {
   FColor = Color;
-
-  while (ColorImageList->Count > 1)
-  {
-    ColorImageList->Delete(1);
-  }
-
-  if (Color != 0)
-  {
-    AddSessionColorImage(ColorImageList, Color, 0);
-  }
+  UpdateControls();
 }
 //---------------------------------------------------------------------------
 TTlsVersion __fastcall TSiteAdvancedDialog::IndexToTlsVersion(int Index)

+ 0 - 1
source/forms/SiteAdvanced.h

@@ -347,7 +347,6 @@ private:
   int __fastcall GetFtpProxyLogonType();
   void __fastcall UpdateNavigationTree();
   TSshProt __fastcall GetSshProt();
-  void __fastcall SetSessionColor(TColor Color);
   void __fastcall SessionColorChange(TColor Color);
   TTlsVersion __fastcall IndexToTlsVersion(int Index);
   int __fastcall TlsVersionToIndex(TTlsVersion TlsVersion);

+ 103 - 36
source/windows/GUITools.cpp

@@ -496,56 +496,123 @@ bool __fastcall DeleteDirectory(const UnicodeString DirName)
   return retval;
 }
 //---------------------------------------------------------------------------
-void __fastcall AddSessionColorImage(
+class TSessionColors : public TComponent
+{
+public:
+  __fastcall TSessionColors(TComponent * Owner) : TComponent(Owner)
+  {
+    Name = QualifiedClassName();
+  }
+
+  static TSessionColors * __fastcall Retrieve(TComponent * Component)
+  {
+    TSessionColors * SessionColors = dynamic_cast<TSessionColors *>(Component->FindComponent(QualifiedClassName()));
+    if (SessionColors == NULL)
+    {
+      SessionColors = new TSessionColors(Component);
+    }
+    return SessionColors;
+  }
+
+  typedef std::map<TColor, int> TColorMap;
+  TColorMap ColorMap;
+};
+//---------------------------------------------------------------------------
+int __fastcall GetSessionColorImage(
   TCustomImageList * ImageList, TColor Color, int MaskIndex)
 {
 
-  // This overly complex drawing is here to support color button on SiteAdvanced
-  // dialog. There we use plain TImageList, instead of TPngImageList,
-  // TButton does not work with transparent images
-  // (not even TBitmap with Transparent = true)
-  std::unique_ptr<TBitmap> MaskBitmap(new TBitmap());
-  ImageList->GetBitmap(MaskIndex, MaskBitmap.get());
+  TSessionColors * SessionColors = TSessionColors::Retrieve(ImageList);
 
-  std::unique_ptr<TPngImage> MaskImage(new TPngImage());
-  MaskImage->Assign(MaskBitmap.get());
+  int Result;
+  TSessionColors::TColorMap::const_iterator I = SessionColors->ColorMap.find(Color);
+  if (I != SessionColors->ColorMap.end())
+  {
+    Result = I->second;
+  }
+  else
+  {
+    // This overly complex drawing is here to support color button on SiteAdvanced
+    // dialog. There we use plain TImageList, instead of TPngImageList,
+    // TButton does not work with transparent images
+    // (not even TBitmap with Transparent = true)
+    std::unique_ptr<TBitmap> MaskBitmap(new TBitmap());
+    ImageList->GetBitmap(MaskIndex, MaskBitmap.get());
 
-  std::unique_ptr<TPngImage> ColorImage(new TPngImage(COLOR_RGB, 16, ImageList->Width, ImageList->Height));
+    std::unique_ptr<TPngImage> MaskImage(new TPngImage());
+    MaskImage->Assign(MaskBitmap.get());
 
-  TColor MaskTransparentColor = MaskImage->Pixels[0][0];
-  TColor TransparentColor = MaskTransparentColor;
-  // Expecting that the color to be replaced is in the centre of the image (HACK)
-  TColor MaskColor = MaskImage->Pixels[ImageList->Width / 2][ImageList->Height / 2];
+    std::unique_ptr<TPngImage> ColorImage(new TPngImage(COLOR_RGB, 16, ImageList->Width, ImageList->Height));
 
-  for (int Y = 0; Y < ImageList->Height; Y++)
-  {
-    for (int X = 0; X < ImageList->Width; X++)
+    TColor MaskTransparentColor = MaskImage->Pixels[0][0];
+    TColor TransparentColor = MaskTransparentColor;
+    // Expecting that the color to be replaced is in the centre of the image (HACK)
+    TColor MaskColor = MaskImage->Pixels[ImageList->Width / 2][ImageList->Height / 2];
+
+    for (int Y = 0; Y < ImageList->Height; Y++)
     {
-      TColor SourceColor = MaskImage->Pixels[X][Y];
-      TColor DestColor;
-      // this branch is pointless as long as MaskTransparentColor and
-      // TransparentColor are the same
-      if (SourceColor == MaskTransparentColor)
-      {
-        DestColor = TransparentColor;
-      }
-      else if (SourceColor == MaskColor)
-      {
-        DestColor = Color;
-      }
-      else
+      for (int X = 0; X < ImageList->Width; X++)
       {
-        DestColor = SourceColor;
+        TColor SourceColor = MaskImage->Pixels[X][Y];
+        TColor DestColor;
+        // this branch is pointless as long as MaskTransparentColor and
+        // TransparentColor are the same
+        if (SourceColor == MaskTransparentColor)
+        {
+          DestColor = TransparentColor;
+        }
+        else if (SourceColor == MaskColor)
+        {
+          DestColor = Color;
+        }
+        else
+        {
+          DestColor = SourceColor;
+        }
+        ColorImage->Pixels[X][Y] = DestColor;
       }
-      ColorImage->Pixels[X][Y] = DestColor;
     }
+
+    std::unique_ptr<TBitmap> Bitmap(new TBitmap());
+    Bitmap->SetSize(ImageList->Width, ImageList->Height);
+    ColorImage->AssignTo(Bitmap.get());
+
+    Result = ImageList->AddMasked(Bitmap.get(), TransparentColor);
+
+    SessionColors->ColorMap.insert(std::make_pair(Color, Result));
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
+void __fastcall RegenerateSessionColorsImageList(TCustomImageList * ImageList, int MaskIndex)
+{
+  TSessionColors * SessionColors = TSessionColors::Retrieve(ImageList);
+
+  std::vector<TColor> Colors;
+  int FixedImages = ImageList->Count;
+  Colors.resize(FixedImages + SessionColors->ColorMap.size());
+  TSessionColors::TColorMap::const_iterator I = SessionColors->ColorMap.begin();
+  while (I != SessionColors->ColorMap.end())
+  {
+    DebugAssert(Colors[I->second] == TColor());
+    Colors[I->second] = I->first;
+    I++;
   }
 
-  std::unique_ptr<TBitmap> Bitmap(new TBitmap());
-  Bitmap->SetSize(ImageList->Width, ImageList->Height);
-  ColorImage->AssignTo(Bitmap.get());
+  TSessionColors::TColorMap ColorMap = SessionColors->ColorMap;
+  SessionColors->ColorMap.clear();
+
+  for (size_t Index = 0; Index < Colors.size(); Index++)
+  {
+    bool IsFixedImageIndex = (Index < FixedImages);
+    DebugAssert((Colors[Index] == TColor()) == IsFixedImageIndex);
+    if (!IsFixedImageIndex)
+    {
+      GetSessionColorImage(ImageList, Colors[Index], MaskIndex);
+    }
+  }
 
-  ImageList->AddMasked(Bitmap.get(), TransparentColor);
+  DebugAssert(SessionColors->ColorMap == ColorMap);
 }
 //---------------------------------------------------------------------------
 void __fastcall SetSubmenu(TTBXCustomItem * Item)

+ 2 - 1
source/windows/GUITools.h

@@ -27,7 +27,8 @@ bool __fastcall SpecialFolderLocation(int PathID, UnicodeString & Path);
 UnicodeString __fastcall UniqTempDir(const UnicodeString BaseDir,
   const UnicodeString Identity, bool Mask = false);
 bool __fastcall DeleteDirectory(const UnicodeString DirName);
-void __fastcall AddSessionColorImage(TCustomImageList * ImageList, TColor Color, int MaskIndex);
+int __fastcall GetSessionColorImage(TCustomImageList * ImageList, TColor Color, int MaskIndex);
+void __fastcall RegenerateSessionColorsImageList(TCustomImageList * ImageList, int MaskIndex);
 void __fastcall SetSubmenu(TTBXCustomItem * Item);
 typedef int __fastcall (*TCalculateWidth)(UnicodeString Text, void * Arg);
 void __fastcall ApplyTabs(