Pārlūkot izejas kodu

python script on imagelist

johann 5 gadi atpakaļ
vecāks
revīzija
aec4d38e18

+ 12 - 0
lazpaint/lazpaintdialogs.inc

@@ -206,6 +206,18 @@ begin
       result := srCancelledByUser;
       result := srCancelledByUser;
 end;
 end;
 
 
+function TLazPaintInstance.ScriptShowDirectoryDialog(AVars: TVariableSet): TScriptResult;
+var
+  chosenDir: string;
+begin
+  if SelectDirectory(AVars.Strings['Prompt'], AVars.Strings['InitialDir'], chosenDir) then
+  begin
+    Avars.Strings['Result'] := chosenDir;
+    result := srOk;
+  end else
+    result := srCancelledByUser;
+end;
+
 function TLazPaintInstance.ShowResampleDialog(AParameters: TVariableSet): boolean;
 function TLazPaintInstance.ShowResampleDialog(AParameters: TVariableSet): boolean;
 begin
 begin
   FormsNeeded;
   FormsNeeded;

+ 3 - 1
lazpaint/lazpaintinstance.pas

@@ -50,6 +50,7 @@ type
     function ScriptImageCanvasSize(AVars: TVariableSet): TScriptResult;
     function ScriptImageCanvasSize(AVars: TVariableSet): TScriptResult;
     function ScriptImageRepeat(AVars: TVariableSet): TScriptResult;
     function ScriptImageRepeat(AVars: TVariableSet): TScriptResult;
     function ScriptImageResample(AParams: TVariableSet): TScriptResult;
     function ScriptImageResample(AParams: TVariableSet): TScriptResult;
