Просмотр исходного кода

Merge pull request #150 from bgrabitmap/dev-lazpaint

Dev lazpaint
circular17 5 лет назад
Родитель
Сommit
c2d0169e00

+ 70 - 92
lazpaint/dialog/ubrowseimages.pas

@@ -10,9 +10,6 @@ uses
   BGRAAnimatedGif, UMySLV, LazPaintType, Masks, LCLType, UFileSystem,
   BGRAAnimatedGif, UMySLV, LazPaintType, Masks, LCLType, UFileSystem,
   UImagePreview;
   UImagePreview;
 
 
-const
-  MaxIconCacheCount = 512;
-
 type
 type
 
 
   { TFBrowseImages }
   { TFBrowseImages }
@@ -87,6 +84,7 @@ type
     FChosenImage: TImageEntry;
     FChosenImage: TImageEntry;
     FPreview: TImagePreview;
     FPreview: TImagePreview;
     FComputeIconCurrentItem: integer;
     FComputeIconCurrentItem: integer;
+    FCacheComputeIconIndexes: array of integer;
     FPreviewFilename: string;
     FPreviewFilename: string;
     FInShowPreview,FInHidePreview: boolean;
     FInShowPreview,FInHidePreview: boolean;
     FSavedDetailsViewWidth: integer;
     FSavedDetailsViewWidth: integer;
@@ -174,10 +172,8 @@ uses BGRAThumbnail, BGRAPaintNet, BGRAOpenRaster, BGRAReadLzp,
     Types, UResourceStrings,
     Types, UResourceStrings,
     UConfig, bgrareadjpeg, FPReadJPEG,
     UConfig, bgrareadjpeg, FPReadJPEG,
     UFileExtensions, BGRAUTF8, LazFileUtils,
     UFileExtensions, BGRAUTF8, LazFileUtils,
-    UGraph, URaw, UDarkTheme, ShellCtrls;
-
-var
-  IconCache: TStringList;
+    UGraph, URaw, UDarkTheme, ShellCtrls,
+    UIconCache;
 
 
 { TFBrowseImages }
 { TFBrowseImages }
 
 
@@ -340,6 +336,9 @@ end;
 
 
 procedure TFBrowseImages.FormHide(Sender: TObject);
 procedure TFBrowseImages.FormHide(Sender: TObject);
 begin
 begin
+  FCacheComputeIconIndexes := nil;
+  StopCaching(true);
+
   FLastBigIcon := (ShellListView1.ViewStyle = vsIcon);
   FLastBigIcon := (ShellListView1.ViewStyle = vsIcon);
   if not IsSaveDialog then FFilename:= FPreviewFilename;
   if not IsSaveDialog then FFilename:= FPreviewFilename;
   Timer1.Enabled := false;
   Timer1.Enabled := false;
@@ -491,6 +490,8 @@ end;
 procedure TFBrowseImages.ShellListView1OnSort(Sender: TObject);
 procedure TFBrowseImages.ShellListView1OnSort(Sender: TObject);
 begin
 begin
   FComputeIconCurrentItem := 0;
   FComputeIconCurrentItem := 0;
