فهرست منبع

ADD: Store light and dark color settings separately (step 3)

Alexander Koblov 2 سال پیش
والد
کامیت
acd0bab58a
6فایلهای تغییر یافته به همراه489 افزوده شده و 82 حذف شده
  1. 2 1
      src/fmain.pas
  2. 2 2
      src/frames/foptionscustomcolumns.lfm
  3. 37 22
      src/frames/foptionscustomcolumns.pas
  4. 1 1
      src/ucolors.pas
  5. 443 55
      src/ucolumns.pas
  6. 4 1
      src/uglobs.pas

+ 2 - 1
src/fmain.pas

@@ -7078,10 +7078,11 @@ begin
   FrameLeft.UpdateColor;
   FrameRight.UpdateColor;
 
+  ColSet.UpdateStyle;
   gColorExt.UpdateStyle;
   gHighlighters.UpdateStyle;
 
-  DCDEbug('AppThemeChange');
+  DCDebug('AppThemeChange');
 
   for Index:= 0 to Screen.CustomFormCount - 1 do
   begin

+ 2 - 2
src/frames/foptionscustomcolumns.lfm

@@ -366,7 +366,7 @@ inherited frmOptionsCustomColumns: TfrmOptionsCustomColumns
         7
         0
         0
-        'Delete'
+        'Column'
         1
         0
         'Caption'
@@ -384,7 +384,7 @@ inherited frmOptionsCustomColumns: TfrmOptionsCustomColumns
         'Move'
         6
         0
-        'Config'
+        'Delete'
       )
     end
     object spGridArea: TSplitter

+ 37 - 22
src/frames/foptionscustomcolumns.pas

@@ -4,7 +4,7 @@
    Custom columns options page
 
    Copyright (C) 2008  Dmitry Kolomiets ([email protected])
-   Copyright (C) 2008-2016 Alexander Koblov ([email protected])
+   Copyright (C) 2008-2023 Alexander Koblov ([email protected])
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -30,7 +30,7 @@ interface
 uses
   //Lazarus, Free-Pascal, etc.
   ComCtrls, Controls, Classes, SysUtils, StdCtrls, ExtCtrls, Forms, ColorBox,
-  Buttons, Spin, Grids, Menus, Dialogs,
+  Buttons, Spin, Grids, Menus, Dialogs, LMessages,
   //DC
   uColumns, fOptionsFrame, uColumnsFileView;
 
@@ -237,6 +237,7 @@ type
     procedure Load; override;
     function Save: TOptionsEditorSaveFlags; override;
     procedure Done; override;
+    procedure CMThemeChanged(var Message: TLMessage); message CM_THEMECHANGED;
 
   public
     class function GetIconIndex: integer; override;
@@ -355,6 +356,11 @@ begin
   end;
 end;
 
+procedure TfrmOptionsCustomColumns.CMThemeChanged(var Message: TLMessage);
+begin
+  cbConfigColumnsChange(cbConfigColumns);
+end;
+
 { TfrmOptionsCustomColumns.GetIconIndex }
 class function TfrmOptionsCustomColumns.GetIconIndex: integer;
 begin
@@ -558,6 +564,7 @@ begin
       stgColumns.Cells[2, i + 1] := IntToStr(ColumnClass.GetColumnWidth(i));
       stgColumns.Cells[3, i + 1] := ColumnClass.GetColumnAlignString(i);
       stgColumns.Cells[4, i + 1] := ColumnClass.GetColumnFuncString(i);
+      stgColumns.Objects[5, i + 1] := ColumnClass.GetColumnItem(i);
       stgColumns.Objects[6, i + 1] := ColumnClass.GetColumnPrm(i);
     end;
   end
@@ -595,26 +602,22 @@ end;
 // ***It is not saved to file yet, but if we do, it will be that one!
 procedure TfrmOptionsCustomColumns.UpdateColumnClass;
 var
-  i, indx: integer;
-  Tit, FuncString: string;
-  Wid: integer;
-  Ali: TAlignment;
+  Index: Integer;
+  AItem: TPanelColumn;
 begin
   // Save fields
-  ColumnClass.Clear;
-
-  for i := 1 to stgColumns.RowCount - 1 do
+  for Index := 1 to stgColumns.RowCount - 1 do
   begin
     with stgColumns do
     begin
-      Tit := Cells[1, i];
-      Wid := StrToInt(Cells[2, i]);
-      Ali := StrToAlign(Cells[3, i]);
-      FuncString := Cells[4, i];
+      AItem:= TPanelColumn(Objects[5, Index]);
+      AItem.Title := Cells[1, Index];
+      AItem.Width := StrToInt(Cells[2, Index]);
+      AItem.Align := StrToAlign(Cells[3, Index]);
+      AItem.FuncString := Cells[4, Index];
     end;