+    function ScriptShowDirectoryDialog(AVars: TVariableSet): TScriptResult;
     procedure SelectionInstanceOnRun(AInstance: TLazPaintCustomInstance);
     procedure SelectionInstanceOnRun(AInstance: TLazPaintCustomInstance);
     procedure ToolFillChanged(Sender: TObject);
     procedure ToolFillChanged(Sender: TObject);
     procedure PythonScriptCommand({%H-}ASender: TObject; ACommand, AParam: UTF8String; out
     procedure PythonScriptCommand({%H-}ASender: TObject; ACommand, AParam: UTF8String; out
@@ -343,6 +344,7 @@ begin
   ScriptContext.RegisterScriptFunction('ColorShiftColors',@ScriptColorShiftColors,ARegister);
   ScriptContext.RegisterScriptFunction('ColorShiftColors',@ScriptColorShiftColors,ARegister);
   ScriptContext.RegisterScriptFunction('ColorIntensity',@ScriptColorIntensity,ARegister);
   ScriptContext.RegisterScriptFunction('ColorIntensity',@ScriptColorIntensity,ARegister);
   ScriptContext.RegisterScriptFunction('ShowMessage',@ScriptShowMessage,ARegister);
   ScriptContext.RegisterScriptFunction('ShowMessage',@ScriptShowMessage,ARegister);
+  ScriptContext.RegisterScriptFunction('ShowDirectoryDialog',@ScriptShowDirectoryDialog,ARegister);
   ScriptContext.RegisterScriptFunction('InputBox',@ScriptInputBox,ARegister);
   ScriptContext.RegisterScriptFunction('InputBox',@ScriptInputBox,ARegister);
 end;
 end;
 
 
@@ -1771,7 +1773,7 @@ end;
 procedure TLazPaintInstance.AddToImageList(const FileNames: array of String);
 procedure TLazPaintInstance.AddToImageList(const FileNames: array of String);
 begin
 begin
   if FImageList <> nil then
   if FImageList <> nil then
-    FImageList.AddFiles (FileNames);
+    FImageList.AddFiles (FileNames, true);
 end;
 end;
 
 
 procedure TLazPaintInstance.UpdateToolbar;
 procedure TLazPaintInstance.UpdateToolbar;

+ 469 - 118
lazpaint/uimagelist.pas

@@ -8,7 +8,8 @@ interface
 uses
 uses
   Classes, SysUtils, Forms, Controls, Graphics, Dialogs,
   Classes, SysUtils, Forms, Controls, Graphics, Dialogs,
   Grids, StdCtrls, Buttons, ComCtrls, ExtCtrls, Menus, UImageObservation,
   Grids, StdCtrls, Buttons, ComCtrls, ExtCtrls, Menus, UImageObservation,
-  LazPaintType, UResourceStrings, UConfig, BGRAImageList, ubrowseimages;
+  LazPaintType, UResourceStrings, UConfig, BGRAImageList, ubrowseimages,
+  UScripting;
 
 
 type
 type
   String1D= array of string;
   String1D= array of string;
@@ -92,13 +93,14 @@ type
     procedure tbAddFilesClick(Sender: TObject);
     procedure tbAddFilesClick(Sender: TObject);
     function GetRowChecked(Row: integer): Boolean;
     function GetRowChecked(Row: integer): Boolean;
     function CheckedExist (Verbose: Boolean=True): Boolean;
     function CheckedExist (Verbose: Boolean=True): Boolean;
-    function SelectedRow: integer;
+    function GetSelectedRow: integer;
     procedure NormalWindow (Normalsize: Boolean= True);
     procedure NormalWindow (Normalsize: Boolean= True);
     function SaveModified: boolean;
     function SaveModified: boolean;
     function OpenImage (FileName: string): boolean;
     function OpenImage (FileName: string): boolean;
     function IsExtensionIsValid (FileName:string): boolean;
     function IsExtensionIsValid (FileName:string): boolean;
     procedure Renumber;
     procedure Renumber;
   private
   private
+    FLazPaintInstance: TLazPaintCustomInstance;
     FBrowseImages: TFBrowseImages;
     FBrowseImages: TFBrowseImages;
     WidthNormal: integer;
     WidthNormal: integer;
     HeightNormal: integer;
     HeightNormal: integer;
@@ -109,13 +111,42 @@ type
 //    ILConfig: TLazPaintConfig;
 //    ILConfig: TLazPaintConfig;
     procedure EnsureGridRectVisible(ARect: TGridRect);
     procedure EnsureGridRectVisible(ARect: TGridRect);
     function GetFileCount: integer;
     function GetFileCount: integer;
-    procedure ImageSaving(AEvent: TLazPaintImageObservationEvent);
+    function GetLongFileName(AIndex: integer): string;
+    procedure ImageSaving({%H-}AEvent: TLazPaintImageObservationEvent);
+    function ScriptAddFiles(AVars: TVariableSet): TScriptResult;
+    function ScriptGetAutoUncheckMode(AVars: TVariableSet): TScriptResult;
+    function ScriptGetAutoZoomFit(AVars: TVariableSet): TScriptResult;
+    function ScriptGetFileChecked(AVars: TVariableSet): TScriptResult;
+    function ScriptGetFileCount(AVars: TVariableSet): TScriptResult;
+    function ScriptGetFileName(AVars: TVariableSet): TScriptResult;
+    function ScriptGetSelectedIndex(AVars: TVariableSet): TScriptResult;
+    function ScriptIndexOfFileName(AVars: TVariableSet): TScriptResult;
+    function ScriptOpenFirst(AVars: TVariableSet): TScriptResult;
+    function ScriptOpenNext(AVars: TVariableSet): TScriptResult;
+    function ScriptOpenPrevious(AVars: TVariableSet): TScriptResult;
+    function ScriptOpenSelected(AVars: TVariableSet): TScriptResult;
+    function ScriptRemoveAll(AVars: TVariableSet): TScriptResult;
+    function ScriptRemoveIndex(AVars: TVariableSet): TScriptResult;
+    function ScriptRemoveNonExistent(AVars: TVariableSet): TScriptResult;
+    function ScriptRemoveUnchecked(AVars: TVariableSet): TScriptResult;
+    function ScriptSetAutoUncheckMode(AVars: TVariableSet): TScriptResult;
+    function ScriptSetAutoZoomFit(AVars: TVariableSet): TScriptResult;
+    function ScriptSetFileChecked(AVars: TVariableSet): TScriptResult;
+    function ScriptSetSelectedIndex(AVars: TVariableSet): TScriptResult;
+    function ScriptUncheckNonExistent(AVars: TVariableSet): TScriptResult;
+    procedure SetLazPaintInstance(AValue: TLazPaintCustomInstance);
     procedure SetRowChecked(AIndex: integer; AValue: boolean);
     procedure SetRowChecked(AIndex: integer; AValue: boolean);
+    procedure RegisterScriptFunctions(ARegister: boolean);
+    procedure CallScriptFunction(AName: string); overload;
+    function CallScriptFunction(AVars: TVariableSet): TScriptResult; overload;
+    procedure SetSelectedRow(AValue: integer);
   public
   public
-    LazPaintInstance: TLazPaintCustomInstance;
-    procedure AddFiles (const FileNames: array of String);
+    function AddFiles (const FileNames: array of String; AAutoOpen: boolean): integer;
     property FileChecked[AIndex: integer]: boolean read GetRowChecked write SetRowChecked;
     property FileChecked[AIndex: integer]: boolean read GetRowChecked write SetRowChecked;
+    property LongFileName[AIndex: integer]: string read GetLongFileName;
     property FileCount: integer read GetFileCount;
     property FileCount: integer read GetFileCount;
+    property LazPaintInstance: TLazPaintCustomInstance read FLazPaintInstance write SetLazPaintInstance;
+    property SelectedRow: integer read GetSelectedRow write SetSelectedRow;
   end;
   end;
 
 
 var
 var
@@ -133,19 +164,6 @@ uses LCLType, UFileExtensions, LazFileUtils, UFileSystem, LCScaleDPI;
 
 
 { TFImageList }
 { TFImageList }
 
 
-procedure SelectRow (aStringGrid: TStringGrid; Row: integer; aSetFocus: Boolean= True);
-var
-   GridRect: TGridRect;
-begin
-  GridRect:= aStringGrid.Selection;
-  GridRect.Top:=Row;
-  GridRect.Bottom:=Row;
-   if Row> aStringGrid.RowCount-1 then Exit;
-   aStringGrid.Row:=Row;
-   aStringGrid.Selection:=GridRect;
-  if aSetFocus then SafeSetFocus(aStringGrid);
-end;
-
 function StringExists (aStringGrid: TStringGrid; Column: integer ;  aStr: String): Boolean;
 function StringExists (aStringGrid: TStringGrid; Column: integer ;  aStr: String): Boolean;
 var
 var
   i:integer;
   i:integer;
@@ -331,43 +349,45 @@ begin
   result := IsExtensionReadable(Filename);
   result := IsExtensionReadable(Filename);
 end;
 end;
 
 
-procedure TFImageList.AddFiles (const FileNames: array of String);
+function TFImageList.AddFiles (const FileNames: array of String; AAutoOpen: boolean): integer;
 var
 var
   PrevRowCount, Row: integer;
   PrevRowCount, Row: integer;
   i: integer;
   i: integer;
   shouldOpenFirst: boolean;
   shouldOpenFirst: boolean;
 begin
 begin
+  result := 0;
   if Length(FileNames) > 0 then
   if Length(FileNames) > 0 then
   begin
   begin
-       shouldOpenFirst := FileCount = 0;
-       LazPaintInstance.Config.SetImageListLastFolder(ExtractFileDir(FileNames[0]));
-       PrevRowCount:=StringGrid1.RowCount;
-       Row:=PrevRowCount;
-       StringGrid1.RowCount:= PrevRowCount+Length(FileNames);
-       for i:= 0 to length(FileNames)- 1 do
-         begin
-           if (not StringExists (StringGrid1,ColLongFname,FileNames[i])) and (IsExtensionIsValid(FileNames[i]))then
-             begin
-               StringGrid1.Cells[colNumber,Row]:=IntToStr (Row);
-               StringGrid1.Cells[ColShortFname,Row]:=ExtractFileName(FileNames[i]);
-               StringGrid1.Cells[ColCB,Row]:='1';   //Checkbox is checked
-               StringGrid1.Cells[ColLongFname,Row]:=FileNames[i];
-               Inc(Row);
-             end;  //if StringExists
-         end;  //for i
-       StringGrid1.RowCount:=Row;
-       if shouldOpenFirst then
+     shouldOpenFirst := AAutoOpen and (FileCount = 0);
+     LazPaintInstance.Config.SetImageListLastFolder(ExtractFileDir(FileNames[0]));
+     PrevRowCount:=StringGrid1.RowCount;
+     Row:=PrevRowCount;
+     StringGrid1.RowCount:= PrevRowCount+Length(FileNames);
+     for i:= 0 to length(FileNames)- 1 do
        begin
        begin
-          tbOpenImageClick(nil);
-          if tbAutoZoomFit.Down then LazPaintInstance.Image.ZoomFit;
-       end;
+         if (not StringExists (StringGrid1,ColLongFname,FileNames[i])) and (IsExtensionIsValid(FileNames[i]))then
+           begin
+             StringGrid1.Cells[colNumber,Row]:=IntToStr (Row);
+             StringGrid1.Cells[ColShortFname,Row]:=ExtractFileName(FileNames[i]);
+             StringGrid1.Cells[ColCB,Row]:='1';   //Checkbox is checked
+             StringGrid1.Cells[ColLongFname,Row]:=FileNames[i];
+             Inc(Row);
+             inc(result);
+           end;  //if StringExists
+       end;  //for i
+     StringGrid1.RowCount:=Row;
+     if shouldOpenFirst then
+     begin
+        tbOpenImageClick(nil);
+        if tbAutoZoomFit.Down then LazPaintInstance.Image.ZoomFit;
+     end;
+     EnableButtons;
   end; //if
   end; //if
-  EnableButtons;
 end;
 end;
 
 
 procedure TFImageList.FormDropFiles(Sender: TObject;  const FileNames: array of String);
 procedure TFImageList.FormDropFiles(Sender: TObject;  const FileNames: array of String);
 begin
 begin
-   AddFiles(FileNames);
+   AddFiles(FileNames, true);
 end;
 end;
 
 
 procedure TFImageList.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
 procedure TFImageList.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
@@ -439,9 +459,7 @@ end;
 
 
 procedure TFImageList.pmRemoveAllClick(Sender: TObject);
 procedure TFImageList.pmRemoveAllClick(Sender: TObject);
 begin
 begin
-  StringGrid1.Clean;
-  StringGrid1.RowCount:= StringGrid1.FixedRows;
-  EnableButtons;
+  CallScriptFunction('ImageListRemoveAll');
 end;
 end;
 
 
 procedure TFImageList.pmRemoveClose(Sender: TObject);
 procedure TFImageList.pmRemoveClose(Sender: TObject);
@@ -450,16 +468,8 @@ begin
 end;
 end;
 
 
 procedure TFImageList.pmRemoveNonexistentClick(Sender: TObject);
 procedure TFImageList.pmRemoveNonexistentClick(Sender: TObject);
-var
-  i:integer;
-  needRenumber: boolean;
 begin
 begin
-  needRenumber := false;
-  for i:=FileCount downto 1 do
-   if not FileManager.FileExists(StringGrid1.Cells[ColLongFname,i])
-      then begin DeleteRow(StringGrid1,i); needRenumber :=true; end;
-  if needRenumber then Renumber;
-  EnableButtons;
+  CallScriptFunction('ImageListRemoveNonexistent');
 end;
 end;
 
 
 procedure TFImageList.pmRemovePopup(Sender: TObject);
 procedure TFImageList.pmRemovePopup(Sender: TObject);
@@ -497,23 +507,264 @@ begin
   result := StringGrid1.RowCount - StringGrid1.FixedRows;
   result := StringGrid1.RowCount - StringGrid1.FixedRows;
 end;
 end;
 
 
+function TFImageList.GetLongFileName(AIndex: integer): string;
+begin
+  result := StringGrid1.Cells[ColLongFname, AIndex];
+end;
+
 procedure TFImageList.ImageSaving(AEvent: TLazPaintImageObservationEvent);
 procedure TFImageList.ImageSaving(AEvent: TLazPaintImageObservationEvent);
 var
 var
   i: Integer;
   i: Integer;
 begin
 begin
   if not pmAutouncheckOnSave.Checked then exit;
   if not pmAutouncheckOnSave.Checked then exit;
   for i:= 1 to FileCount do
   for i:= 1 to FileCount do
-   if StringGrid1.Cells[ColLongFname,i] = LazPaintInstance.Image.currentFilenameUTF8 then
+   if LongFileName[i] = LazPaintInstance.Image.currentFilenameUTF8 then
      FileChecked[i] := false;
      FileChecked[i] := false;
 end;
 end;
 
 
-procedure TFImageList.SetRowChecked(AIndex: integer; AValue: boolean);
+function TFImageList.ScriptAddFiles(AVars: TVariableSet): TScriptResult;
+var
+  files: TScriptVariableReference;
+  fileArray: array of string;
+  i: Integer;
 begin
 begin
-  StringGrid1.Cells[ColCB,AIndex]:= BoolToStr(AValue, '1', '0');
+  files := AVars.GetVariable('FileNames');
+  setLength(fileArray, AVars.GetListCount(files));
+  for i := 0 to high(fileArray) do
+    fileArray[i] := AVars.GetStringAt(files, i);
+  AVars.Integers['Result'] := AddFiles(fileArray, false);
+  result := srOk;
+end;
+
+function TFImageList.ScriptGetAutoUncheckMode(AVars: TVariableSet): TScriptResult;
+begin
+  if tbAutoUncheck.Down then
+  begin
+    if pmAutouncheckOnOpen.Checked then
+      AVars.Strings['Result'] := 'UncheckOnOpen'
+    else
+      AVars.Strings['Result'] := 'UncheckOnSave';
+  end else
+    AVars.Strings['Result'] := 'UncheckOff';
+  result := srOk;
+end;
+
+function TFImageList.ScriptGetAutoZoomFit(AVars: TVariableSet): TScriptResult;
+begin
+  AVars.Booleans['Result'] := tbAutoZoomFit.Down;
+  result := srOk;
+end;
+
+function TFImageList.ScriptGetFileChecked(AVars: TVariableSet): TScriptResult;
+var
+  idx: Int64;
+begin
+  if AVars.IsDefined('Index') then
+  begin
+    idx := AVars.Integers['Index'];
+    if (idx < 1) or (idx > FileCount) then exit(srInvalidParameters);
+    AVars.Booleans['Result'] := FileChecked[idx];
+    result := srOk;
+  end else
+  begin
+    if SelectedRow >= 1 then
+    begin
+      AVars.Booleans['Result'] := FileChecked[SelectedRow];
+      result := srOk;
+    end else
+      result := srException;
+  end;
+end;
+
+function TFImageList.ScriptGetFileCount(AVars: TVariableSet): TScriptResult;
+begin
+  AVars.Integers['Result'] := FileCount;
+  result := srOk;
+end;
+
+function TFImageList.ScriptGetFileName(AVars: TVariableSet): TScriptResult;
+var
+  idx: Int64;
+begin
+  if AVars.IsDefined('Index') then
+  begin
+    idx := AVars.Integers['Index'];
+    if (idx < 1) or (idx > FileCount) then exit(srInvalidParameters);
+    AVars.Strings['Result'] := LongFileName[idx];
+    result := srOk;
+  end else
+  begin
+    if SelectedRow >= 1 then
+    begin
+      AVars.Strings['Result'] := LongFileName[SelectedRow];
+      result := srOk;
+    end else
+      result := srException;
+  end;
+end;
+
+function TFImageList.ScriptGetSelectedIndex(AVars: TVariableSet): TScriptResult;
+begin
+  AVars.Integers['Result'] := SelectedRow;
+  result := srOk;
+end;
+
+function TFImageList.ScriptIndexOfFileName(AVars: TVariableSet): TScriptResult;
+var
+  fn: String;
+  i: Integer;
+begin
+  fn := AVars.Strings['FileName'];
+  for i := 1 to FileCount do
+    if LongFileName[i] = fn then
+    begin
+      AVars.Integers['Result'] := i;
+      exit(srOk);
+    end;
+  AVars.Remove('Result');
+  result := srOk;
+end;
+
+function TFImageList.ScriptOpenFirst(AVars: TVariableSet): TScriptResult;
+var
+  i: Integer;
+  subVars: TVariableSet;
+begin
+  for i := 1 to FileCount do
+    if FileChecked[i] then
+    begin
+      SelectedRow := i;
+      subVars := TVariableSet.Create('ImageListOpenSelected');
+      subVars.Booleans['SkipSave'] := Avars.Booleans['SkipSave'];
+      result := CallScriptFunction(subVars);
+      AVars.Booleans['Result'] := true;
+      subVars.Free;
+      exit;
+    end;
+  AVars.Booleans['Result'] := false;
+  result := srOk;
+end;
+
+function TFImageList.ScriptOpenNext(AVars: TVariableSet): TScriptResult;
+var
+  i:integer;
+begin
+  if not CheckedExist(not AVars.Booleans['Silent']) then
+  begin
+    AVars.Booleans['Result'] := false;
+    exit(srOk);
+  end;
+  if not (AVars.Booleans['SkipSave'] or SaveModified) then exit(srCancelledByUser);
+  if SelectedRow < FileCount then
+    for i:= SelectedRow + 1 to FileCount do
+      if FileChecked[i] then
+        begin
+          if not OpenImage(LongFileName[i]) then exit(srException);
+          SelectedRow := i;
+          if (tbAutoUncheck.Down and pmAutouncheckOnOpen.Checked) then
+            FileChecked[SelectedRow]:= false;
+          AVars.Booleans['Result'] := true;
+          Exit(srOk);
+        end;
+  if AVars.Booleans['CanCycle'] then
+    for i:= 1 to SelectedRow do
+      if FileChecked[i] then
+        begin
+          if not OpenImage(LongFileName[i]) then exit(srException);
+          SelectedRow := i;
+          if (tbAutoUncheck.Down and pmAutouncheckOnOpen.Checked) then
+            FileChecked[SelectedRow]:= false;
+          AVars.Booleans['Result'] := true;
+          Exit(srOk);
+        end;
+  AVars.Booleans['Result'] := false;
+  exit(srOk);
+end;
+
+function TFImageList.ScriptOpenPrevious(AVars: TVariableSet): TScriptResult;
+var
+    i:integer;
+begin
+  if not CheckedExist(not AVars.Booleans['Silent']) then
+  begin
+    AVars.Booleans['Result'] := false;
+    exit(srOk);
+  end;
+  if not (AVars.Booleans['SkipSave'] or SaveModified) then exit;
+  if SelectedRow > 1 then
+    for i:= SelectedRow -1 downto 1 do
+      if FileChecked[i] then
+        begin
+          if not OpenImage(LongFileName[i]) then exit(srException);
+          SelectedRow := i;
+          if (tbAutoUncheck.Down and pmAutouncheckOnOpen.Checked) then
+            FileChecked[SelectedRow]:= false;
+          AVars.Booleans['Result'] := true;
+          Exit(srOk);
+        end; //if
+  if AVars.Booleans['CanCycle'] then
+    for i:= FileCount downto SelectedRow do
+      if FileChecked[i] then
+        begin
+          if not OpenImage(LongFileName[i]) then exit(srException);
+          SelectedRow := i;
+          if (tbAutoUncheck.Down and pmAutouncheckOnOpen.Checked) then
+            FileChecked[SelectedRow] := false;
+          AVars.Booleans['Result'] := true;
+          Exit(srOk);
+        end; //if
+  AVars.Booleans['Result'] := false;
+  exit(srOk);
+end;
+
+function TFImageList.ScriptOpenSelected(AVars: TVariableSet): TScriptResult;
+begin
+   if AVars.Booleans['SkipSave'] or SaveModified then
+   begin
+     if tbAutoUncheck.Down and pmAutouncheckOnOpen.Checked then
+       FileChecked[SelectedRow]:= false;
+     if not OpenImage (LongFileName[SelectedRow]) then
+       result := srException
+     else
+       result := srOk;
+   end else
+     result := srCancelledByUser;
+end;
+
+function TFImageList.ScriptRemoveAll(AVars: TVariableSet): TScriptResult;
+begin
+  StringGrid1.Clean;
+  StringGrid1.RowCount:= StringGrid1.FixedRows;
   EnableButtons;
   EnableButtons;
+  result := srOk;
 end;
 end;
 
 
-procedure TFImageList.pmRemoveUncheckedClick(Sender: TObject);
+function TFImageList.ScriptRemoveIndex(AVars: TVariableSet): TScriptResult;
+var
+  idx: Int64;
+begin
+  idx := AVars.Integers['Index'];
+  if (idx < 1) or (idx > FileCount) then exit(srInvalidParameters);
+  DeleteRow(StringGrid1, idx);
+  EnableButtons;
+  result := srOk;
+end;
+
+function TFImageList.ScriptRemoveNonExistent(AVars: TVariableSet): TScriptResult;
+var
+  i:integer;
+  needRenumber: boolean;
+begin
+  needRenumber := false;
+  for i:=FileCount downto 1 do
+   if not FileManager.FileExists(LongFileName[i])
+      then begin DeleteRow(StringGrid1,i); needRenumber :=true; end;
+  if needRenumber then Renumber;
+  EnableButtons;
+  result := srOk;
+end;
+
+function TFImageList.ScriptRemoveUnchecked(AVars: TVariableSet): TScriptResult;
 var
 var
   i:integer;
   i:integer;
   needRenumber: boolean;
   needRenumber: boolean;
@@ -524,21 +775,160 @@ begin
       begin DeleteRow(StringGrid1,i); needRenumber :=true; end;
       begin DeleteRow(StringGrid1,i); needRenumber :=true; end;
   if needRenumber then Renumber;
   if needRenumber then Renumber;
   EnableButtons;
   EnableButtons;
+  result := srOk;
 end;
 end;
 
 
-procedure TFImageList.pmUncheckClose(Sender: TObject);
+function TFImageList.ScriptSetAutoUncheckMode(AVars: TVariableSet): TScriptResult;
 begin
 begin
-  tbUncheckDropDown.Down := false;
+  case AVars.Strings['Mode'] of
+    'UncheckOnOpen': begin
+      tbAutoUncheck.Down := true;
+      pmAutouncheckOnSave.Checked := false;
+      pmAutouncheckOnOpen.Checked := true;
+      LazPaintInstance.Config.SetImageListAutoUncheckMode(1);
+    end;
+    'UncheckOnSave': begin
+      tbAutoUncheck.Down := true;
+      pmAutouncheckOnSave.Checked := true;
+      pmAutouncheckOnOpen.Checked := false;
+      LazPaintInstance.Config.SetImageListAutoUncheckMode(0);
+    end;
+    else
+      tbAutoUncheck.Down := false;
+  end;
+  LazPaintInstance.Config.SetImageListAutoUncheck(true);
+  result := srOk;
 end;
 end;
 
 
-procedure TFImageList.pmUncheckNonexistentClick(Sender: TObject);
+function TFImageList.ScriptSetAutoZoomFit(AVars: TVariableSet): TScriptResult;
+begin
+  tbAutoZoomFit.Down := AVars.Booleans['Enabled'];
+  LazPaintInstance.Config.SetImageListAutoZoom(AVars.Booleans['Enabled']);
+  result := srOk;
+end;
+
+function TFImageList.ScriptSetFileChecked(AVars: TVariableSet): TScriptResult;
 var
 var
-i: integer;
+  idx: Int64;
+begin
+  if AVars.IsDefined('Index') then
+  begin
+    idx := AVars.Integers['Index'];
+    if (idx < 1) or (idx > FileCount) then exit(srInvalidParameters);
+    FileChecked[idx] := AVars.Booleans['Checked'];
+    result := srOk;
+  end else
+  begin
+    if SelectedRow >= 1 then
+    begin
+      FileChecked[SelectedRow] := AVars.Booleans['Checked'];
+      result := srOk;
+    end else
+      result := srException;
+  end;
+end;
+
+function TFImageList.ScriptSetSelectedIndex(AVars: TVariableSet): TScriptResult;
+var
+  idx: Int64;
+begin
+  idx := AVars.Integers['Index'];
+  if (idx < 1) or (idx > FileCount) then exit(srInvalidParameters);
+  SelectedRow := idx;
+  result := srOk;
+end;
+
+function TFImageList.ScriptUncheckNonExistent(AVars: TVariableSet): TScriptResult;
+var
+  i: integer;
 begin
 begin
   for i:= 1 to FileCount do
   for i:= 1 to FileCount do
-     if not FileManager.FileExists(StringGrid1.Cells[ColLongFname,i])
+     if not FileManager.FileExists(LongFileName[i])
          then FileChecked[i] := false;
          then FileChecked[i] := false;
   EnableButtons;
   EnableButtons;
+  result := srOk;
+end;
+
+procedure TFImageList.SetLazPaintInstance(AValue: TLazPaintCustomInstance);
+begin
+  if FLazPaintInstance=AValue then Exit;
+  RegisterScriptFunctions(False);
+  FLazPaintInstance:=AValue;
+  RegisterScriptFunctions(True);
+end;
+
+procedure TFImageList.SetRowChecked(AIndex: integer; AValue: boolean);
+begin
+  StringGrid1.Cells[ColCB,AIndex]:= BoolToStr(AValue, '1', '0');
+  EnableButtons;
+end;
+
+procedure TFImageList.RegisterScriptFunctions(ARegister: boolean);
+begin
+  if LazPaintInstance = nil then exit;
+  LazPaintInstance.ScriptContext.RegisterScriptFunction('ImageListGetFileCount', @ScriptGetFileCount, ARegister);
+  LazPaintInstance.ScriptContext.RegisterScriptFunction('ImageListAddFiles', @ScriptAddFiles, ARegister);
+  LazPaintInstance.ScriptContext.RegisterScriptFunction('ImageListRemoveIndex', @ScriptRemoveIndex, ARegister);
+  LazPaintInstance.ScriptContext.RegisterScriptFunction('ImageListRemoveUnchecked', @ScriptRemoveUnchecked, ARegister);
+  LazPaintInstance.ScriptContext.RegisterScriptFunction('ImageListRemoveNonExistent', @ScriptRemoveNonExistent, ARegister);
+  LazPaintInstance.ScriptContext.RegisterScriptFunction('ImageListRemoveAll', @ScriptRemoveAll, ARegister);
+  LazPaintInstance.ScriptContext.RegisterScriptFunction('ImageListUncheckNonExistent', @ScriptUncheckNonExistent, ARegister);
+  LazPaintInstance.ScriptContext.RegisterScriptFunction('ImageListOpenFirst', @ScriptOpenFirst, ARegister);
+  LazPaintInstance.ScriptContext.RegisterScriptFunction('ImageListOpenSelected', @ScriptOpenSelected, ARegister);
+  LazPaintInstance.ScriptContext.RegisterScriptFunction('ImageListOpenNext', @ScriptOpenNext, ARegister);
+  LazPaintInstance.ScriptContext.RegisterScriptFunction('ImageListOpenPrevious', @ScriptOpenPrevious, ARegister);
+  LazPaintInstance.ScriptContext.RegisterScriptFunction('ImageListGetSelectedIndex', @ScriptGetSelectedIndex, ARegister);
+  LazPaintInstance.ScriptContext.RegisterScriptFunction('ImageListSetSelectedIndex', @ScriptSetSelectedIndex, ARegister);
+  LazPaintInstance.ScriptContext.RegisterScriptFunction('ImageListIndexOfFileName', @ScriptIndexOfFileName, ARegister);
+  LazPaintInstance.ScriptContext.RegisterScriptFunction('ImageListGetFileName', @ScriptGetFileName, ARegister);
+  LazPaintInstance.ScriptContext.RegisterScriptFunction('ImageListGetFileChecked', @ScriptGetFileChecked, ARegister);
+  LazPaintInstance.ScriptContext.RegisterScriptFunction('ImageListSetFileChecked', @ScriptSetFileChecked, ARegister);
+  LazPaintInstance.ScriptContext.RegisterScriptFunction('ImageListGetAutoUncheckMode', @ScriptGetAutoUncheckMode, ARegister);
+  LazPaintInstance.ScriptContext.RegisterScriptFunction('ImageListSetAutoUncheckMode', @ScriptSetAutoUncheckMode, ARegister);
+  LazPaintInstance.ScriptContext.RegisterScriptFunction('ImageListGetAutoZoomFit', @ScriptGetAutoZoomFit, ARegister);
+  LazPaintInstance.ScriptContext.RegisterScriptFunction('ImageListSetAutoZoomFit', @ScriptSetAutoZoomFit, ARegister);
+end;
+
+procedure TFImageList.CallScriptFunction(AName: string);
+begin
+  case LazPaintInstance.ScriptContext.CallScriptFunction(AName) of
+    srFunctionNotDefined: LazPaintInstance.ShowMessage(rsScript, StringReplace(rsFunctionNotDefined, '%1', AName, []));
+  end;
+end;
+
+function TFImageList.CallScriptFunction(AVars: TVariableSet): TScriptResult;
+begin
+  result := LazPaintInstance.ScriptContext.CallScriptFunction(AVars);
+  case result of
+    srFunctionNotDefined: LazPaintInstance.ShowMessage(rsScript, StringReplace(rsFunctionNotDefined, '%1', AVars.FunctionName, []));
+  end;
+end;
+
+procedure TFImageList.SetSelectedRow(AValue: integer);
+var
+  gr: TGridRect;
+begin
+  StringGrid1.Row := AValue;
+  gr := StringGrid1.Selection;
+  gr.Top := AValue;
+  gr.Bottom:= AValue;
+  StringGrid1.Selection := gr;
+  if pnlButtonsNormalWindow.Visible and self.Visible then SafeSetFocus(StringGrid1);
+end;
+
+procedure TFImageList.pmRemoveUncheckedClick(Sender: TObject);
+begin
+  CallScriptFunction('ImageListRemoveUnchecked');
+end;
+
+procedure TFImageList.pmUncheckClose(Sender: TObject);
+begin
+  tbUncheckDropDown.Down := false;
+end;
+
+procedure TFImageList.pmUncheckNonexistentClick(Sender: TObject);
+begin
+  CallScriptFunction('ImageListUncheckNonexistent');
 end;
 end;
 
 
 procedure TFImageList.pmUncheckPopup(Sender: TObject);
 procedure TFImageList.pmUncheckPopup(Sender: TObject);
@@ -610,15 +1000,10 @@ end;
 
 
 procedure TFImageList.tbOpenImageClick(Sender: TObject);
 procedure TFImageList.tbOpenImageClick(Sender: TObject);
 begin
 begin
-   if SaveModified= True then
-   begin
-     if tbAutoUncheck.Down and pmAutouncheckOnOpen.Checked then
-       FileChecked[SelectedRow]:= false;
-     OpenImage (StringGrid1.Cells[ColLongFname,SelectedRow]);
-   end;
+  CallScriptFunction('ImageListOpenSelected');
 end;
 end;
 
 
-function TFImageList.SelectedRow: integer;
+function TFImageList.GetSelectedRow: integer;
 begin
 begin
   Result:=StringGrid1.Selection.Top;
   Result:=StringGrid1.Selection.Top;
 end;
 end;
@@ -634,7 +1019,8 @@ begin
         Result:=True;
         Result:=True;
         Break;
         Break;
       end;
       end;
-  if (Result = false) and (Verbose= True) then QuestionDlg (rsInformation, rsThereAreNoCheckedItems, mtInformation, [mrOk, rsOkay],'');
+  if (Result = false) and (Verbose= True) then
+    QuestionDlg (rsInformation, rsThereAreNoCheckedItems, mtInformation, [mrOk, rsOkay],'');
 end;
 end;
 
 
 function TFImageList.SaveModified: boolean;
 function TFImageList.SaveModified: boolean;
@@ -664,57 +1050,22 @@ end;
 
 
 procedure TFImageList.tbOpenNextClick(Sender: TObject);
 procedure TFImageList.tbOpenNextClick(Sender: TObject);
 var
 var
-  i:integer;
+  vars: TVariableSet;
 begin
 begin
-  if not CheckedExist then Exit;
-  if SaveModified= False then exit;
-  if SelectedRow<FileCount
-     then
-       for i:= SelectedRow + 1 to FileCount do
-         if FileChecked[i] then
-           begin
-              OpenImage(StringGrid1.Cells[ColLongFname,i]);
-              SelectRow(StringGrid1,i, pnlButtonsNormalWindow.Visible);
-              if (tbAutoUncheck.Down and pmAutouncheckOnOpen.Checked) then
-                FileChecked[SelectedRow]:= false;
-              Exit;
-           end;
-       for i:= 1 to SelectedRow-1 do
-          if FileChecked[i] then
-            begin
-              OpenImage(StringGrid1.Cells[ColLongFname,i]);
-              SelectRow(StringGrid1,i,pnlButtonsNormalWindow.Visible);
-              if (tbAutoUncheck.Down and pmAutouncheckOnOpen.Checked) then
-                FileChecked[SelectedRow]:= false;
-              Exit;
-            end;
+  vars := TVariableSet.Create('ImageListOpenNext');
+  vars.Booleans['CanCycle'] := true;
+  CallScriptFunction(vars);
+  vars.Free;
 end;
 end;
 
 
 procedure TFImageList.tbOpenPrevClick(Sender: TObject);
 procedure TFImageList.tbOpenPrevClick(Sender: TObject);
 var
 var
-    i:integer;
+  vars: TVariableSet;
 begin
 begin
-  if not CheckedExist then Exit;
-  if SaveModified= False then exit;
-  if SelectedRow>1 then
-     for i:= SelectedRow -1 downto 1 do
-       if FileChecked[i] then
-         begin
-            OpenImage(StringGrid1.Cells[ColLongFname,i]);
-            SelectRow(StringGrid1,i,pnlButtonsNormalWindow.Visible);
-            if (tbAutoUncheck.Down and pmAutouncheckOnOpen.Checked) then
-              FileChecked[SelectedRow]:= false;
-            Exit;
-         end; //if
-  for i:= FileCount downto SelectedRow+1 do
-    if FileChecked[i] then
-      begin
-        OpenImage(StringGrid1.Cells[ColLongFname,i]);
-        SelectRow(StringGrid1,i,pnlButtonsNormalWindow.Visible);
-        if (tbAutoUncheck.Down and pmAutouncheckOnOpen.Checked) then
-          FileChecked[SelectedRow] := false;
-        Exit;
-      end; //if
+  vars := TVariableSet.Create('ImageListOpenPrevious');
+  vars.Booleans['CanCycle'] := true;
+  CallScriptFunction(vars);
+  vars.Free;
 end;
 end;
 
 
 procedure TFImageList.tbRemoveItemClick(Sender: TObject);
 procedure TFImageList.tbRemoveItemClick(Sender: TObject);
@@ -792,13 +1143,13 @@ begin
       setlength(fileNames,FBrowseImages.SelectedFileCount);
       setlength(fileNames,FBrowseImages.SelectedFileCount);
       for i := 0 to high(fileNames) do
       for i := 0 to high(fileNames) do
         fileNames[i] := FBrowseImages.SelectedFile[i];
         fileNames[i] := FBrowseImages.SelectedFile[i];
-      AddFiles(Filenames);
+      AddFiles(Filenames, true);
       FBrowseImages.FreeChosenImage;
       FBrowseImages.FreeChosenImage;
     end;
     end;
   end else
   end else
   begin
   begin
     if Length(LazPaintInstance.Config.ImageListLastFolder)>0 then OpenDialog1.InitialDir:=LazPaintInstance.Config.ImageListLastFolder;
     if Length(LazPaintInstance.Config.ImageListLastFolder)>0 then OpenDialog1.InitialDir:=LazPaintInstance.Config.ImageListLastFolder;
-    if OpenDialog1.Execute= True then AddFiles(StringsToStringArray(OpenDialog1.Files));
+    if OpenDialog1.Execute= True then AddFiles(StringsToStringArray(OpenDialog1.Files), true);
   end;
   end;
 
 
   LazPaintInstance.ShowTopmost(topMostInfo);
   LazPaintInstance.ShowTopmost(topMostInfo);

+ 3 - 0
scripts/lazpaint/dialog.py

@@ -5,6 +5,9 @@ def show_message(message):
   # wait for validation before continuing script
   # wait for validation before continuing script
   command.send("ShowMessage?", Message=message)
   command.send("ShowMessage?", Message=message)
 
 
+def show_directory_dialog(prompt, initial_dir=None) -> str:
+  return command.send("ShowDirectoryDialog?", Prompt=prompt, InitialDir=initial_dir)
+
 def input_text(prompt, default=None) -> str:
 def input_text(prompt, default=None) -> str:
   return command.send("InputBox?", Prompt=prompt, Default=default)
   return command.send("InputBox?", Prompt=prompt, Default=default)
 
 

+ 7 - 0
scripts/lazpaint/image.py

@@ -1,4 +1,5 @@
 from lazpaint import command, dialog, colors
 from lazpaint import command, dialog, colors
+import os
 
 
 if __name__ == "__main__":
 if __name__ == "__main__":
   dialog.show_message("Library to act on the whole image.")
   dialog.show_message("Library to act on the whole image.")
@@ -93,6 +94,12 @@ def save_as(file_name=None, validate=False, overwrite=False, skip_options=False)
 def export(file_name=None, validate=False, overwrite=False, skip_options=False) -> str:
 def export(file_name=None, validate=False, overwrite=False, skip_options=False) -> str:
   return command.send("FileSaveAs?", FileName=file_name, Validate=validate, Overwrite=overwrite, SkipOptions=skip_options, Export=True)
   return command.send("FileSaveAs?", FileName=file_name, Validate=validate, Overwrite=overwrite, SkipOptions=skip_options, Export=True)
 
 
+def change_file_extension(file_name: str, new_extension: str) -> str:
+  base, ext = os.path.splitext(file_name)
+  if len(new_extension) > 0 and new_extension[0:1] != ".":
+    new_extension = "." + new_extension
+  return base + new_extension
+
 def get_temporary_name() -> str:
 def get_temporary_name() -> str:
   return command.send("FileGetTemporaryName?")
   return command.send("FileGetTemporaryName?")
 
 

+ 81 - 0
scripts/lazpaint/imagelist.py

@@ -0,0 +1,81 @@
+from lazpaint import command, dialog
+import glob
+
+if __name__ == "__main__":
+  dialog.show_message("Library to act on the image list.")
+
+UNCHECK_OFF = 'UncheckOff'
+UNCHECK_ON_OPEN = 'UncheckOnOpen'
+UNCHECK_ON_SAVE = 'UncheckOnSave'
+
+def get_file_count() -> int:
+  return command.send("ImageListGetFileCount?")
+
+def get_selected_index() -> int:
+  return command.send("ImageListGetSelectedIndex?")
+
+def set_selected_index(index: int):
+  command.send("ImageListSetSelectedIndex", Index=index)
+
+def add_files(file_names: list) -> int:
+  if isinstance(file_names, str):
+    file_names = glob.glob(file_names)
+  return command.send("ImageListAddFiles?", FileNames=file_names)
+
+def index_of_file(file_name: str) -> int:
+  return command.send("ImageListIndexOfFileName?", FileName=file_name)
+
+def get_file_name(index = None) -> str:
+  return command.send("ImageListGetFileName?", Index=index)
+
+def remove_index(index: int):
+  command.send("ImageListRemoveIndex", Index=index)
+
+def remove_unchecked():
+  command.send("ImageListRemoveUnchecked")
+
+def remove_all():
+  command.send("ImageListRemoveAll")
+
+def clear():
+  remove_all()
+
+def uncheck_nonexistent():
+  command.send("ImageListUncheckNonExistent")
+
+def open_first(skip_save) -> bool:
+  return command.send("ImageListOpenFirst?", SkipSave=skip_save)
+
+def open_selected(skip_save):
+  return command.send("ImageListOpenSelected", SkipSave=skip_save)
+
+def open_next(skip_save, silent = True, can_cycle = False) -> bool:
+  return command.send("ImageListOpenNext?", SkipSave=skip_save, Silent=silent, CanCycle=can_cycle)
+
+def open_previous(skip_save, silent = True, can_cycle = False) -> bool:
+  return command.send("ImageListOpenPrevious?", SkipSave=skip_save, Silent=silent, CanCycle=can_cycle)
+
+def iterate(skip_save):
+  if open_first(skip_save):
+    yield get_file_name()
+    while open_next(skip_save):
+      yield get_file_name()
+
+def get_file_checked(index = None) -> bool:
+  return command.send("ImageListGetFileChecked?", Index=index)
+
+def set_file_checked(index = None, checked = True) -> bool:
+  return command.send("ImageListSetFileChecked", Index=index, Checked=checked)
+
+def get_auto_uncheck_mode() -> str:
+  return command.send("ImageListGetAutoUncheckMode?")
+
+def set_auto_uncheck_mode(mode: str):
+  command.send("ImageListSetAutoUncheckMode", Mode=mode)
+
+def get_auto_zoom_fit() -> bool:
+  return command.send("ImageListGetAutoZoomFit?")
+
+def set_auto_zoom_fit(enabled: bool):
+  command.send("ImageListSetAutoZoomFit", Enabled=enabled)
+

+ 31 - 0
scripts/test/test_imagelist.py

@@ -0,0 +1,31 @@
+# Make thumbnails of JPG as PNG format
+from lazpaint import imagelist, image, dialog, view
+
+THUMBNAIL_WIDTH = 128
+THUMBNAIL_HEIGHT = 128
+
+path = dialog.show_directory_dialog("Select a directory of pictures")
+imagelist.clear()
+imagelist.set_auto_uncheck_mode(imagelist.UNCHECK_ON_SAVE)
+imagelist.set_auto_zoom_fit(True)
+imagelist.add_files(path + "/*.jpg")
+if imagelist.get_file_count() == 0:
+  dialog.show_message("No JPG file found")
+  exit()
+
+thumbnails = []
+for filename in imagelist.iterate(True):
+  width, height = image.get_size()
+  ratio_x = THUMBNAIL_WIDTH / width
+  ratio_y = THUMBNAIL_HEIGHT / height
+  ratio = min(ratio_x, ratio_y)
+  image.resample(max(1, width*ratio), max(1, height*ratio))
+  view.set_zoom()
+  new_filename = image.change_file_extension(filename, "png")
+  image.export(file_name=new_filename, validate=True, overwrite=False, skip_options=True)
+  thumbnails.append(new_filename)
+
+imagelist.clear()
+imagelist.add_files(thumbnails)
+imagelist.open_first(True)
+