+  FCacheComputeIconIndexes := nil;
+  StopCaching;
 end;
 end;
 
 
 procedure TFBrowseImages.ShellListView1OnFormatType(Sender: Tobject;
 procedure TFBrowseImages.ShellListView1OnFormatType(Sender: Tobject;
@@ -512,98 +513,83 @@ begin
 end;
 end;
 
 
 procedure TFBrowseImages.Timer1Timer(Sender: TObject);
 procedure TFBrowseImages.Timer1Timer(Sender: TObject);
-var i: integer;
-  iconRect,shellRect:TRect;
-  endDate: TDateTime;
-
-  function DetermineIcon(i: integer): boolean;
-  var itemPath,cacheName,dummyCaption: string;
-    cacheIndex: integer;
-    found: boolean;
-    mem: TMemoryStream;
-    s: TStream;
+const MaxCacheComputeCount = 10;
+var
+  bmpIcon: TBGRABitmap;
+  iconRect, shellRect:TRect;
+  i,j,cacheComputeCount: Integer;
+  newFilenames: array of string;
+  newLastModifications: array of TDateTime;
+begin
+  Timer1.Enabled:= false;
+  if FPreview.Filename <> FPreviewFilename then
+    UpdatePreview
+  else
+    FPreview.HandleTimer;
+
+  if not IsCacheBusy and (length(FCacheComputeIconIndexes) > 0) then
   begin
   begin
-    result := false;
-    if ShellListView1.GetItemImage(i) = FImageFileNotChecked then
+    //retrieve computed icons
+    for i := 0 to high(FCacheComputeIconIndexes) do
     begin
     begin
-      if ShellListView1.ItemIsFolder[i] then
-        ShellListView1.SetItemImage(i,FImageFolder,false)
-      else
+      j := FCacheComputeIconIndexes[i];
+      if ShellListView1.GetItemImage(j) = FImageFileNotChecked then
       begin
       begin
-        itemPath := ShellListView1.ItemFullName[i];
-        cacheName := itemPath+':'+FloatToStr(ShellListView1.ItemLastModification[i]);
-        cacheIndex := IconCache.IndexOf(cacheName);
-        if not Assigned(FBmpIcon) then FBmpIcon := TBGRABitmap.Create;
-        if cacheIndex <> -1 then
-        begin
-          TStream(IconCache.Objects[cacheIndex]).Position:= 0;
-          TBGRAReaderLazPaint.LoadRLEImage(TStream(IconCache.Objects[cacheIndex]),FBmpIcon,dummyCaption);
-          found := true;
-        end
+        bmpIcon := GetCachedIcon(ShellListView1.ItemFullName[j],
+                                 ShellListView1.ItemLastModification[j],
+                                 FImageFileUnkown);
+        if Assigned(bmpIcon) then
+          ShellListView1.SetItemImage(j, bmpIcon, bmpIcon <> FImageFileUnkown)
         else
         else
-        begin
-          try
-            s := FileManager.CreateFileStream(itemPath, fmOpenRead or fmShareDenyWrite);
-            try
-              if IsRawFilename(itemPath) then
-              begin
-                found := GetRawStreamThumbnail(s,ShellListView1.LargeIconSize,ShellListView1.LargeIconSize, BGRAPixelTransparent, True, FBmpIcon) <> nil;
-              end else
-                found := GetStreamThumbnail(s,ShellListView1.LargeIconSize,ShellListView1.LargeIconSize, BGRAPixelTransparent, True, ExtractFileExt(itemPath), FBmpIcon) <> nil;
-            finally
-              s.Free;
-            end;
-          except
-            found := false;
-          end;
-          if found then
-          begin
-            if IconCache.Count >= MaxIconCacheCount then IconCache.Delete(0);
-            mem := TMemoryStream.Create;
-            TBGRAWriterLazPaint.WriteRLEImage(mem,FBmpIcon);
-            IconCache.AddObject(cacheName,mem);
-          end;
-        end;
-        if found then
-        begin
-          ShellListView1.SetItemImage(i,FBmpIcon.Duplicate as TBGRABitmap,True);
-        end else
-          ShellListView1.SetItemImage(i,FImageFileUnkown,False);
+          if j <  FComputeIconCurrentItem then
+            FComputeIconCurrentItem := j;
       end;
       end;
-      result := true;
     end;
     end;
+    FCacheComputeIconIndexes := nil;
   end;
   end;
 
 
-var someIconDone: boolean;
-
-begin
-  Timer1.Enabled:= false;
-  EndDate := Now + 50 / MSecsPerDay;
-  if FPreview.Filename <> FPreviewFilename then
-    UpdatePreview
-  else
-    FPreview.HandleTimer;
-  if FComputeIconCurrentItem < ShellListView1.ItemCount then
+  if not IsCacheBusy and (FComputeIconCurrentItem < ShellListView1.ItemCount) then
   begin
   begin
-    vsList.Cursor := crAppStart;
+    //queue icons to compute
+    setlength(FCacheComputeIconIndexes, MaxCacheComputeCount);
+    cacheComputeCount := 0;
+
+    //compute icons for visible items
     shellRect := rect(0,0,ShellListView1.Width,ShellListView1.Height);
     shellRect := rect(0,0,ShellListView1.Width,ShellListView1.Height);
-    someIconDone := false;
     for i := FComputeIconCurrentItem to ShellListView1.ItemCount-1 do
     for i := FComputeIconCurrentItem to ShellListView1.ItemCount-1 do
     if ShellListView1.GetItemImage(i) = FImageFileNotChecked then
     if ShellListView1.GetItemImage(i) = FImageFileNotChecked then
-    If Now >= EndDate then break else
     begin
     begin
       iconRect := ShellListView1.ItemDisplayRect[i];
       iconRect := ShellListView1.ItemDisplayRect[i];
-      if IntersectRect(iconRect,iconRect,shellRect) then
-        if DetermineIcon(i) then someIconDone := true;
+      if IntersectRect(iconRect, iconRect, shellRect) then
+      begin
+        FCacheComputeIconIndexes[cacheComputeCount] := i;
+        inc(cacheComputeCount);
+        if cacheComputeCount = MaxCacheComputeCount then break;
+      end;
     end;
     end;
-    if not someIconDone then EndDate := Now + 50 / MSecsPerDay;
-    for i := FComputeIconCurrentItem to ShellListView1.ItemCount-1 do
-    If Now >= EndDate then break else
+
+    //compute icons in current display order
+    while (FComputeIconCurrentItem < ShellListView1.ItemCount-1)
+      and (cacheComputeCount < MaxCacheComputeCount) do
+    begin
+      if ShellListView1.GetItemImage(FComputeIconCurrentItem) = FImageFileNotChecked then
+      begin
+        FCacheComputeIconIndexes[cacheComputeCount] := FComputeIconCurrentItem;
+        inc(cacheComputeCount);
+      end;
+      inc(FComputeIconCurrentItem);
+    end;
+
+    setlength(FCacheComputeIconIndexes, cacheComputeCount);
+    setlength(newFilenames, cacheComputeCount);
+    setlength(newLastModifications, cacheComputeCount);
+    for i := 0 to cacheComputeCount-1 do
     begin
     begin
-      FComputeIconCurrentItem := i+1;
-      DetermineIcon(i);
+      j := FCacheComputeIconIndexes[i];
+      newFilenames[i] := ShellListView1.ItemFullName[j];
+      newLastModifications[i] := ShellListView1.ItemLastModification[j];
     end;
     end;
-    vsList.Cursor := crDefault;
+    AddToCache(newFilenames, newLastModifications, ShellListView1.LargeIconSize);
   end;
   end;
   vsList.SetBounds(vsList.Left, vsList.Top, Panel2.Width, Panel2.Height-Panel3.Height);
   vsList.SetBounds(vsList.Left, vsList.Top, Panel2.Width, Panel2.Height-Panel3.Height);
   ShellListView1.Update;
   ShellListView1.Update;
@@ -916,6 +902,8 @@ begin
         ShellListView1.SetItemImage(i,FImageFileNotChecked,false);
         ShellListView1.SetItemImage(i,FImageFileNotChecked,false);
     end;
     end;
   FComputeIconCurrentItem := 0;
   FComputeIconCurrentItem := 0;
+  FCacheComputeIconIndexes := nil;
+  StopCaching;
 end;
 end;
 
 
 procedure TFBrowseImages.SelectCurrentDir;
 procedure TFBrowseImages.SelectCurrentDir;
@@ -1248,15 +1236,5 @@ begin
   FreeAndNil(FChosenImage.bmp);
   FreeAndNil(FChosenImage.bmp);
 end;
 end;
 
 
-initialization
-
-IconCache := TStringList.Create;
-IconCache.CaseSensitive := true;
-IconCache.OwnsObjects := true;
-
-finalization
-
-IconCache.Free;
-
 end.
 end.
 
 

+ 1 - 1
lazpaint/image/uimage.pas

@@ -464,7 +464,7 @@ begin
   begin
   begin
     if (Width > 256) or (Height > 256) then
     if (Width > 256) or (Height > 256) then
     begin
     begin
-      ShowMessage(rsNotReasonableFormat);
+      ShowMessage(rsNotReasonableFormat + ' (> 256x256)');
       result := false;
       result := false;
     end;
     end;
   end;
   end;

+ 7 - 2
lazpaint/lazpaint.lpi

@@ -24,9 +24,9 @@
       <UseVersionInfo Value="True"/>
       <UseVersionInfo Value="True"/>
       <MajorVersionNr Value="7"/>
       <MajorVersionNr Value="7"/>
       <MinorVersionNr Value="1"/>
       <MinorVersionNr Value="1"/>
+      <RevisionNr Value="2"/>
       <CharSet Value="04B0"/>
       <CharSet Value="04B0"/>
       <StringTable CompanyName="http://sourceforge.net/projects/lazpaint/" ProductName="LazPaint" InternalName="lazpaint" OriginalFilename="lazpaint.exe"/>
       <StringTable CompanyName="http://sourceforge.net/projects/lazpaint/" ProductName="LazPaint" InternalName="lazpaint" OriginalFilename="lazpaint.exe"/>
-      <RevisionNr Value="1"/>
     </VersionInfo>
     </VersionInfo>
     <BuildModes Count="8">
     <BuildModes Count="8">
       <Item1 Name="Debug" Default="True"/>
       <Item1 Name="Debug" Default="True"/>
@@ -350,7 +350,7 @@
         <PackageName Value="LCL"/>
         <PackageName Value="LCL"/>
       </Item5>
       </Item5>
     </RequiredPackages>
     </RequiredPackages>
-    <Units Count="105">
+    <Units Count="106">
       <Unit0>
       <Unit0>
         <Filename Value="lazpaint.lpr"/>
         <Filename Value="lazpaint.lpr"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
@@ -968,6 +968,11 @@
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
         <UnitName Value="UImageBackup"/>
         <UnitName Value="UImageBackup"/>
       </Unit104>
       </Unit104>
+      <Unit105>
+        <Filename Value="uiconcache.pas"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="UIconCache"/>
+      </Unit105>
     </Units>
     </Units>
   </ProjectOptions>
   </ProjectOptions>
   <CompilerOptions>
   <CompilerOptions>

+ 1 - 1
lazpaint/lazpaint.lpr

@@ -40,7 +40,7 @@ uses
   URainType, UFormRain, UPaletteToolbar, uselectionhighlight,
   URainType, UFormRain, UPaletteToolbar, uselectionhighlight,
   UImagePreview, UPreviewDialog, UQuestion, UTiff, UImageView,
   UImagePreview, UPreviewDialog, UQuestion, UTiff, UImageView,
   UDarkTheme, URaw, UProcessAuto, UPython, UImageBackup, ULayerStackInterface,
   UDarkTheme, URaw, UProcessAuto, UPython, UImageBackup, ULayerStackInterface,
-  UChooseColorInterface;
+  UChooseColorInterface, UIconCache;
 
 
 //sometimes LResources disappear in the uses clause
 //sometimes LResources disappear in the uses clause
 
 

+ 1 - 1
lazpaint/lazpaintembeddedpack.lpk

@@ -26,7 +26,7 @@
         </Debugging>
         </Debugging>
       </Linking>
       </Linking>
     </CompilerOptions>
     </CompilerOptions>
-    <Version Major="7" Minor="1" Release="1"/>
+    <Version Major="7" Minor="1" Release="2"/>
     <Files Count="94">
     <Files Count="94">
       <Item1>
       <Item1>
         <Filename Value="lazpaintinstance.pas"/>
         <Filename Value="lazpaintinstance.pas"/>

+ 6 - 1
lazpaint/lazpaintmainform.pas

@@ -947,7 +947,12 @@ begin
   btnLeftDown := false;
   btnLeftDown := false;
   btnRightDown := false;
   btnRightDown := false;
   btnMiddleDown:= false;
   btnMiddleDown:= false;
-  FTablet := TLazTablet.Create(self);
+  try
+    FTablet := TLazTablet.Create(self);
+  except
+    on ex: exception do
+      FTablet := nil;
+  end;
   spacePressed:= false;
   spacePressed:= false;
   altPressed:= false;
   altPressed:= false;
   snapPressed:= false;
   snapPressed:= false;

+ 1 - 1
lazpaint/lazpainttype.pas

@@ -10,7 +10,7 @@ uses
   {$IFDEF LINUX}, InterfaceBase{$ENDIF};
   {$IFDEF LINUX}, InterfaceBase{$ENDIF};
 
 
 const
 const
-  LazPaintVersion = 7010100;
+  LazPaintVersion = 7010200;
 
 
   function LazPaintVersionStr: string;
   function LazPaintVersionStr: string;
 
 

+ 14 - 0
lazpaint/release/changelog

@@ -186,3 +186,17 @@ lazpaint (7.1) stable; urgency=low
 
 
 -- circular <[email protected]>  Fri, 10 Apr 2020 12:07:00 +0100
 -- circular <[email protected]>  Fri, 10 Apr 2020 12:07:00 +0100
 
 
+lazpaint (7.1.2) stable; urgency=low
+
+  * installer: add scripts on Windows
+  * installer: add new extensions on Windows (oXo, cur, jpeg, tif, tga, webp, xpm)
+  * rendering: phong shape undo
+  * rendering: vector layer with selection and transform
+  * rendering: add font kerning for text shape
+  * file browser: load thumbnails in separate thread to prevent freeze
+  * file browser: generate less file extensions to avoid slowdown
+  * crash fixes: skip when matrix transform is invalid
+  * crash fixes: catch tablet initialization error
+
+-- circular <[email protected]>  Fri, 24 Apr 2020 14:19:00 +0100
+

+ 14 - 0
lazpaint/release/debian/linux32/DEBIAN/changelog

@@ -186,3 +186,17 @@ lazpaint (7.1) stable; urgency=low
 
 
 -- circular <[email protected]>  Fri, 10 Apr 2020 12:07:00 +0100
 -- circular <[email protected]>  Fri, 10 Apr 2020 12:07:00 +0100
 
 
+lazpaint (7.1.2) stable; urgency=low
+
+  * installer: add scripts on Windows
+  * installer: add new extensions on Windows (oXo, cur, jpeg, tif, tga, webp, xpm)
+  * rendering: phong shape undo
+  * rendering: vector layer with selection and transform
+  * rendering: add font kerning for text shape
+  * file browser: load thumbnails in separate thread to prevent freeze
+  * file browser: generate less file extensions to avoid slowdown
+  * crash fixes: skip when matrix transform is invalid
+  * crash fixes: catch tablet initialization error
+
+-- circular <[email protected]>  Fri, 24 Apr 2020 14:19:00 +0100
+

+ 1 - 1
lazpaint/release/debian/linux32/DEBIAN/control

@@ -1,5 +1,5 @@
 Package: lazpaint
 Package: lazpaint
-Version: 7.1.1
+Version: 7.1.2
 Section: base
 Section: base
 Priority: optional
 Priority: optional
 Architecture: i386
 Architecture: i386

+ 14 - 0
lazpaint/release/debian/linux64/DEBIAN/changelog

@@ -186,3 +186,17 @@ lazpaint (7.1) stable; urgency=low
 
 
 -- circular <[email protected]>  Fri, 10 Apr 2020 12:07:00 +0100
 -- circular <[email protected]>  Fri, 10 Apr 2020 12:07:00 +0100
 
 
+lazpaint (7.1.2) stable; urgency=low
+
+  * installer: add scripts on Windows
+  * installer: add new extensions on Windows (oXo, cur, jpeg, tif, tga, webp, xpm)
+  * rendering: phong shape undo
+  * rendering: vector layer with selection and transform
+  * rendering: add font kerning for text shape
+  * file browser: load thumbnails in separate thread to prevent freeze
+  * file browser: generate less file extensions to avoid slowdown
+  * crash fixes: skip when matrix transform is invalid
+  * crash fixes: catch tablet initialization error
+
+-- circular <[email protected]>  Fri, 24 Apr 2020 14:19:00 +0100
+

+ 1 - 1
lazpaint/release/debian/linux64/DEBIAN/control

@@ -1,5 +1,5 @@
 Package: lazpaint
 Package: lazpaint
-Version: 7.1.1
+Version: 7.1.2
 Section: base
 Section: base
 Priority: optional
 Priority: optional
 Architecture: amd64
 Architecture: amd64

+ 2 - 2
lazpaint/release/macOS/LazPaint.app/Contents/Info.plist

@@ -19,9 +19,9 @@
     <key>CFBundleSignature</key>
     <key>CFBundleSignature</key>
     <string>lazp</string>
     <string>lazp</string>
     <key>CFBundleShortVersionString</key>
     <key>CFBundleShortVersionString</key>
-    <string>7.1.1</string>
+    <string>7.1.2</string>
     <key>CFBundleVersion</key>
     <key>CFBundleVersion</key>
-    <string>7.1.1</string>
+    <string>7.1.2</string>
     <key>CSResourcesFileMapped</key>
     <key>CSResourcesFileMapped</key>
     <true/>
     <true/>
     <key>CFBundleDocumentTypes</key>
     <key>CFBundleDocumentTypes</key>

+ 1 - 1
lazpaint/release/macOS/makedmg.sh

@@ -12,7 +12,7 @@ fi
 
 
 
 
 appname=LazPaint
 appname=LazPaint
-appversion=7.1.1
+appversion=7.1.2
 pkgversion=0
 pkgversion=0
 appnamenospaces=lazpaint
 appnamenospaces=lazpaint
 appbundle="$appname.app"
 appbundle="$appname.app"

+ 69 - 2
lazpaint/release/windows/lazpaint.iss

@@ -1,13 +1,14 @@
 #define MyAppName "LazPaint"
 #define MyAppName "LazPaint"
 #define MyAppOutputName "lazpaint"
 #define MyAppOutputName "lazpaint"
 #define MyInstallerSuffix "_setup_win32_win64"
 #define MyInstallerSuffix "_setup_win32_win64"
-#define MyAppVersion "7.1.1"
+#define MyAppVersion "7.1.2"
 #define MyAppPublisher "Circular, Fabien Wang, Lainz and others"
 #define MyAppPublisher "Circular, Fabien Wang, Lainz and others"
 #define MyAppURL "http://sourceforge.net/projects/lazpaint/"
 #define MyAppURL "http://sourceforge.net/projects/lazpaint/"
 #define MyAppExeName "lazpaint.exe"
 #define MyAppExeName "lazpaint.exe"
 #define DCRawExeName "dcraw.exe"
 #define DCRawExeName "dcraw.exe"
 #define LibWebPDllName "libwebp.dll"
 #define LibWebPDllName "libwebp.dll"
 #define ReleaseDir "..\bin\"
 #define ReleaseDir "..\bin\"
+#define ScriptsDir "..\..\..\scripts\"
 
 
 [Setup]
 [Setup]
 AppId={{A177F82E-B44A-4348-A265-3D1C089D6304}
 AppId={{A177F82E-B44A-4348-A265-3D1C089D6304}
@@ -84,13 +85,20 @@ Name: "ukrainian"; MessagesFile: "compiler:Languages\Ukrainian.isl"
 Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"
 Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"
 Name: "assoc_lzp"; Description: "{cm:AssocFileExtension,{#MyAppName},.lzp}"
 Name: "assoc_lzp"; Description: "{cm:AssocFileExtension,{#MyAppName},.lzp}"
 Name: "assoc_ora"; Description: "{cm:AssocFileExtension,{#MyAppName},.ora}"
 Name: "assoc_ora"; Description: "{cm:AssocFileExtension,{#MyAppName},.ora}"
+Name: "assoc_oxo"; Description: "{cm:AssocFileExtension,{#MyAppName},.oxo}"; Flags: unchecked
 Name: "assoc_pdn"; Description: "{cm:AssocFileExtension,{#MyAppName},.pdn}"; Flags: unchecked
 Name: "assoc_pdn"; Description: "{cm:AssocFileExtension,{#MyAppName},.pdn}"; Flags: unchecked
 Name: "assoc_bmp"; Description: "{cm:AssocFileExtension,{#MyAppName},.bmp}"; Flags: unchecked
 Name: "assoc_bmp"; Description: "{cm:AssocFileExtension,{#MyAppName},.bmp}"; Flags: unchecked
 Name: "assoc_pcx"; Description: "{cm:AssocFileExtension,{#MyAppName},.pcx}"; Flags: unchecked
 Name: "assoc_pcx"; Description: "{cm:AssocFileExtension,{#MyAppName},.pcx}"; Flags: unchecked
 Name: "assoc_png"; Description: "{cm:AssocFileExtension,{#MyAppName},.png}"; Flags: unchecked
 Name: "assoc_png"; Description: "{cm:AssocFileExtension,{#MyAppName},.png}"; Flags: unchecked
-Name: "assoc_jpg"; Description: "{cm:AssocFileExtension,{#MyAppName},.jpg}"; Flags: unchecked
+Name: "assoc_jpg"; Description: "{cm:AssocFileExtension,{#MyAppName},.jpg .jpeg}"; Flags: unchecked
 Name: "assoc_gif"; Description: "{cm:AssocFileExtension,{#MyAppName},.gif}"; Flags: unchecked
 Name: "assoc_gif"; Description: "{cm:AssocFileExtension,{#MyAppName},.gif}"; Flags: unchecked
 Name: "assoc_ico"; Description: "{cm:AssocFileExtension,{#MyAppName},.ico}"; Flags: unchecked
 Name: "assoc_ico"; Description: "{cm:AssocFileExtension,{#MyAppName},.ico}"; Flags: unchecked
+Name: "assoc_cur"; Description: "{cm:AssocFileExtension,{#MyAppName},.cur}"; Flags: unchecked
+Name: "assoc_tga"; Description: "{cm:AssocFileExtension,{#MyAppName},.tga}"; Flags: unchecked
+Name: "assoc_tiff"; Description: "{cm:AssocFileExtension,{#MyAppName},.tif .tiff}"; Flags: unchecked
+Name: "assoc_webp"; Description: "{cm:AssocFileExtension,{#MyAppName},.webp}"; Flags: unchecked
+Name: "assoc_xpm"; Description: "{cm:AssocFileExtension,{#MyAppName},.xpm}"; Flags: unchecked
+
 
 
 [Files]
 [Files]
 Source: "{#ReleaseDir}lazpaint32.exe"; DestDir: "{app}"; DestName: "{#MyAppExeName}"; Flags: ignoreversion; Check: not Is64BitInstallMode
 Source: "{#ReleaseDir}lazpaint32.exe"; DestDir: "{app}"; DestName: "{#MyAppExeName}"; Flags: ignoreversion; Check: not Is64BitInstallMode
@@ -102,6 +110,9 @@ Source: "libwebp\libwebp64.dll"; DestDir: "{app}"; DestName: "{#LibWebPDllName}"
 Source: "{#ReleaseDir}i18n\*.po"; DestDir: "{app}\i18n"; Excludes: "i18n\lazpaint_x64.po"; Flags: ignoreversion
 Source: "{#ReleaseDir}i18n\*.po"; DestDir: "{app}\i18n"; Excludes: "i18n\lazpaint_x64.po"; Flags: ignoreversion
 Source: "{#ReleaseDir}models\*.*"; DestDir: "{app}\models"; Flags: ignoreversion
 Source: "{#ReleaseDir}models\*.*"; DestDir: "{app}\models"; Flags: ignoreversion
 Source: "{#ReleaseDir}readme.txt"; DestDir: "{app}"; Flags: ignoreversion
 Source: "{#ReleaseDir}readme.txt"; DestDir: "{app}"; Flags: ignoreversion
+Source: "{#ScriptsDir}*"; DestDir: "{app}\scripts"; Flags: ignoreversion; Excludes: "\__pycache__\*";  
+Source: "{#ScriptsDir}\lazpaint\*"; DestDir: "{app}\scripts\lazpaint"; Flags: ignoreversion; Excludes: "\__pycache__\*";  
+Source: "{#ScriptsDir}\test\*"; DestDir: "{app}\scripts\test"; Flags: ignoreversion; Excludes: "\__pycache__\*";  
 
 
 [Icons]
 [Icons]
 Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Comment: "LazPaint"
 Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Comment: "LazPaint"
@@ -123,6 +134,11 @@ Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.ora\DefaultIcon"; Value
 Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.ora\Shell\Open"; ValueName: Icon; ValueType: String; ValueData: "{app}\{#MyAppExeName}"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.ora\Shell\Open"; ValueName: Icon; ValueType: String; ValueData: "{app}\{#MyAppExeName}"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.ora\Shell\Open\Command"; ValueType: String; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.ora\Shell\Open\Command"; ValueType: String; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey
 
 
+Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.oxo"; ValueType: String; ValueData: "PhoXo"; Flags: uninsdeletekey
+Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.oxo\DefaultIcon"; ValueType: String; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletekey
+Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.oxo\Shell\Open"; ValueName: Icon; ValueType: String; ValueData: "{app}\{#MyAppExeName}"; Flags: uninsdeletekey
+Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.oxo\Shell\Open\Command"; ValueType: String; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey
+
 Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.bmp"; ValueType: String; ValueData: "Bitmap"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.bmp"; ValueType: String; ValueData: "Bitmap"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.bmp\DefaultIcon"; ValueType: String; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.bmp\DefaultIcon"; ValueType: String; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.bmp\Shell\Open"; ValueName: Icon; ValueType: String; ValueData: "{app}\{#MyAppExeName}"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.bmp\Shell\Open"; ValueName: Icon; ValueType: String; ValueData: "{app}\{#MyAppExeName}"; Flags: uninsdeletekey
@@ -138,6 +154,11 @@ Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.jpg\DefaultIcon"; Value
 Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.jpg\Shell\Open"; ValueName: Icon; ValueType: String; ValueData: "{app}\{#MyAppExeName}"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.jpg\Shell\Open"; ValueName: Icon; ValueType: String; ValueData: "{app}\{#MyAppExeName}"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.jpg\Shell\Open\Command"; ValueType: String; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.jpg\Shell\Open\Command"; ValueType: String; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey
 
 
+Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.jpeg"; ValueType: String; ValueData: "JPEG"; Flags: uninsdeletekey
+Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.jpeg\DefaultIcon"; ValueType: String; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletekey
+Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.jpeg\Shell\Open"; ValueName: Icon; ValueType: String; ValueData: "{app}\{#MyAppExeName}"; Flags: uninsdeletekey
+Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.jpeg\Shell\Open\Command"; ValueType: String; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey
+
 Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.pdn"; ValueType: String; ValueData: "Paint.NET image"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.pdn"; ValueType: String; ValueData: "Paint.NET image"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.pdn\DefaultIcon"; ValueType: String; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.pdn\DefaultIcon"; ValueType: String; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.pdn\Shell\Open"; ValueName: Icon; ValueType: String; ValueData: "{app}\{#MyAppExeName}"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.pdn\Shell\Open"; ValueName: Icon; ValueType: String; ValueData: "{app}\{#MyAppExeName}"; Flags: uninsdeletekey
@@ -153,32 +174,78 @@ Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.ico\DefaultIcon"; Value
 Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.ico\Shell\Open"; ValueName: Icon; ValueType: String; ValueData: "{app}\{#MyAppExeName}"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.ico\Shell\Open"; ValueName: Icon; ValueType: String; ValueData: "{app}\{#MyAppExeName}"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.ico\Shell\Open\Command"; ValueType: String; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.ico\Shell\Open\Command"; ValueType: String; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey
 
 
+Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.cur"; ValueType: String; ValueData: "Cursor"; Flags: uninsdeletekey
+Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.cur\DefaultIcon"; ValueType: String; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletekey
+Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.cur\Shell\Open"; ValueName: Icon; ValueType: String; ValueData: "{app}\{#MyAppExeName}"; Flags: uninsdeletekey
+Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.cur\Shell\Open\Command"; ValueType: String; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey
+
 Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.pcx"; ValueType: String; ValueData: "Personal Computer eXchange"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.pcx"; ValueType: String; ValueData: "Personal Computer eXchange"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.pcx\DefaultIcon"; ValueType: String; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.pcx\DefaultIcon"; ValueType: String; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.pcx\Shell\Open"; ValueName: Icon; ValueType: String; ValueData: "{app}\{#MyAppExeName}"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.pcx\Shell\Open"; ValueName: Icon; ValueType: String; ValueData: "{app}\{#MyAppExeName}"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.pcx\Shell\Open\Command"; ValueType: String; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.pcx\Shell\Open\Command"; ValueType: String; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey
 
 
+Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.tga"; ValueType: String; ValueData: "Targa"; Flags: uninsdeletekey
+Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.tga\DefaultIcon"; ValueType: String; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletekey
+Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.tga\Shell\Open"; ValueName: Icon; ValueType: String; ValueData: "{app}\{#MyAppExeName}"; Flags: uninsdeletekey
+Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.tga\Shell\Open\Command"; ValueType: String; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey
+
+Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.tif"; ValueType: String; ValueData: "Tiff"; Flags: uninsdeletekey
+Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.tif\DefaultIcon"; ValueType: String; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletekey
+Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.tif\Shell\Open"; ValueName: Icon; ValueType: String; ValueData: "{app}\{#MyAppExeName}"; Flags: uninsdeletekey
+Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.tif\Shell\Open\Command"; ValueType: String; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey
+
+Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.tiff"; ValueType: String; ValueData: "Tiff"; Flags: uninsdeletekey
+Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.tiff\DefaultIcon"; ValueType: String; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletekey
+Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.tiff\Shell\Open"; ValueName: Icon; ValueType: String; ValueData: "{app}\{#MyAppExeName}"; Flags: uninsdeletekey
+Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.tiff\Shell\Open\Command"; ValueType: String; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey
+
+Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.webp"; ValueType: String; ValueData: "WebP"; Flags: uninsdeletekey
+Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.webp\DefaultIcon"; ValueType: String; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletekey
+Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.webp\Shell\Open"; ValueName: Icon; ValueType: String; ValueData: "{app}\{#MyAppExeName}"; Flags: uninsdeletekey
+Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.webp\Shell\Open\Command"; ValueType: String; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey
+
+Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.xpm"; ValueType: String; ValueData: "X PixMap"; Flags: uninsdeletekey
+Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.xpm\DefaultIcon"; ValueType: String; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletekey
+Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.xpm\Shell\Open"; ValueName: Icon; ValueType: String; ValueData: "{app}\{#MyAppExeName}"; Flags: uninsdeletekey
+Root: HKLM; Subkey: "Software\Classes\LazPaint.AssocFile.xpm\Shell\Open\Command"; ValueType: String; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey
+
 Root: HKLM; Subkey: "Software\Classes\.bmp"; ValueType: String; ValueData: "LazPaint.AssocFile.bmp"; Flags: uninsdeletevalue uninsdeletekeyifempty; Tasks: assoc_bmp
 Root: HKLM; Subkey: "Software\Classes\.bmp"; ValueType: String; ValueData: "LazPaint.AssocFile.bmp"; Flags: uninsdeletevalue uninsdeletekeyifempty; Tasks: assoc_bmp
 Root: HKLM; Subkey: "Software\Classes\.lzp"; ValueType: String; ValueData: "LazPaint.AssocFile.lzp"; Flags: uninsdeletevalue uninsdeletekeyifempty; Tasks: assoc_lzp
 Root: HKLM; Subkey: "Software\Classes\.lzp"; ValueType: String; ValueData: "LazPaint.AssocFile.lzp"; Flags: uninsdeletevalue uninsdeletekeyifempty; Tasks: assoc_lzp
 Root: HKLM; Subkey: "Software\Classes\.ora"; ValueType: String; ValueData: "LazPaint.AssocFile.ora"; Flags: uninsdeletevalue uninsdeletekeyifempty; Tasks: assoc_ora
 Root: HKLM; Subkey: "Software\Classes\.ora"; ValueType: String; ValueData: "LazPaint.AssocFile.ora"; Flags: uninsdeletevalue uninsdeletekeyifempty; Tasks: assoc_ora
+Root: HKLM; Subkey: "Software\Classes\.oxo"; ValueType: String; ValueData: "LazPaint.AssocFile.oxo"; Flags: uninsdeletevalue uninsdeletekeyifempty; Tasks: assoc_oxo
 Root: HKLM; Subkey: "Software\Classes\.png"; ValueType: String; ValueData: "LazPaint.AssocFile.png"; Flags: uninsdeletevalue uninsdeletekeyifempty; Tasks: assoc_png
 Root: HKLM; Subkey: "Software\Classes\.png"; ValueType: String; ValueData: "LazPaint.AssocFile.png"; Flags: uninsdeletevalue uninsdeletekeyifempty; Tasks: assoc_png
 Root: HKLM; Subkey: "Software\Classes\.jpg"; ValueType: String; ValueData: "LazPaint.AssocFile.jpg"; Flags: uninsdeletevalue uninsdeletekeyifempty; Tasks: assoc_jpg
 Root: HKLM; Subkey: "Software\Classes\.jpg"; ValueType: String; ValueData: "LazPaint.AssocFile.jpg"; Flags: uninsdeletevalue uninsdeletekeyifempty; Tasks: assoc_jpg
+Root: HKLM; Subkey: "Software\Classes\.jpg"; ValueType: String; ValueData: "LazPaint.AssocFile.jpeg"; Flags: uninsdeletevalue uninsdeletekeyifempty; Tasks: assoc_jpg
 Root: HKLM; Subkey: "Software\Classes\.pdn"; ValueType: String; ValueData: "LazPaint.AssocFile.pdn"; Flags: uninsdeletevalue uninsdeletekeyifempty; Tasks: assoc_pdn
 Root: HKLM; Subkey: "Software\Classes\.pdn"; ValueType: String; ValueData: "LazPaint.AssocFile.pdn"; Flags: uninsdeletevalue uninsdeletekeyifempty; Tasks: assoc_pdn
 Root: HKLM; Subkey: "Software\Classes\.gif"; ValueType: String; ValueData: "LazPaint.AssocFile.gif"; Flags: uninsdeletevalue uninsdeletekeyifempty; Tasks: assoc_gif
 Root: HKLM; Subkey: "Software\Classes\.gif"; ValueType: String; ValueData: "LazPaint.AssocFile.gif"; Flags: uninsdeletevalue uninsdeletekeyifempty; Tasks: assoc_gif
 Root: HKLM; Subkey: "Software\Classes\.ico"; ValueType: String; ValueData: "LazPaint.AssocFile.ico"; Flags: uninsdeletevalue uninsdeletekeyifempty; Tasks: assoc_ico
 Root: HKLM; Subkey: "Software\Classes\.ico"; ValueType: String; ValueData: "LazPaint.AssocFile.ico"; Flags: uninsdeletevalue uninsdeletekeyifempty; Tasks: assoc_ico
 Root: HKLM; Subkey: "Software\Classes\.pcx"; ValueType: String; ValueData: "LazPaint.AssocFile.pcx"; Flags: uninsdeletevalue uninsdeletekeyifempty; Tasks: assoc_pcx
 Root: HKLM; Subkey: "Software\Classes\.pcx"; ValueType: String; ValueData: "LazPaint.AssocFile.pcx"; Flags: uninsdeletevalue uninsdeletekeyifempty; Tasks: assoc_pcx
+Root: HKLM; Subkey: "Software\Classes\.tif"; ValueType: String; ValueData: "LazPaint.AssocFile.tiff"; Flags: uninsdeletevalue uninsdeletekeyifempty; Tasks: assoc_tiff
+Root: HKLM; Subkey: "Software\Classes\.tiff"; ValueType: String; ValueData: "LazPaint.AssocFile.tiff"; Flags: uninsdeletevalue uninsdeletekeyifempty; Tasks: assoc_tiff
+Root: HKLM; Subkey: "Software\Classes\.xpm"; ValueType: String; ValueData: "LazPaint.AssocFile.xpm"; Flags: uninsdeletevalue uninsdeletekeyifempty; Tasks: assoc_xpm
+Root: HKLM; Subkey: "Software\Classes\.webp"; ValueType: String; ValueData: "LazPaint.AssocFile.webp"; Flags: uninsdeletevalue uninsdeletekeyifempty; Tasks: assoc_webp
+Root: HKLM; Subkey: "Software\Classes\.tga"; ValueType: String; ValueData: "LazPaint.AssocFile.tga"; Flags: uninsdeletevalue uninsdeletekeyifempty; Tasks: assoc_tga
+Root: HKLM; Subkey: "Software\Classes\.cur"; ValueType: String; ValueData: "LazPaint.AssocFile.cur"; Flags: uninsdeletevalue uninsdeletekeyifempty; Tasks: assoc_cur
 
 
 Root: HKLM; Subkey: "Software\LazPaint"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\LazPaint"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\LazPaint\Capabilities"; ValueType: String; ValueName: "ApplicationName"; ValueData: "LazPaint"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\LazPaint\Capabilities"; ValueType: String; ValueName: "ApplicationName"; ValueData: "LazPaint"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\LazPaint\Capabilities"; ValueType: String; ValueName: "ApplicationDescription"; ValueData: "This program is designed to draw like with Paint.Net and to experiment this kind of programming with Lazarus."; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\LazPaint\Capabilities"; ValueType: String; ValueName: "ApplicationDescription"; ValueData: "This program is designed to draw like with Paint.Net and to experiment this kind of programming with Lazarus."; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\LazPaint\Capabilities\FileAssociations"; ValueName: ".lzp"; ValueType: String; ValueData: "LazPaint.AssocFile.lzp"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\LazPaint\Capabilities\FileAssociations"; ValueName: ".lzp"; ValueType: String; ValueData: "LazPaint.AssocFile.lzp"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\LazPaint\Capabilities\FileAssociations"; ValueName: ".ora"; ValueType: String; ValueData: "LazPaint.AssocFile.ora"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\LazPaint\Capabilities\FileAssociations"; ValueName: ".ora"; ValueType: String; ValueData: "LazPaint.AssocFile.ora"; Flags: uninsdeletekey
+Root: HKLM; Subkey: "Software\LazPaint\Capabilities\FileAssociations"; ValueName: ".oxo"; ValueType: String; ValueData: "LazPaint.AssocFile.oxo"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\LazPaint\Capabilities\FileAssociations"; ValueName: ".bmp"; ValueType: String; ValueData: "LazPaint.AssocFile.bmp"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\LazPaint\Capabilities\FileAssociations"; ValueName: ".bmp"; ValueType: String; ValueData: "LazPaint.AssocFile.bmp"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\LazPaint\Capabilities\FileAssociations"; ValueName: ".png"; ValueType: String; ValueData: "LazPaint.AssocFile.png"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\LazPaint\Capabilities\FileAssociations"; ValueName: ".png"; ValueType: String; ValueData: "LazPaint.AssocFile.png"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\LazPaint\Capabilities\FileAssociations"; ValueName: ".jpg"; ValueType: String; ValueData: "LazPaint.AssocFile.jpg"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\LazPaint\Capabilities\FileAssociations"; ValueName: ".jpg"; ValueType: String; ValueData: "LazPaint.AssocFile.jpg"; Flags: uninsdeletekey
+Root: HKLM; Subkey: "Software\LazPaint\Capabilities\FileAssociations"; ValueName: ".jpeg"; ValueType: String; ValueData: "LazPaint.AssocFile.jpeg"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\LazPaint\Capabilities\FileAssociations"; ValueName: ".pdn"; ValueType: String; ValueData: "LazPaint.AssocFile.pdn"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\LazPaint\Capabilities\FileAssociations"; ValueName: ".pdn"; ValueType: String; ValueData: "LazPaint.AssocFile.pdn"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\LazPaint\Capabilities\FileAssociations"; ValueName: ".gif"; ValueType: String; ValueData: "LazPaint.AssocFile.gif"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\LazPaint\Capabilities\FileAssociations"; ValueName: ".gif"; ValueType: String; ValueData: "LazPaint.AssocFile.gif"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\LazPaint\Capabilities\FileAssociations"; ValueName: ".ico"; ValueType: String; ValueData: "LazPaint.AssocFile.ico"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\LazPaint\Capabilities\FileAssociations"; ValueName: ".ico"; ValueType: String; ValueData: "LazPaint.AssocFile.ico"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\LazPaint\Capabilities\FileAssociations"; ValueName: ".pcx"; ValueType: String; ValueData: "LazPaint.AssocFile.pcx"; Flags: uninsdeletekey
 Root: HKLM; Subkey: "Software\LazPaint\Capabilities\FileAssociations"; ValueName: ".pcx"; ValueType: String; ValueData: "LazPaint.AssocFile.pcx"; Flags: uninsdeletekey
+Root: HKLM; Subkey: "Software\LazPaint\Capabilities\FileAssociations"; ValueName: ".tif"; ValueType: String; ValueData: "LazPaint.AssocFile.tiff"; Flags: uninsdeletekey
+Root: HKLM; Subkey: "Software\LazPaint\Capabilities\FileAssociations"; ValueName: ".tiff"; ValueType: String; ValueData: "LazPaint.AssocFile.tiff"; Flags: uninsdeletekey
+Root: HKLM; Subkey: "Software\LazPaint\Capabilities\FileAssociations"; ValueName: ".xpm"; ValueType: String; ValueData: "LazPaint.AssocFile.xpm"; Flags: uninsdeletekey
+Root: HKLM; Subkey: "Software\LazPaint\Capabilities\FileAssociations"; ValueName: ".webp"; ValueType: String; ValueData: "LazPaint.AssocFile.webp"; Flags: uninsdeletekey
+Root: HKLM; Subkey: "Software\LazPaint\Capabilities\FileAssociations"; ValueName: ".tga"; ValueType: String; ValueData: "LazPaint.AssocFile.tga"; Flags: uninsdeletekey
+Root: HKLM; Subkey: "Software\LazPaint\Capabilities\FileAssociations"; ValueName: ".cur"; ValueType: String; ValueData: "LazPaint.AssocFile.cur"; Flags: uninsdeletekey
 
 
 Root: HKLM; Subkey: "Software\RegisteredApplications"; ValueType: String; ValueName: "LazPaint"; ValueData: "Software\LazPaint\Capabilities"; Flags: uninsdeletevalue uninsdeletekeyifempty
 Root: HKLM; Subkey: "Software\RegisteredApplications"; ValueType: String; ValueName: "LazPaint"; ValueData: "Software\LazPaint\Capabilities"; Flags: uninsdeletevalue uninsdeletekeyifempty

+ 2 - 1
lazpaint/tablet/laztabletwin.pas

@@ -81,6 +81,7 @@ var
   AContext: TLogContext;
   AContext: TLogContext;
 begin
 begin
   inherited Create(AOwner);
   inherited Create(AOwner);
+  FTablet := nil;
   FTablet := TTablet.Create(Self);
   FTablet := TTablet.Create(Self);
 
 
   FTablet.OnPacket := @TabletPacket;
   FTablet.OnPacket := @TabletPacket;
@@ -118,7 +119,7 @@ end;
 
 
 destructor TCustomLazTablet.Destroy;
 destructor TCustomLazTablet.Destroy;
 begin
 begin
-  FTablet.Close;
+  if Assigned(FTablet) then FTablet.Close;
   inherited Destroy;
   inherited Destroy;
 end;
 end;
 
 

+ 28 - 16
lazpaint/tools/utoolvectorial.pas

@@ -926,7 +926,7 @@ function TEditShapeTool.Render(VirtualScreen: TBGRABitmap; VirtualScreenWidth,
   BitmapToVirtualScreen: TBitmapToVirtualScreenFunction): TRect;
   BitmapToVirtualScreen: TBitmapToVirtualScreenFunction): TRect;
 var
 var
   orig, xAxis, yAxis: TPointF;
   orig, xAxis, yAxis: TPointF;
-  viewMatrix: TAffineMatrix;
+  viewMatrix, editMatrix: TAffineMatrix;
 begin
 begin
   if InvalidEditMode then StopEdit(false,false);
   if InvalidEditMode then StopEdit(false,false);
   with LayerOffset do
   with LayerOffset do
@@ -968,15 +968,21 @@ begin
         FRectEditor.PointSize := DoScaleX(PointSize,OriginalDPI);
         FRectEditor.PointSize := DoScaleX(PointSize,OriginalDPI);
       end;
       end;
       FRectEditor.Clear;
       FRectEditor.Clear;
-      FRectEditor.Matrix := AffineMatrixTranslation(-0.5,-0.5)*viewMatrix*AffineMatrixTranslation(0.5,0.5);
-      if Assigned(FOriginalRect) then FOriginalRect.ConfigureEditor(FRectEditor);
-      if Assigned(FSelectionRect) then FSelectionRect.ConfigureEditor(FRectEditor);
-      if Assigned(VirtualScreen) then
-        result := FRectEditor.Render(VirtualScreen,
-          rect(0,0,VirtualScreenWidth,VirtualScreenHeight))
+      editMatrix := AffineMatrixTranslation(-0.5,-0.5)*viewMatrix*AffineMatrixTranslation(0.5,0.5);
+      if IsAffineMatrixInversible(editMatrix) then
+      begin
+        FRectEditor.Matrix := editMatrix;
+        if Assigned(FOriginalRect) then FOriginalRect.ConfigureEditor(FRectEditor);
+        if Assigned(FSelectionRect) then FSelectionRect.ConfigureEditor(FRectEditor);
+        if Assigned(VirtualScreen) then
+          result := FRectEditor.Render(VirtualScreen,
+            rect(0,0,VirtualScreenWidth,VirtualScreenHeight))
+        else
+          result := FRectEditor.GetRenderBounds(
+            rect(0,0,VirtualScreenWidth,VirtualScreenHeight));
+      end
       else
       else
-        result := FRectEditor.GetRenderBounds(
-          rect(0,0,VirtualScreenWidth,VirtualScreenHeight));
+        result := EmptyRect;
     end;
     end;
   else
   else
     begin
     begin
@@ -2320,6 +2326,7 @@ function TVectorialTool.Render(VirtualScreen: TBGRABitmap; VirtualScreenWidth,
   BitmapToVirtualScreen: TBitmapToVirtualScreenFunction): TRect;
   BitmapToVirtualScreen: TBitmapToVirtualScreenFunction): TRect;
 var
 var
   orig, xAxis, yAxis: TPointF;
   orig, xAxis, yAxis: TPointF;
+  editMatrix: TAffineMatrix;
 begin
 begin
   if Assigned(FShape) then
   if Assigned(FShape) then
   begin
   begin
@@ -2329,14 +2336,19 @@ begin
       xAxis := BitmapToVirtualScreen(PointF(1,0));
       xAxis := BitmapToVirtualScreen(PointF(1,0));
       yAxis := BitmapToVirtualScreen(PointF(0,1));
       yAxis := BitmapToVirtualScreen(PointF(0,1));
     end;
     end;
-    Editor.Matrix := AffineMatrix(xAxis-orig,yAxis-orig,orig)*VectorTransform(true);
     Editor.Clear;
     Editor.Clear;
-    Editor.PointSize := DoScaleX(PointSize, OriginalDPI);
-    if Assigned(FShape) then FShape.ConfigureEditor(Editor);
-    if Assigned(VirtualScreen) then
-      Result:= Editor.Render(VirtualScreen, rect(0,0,VirtualScreen.Width,VirtualScreen.Height))
-    else
-      Result:= Editor.GetRenderBounds(rect(0,0,VirtualScreenWidth,VirtualScreenHeight));
+    editMatrix := AffineMatrix(xAxis-orig,yAxis-orig,orig)*VectorTransform(true);
+    if IsAffineMatrixInversible(editMatrix) then
+    begin
+      Editor.Matrix := editMatrix;
+      Editor.PointSize := DoScaleX(PointSize, OriginalDPI);
+      if Assigned(FShape) then FShape.ConfigureEditor(Editor);
+      if Assigned(VirtualScreen) then
+        Result:= Editor.Render(VirtualScreen, rect(0,0,VirtualScreen.Width,VirtualScreen.Height))
+      else
+        Result:= Editor.GetRenderBounds(rect(0,0,VirtualScreenWidth,VirtualScreenHeight));
+    end else
+      result := EmptyRect;
   end else
   end else
   begin
   begin
     result := EmptyRect;
     result := EmptyRect;

+ 17 - 42
lazpaint/ufileextensions.pas

@@ -181,53 +181,28 @@ begin
   if AUppercase then Result:=UTF8UpperCase(AStrUtf8) else Result:= UTF8LowerCase(AStrUtf8);
   if AUppercase then Result:=UTF8UpperCase(AStrUtf8) else Result:= UTF8LowerCase(AStrUtf8);
 end;
 end;
 
 
-{(en) Generates all possible upper and lowercase combinations of a string}
+{(en) Generates various cases that may be encountered}
 function SingleExtAllCases (ASingleExtension: string; Delimiter: String=';'; Prefix: string=''; Suffix: String=''):string;
 function SingleExtAllCases (ASingleExtension: string; Delimiter: String=';'; Prefix: string=''; Suffix: String=''):string;
 var
 var
-  FWord,FChar:integer;
-  Len: integer;
-  Count: integer;
-  OrigArray,LCArray,UCArray: array of String;
-  CExt:string='';
-  Cased: Boolean;
+  otherCase: String;
 begin
 begin
-  Result := '';
-  Len:= Length(ASingleExtension);
-  Len:=UTF8Length(ASingleExtension);
-  Count:=(1 shl len) - 1;
-  SetLength(OrigArray,Len);
-  SetLength(LCArray,Len);
-  SetLength(UCArray,Len);
-  for FChar:=0 to Len -1 do
-  begin
-     OrigArray[FChar]:=Utf8Copy (ASingleExtension,FChar+1,1);
-     LCArray[FChar]:=UTF8LowerCase(OrigArray[FChar]);
-     UCArray[FChar]:=UTF8UpperCase(OrigArray[FChar]);
-  end;
-  for FWord:=0 to Count do
-  begin
-    CExt:='';
-    Cased:=True;
-    for FChar:=0 to Len-1 do
-    begin
-      if not GetBit(FWord,FChar) or (LCArray[FChar]<>UCArray[FChar]) then
-      begin
-        if (OrigArray[FChar] = UCArray[FChar]) xor GetBit(FWord,FChar) then
-          CExt += UCArray[FChar]
-        else
-          CExt += LCArray[FChar];
-      end
-      else begin Cased:= False; Break; end;
-    end; //for FChar
-    if Cased then
-    begin
-      if length(Result) > 0 then result += Delimiter;
-      Result:= Result+ Prefix+ CExt + Suffix;
-    end;  //if
-  end; //for FWord
+  Result := Prefix + ASingleExtension + Suffix;
+
+  otherCase := UTF8LowerCase(ASingleExtension);
+  if otherCase <> ASingleExtension then
+    Result += Delimiter + Prefix + otherCase + Suffix;
+
+  otherCase := UTF8UpperCase(ASingleExtension);
+  if otherCase <> ASingleExtension then
+    Result += Delimiter + Prefix + otherCase + Suffix;
+
+  otherCase := UTF8UpperCase(UTF8Copy(ASingleExtension, 1, 1)) +
+               UTF8LowerCase(UTF8Copy(ASingleExtension, 2, UTF8Length(ASingleExtension) - 1));
+  if otherCase <> ASingleExtension then
+    Result += Delimiter + Prefix + otherCase + Suffix;
 end;
 end;
 
 
-{(en) Generates all possible upper and lowercase combinations of file extensions}
+{(en) Generates various cases of file extensions}
 function ExtensionsAllCases (AllExtensions: String; ADelimiter: string = ';'; APrefix:string = '*.'): String;
 function ExtensionsAllCases (AllExtensions: String; ADelimiter: string = ';'; APrefix:string = '*.'): String;
 var
 var
   ExtList: TStringList;
   ExtList: TStringList;

+ 170 - 0
lazpaint/uiconcache.pas

@@ -0,0 +1,170 @@
+unit UIconCache;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, BGRABitmap;
+
+procedure AddToCache(AFilenames: array of string; ALastModifications: array of TDateTime;
+          AIconSize: integer);
+function GetCachedIcon(AFilename: string; ALastModification: TDateTime; AInvalidIcon: TBGRABitmap): TBGRABitmap;
+procedure StopCaching(AWait: boolean = false);
+function IsCacheBusy: boolean;
+
+implementation
+
+uses URaw, BGRAThumbnail, UFileSystem, BGRAReadLzp, BGRABitmapTypes, BGRAWriteLzp;
+
+const
+  MaxIconCacheCount = 512;
+
+type
+
+  { TIconCacheThread }
+
+  TIconCacheThread = class(TThread)
+  private
+    FFilenames: array of string;
+    FLastModifications: array of TDateTime;
+    FIconSize: integer;
+  public
+    constructor Create(AFilenames: array of string;
+      ALastModifications: array of TDateTime; AIconSize: integer);
+    procedure Execute; override;
+  end;
+
+var
+  IconCache: TStringList;
+  IconCacheInvalid: TStringList;
+  CacheThread: TIconCacheThread;
+
+procedure AddToCache(AFilenames: array of string;
+  ALastModifications: array of TDateTime; AIconSize: integer);
+begin
+  if IsCacheBusy then
+    raise exception.Create('Cache is busy');
+  FreeAndNil(CacheThread);
+  CacheThread := TIconCacheThread.Create(AFilenames, ALastModifications, AIconSize);
+end;
+
+function GetCachedIcon(AFilename: string; ALastModification: TDateTime; AInvalidIcon: TBGRABitmap): TBGRABitmap;
+var
+  cacheName, dummyCaption: String;
+  cacheIndex: Integer;
+begin
+  if IsCacheBusy then exit(nil);
+  cacheName := AFilename+':'+FloatToStr(ALastModification);
+  cacheIndex := IconCache.IndexOf(cacheName);
+  if cacheIndex <> -1 then
+  begin
+    TStream(IconCache.Objects[cacheIndex]).Position:= 0;
+    result := TBGRABitmap.Create;
+    TBGRAReaderLazPaint.LoadRLEImage(TStream(IconCache.Objects[cacheIndex]), result, dummyCaption);
+    exit;
+  end else
+  if IconCacheInvalid.IndexOf(cacheName) <> -1 then
+    exit(AInvalidIcon)
+  else
+    exit(nil);
+end;
+
+procedure StopCaching(AWait: boolean);
+begin
+  if Assigned(CacheThread) then
+  begin
+    CacheThread.Terminate;
+    if AWait then CacheThread.WaitFor;
+  end;
+end;
+
+function IsCacheBusy: boolean;
+begin
+  result := Assigned(CacheThread) and not CacheThread.Finished;
+end;
+
+{ TIconCacheThread }
+
+constructor TIconCacheThread.Create(AFilenames: array of string;
+  ALastModifications: array of TDateTime; AIconSize: integer);
+var
+  i: Integer;
+begin
+  if length(AFilenames)<>length(ALastModifications) then
+    raise exception.Create('Array size mismatch');
+  setlength(FFilenames, length(AFilenames));
+  setlength(FLastModifications, length(FFilenames));
+  for i := 0 to high(FFilenames) do
+  begin
+    FFilenames[i] := AFilenames[i];
+    FLastModifications[i] := ALastModifications[i];
+  end;
+  FIconSize := AIconSize;
+
+  inherited Create(False);
+end;
+
+procedure TIconCacheThread.Execute;
+var
+  i, cacheIndex: Integer;
+  cacheName: String;
+  bmpIcon: TBGRABitmap;
+  found: Boolean;
+  s: TStream;
+  mem: TMemoryStream;
+  endTime: TDateTime;
+begin
+  bmpIcon := TBGRABitmap.Create;
+  endTime := Now + 150/MSecsPerDay;
+  for i := 0 to high(FFilenames) do
+  begin
+    if Terminated or (Now > endTime) then break;
+    cacheName := FFilenames[i] + ':' + FloatToStr(FLastModifications[i]);
+    cacheIndex := IconCache.IndexOf(cacheName);
+    if cacheIndex <> -1 then Continue;
+    try
+      s := FileManager.CreateFileStream(FFilenames[i], fmOpenRead or fmShareDenyWrite);
+      try
+        if IsRawFilename(FFilenames[i]) then
+        begin
+          found := GetRawStreamThumbnail(s, FIconSize, FIconSize, BGRAPixelTransparent,
+                                         True, bmpIcon) <> nil;
+        end else
+          found := GetStreamThumbnail(s, FIconSize, FIconSize, BGRAPixelTransparent,
+                                         True, ExtractFileExt(FFilenames[i]), bmpIcon) <> nil;
+      finally
+        s.Free;
+      end;
+    except
+      found := false;
+    end;
+    if found then
+    begin
+      if IconCache.Count >= MaxIconCacheCount then IconCache.Delete(0);
+      mem := TMemoryStream.Create;
+      TBGRAWriterLazPaint.WriteRLEImage(mem, bmpIcon);
+      IconCache.AddObject(cacheName, mem); //mem owned by IconCache
+    end else
+      IconCacheInvalid.Add(cacheName);
+  end;
+  bmpIcon.Free;
+end;
+
+
+initialization
+
+  IconCache := TStringList.Create;
+  IconCache.CaseSensitive := true;
+  IconCache.OwnsObjects := true;
+  IconCacheInvalid := TStringList.Create;
+  IconCacheInvalid.CaseSensitive := true;
+
+finalization
+
+  StopCaching(true);
+  CacheThread.Free;
+  IconCacheInvalid.Free;
+  IconCache.Free;
+
+end.

+ 18 - 4
lazpaint/uraw.pas

@@ -58,6 +58,9 @@ implementation
 
 
 uses process, BGRAThumbnail, UResourceStrings, UFileSystem, Forms, LazFileUtils;
 uses process, BGRAThumbnail, UResourceStrings, UFileSystem, Forms, LazFileUtils;
 
 
+var
+  RawCriticalSection: TRTLCriticalSection;
+
 function GetAllRawExtensions: string;
 function GetAllRawExtensions: string;
 var
 var
   i: Integer;
   i: Integer;
@@ -83,12 +86,18 @@ begin
   tempName := '';
   tempName := '';
   p := nil;
   p := nil;
   try
   try
-    tempName := GetTempFileName;
-    s := TFileStream.Create(tempName, fmCreate);
+
+    EnterCriticalsection(RawCriticalSection);
     try
     try
-      s.CopyFrom(AInputStream, AInputStream.Size);
+      tempName := GetTempFileName;
+      s := TFileStream.Create(tempName, fmCreate);
+      try
+        s.CopyFrom(AInputStream, AInputStream.Size);
+      finally
+        s.Free;
+      end;
     finally
     finally
-      s.Free;
+      LeaveCriticalsection(RawCriticalSection);
     end;
     end;
 
 
     p := TProcess.Create(nil);
     p := TProcess.Create(nil);
@@ -218,6 +227,11 @@ end;
 initialization
 initialization
 
 
   AllRawExtensions := GetAllRawExtensions;
   AllRawExtensions := GetAllRawExtensions;
+  InitCriticalSection(RawCriticalSection);
+
+finalization
+
+  DoneCriticalsection(RawCriticalSection);
 
 
 end.
 end.
 
 

+ 5 - 3
lazpaintcontrols/lcvectororiginal.pas

@@ -2427,6 +2427,7 @@ var
   sb: TRectF;
   sb: TRectF;
   m: TAffineMatrix;
   m: TAffineMatrix;
 begin
 begin
+  if not IsAffineMatrixInversible(AMatrix) then exit;
   sb := GetAlignBounds(ABounds, AMatrix);
   sb := GetAlignBounds(ABounds, AMatrix);
   case AAlign of
   case AAlign of
   taRightJustify: m := AffineMatrixTranslation(ABounds.Right-sb.Right,0);
   taRightJustify: m := AffineMatrixTranslation(ABounds.Right-sb.Right,0);
@@ -2442,6 +2443,7 @@ var
   sb: TRectF;
   sb: TRectF;
   m: TAffineMatrix;
   m: TAffineMatrix;
 begin
 begin
+  if not IsAffineMatrixInversible(AMatrix) then exit;
   sb := GetAlignBounds(ABounds, AMatrix);
   sb := GetAlignBounds(ABounds, AMatrix);
   case AAlign of
   case AAlign of
   tlBottom: m := AffineMatrixTranslation(0,ABounds.Bottom-sb.Bottom);
   tlBottom: m := AffineMatrixTranslation(0,ABounds.Bottom-sb.Bottom);
@@ -3234,9 +3236,9 @@ begin
       allRectF := rectF(0,0,ADest.Width,ADest.Height);
       allRectF := rectF(0,0,ADest.Width,ADest.Height);
       FUnfrozenRangeStart := newUnfrozenRangeStart;
       FUnfrozenRangeStart := newUnfrozenRangeStart;
       FUnfrozenRangeEnd := newUnfrozenRangeEnd;
       FUnfrozenRangeEnd := newUnfrozenRangeEnd;
+      FreeAndNil(FFrozenShapesUnderSelection);
       if FUnfrozenRangeStart > 0 then
       if FUnfrozenRangeStart > 0 then
       begin
       begin
-        FreeAndNil(FFrozenShapesUnderSelection);
         FFrozenShapesUnderBounds := GetRenderBounds(rect(0,0,ADest.Width,ADest.Height), mOfs,
         FFrozenShapesUnderBounds := GetRenderBounds(rect(0,0,ADest.Width,ADest.Height), mOfs,
                                       0, FUnfrozenRangeStart-1);
                                       0, FUnfrozenRangeStart-1);
         FFrozenShapesUnderBounds.Intersect(rect(0,0,ADest.Width,ADest.Height));
         FFrozenShapesUnderBounds.Intersect(rect(0,0,ADest.Width,ADest.Height));
@@ -3261,10 +3263,10 @@ begin
       for i := FUnfrozenRangeStart to FUnfrozenRangeEnd-1 do
       for i := FUnfrozenRangeStart to FUnfrozenRangeEnd-1 do
         if FShapes[i].GetRenderBounds(ADest.ClipRect, mOfs, []).IntersectsWith(clipRectF) then
         if FShapes[i].GetRenderBounds(ADest.ClipRect, mOfs, []).IntersectsWith(clipRectF) then
           FShapes[i].Render(ADest, ARenderOffset, AMatrix, ADraft);
           FShapes[i].Render(ADest, ARenderOffset, AMatrix, ADraft);
+      FreeAndNil(FFrozenShapesOverSelection);
       if FUnfrozenRangeEnd < FShapes.Count then
       if FUnfrozenRangeEnd < FShapes.Count then
       begin
       begin
-        FreeAndNil(FFrozenShapesOverSelection);
-        FFrozenShapesOverBounds := GetRenderBounds(rect(0,0,ADest.Width,ADest.Height), AMatrix,
+        FFrozenShapesOverBounds := GetRenderBounds(rect(0,0,ADest.Width,ADest.Height), mOfs,
                                      FUnfrozenRangeEnd, FShapes.Count-1);
                                      FUnfrozenRangeEnd, FShapes.Count-1);
         FFrozenShapesOverBounds.Intersect(rect(0,0,ADest.Width,ADest.Height));
         FFrozenShapesOverBounds.Intersect(rect(0,0,ADest.Width,ADest.Height));
         FFrozenShapesOverSelection := TBGRABitmap.Create(FFrozenShapesOverBounds.Width, FFrozenShapesOverBounds.Height);
         FFrozenShapesOverSelection := TBGRABitmap.Create(FFrozenShapesOverBounds.Width, FFrozenShapesOverBounds.Height);

+ 1 - 0
lazpaintcontrols/lcvectorpolyshapes.pas

@@ -1102,6 +1102,7 @@ var
   i, nbTotal: Integer;
   i, nbTotal: Integer;
 begin
 begin
   FViewMatrix := AEditor.Matrix;
   FViewMatrix := AEditor.Matrix;
+  if not IsAffineMatrixInversible(FViewMatrix) then exit;
   FViewMatrixInverse := AffineMatrixInverse(FViewMatrix);
   FViewMatrixInverse := AffineMatrixInverse(FViewMatrix);
   FGridMatrix := AEditor.GridMatrix;
   FGridMatrix := AEditor.GridMatrix;
 
 

+ 9 - 5
lazpaintcontrols/lcvectorrectshapes.pas

@@ -243,10 +243,12 @@ procedure TPhongShapeDiff.Unapply(AEndShape: TVectorShape);
 begin
 begin
   with (AEndShape as TPhongShape) do
   with (AEndShape as TPhongShape) do
   begin
   begin
+    BeginUpdate;
     FShapeKind := FStartShapeKind;
     FShapeKind := FStartShapeKind;
     FLightPosition := FStartLightPosition;
     FLightPosition := FStartLightPosition;
     FShapeAltitudePercent := FStartShapeAltitudePercent;
     FShapeAltitudePercent := FStartShapeAltitudePercent;
     FBorderSizePercent := FStartBorderSizePercent;
     FBorderSizePercent := FStartBorderSizePercent;
+    EndUpdate;
   end;
   end;
 end;
 end;
 
 
@@ -1624,7 +1626,7 @@ var
   mapWidth,mapHeight: integer;
   mapWidth,mapHeight: integer;
   shader: TPhongShading;
   shader: TPhongShading;
   approxFactor,borderSize: single;
   approxFactor,borderSize: single;
-  m: TAffineMatrix;
+  m,mInv: TAffineMatrix;
   h, lightPosZ: single;
   h, lightPosZ: single;
   map,raster: TBGRABitmap;
   map,raster: TBGRABitmap;
   u,v,lightPosF: TPointF;
   u,v,lightPosF: TPointF;
@@ -1644,9 +1646,9 @@ begin
 
 
   //determine map size before transform
   //determine map size before transform
   ab := GetAffineBox(AMatrix, false);
   ab := GetAffineBox(AMatrix, false);
+  if (ab.Width = 0) or (ab.Height = 0) then exit;
   if ab.Width > ab.Height then
   if ab.Width > ab.Height then
   begin
   begin
-    if ab.Width = 0 then exit;
     mapWidth := ceil(ab.Width);
     mapWidth := ceil(ab.Width);
     mapHeight := ceil(ab.Surface/ab.Width);
     mapHeight := ceil(ab.Surface/ab.Width);
   end else
   end else
@@ -1672,6 +1674,8 @@ begin
   v := (ab.BottomLeft-ab.TopLeft)*(1/ab.Height);
   v := (ab.BottomLeft-ab.TopLeft)*(1/ab.Height);
   m := AffineMatrix(u,v,ab.TopLeft)*AffineMatrixScale(ab.Width/mapWidth,ab.Height/mapHeight);
   m := AffineMatrix(u,v,ab.TopLeft)*AffineMatrixScale(ab.Width/mapWidth,ab.Height/mapHeight);
   borderSize := FBorderSizePercent/200*min(ab.Width,ab.Height);
   borderSize := FBorderSizePercent/200*min(ab.Width,ab.Height);
+  if not IsAffineMatrixInversible(m) then exit;
+  mInv := AffineMatrixInverse(m);
 
 
   try
   try
     //create height map
     //create height map
@@ -1713,7 +1717,7 @@ begin
       end;
       end;
     end;
     end;
 
 
-    abRaster := AffineMatrixInverse(m)*TAffineBox.AffineBox(rectRenderF);
+    abRaster := mInv*TAffineBox.AffineBox(rectRenderF);
     rectRasterF := abRaster.RectBoundsF;
     rectRasterF := abRaster.RectBoundsF;
     rectRaster := rect(floor(rectRasterF.Left),floor(rectRasterF.Top),ceil(rectRasterF.Right),ceil(rectRasterF.Bottom));
     rectRaster := rect(floor(rectRasterF.Left),floor(rectRasterF.Top),ceil(rectRasterF.Right),ceil(rectRasterF.Bottom));
 
 
@@ -1725,7 +1729,7 @@ begin
       shader.AmbientFactor := 0.5;
       shader.AmbientFactor := 0.5;
       shader.NegativeDiffusionFactor := 0.15;
       shader.NegativeDiffusionFactor := 0.15;
       lightPosF := AffineMatrixTranslation(-rectRaster.Left,-rectRaster.Top)
       lightPosF := AffineMatrixTranslation(-rectRaster.Left,-rectRaster.Top)
-                    *AffineMatrixInverse(m)*AMatrix*FLightPosition;
+                    *mInv*AMatrix*FLightPosition;
       lightPosZ := 100*Power(approxFactor,1.1);
       lightPosZ := 100*Power(approxFactor,1.1);
       if h*3/2 > lightPosZ then lightposZ := h*3/2;
       if h*3/2 > lightPosZ then lightposZ := h*3/2;
       shader.LightPosition3D := Point3D(lightPosF.x,lightPosF.y,lightPosZ);
       shader.LightPosition3D := Point3D(lightPosF.x,lightPosF.y,lightPosZ);
@@ -1735,7 +1739,7 @@ begin
         shader.Draw(raster,map,h,-rectRaster.Left,-rectRaster.Top,BackFill.SolidColor)
         shader.Draw(raster,map,h,-rectRaster.Left,-rectRaster.Top,BackFill.SolidColor)
       else
       else
       begin
       begin
-        scan := BackFill.CreateScanner(AffineMatrixTranslation(-rectRaster.left,-rectRaster.top)*AffineMatrixInverse(m)*AMatrix,ADraft);
+        scan := BackFill.CreateScanner(AffineMatrixTranslation(-rectRaster.left,-rectRaster.top)*mInv*AMatrix,ADraft);
         shader.DrawScan(raster,map,h,-rectRaster.Left,-rectRaster.Top,scan);
         shader.DrawScan(raster,map,h,-rectRaster.Left,-rectRaster.Top,scan);
         scan.Free;
         scan.Free;
       end;
       end;

+ 8 - 2
lazpaintcontrols/lcvectortextshapes.pas

@@ -931,10 +931,13 @@ var
   newPos: Integer;
   newPos: Integer;
   tl: TBidiTextLayout;
   tl: TBidiTextLayout;
   zoom: Single;
   zoom: Single;
+  untransformed: TAffineMatrix;
 begin
 begin
   tl := GetTextLayout;
   tl := GetTextLayout;
   zoom := GetTextRenderZoom;
   zoom := GetTextRenderZoom;
-  newPos := tl.GetCharIndexAt(AffineMatrixScale(zoom,zoom)*AffineMatrixInverse(GetUntransformedMatrix)*PointF(X,Y));
+  untransformed := GetUntransformedMatrix;
+  if not IsAffineMatrixInversible(untransformed) then exit;
+  newPos := tl.GetCharIndexAt(AffineMatrixScale(zoom,zoom)*AffineMatrixInverse(untransformed)*PointF(X,Y));
   if newPos<>-1 then
   if newPos<>-1 then
   begin
   begin
     if (newPos <> FSelEnd) or (not AExtend and (FSelStart <> FSelEnd)) or (UserMode <> vsuEditText) then
     if (newPos <> FSelEnd) or (not AExtend and (FSelStart <> FSelEnd)) or (UserMode <> vsuEditText) then
@@ -1497,12 +1500,15 @@ var
   tl: TBidiTextLayout;
   tl: TBidiTextLayout;
   pt: TPointF;
   pt: TPointF;
   i: Integer;
   i: Integer;
+  untransformed: TAffineMatrix;
 begin
 begin
   if not GetAffineBox(AffineMatrixIdentity,true).Contains(APoint) then
   if not GetAffineBox(AffineMatrixIdentity,true).Contains(APoint) then
     exit(false);
     exit(false);
   SetGlobalMatrix(AffineMatrixIdentity);
   SetGlobalMatrix(AffineMatrixIdentity);
   tl := GetTextLayout;
   tl := GetTextLayout;
-  pt := AffineMatrixInverse(GetUntransformedMatrix)*APoint;
+  untransformed := GetUntransformedMatrix;
+  if not IsAffineMatrixInversible(untransformed) then exit;
+  pt := AffineMatrixInverse(untransformed)*APoint;
   for i := 0 to tl.PartCount-1 do
   for i := 0 to tl.PartCount-1 do
     if tl.PartAffineBox[i].Contains(pt) then exit(true);
     if tl.PartAffineBox[i].Contains(pt) then exit(true);
   result := false;
   result := false;