-    indx := ColumnClass.Add(Tit, FuncString, Wid, Ali);
-    if stgColumns.Objects[6, i] <> nil then
-      ColumnClass.SetColumnPrm(Indx, TColPrm(stgColumns.Objects[6, i]));
+    if stgColumns.Objects[6, Index] <> nil then
+      ColumnClass.SetColumnPrm(Index - 1, TColPrm(stgColumns.Objects[6, Index]));
   end;
 
   ColumnClass.FileSystem := cmbFileSystem.Text;
@@ -903,14 +906,23 @@ end;
 
 { TfrmOptionsCustomColumns.AddNewField }
 procedure TfrmOptionsCustomColumns.AddNewField;
+var
+  Index: Integer;
+  AItem: TPanelColumn;
 begin
-  stgColumns.RowCount := stgColumns.RowCount + 1;
-  stgColumns.Cells[1, stgColumns.RowCount - 1] := EmptyStr;
-  stgColumns.Cells[2, stgColumns.RowCount - 1] := '50';
-  stgColumns.Cells[3, stgColumns.RowCount - 1] := '<-';
-  stgColumns.Cells[4, stgColumns.RowCount - 1] := '';
-  stgColumns.Objects[6, stgColumns.RowCount - 1] := TColPrm.Create;
+  Index:= stgColumns.RowCount;
+  AItem:= TPanelColumn.CreateNew;
+  stgColumns.RowCount := Index + 1;
+
+  stgColumns.Cells[1, Index] := EmptyStr;
+  stgColumns.Cells[2, Index] := '50';
+  stgColumns.Cells[3, Index] := '<-';
+  stgColumns.Cells[4, Index] := '';
+  stgColumns.Objects[5, Index] := AItem;
+  stgColumns.Objects[6, Index] := TColPrm.Create;
 
+
+  ColumnClass.Add(AItem);
   UpdateColumnClass;
 end;
 
@@ -952,6 +964,8 @@ begin
     stgColumns.Objects[6, RowNr] := nil;
   end;
 
+  ColumnClass.Delete(RowNr - 1);
+
   stgColumns.DeleteColRow(False, RowNr);
   EditorSaveResult(Sender);
 
@@ -986,6 +1000,7 @@ end;
 { TfrmOptionsCustomColumns.UpDownXClick }
 procedure TfrmOptionsCustomColumns.UpDownXClick(Sender: TObject; Button: TUDBtnType);
 begin
+  ColumnClass.Exchange(updMove.Tag - 1, abs(updMove.Position) - 1);
   stgColumns.ExchangeColRow(False, updMove.Tag, abs(updMove.Position));
   with updMove do
   begin

+ 1 - 1
src/ucolors.pas

@@ -344,7 +344,7 @@ begin
 
     LoadedConfigVersion := GetAttr(Root, 'ConfigVersion', ConfigVersion);
 
-    if (LoadedConfigVersion >= ConfigVersion) then Exit;
+    if (LoadedConfigVersion >= 14) then Exit;
 
     ColorTheme:= Current;
 

+ 443 - 55
src/ucolumns.pas

@@ -4,7 +4,7 @@
    Filepanel columns implementation unit
 
    Copyright (C) 2008  Dmitry Kolomiets ([email protected])
-   Copyright (C) 2015  Alexander Koblov ([email protected])
+   Copyright (C) 2015-2023  Alexander Koblov ([email protected])
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -29,8 +29,8 @@ unit uColumns;
 interface
 
 uses
-  Classes, SysUtils, DCClassesUtf8, Graphics, uFile, uFileSource,
-  DCXmlConfig, DCBasicTypes, uFileFunctions;
+  Classes, SysUtils, Graphics, uFile, uFileSource,
+  DCXmlConfig, FpJson, DCBasicTypes, uFileFunctions, uColors;
 
 const
   FS_GENERAL = '<General>';
@@ -62,8 +62,10 @@ type
 
   TPanelColumn = class
   private
+    FUnique: String;
     FFuncString: String;
 
+    procedure SetUnique(const AValue: String);
     procedure SetFuncString(NewValue: String);
 
     function GetColumnResultString(AFile: TFile; const AFileSource: IFileSource): String;
@@ -96,9 +98,11 @@ type
     //---------------------
 
     constructor Create;
+    constructor CreateNew;
     destructor Destroy; override;
 
     //------------------------------------------------------
+    property Unique: String read FUnique write SetUnique;
     property FuncString: String read FFuncString write SetFuncString;
   end;
 
@@ -108,6 +112,7 @@ type
     //------------------------------------------------------
   private
     FList: TList;
+    FUnique: String;
     fSetName: String;
 
     // Global settings for columns view.
@@ -120,6 +125,7 @@ type
     function GetCursorBorder: boolean;
     function GetCursorBorderColor: TColor;
     function GetUseFrameCursor: Boolean;
+    procedure SetUnique(const AValue: String);
   public
     constructor Create;
     destructor Destroy; override;
@@ -190,21 +196,25 @@ type
     procedure SetColumnPrm(const Index: Integer; Value: TColPrm);
     //---------------------
     procedure Delete(const Index: Integer);
+    procedure Exchange(Index1, Index2: Integer);
     procedure Clear;
     procedure AddDefaultColumns;
     procedure AddDefaultEverything;
     //---------------------
-    procedure Load(AConfig: TXmlConfig; ANode: TXmlNode); overload;
+    procedure Load(AConfig: TXmlConfig; ANode: TXmlNode);
     //---------------------
-    procedure Save(AConfig: TXmlConfig; ANode: TXmlNode); overload;
+    procedure Save(AConfig: TXmlConfig; ANode: TXmlNode);
+    //---------------------
+    procedure LoadColors(ANode: TJSONObject);
+    procedure SaveColors(ANode: TJSONObject);
+    procedure Synchronize(ANode: TJSONObject);
     //---------------------
     function GetSignature(Seed:dword=$000000):dword;
     property ColumnsCount: Integer read GetCount;
     property Count: Integer read GetCount;
     property CustomView: Boolean read FCustomView write FCustomView;
-    property CurrentColumnsSetName: String read fSetName write fSetName;
-    property SetName: String read fSetName write fSetName;
     property Name: String read fSetName write fSetName;
+    property Unique: String read FUnique write SetUnique;
     property FileSystem: String read FFileSystem write FFileSystem;
     property UseCursorBorder: boolean read GetCursorBorder write FCursorBorder;
     property CursorBorderColor: TColor read GetCursorBorderColor write FCursorBorderColor;
@@ -216,13 +226,22 @@ type
 
   TPanelColumnsList = class
   private
+    FStyle: Integer;
     fSet: TStringList;
+    FStyles: array[0..Pred(THEME_COUNT)] of TJSONArray;
+  private
     function GetCount: Integer;
+    procedure Synchronize(Item: TPanelColumnsClass);
   public
     constructor Create;
     destructor Destroy; override;
     //---------------------
     procedure Clear;
+    procedure UpdateStyle;
+    procedure LoadColors; overload;
+    procedure SaveColors; overload;
+    procedure LoadColors(AConfig: TJSONObject); overload;
+    procedure SaveColors(AConfig: TJSONObject); overload;
     procedure Load(AConfig: TXmlConfig; ANode: TXmlNode); overload;
     procedure Save(AConfig: TXmlConfig; ANode: TXmlNode); overload;
     function Add(Item: TPanelColumnsClass): Integer;
@@ -243,9 +262,13 @@ type
 implementation
 
 uses
-  LCLType, Forms, crc, DCStrUtils, uDebug, uLng, uGlobs;
+  StrUtils, LCLType, Forms, crc, DCStrUtils, uDebug, uLng, uGlobs, uDCUtils;
+
+const
+  JsonConfigVersion = 15;
 
 var
+  LoadedConfigVersion: Integer;
   DefaultTitleHash: LongWord = 0;
 
 procedure UpdateDefaultTitleHash;
@@ -269,6 +292,11 @@ begin
     Result := taCenter;
 end;
 
+function GetUnique: String;
+begin
+  Result:= TrimSet(GuidToString(DCGetNewGUID), ['{', '}']);
+end;
+
 { TPanelColumnsType }
 
 function TPanelColumnsClass.GetColumnTitle(const Index: Integer): String;
@@ -550,6 +578,15 @@ begin
     Result := gUseFrameCursor;
 end;
 
+procedure TPanelColumnsClass.SetUnique(const AValue: String);
+begin
+  if Length(AValue) > 0 then
+    FUnique:= AValue
+  else begin
+    FUnique:= GetUnique;
+  end;
+end;
+
 function TPanelColumnsClass.GetCursorBorder: boolean;
 begin
   if FCustomView then
@@ -598,6 +635,7 @@ begin
     Exit;
 
   Name := OtherColumnsClass.Name;
+  FUnique := OtherColumnsClass.Unique;
   FFileSystem := OtherColumnsClass.FFileSystem;
   FCustomView := OtherColumnsClass.FCustomView;
   FCursorBorder := OtherColumnsClass.FCursorBorder;
@@ -610,6 +648,7 @@ begin
     NewColumn := TPanelColumn.Create;
     Add(NewColumn);
 
+    NewColumn.FUnique     := OldColumn.FUnique;
     NewColumn.Title       := OldColumn.Title;
     NewColumn.FuncString  := OldColumn.FuncString;
     NewColumn.Width       := OldColumn.Width;
@@ -646,7 +685,7 @@ function TPanelColumnsClass.Add(const Title, FuncString: String;
 var
   AColumn: TPanelColumn;
 begin
-  AColumn := TPanelColumn.Create;
+  AColumn := TPanelColumn.CreateNew;
   Result := FList.Add(AColumn);
 
   AColumn.Title       := Title;
@@ -822,7 +861,7 @@ procedure TPanelColumnsClass.AddDefaultColumns;
 var
   DCFunc: String;
 begin
-  SetName := 'Default';
+  fSetName := 'Default';
   FFileSystem := FS_GENERAL;
   DCFunc := '[' + sFuncTypeDC + '().%s{}]';
   // file name
@@ -857,13 +896,18 @@ var
   AColumn: TPanelColumn;
   APixelsPerInch: Integer;
 begin
+  Unique := AConfig.GetValue(ANode, 'Unique', EmptyStr);
   FCustomView := AConfig.GetValue(ANode, 'CustomView', False);
   FFileSystem := AConfig.GetValue(ANode, 'FileSystem', FS_GENERAL);
   APixelsPerInch:= AConfig.GetValue(ANode, 'PixelsPerInch', Screen.PixelsPerInch);
   FCursorBorder := AConfig.GetAttr(ANode, 'CursorBorder/Enabled', gUseCursorBorder);
-  FCursorBorderColor := TColor(AConfig.GetValue(ANode, 'CursorBorder/Color', gColors.FilePanel^.CursorBorderColor));
   FUseFrameCursor := AConfig.GetAttr(ANode, 'UseFrameCursor', gUseFrameCursor);
 
+  if (LoadedConfigVersion < JsonConfigVersion) then
+  begin
+    FCursorBorderColor := TColor(AConfig.GetValue(ANode, 'CursorBorder/Color', gColors.FilePanel^.CursorBorderColor));
+  end;
+
   Clear;
 
   SubNode := ANode.FindNode('Columns');
@@ -878,22 +922,27 @@ begin
         FList.Add(AColumn);
 
         AColumn.Title := AConfig.GetValue(SubNode, 'Title', '');
+        AColumn.Unique := AConfig.GetValue(SubNode, 'Unique', '');
         AColumn.FuncString := AConfig.GetValue(SubNode, 'FuncString', '');
         AColumn.Width := AConfig.GetValue(SubNode, 'Width', 50);
         AColumn.Width := MulDiv(AColumn.Width, Screen.PixelsPerInch, APixelsPerInch);
         AColumn.Align := TAlignment(AConfig.GetValue(SubNode, 'Align', Integer(0)));
         AConfig.GetFont(SubNode, 'Font', AColumn.FontName, AColumn.FontSize, Integer(AColumn.FontStyle), Quality,
                         gFonts[dcfMain].Name, gFonts[dcfMain].Size, Integer(gFonts[dcfMain].Style), Quality);
-        with gColors.FilePanel^ do
+
+        if (LoadedConfigVersion < JsonConfigVersion) then
         begin
-          AColumn.TextColor := TColor(AConfig.GetValue(SubNode, 'TextColor', ForeColor));
-          AColumn.Background := TColor(AConfig.GetValue(SubNode, 'Background', BackColor));
-          AColumn.Background2 := TColor(AConfig.GetValue(SubNode, 'Background2', BackColor2));
-          AColumn.MarkColor := TColor(AConfig.GetValue(SubNode, 'MarkColor', MarkColor));
-          AColumn.CursorColor := TColor(AConfig.GetValue(SubNode, 'CursorColor', CursorColor));
-          AColumn.CursorText := TColor(AConfig.GetValue(SubNode, 'CursorText', CursorText));
-          AColumn.InactiveCursorColor := TColor(AConfig.GetValue(SubNode, 'InactiveCursorColor', InactiveCursorColor));
-          AColumn.InactiveMarkColor := TColor(AConfig.GetValue(SubNode, 'InactiveMarkColor', InactiveMarkColor));
+          with gColors.FilePanel^ do
+          begin
+            AColumn.TextColor := TColor(AConfig.GetValue(SubNode, 'TextColor', ForeColor));
+            AColumn.Background := TColor(AConfig.GetValue(SubNode, 'Background', BackColor));
+            AColumn.Background2 := TColor(AConfig.GetValue(SubNode, 'Background2', BackColor2));
+            AColumn.MarkColor := TColor(AConfig.GetValue(SubNode, 'MarkColor', MarkColor));
+            AColumn.CursorColor := TColor(AConfig.GetValue(SubNode, 'CursorColor', CursorColor));
+            AColumn.CursorText := TColor(AConfig.GetValue(SubNode, 'CursorText', CursorText));
+            AColumn.InactiveCursorColor := TColor(AConfig.GetValue(SubNode, 'InactiveCursorColor', InactiveCursorColor));
+            AColumn.InactiveMarkColor := TColor(AConfig.GetValue(SubNode, 'InactiveMarkColor', InactiveMarkColor));
+          end;
         end;
         AColumn.UseInvertedSelection := AConfig.GetValue(SubNode, 'UseInvertedSelection', gUseInvertedSelection);
         AColumn.UseInactiveSelColor := AConfig.GetValue(SubNode, 'UseInactiveSelColor', gUseInactiveSelColor);
@@ -932,12 +981,11 @@ var
   SubNode: TXmlNode;
   AColumn: TPanelColumn;
 begin
+  AConfig.SetValue(ANode, 'Unique', Unique);
   AConfig.SetValue(ANode, 'CustomView', FCustomView);
   AConfig.SetValue(ANode, 'FileSystem', FFileSystem);
   AConfig.SetValue(ANode, 'PixelsPerInch', Screen.PixelsPerInch);
   AConfig.SetAttr(ANode, 'CursorBorder/Enabled', FCursorBorder);
-  if FCursorBorderColor <> clNone then
-    AConfig.SetValue(ANode, 'CursorBorder/Color', FCursorBorderColor);
   AConfig.SetAttr(ANode, 'UseFrameCursor', FUseFrameCursor);
 
   ANode := AConfig.FindNode(ANode, 'Columns', True);
@@ -949,35 +997,170 @@ begin
       SubNode := AConfig.AddNode(ANode, 'Column');
 
       AConfig.AddValue(SubNode, 'Title', AColumn.Title);
+      AConfig.AddValue(SubNode, 'Unique', AColumn.Unique);
       AConfig.AddValue(SubNode, 'FuncString', AColumn.FuncString);
       AConfig.AddValue(SubNode, 'Width', AColumn.Width);
       AConfig.AddValue(SubNode, 'Align', Integer(AColumn.Align));
       AConfig.SetFont(SubNode, 'Font', AColumn.FontName,
                       AColumn.FontSize, Integer(AColumn.FontStyle), 0);
 
-      if AColumn.TextColor <> clNone then
-        AConfig.AddValue(SubNode, 'TextColor', AColumn.TextColor);
-      if AColumn.Background <> clNone then
-        AConfig.AddValue(SubNode, 'Background', AColumn.Background);
-      if AColumn.Background2 <> clNone then
-        AConfig.AddValue(SubNode, 'Background2', AColumn.Background2);
-      if AColumn.MarkColor <> clNone then
-        AConfig.AddValue(SubNode, 'MarkColor', AColumn.MarkColor);
-      if AColumn.CursorColor <> clNone then
-        AConfig.AddValue(SubNode, 'CursorColor', AColumn.CursorColor);
-      if AColumn.CursorText <> clNone then
-        AConfig.AddValue(SubNode, 'CursorText', AColumn.CursorText);
-      if AColumn.InactiveCursorColor <> clNone then
-        AConfig.AddValue(SubNode, 'InactiveCursorColor', AColumn.InactiveCursorColor);
-      if AColumn.InactiveMarkColor <> clNone then
-        AConfig.AddValue(SubNode, 'InactiveMarkColor', AColumn.InactiveMarkColor);
-
       AConfig.AddValue(SubNode, 'UseInvertedSelection', AColumn.UseInvertedSelection);
       AConfig.AddValue(SubNode, 'UseInactiveSelColor', AColumn.UseInactiveSelColor);
       AConfig.AddValue(SubNode, 'Overcolor', AColumn.Overcolor);
     end;
 end;
 
+procedure TPanelColumnsClass.LoadColors(ANode: TJSONObject);
+var
+  I, J: Integer;
+  AName: String;
+  AList: TJSONArray;
+  AItem: TJSONObject;
+  AColumn: TPanelColumn;
+begin
+  FCursorBorderColor:= ANode.Get('CursorBorderColor', gColors.FilePanel^.CursorBorderColor);
+  if ANode.Find('Columns', AList) then
+  begin
+    for I:= 0 to Count - 1 do
+    begin
+      AColumn:= GetColumnItem(I);
+
+      for J:= 0 to AList.Count - 1 do
+      begin
+        AItem:= AList.Objects[J];
+        AName:= AItem.Get('Unique', EmptyStr);
+
+        if AColumn.FUnique = AName then
+        begin
+          with gColors.FilePanel^ do
+          begin
+            AColumn.TextColor := AItem.Get('TextColor', ForeColor);
+            AColumn.Background := AItem.Get('Background', BackColor);
+            AColumn.Background2 := AItem.Get('Background2', BackColor2);
+            AColumn.MarkColor := AItem.Get('MarkColor', MarkColor);
+            AColumn.CursorColor := AItem.Get('CursorColor', CursorColor);
+            AColumn.CursorText := AItem.Get('CursorText', CursorText);
+            AColumn.InactiveCursorColor := AItem.Get('InactiveCursorColor', InactiveCursorColor);
+            AColumn.InactiveMarkColor := AItem.Get('InactiveMarkColor', InactiveMarkColor);
+          end;
+          Break;
+        end;
+      end;
+    end;
+  end;
+end;
+
+procedure TPanelColumnsClass.SaveColors(ANode: TJSONObject);
+var
+  I: Integer;
+  AList: TJSONArray;
+  AItem: TJSONObject;
+  AColumn: TPanelColumn;
+begin
+  ANode.Add('Unique', Unique);
+  ANode.Add('Name', Name);
+  ANode.Add('CursorBorderColor', FCursorBorderColor);
+
+  if ANode.Find('Columns', AList) then
+    AList.Clear
+  else begin
+    AList:= TJSONArray.Create;
+    ANode.Add('Columns', AList);
+  end;
+
+  for I := 0 to FList.Count - 1 do
+  begin
+    AItem:= TJSONObject.Create;
+    AColumn:= TPanelColumn(FList[I]);
+
+    AItem.Add('Unique', AColumn.Unique);
+    AItem.Add('Title', AColumn.Title);
+
+    AItem.Add('TextColor', AColumn.TextColor);
+    AItem.Add('Background', AColumn.Background);
+    AItem.Add('Background2', AColumn.Background2);
+    AItem.Add('MarkColor', AColumn.MarkColor);
+    AItem.Add('CursorColor', AColumn.CursorColor);
+    AItem.Add('CursorText', AColumn.CursorText);
+    AItem.Add('InactiveCursorColor', AColumn.InactiveCursorColor);
+    AItem.Add('InactiveMarkColor', AColumn.InactiveMarkColor);
+
+    AList.Add(AItem);
+  end;
+end;
+
+procedure TPanelColumnsClass.Synchronize(ANode: TJSONObject);
+var
+  I, J: Integer;
+  AName: String;
+  Found: Boolean;
+  AList: TJSONArray;
+  AItem: TJSONObject;
+  AColumn: TPanelColumn;
+begin
+  ANode.Strings['Name']:= Name;
+  if ANode.Find('Columns', AList) then
+  begin
+    // Insert
+    for I:= 0 to Count - 1 do
+    begin
+      Found:= False;
+      AColumn:= GetColumnItem(I);
+
+      for J:= 0 to AList.Count - 1 do
+      begin
+        AItem:= AList.Objects[J];
+        AName:= AItem.Get('Unique', EmptyStr);
+
+        if AColumn.FUnique = AName then
+        begin
+          Found:= True;
+          Break;
+        end;
+      end;
+
+      if not Found then
+      begin
+        AItem:= TJSONObject.Create;
+
+        AItem.Add('Unique', AColumn.Unique);
+        AItem.Add('Title', AColumn.Title);
+
+        AItem.Add('TextColor', AColumn.TextColor);
+        AItem.Add('Background', AColumn.Background);
+        AItem.Add('Background2', AColumn.Background2);
+        AItem.Add('MarkColor', AColumn.MarkColor);
+        AItem.Add('CursorColor', AColumn.CursorColor);
+        AItem.Add('CursorText', AColumn.CursorText);
+        AItem.Add('InactiveCursorColor', AColumn.InactiveCursorColor);
+        AItem.Add('InactiveMarkColor', AColumn.InactiveMarkColor);
+
+        AList.Add(AItem);
+      end;
+    end;
+    // Delete
+    for I:= AList.Count - 1 downto 0 do
+    begin
+      Found:= False;
+      AItem:= AList.Objects[I];
+      AName:= AItem.Get('Unique', EmptyStr);
+      for J:= 0 to Count - 1 do
+      begin
+        AColumn:= GetColumnItem(J);
+        if AColumn.FUnique = AName then
+        begin
+          Found:= True;
+          Break;
+        end;
+      end;
+      if not Found then
+      begin
+        AList.Delete(I);
+      end;
+    end;
+  end;
+end;
+
 procedure TPanelColumnsClass.Delete(const Index: Integer);
 begin
   if Index > Flist.Count then
@@ -986,6 +1169,11 @@ begin
   FList.Delete(Index);
 end;
 
+procedure TPanelColumnsClass.Exchange(Index1, Index2: Integer);
+begin
+  FList.Exchange(Index1, Index2);
+end;
+
 function TPanelColumnsClass.GetSignature(Seed:dword=$000000):dword;
   procedure ProgressSignatureWithThisString(sSomething:string);
   begin
@@ -1041,13 +1229,18 @@ begin
   FuncList := TStringList.Create;
 end;
 
+constructor TPanelColumn.CreateNew;
+begin
+  Create;
+  FUnique:= GetUnique;
+end;
+
 destructor TPanelColumn.Destroy;
 begin
   FreeAndNil(FuncList);
   inherited Destroy;
 end;
 
-
 function TPanelColumn.GetColumnResultString(AFile: TFile; const AFileSource: IFileSource): String;
 var
   i: Integer;
@@ -1071,7 +1264,17 @@ begin
   Result := s;
 end;
 
+procedure TPanelColumn.SetUnique(const AValue: String);
+begin
+  if Length(AValue) > 0 then
+    FUnique:= AValue
+  else begin
+    FUnique:= GetUnique;
+  end;
+end;
+
 procedure TPanelColumn.SetFuncString(NewValue: String);
+
   procedure FillListFromString(List: TStrings; FuncS: String);
   var
     p: Integer;
@@ -1098,6 +1301,7 @@ procedure TPanelColumn.SetFuncString(NewValue: String);
   end;
 
 begin
+  FuncList.Clear;
   FFuncString := NewValue;
   FillListFromString(FuncList, NewValue);
 end;
@@ -1109,9 +1313,63 @@ begin
   Result := fSet.Count;
 end;
 
+procedure TPanelColumnsList.Synchronize(Item: TPanelColumnsClass);
+var
+  AName: String;
+  Index: Integer;
+  Found: Boolean;
+  AList: TJSONArray;
+  AItem: TJSONObject;
+
+  procedure AddItem;
+  begin
+    AItem:= TJSONObject.Create;
+    Item.SaveColors(AItem);
+    AList.Add(AItem);
+  end;
+
+begin
+  // Current style
+  Found:= False;
+  AName:= Item.Unique;
+  AList:= FStyles[FStyle];
+
+  for Index:= 0 to AList.Count - 1 do
+  begin
+    AItem:= AList.Objects[Index];
+    if AName = AItem.Get('Unique', EmptyStr) then
+    begin
+      AItem.Clear;
+      Found:= True;
+      Item.SaveColors(AItem);
+      Break;
+    end;
+  end;
+
+  if not Found then AddItem;
+
+  // Second style
+  AList:= FStyles[Abs(FStyle - 1)];
+
+  for Index:= 0 to AList.Count - 1 do
+  begin
+    AItem:= AList.Objects[Index];
+    if AName = AItem.Get('Unique', EmptyStr) then
+    begin
+      Item.Synchronize(AItem);
+      Exit;
+    end;
+  end;
+
+  AddItem;
+end;
+
 constructor TPanelColumnsList.Create;
 begin
   FSet := TStringList.Create;
+  FStyles[0]:= TJSONArray.Create;
+  FStyles[1]:= TJSONArray.Create;
+  FStyle:= TColorThemes.StyleIndex;
 end;
 
 destructor TPanelColumnsList.Destroy;
@@ -1125,6 +1383,9 @@ begin
     FreeAndNil(FSet);
   end;
 
+  FStyles[0].Free;
+  FStyles[1].Free;
+
   inherited Destroy;
 end;
 
@@ -1137,6 +1398,20 @@ begin
   Fset.Clear;
 end;
 
+procedure TPanelColumnsList.UpdateStyle;
+var
+  ANewStyle: Integer;
+begin
+  ANewStyle:= TColorThemes.StyleIndex;
+
+  if FStyle <> ANewStyle then
+  begin
+    SaveColors;
+    FStyle:= ANewStyle;
+    LoadColors;
+  end;
+end;
+
 procedure TPanelColumnsList.Load(AConfig: TXmlConfig; ANode: TXmlNode);
 var
   AName: String;
@@ -1144,6 +1419,8 @@ var
 begin
   Clear;
 
+  LoadedConfigVersion := AConfig.GetAttr(AConfig.RootNode, 'ConfigVersion', ConfigVersion);
+
   ANode := ANode.FindNode('ColumnsSets');
   if Assigned(ANode) then
   begin
@@ -1166,6 +1443,13 @@ begin
       ANode := ANode.NextSibling;
     end;
   end;
+
+  if (LoadedConfigVersion < JsonConfigVersion) then
+  begin
+    SaveColors;
+    FStyles[Abs(FStyle - 1)].Free;
+    FStyles[Abs(FStyle - 1)]:= FStyles[FStyle].Clone as TJSONArray;
+  end;
 end;
 
 procedure TPanelColumnsList.Save(AConfig: TXmlConfig; ANode: TXmlNode);
@@ -1184,14 +1468,129 @@ begin
   end;
 end;
 
+procedure TPanelColumnsList.LoadColors;
+var
+  I, J: Integer;
+  AList: TJSONArray;
+  AItem: TJSONObject;
+  AColSet: TPanelColumnsClass;
+begin
+  AList:= FStyles[FStyle];
+
+  for I := 0 to FSet.Count - 1 do
+  begin
+    AColSet:= GetColumnSet(I);
+
+    for J:= 0 to AList.Count - 1 do
+    begin
+      AItem:= AList.Objects[J];
+      if AColSet.FUnique = AItem.Get('Unique', EmptyStr) then
+      begin
+        AColSet.LoadColors(AItem);
+        Break;
+      end;
+    end;
+  end;
+end;
+
+procedure TPanelColumnsList.SaveColors;
+var
+  Index: Integer;
+  AList: TJSONArray;
+  AItem: TJSONObject;
+  AColSet: TPanelColumnsClass;
+begin
+  AList:= FStyles[FStyle];
+  AList.Clear;
+
+  for Index := 0 to FSet.Count - 1 do
+  begin
+    AColSet:= GetColumnSet(Index);
+
+    AItem:= TJSONObject.Create;
+    AColSet.SaveColors(AItem);
+
+    AList.Add(AItem);
+  end;
+end;
+
+procedure TPanelColumnsList.LoadColors(AConfig: TJSONObject);
+var
+  AName: String;
+  Index: Integer;
+  Style: TJSONArray;
+  Theme: TJSONObject;
+  Themes: TJSONArray;
+  Empty: TJSONArray;
+begin
+  Themes:= AConfig.Get('Styles', TJSONArray(nil));
+
+  if Assigned(Themes) then
+  begin
+    Empty:= TJSONArray.Create;
+    try
+      for Index:= 0 to Themes.Count - 1 do
+      begin
+        Theme:= Themes.Objects[Index];
+        AName:= Theme.Get('Name', EmptyStr);
+        if (AName = LIGHT_THEME) then
+        begin
+          FStyles[0].Free;
+          Style:= Theme.Get('ColumnSets', Empty);
+          FStyles[0]:= Style.Clone as TJSONArray;
+        end
+        else if (AName = DARK_THEME) then
+        begin
+          FStyles[1].Free;
+          Style:= Theme.Get('ColumnSets', Empty);
+          FStyles[1]:= Style.Clone as TJSONArray;
+        end
+      end;
+    finally
+      Empty.Free;
+    end;
+  end;
+  LoadColors;
+end;
+
+procedure TPanelColumnsList.SaveColors(AConfig: TJSONObject);
+var
+  AName: String;
+  Index: Integer;
+  Theme: TJSONObject;
+  Themes: TJSONArray;
+begin
+  SaveColors;
+  Themes:= AConfig.Get('Styles', TJSONArray(nil));
+
+  if Assigned(Themes) then
+  begin
+    for Index:= 0 to Themes.Count - 1 do
+    begin
+      Theme:= Themes.Objects[Index];
+      AName:= Theme.Get('Name', EmptyStr);
+      if (AName = LIGHT_THEME) then
+      begin
+        Theme.Arrays['ColumnSets']:= FStyles[0].Clone as TJSONArray;
+      end
+      else if (AName = DARK_THEME) then
+      begin
+        Theme.Arrays['ColumnSets']:= FStyles[1].Clone as TJSONArray;
+      end
+    end;
+  end;
+end;
+
 function TPanelColumnsList.Add(Item: TPanelColumnsClass): Integer;
 begin
   Result := Fset.AddObject(Item.Name, Item);
+  Synchronize(Item);
 end;
 
 procedure TPanelColumnsList.Insert(AIndex: Integer; Item: TPanelColumnsClass);
 begin
   Fset.InsertObject(AIndex, Item.Name, Item);
+  Synchronize(Item);
 end;
 
 procedure TPanelColumnsList.DeleteColumnSet(SetName: String);
@@ -1240,28 +1639,17 @@ begin
   begin
     if fset.Count = 0 then
     begin
-      Fset.AddObject('Default', TPanelColumnsClass.Create);
-      TPanelColumnsClass(Fset.Objects[0]).AddDefaultColumns;
+      Result:= TPanelColumnsClass.Create;
+      Result.AddDefaultColumns;
+      Add(Result);
     end;
     Result := TPanelColumnsClass(Fset.Objects[0]);
   end;
 end;
 
 function TPanelColumnsList.GetColumnSet(Setname: String): TPanelColumnsClass;
-var
-  Index: Integer;
 begin
-  Index:= fset.IndexOf(Setname);
-  if Index > -1 then
-    Result := TPanelColumnsClass(Fset.Objects[Index])
-  else begin
-    if fset.Count = 0 then
-    begin
-      Fset.AddObject('Default', TPanelColumnsClass.Create);
-      TPanelColumnsClass(Fset.Objects[0]).AddDefaultColumns;
-    end;
-    Result := TPanelColumnsClass(Fset.Objects[0]);
-  end;
+  Result:= GetColumnSet(FSet.IndexOf(Setname));
 end;
 
 function TPanelColumnsList.GetColumnSet(const AName, FileSystem: String): TPanelColumnsClass;

+ 4 - 1
src/uglobs.pas

@@ -212,7 +212,8 @@ const
   //       Loading a config prior of version 11 should ignore that setting and keep default.
   // 13 -  Replace Configuration/UseConfigInProgramDir by doublecmd.inf
   // 14 -  Move some colors to colors.json
-  ConfigVersion = 14;
+  // 15 -  Move custom columns colors to colors.json
+  ConfigVersion = 15;
 
   COLORS_JSON = 'colors.json';
 
@@ -823,6 +824,7 @@ procedure SaveColorsConfig;
 begin
   gColors.Save(gStyles.Root);
   gColorExt.Save(gStyles.Root);
+  ColSet.SaveColors(gStyles.Root);
   gHighlighters.SaveColors(gStyles.Root);
   gStyles.SaveToFile(gpCfgDir + COLORS_JSON);
 end;
@@ -870,6 +872,7 @@ begin
   gStyles.LoadFromFile(gpCfgDir + COLORS_JSON);
   gColors.Load(gStyles.Root);
   gColorExt.Load(gStyles.Root);
+  ColSet.LoadColors(gStyles.Root);
   gHighlighters.LoadColors(gStyles.Root);
   Result := True;
 end;